chore(main): release 1.6.1 (#77) #84
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: Publish image | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| # release-please creates its tags with a PAT (not GITHUB_TOKEN), so that tag | |
| # push isn't subject to GitHub's anti-recursion trigger suppression and the | |
| # `tags:` rule above fires on its own — no dispatch needed. Kept for anyone | |
| # who wants to manually rebuild pinned images from an existing tag. | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Existing vX.Y.Z tag to build pinned images for" | |
| required: true | |
| type: string | |
| # One publish run per ref at a time, but let a superseded run finish rather | |
| # than cancelling it (cancel-in-progress: false). release-please's auto-merge | |
| # means the release-bump commit almost always lands on `main` seconds behind | |
| # the feature commit it bundles — two pushes to the same ref within the same | |
| # concurrency window. With cancel-in-progress: true, whichever of those two | |
| # runs happened to be mid-flight when the other queued got killed, and if | |
| # that was the *later* (release-bump) commit's run, `:latest` stayed built | |
| # from the pre-bump commit until some unrelated future push rebuilt it — | |
| # confirmed live: v1.6.0's `:latest` build was cancelled this way, leaving | |
| # GHCR's `:latest` several commits stale (right features, wrong version | |
| # label) with no error surfaced anywhere. Queueing instead of cancelling | |
| # costs a redundant build occasionally; it never leaves `:latest` wrong. | |
| concurrency: | |
| group: publish-${{ inputs.tag || github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| # Gate the image publish on the same tests CI runs, so a red test never | |
| # ships an image. | |
| verify: | |
| name: Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| # On dispatch, test the tag being built (empty ref = event's own ref). | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ inputs.tag || '' }} | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: "22" | |
| - name: Server tests | |
| working-directory: server | |
| run: npm ci && npm test | |
| - name: Client build | |
| working-directory: client | |
| run: npm ci && npm run build | |
| publish: | |
| name: Build and push to GHCR | |
| needs: verify | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: ${{ inputs.tag || '' }} | |
| # GHCR image names must be lowercase; the owner may not be. | |
| - name: Compute lowercase image name | |
| id: img | |
| run: echo "name=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" | |
| - name: Docker metadata (tags/labels) | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ steps.img.outputs.name }} | |
| flavor: latest=false | |
| # Use explicit ref checks rather than {{is_default_branch}} — the | |
| # repo's default branch isn't necessarily `main`, which would leave | |
| # a push to main with zero tags (and buildx refuses to push then). | |
| # The `value=` semver entries cover dispatch (github.ref is main | |
| # there, so the ref-derived semver entries produce nothing). | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{version}},value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }} | |
| type=semver,pattern={{major}}.{{minor}},value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }} | |
| type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }} | |
| # Pin a recent QEMU build. The default binfmt image lagged the toolchain | |
| # in node:22-alpine (gcc 15 / musl 1.2.6), and emulating those newer | |
| # arm64 binaries crashed with "uncaught target signal 4 (Illegal | |
| # instruction)", which core-dumped and left the build hung. A current | |
| # QEMU emulates the new userspace correctly. | |
| - uses: docker/setup-qemu-action@v4 | |
| with: | |
| image: tonistiigi/binfmt:qemu-v10.2.3 | |
| - uses: docker/setup-buildx-action@v4 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| file: server/Dockerfile | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # NOTE: the GitHub Release itself is created by release-please.yml (with a | |
| # changelog grouped by feat/fix/deps), not here — it creates the git tag as a | |
| # side effect of publishing the Release, which is what triggers this workflow's | |
| # tag push above. See release-please-config.json / release-please.yml. |