| 1 | name: Branch Artifacts |
| 2 | |
| 3 | permissions: |
| 4 | contents: read |
| 5 | packages: write |
| 6 | |
| 7 | on: |
| 8 | workflow_dispatch: |
| 9 | inputs: |
| 10 | ref: |
| 11 | description: Branch, tag, or commit SHA to build. Leave empty to build the workflow branch. |
| 12 | required: false |
| 13 | |
| 14 | env: |
| 15 | BUILD_REF: ${{ inputs.ref || github.ref_name }} |
| 16 | REGISTRY: ghcr.io |
| 17 | PLATFORMS: linux/amd64,linux/arm64 |
| 18 | |
| 19 | concurrency: |
| 20 | group: branch-artifacts-${{ inputs.ref || github.ref_name }} |
| 21 | cancel-in-progress: true |
| 22 | |
| 23 | jobs: |
| 24 | build: |
| 25 | name: Build Artifacts |
| 26 | runs-on: ubuntu-latest |
| 27 | |
| 28 | steps: |
| 29 | - name: Checkout selected ref |
| 30 | uses: actions/checkout@v6 |
| 31 | with: |
| 32 | ref: ${{ env.BUILD_REF }} |
| 33 | |
| 34 | - name: Set up Go |
| 35 | uses: actions/setup-go@v6 |
| 36 | with: |
| 37 | go-version-file: go.mod |
| 38 | cache: true |
| 39 | |
| 40 | - name: Prepare artifact metadata |
| 41 | id: meta |
| 42 | shell: bash |
| 43 | run: | |
| 44 | safe_ref="$(printf '%s' "$BUILD_REF" | tr '[:upper:]' '[:lower:]' | tr '/:@' '---' | tr -cd 'a-z0-9._-')" |
| 45 | if [ -z "$safe_ref" ]; then |
| 46 | safe_ref="selected-ref" |
| 47 | fi |
| 48 | safe_ref="${safe_ref:0:80}" |
| 49 | short_sha="$(git rev-parse --short=12 HEAD)" |
| 50 | echo "safe_ref=$safe_ref" >> "$GITHUB_OUTPUT" |
| 51 | echo "short_sha=$short_sha" >> "$GITHUB_OUTPUT" |
| 52 | echo "commit_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" |
| 53 | { |
| 54 | echo "portal_image_tags<<EOF" |
| 55 | echo "${REGISTRY}/gosuda/portal:branch-${safe_ref}" |
| 56 | echo "${REGISTRY}/gosuda/portal:branch-${safe_ref}-${short_sha}" |
| 57 | echo "EOF" |
| 58 | echo "frontend_image_tags<<EOF" |
| 59 | echo "${REGISTRY}/gosuda/portal-frontend:branch-${safe_ref}" |
| 60 | echo "${REGISTRY}/gosuda/portal-frontend:branch-${safe_ref}-${short_sha}" |
| 61 | echo "EOF" |
| 62 | echo "portal_api_image_tags<<EOF" |
| 63 | echo "${REGISTRY}/gosuda/portal-api:branch-${safe_ref}" |
| 64 | echo "${REGISTRY}/gosuda/portal-api:branch-${safe_ref}-${short_sha}" |
| 65 | echo "EOF" |
| 66 | } >> "$GITHUB_OUTPUT" |
| 67 | |
| 68 | - name: Log in to Container Registry |
| 69 | uses: docker/login-action@v3 |
| 70 | with: |
| 71 | registry: ${{ env.REGISTRY }} |
| 72 | username: ${{ github.actor }} |
| 73 | password: ${{ secrets.GITHUB_TOKEN }} |
| 74 | |
| 75 | - name: Set up QEMU |
| 76 | uses: docker/setup-qemu-action@v3 |
| 77 | |
| 78 | - name: Set up Docker Buildx |
| 79 | uses: docker/setup-buildx-action@v3 |
| 80 | |
| 81 | - name: Build and push portal Docker image |
| 82 | uses: docker/build-push-action@v6 |
| 83 | with: |
| 84 | context: . |
| 85 | file: Dockerfile |
| 86 | platforms: ${{ env.PLATFORMS }} |
| 87 | push: true |
| 88 | tags: ${{ steps.meta.outputs.portal_image_tags }} |
| 89 | labels: | |
| 90 | org.opencontainers.image.source=https://github.com/${{ github.repository }} |
| 91 | org.opencontainers.image.revision=${{ steps.meta.outputs.commit_sha }} |
| 92 | org.opencontainers.image.ref.name=${{ env.BUILD_REF }} |
| 93 | cache-from: type=gha,scope=portal |
| 94 | cache-to: type=gha,mode=max,scope=portal |
| 95 | |
| 96 | - name: Build and push frontend Docker image |
| 97 | uses: docker/build-push-action@v6 |
| 98 | with: |
| 99 | context: ./frontend |
| 100 | file: ./frontend/Dockerfile |
| 101 | platforms: ${{ env.PLATFORMS }} |
| 102 | push: true |
| 103 | tags: ${{ steps.meta.outputs.frontend_image_tags }} |
| 104 | labels: | |
| 105 | org.opencontainers.image.source=https://github.com/${{ github.repository }} |
| 106 | org.opencontainers.image.revision=${{ steps.meta.outputs.commit_sha }} |
| 107 | org.opencontainers.image.ref.name=${{ env.BUILD_REF }} |
| 108 | cache-from: type=gha,scope=frontend |
| 109 | cache-to: type=gha,mode=max,scope=frontend |
| 110 | |
| 111 | - name: Build and push portal API Docker image |
| 112 | uses: docker/build-push-action@v6 |
| 113 | with: |
| 114 | context: ./frontend |
| 115 | file: ./frontend/Dockerfile |
| 116 | target: api |
| 117 | platforms: ${{ env.PLATFORMS }} |
| 118 | push: true |
| 119 | tags: ${{ steps.meta.outputs.portal_api_image_tags }} |
| 120 | labels: | |
| 121 | org.opencontainers.image.source=https://github.com/${{ github.repository }} |
| 122 | org.opencontainers.image.revision=${{ steps.meta.outputs.commit_sha }} |
| 123 | org.opencontainers.image.ref.name=${{ env.BUILD_REF }} |
| 124 | cache-from: type=gha,scope=portal-api |
| 125 | cache-to: type=gha,mode=max,scope=portal-api |
| 126 | |
| 127 | - name: Build binaries |
| 128 | shell: bash |
| 129 | run: | |
| 130 | mkdir -p release |
| 131 | |
| 132 | make build-tunnel |
| 133 | cp cmd/relay-server/dist/tunnel/portal-* release/ |
| 134 | |
| 135 | for GOARCH in amd64 arm64; do |
| 136 | out="release/relay-server-linux-${GOARCH}" |
| 137 | echo " - ${out}" |
| 138 | CGO_ENABLED=0 GOOS=linux GOARCH="${GOARCH}" go build -trimpath -ldflags "-s -w" -o "${out}" ./cmd/relay-server |
| 139 | done |
| 140 | |
| 141 | cp cmd/portal-tunnel/installer/install.sh release/install.sh |
| 142 | cp cmd/portal-tunnel/installer/install.ps1 release/install.ps1 |
| 143 | |
| 144 | - name: Generate SHA256 checksums |
| 145 | shell: bash |
| 146 | run: | |
| 147 | cd release |
| 148 | sha256sum * > checksums.txt |
| 149 | while read -r sum file; do |
| 150 | printf '%s %s\n' "$sum" "$file" > "${file}.sha256" |
| 151 | done < checksums.txt |
| 152 | |
| 153 | - name: Upload artifact |
| 154 | uses: actions/upload-artifact@v4 |
| 155 | with: |
| 156 | name: portal-${{ steps.meta.outputs.safe_ref }}-${{ steps.meta.outputs.short_sha }} |
| 157 | path: release/* |
| 158 | if-no-files-found: error |