Repository navigation
fix(web): 1.10.0 follow-ups - friendly status copy, migration progres… #514
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Docker Publish | |
| on: | |
| push: | |
| branches: [main, 'release/1.1.x'] | |
| tags: ['v*'] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Image tag (e.g., v1.0.0, latest)' | |
| required: true | |
| default: 'latest' | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| DOCKERHUB_IMAGE: artifactkeeper/web | |
| jobs: | |
| version-check: | |
| name: Version Matches Tag | |
| # Gates the whole publish: a tag build whose package.json disagrees with | |
| # the tag ships a UI that misreports its own version (#784). | |
| # | |
| # The job itself is unconditional and the assertion step carries the `if`, | |
| # rather than the other way round. A job-level `if` that evaluates false is | |
| # *skipped*, and a skipped job skips everything that `needs` it -- which | |
| # would silently disable the build on every branch push. | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Assert package.json version matches the tag | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| run: ./scripts/assert-version-matches-tag.sh "${GITHUB_REF_NAME}" | |
| build: | |
| name: Build (${{ matrix.platform }}) | |
| runs-on: ${{ matrix.runner }} | |
| needs: version-check | |
| permissions: | |
| contents: read | |
| packages: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ak-ci-runners | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 | |
| - name: Log in to Container Registry | |
| uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| platforms: ${{ matrix.platform }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true | |
| cache-from: type=gha,scope=web-${{ matrix.platform }} | |
| cache-to: type=gha,scope=web-${{ matrix.platform }},mode=max | |
| sbom: true | |
| provenance: mode=max | |
| build-args: | | |
| GIT_SHA=${{ github.sha }} | |
| APP_VERSION=${{ github.ref_name }} | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: digests-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge: | |
| name: Multi-Arch Manifest | |
| runs-on: ubuntu-latest | |
| needs: build | |
| outputs: | |
| version: ${{ steps.meta.outputs.version }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - name: Download digests | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Extract metadata (ghcr.io) | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=sha | |
| type=raw,value=dev,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} | |
| type=raw,value=1.1-dev,enable=${{ github.ref == format('refs/heads/{0}', 'release/1.1.x') }} | |
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-') }} | |
| type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }} | |
| - name: Extract metadata (Docker Hub) | |
| id: meta-dockerhub | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 | |
| with: | |
| images: docker.io/${{ env.DOCKERHUB_IMAGE }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=sha | |
| type=raw,value=dev,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} | |
| type=raw,value=1.1-dev,enable=${{ github.ref == format('refs/heads/{0}', 'release/1.1.x') }} | |
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-') }} | |
| type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }} | |
| - name: Create manifest list and push (ghcr.io) | |
| working-directory: /tmp/digests | |
| run: | | |
| docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) | |
| env: | |
| DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }} | |
| - name: Inspect image | |
| id: inspect | |
| run: | | |
| docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | |
| DIGEST=$(docker buildx imagetools inspect --format '{{json .Manifest}}' \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | jq -r '.digest') | |
| echo "digest=${DIGEST}" >> $GITHUB_OUTPUT | |
| - name: Copy to Docker Hub | |
| run: | | |
| docker buildx imagetools create \ | |
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta-dockerhub.outputs.json }}') \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.inspect.outputs.digest }} | |
| - name: Generate artifact attestation | |
| uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 | |
| with: | |
| subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| subject-digest: ${{ steps.inspect.outputs.digest }} | |
| push-to-registry: true | |
| # Deliberately NOT continue-on-error. A soft-failed attestation step | |
| # leaves the job result `success`, so `needs.merge.result` stays green | |
| # and the image publishes with no provenance and no annotation -- | |
| # the failure mode that shipped backend 1.6.1 unsigned | |
| # (artifact-keeper#2824). If provenance cannot be attached, the | |
| # publish should fail loudly. See #815. | |
| # Run compatibility tests AFTER images are published. The gate is advisory: | |
| # it does not block the image publish. If the gate fails, investigate but | |
| # the images are already available for users. | |
| release-gate: | |
| name: Release Gate (Compatibility) | |
| needs: [merge] | |
| if: startsWith(github.ref, 'refs/tags/v') && github.event_name != 'workflow_dispatch' | |
| uses: artifact-keeper/artifact-keeper-test/.github/workflows/release-gate.yml@main | |
| with: | |
| backend_tag: latest | |
| web_tag: ${{ needs.merge.outputs.version }} | |
| test_suite: compatibility | |
| secrets: inherit |