From 45f8b340205ccd794abc2a9ef3b5115a64fa924e Mon Sep 17 00:00:00 2001 From: Andrey Bragin Date: Wed, 9 Sep 2026 13:08:08 +0200 Subject: [PATCH] ci: don't wait for CI workflow when publishing preview releases, replace --dry-run with real publication (#1113) --- .github/workflows/publish.yml | 42 ++++++++++------------------------- docs/RELEASES.md | 14 +++++------- 2 files changed, 18 insertions(+), 38 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ceb64187..a7e23087 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,13 +3,6 @@ on: push: branches: - main - # Previews are gated on CI, so they hang off the CI workflow finishing rather than - # off the push itself. `branches` filters on the *validated* branch, which keeps - # every PR CI run from spawning a Publish and Release run with all jobs skipped. - workflow_run: - workflows: [CI] - types: [completed] - branches: [main] workflow_dispatch: inputs: channel: @@ -92,21 +85,16 @@ jobs: publish-npm-preview: name: Publish preview to npm runs-on: ubuntu-latest - # Every CI-green push to main gets a preview, except release-please's own release - # merge: merging that PR already published this exact tree as a stable version, so - # a preview of it would be a double release. release-please's `releases_created` - # output would be the sharper signal, but it belongs to the push-triggered run and - # this job runs in the workflow_run one, so the commit is checked instead — by - # author and by the subject release-please generates, either of which is enough. + # Every push to main gets a preview without waiting for CI or release-please, + # except release-please's own release merge, which publishes a stable version. + # Check the commit author and the generated release subject to avoid publishing + # the same tree twice; either match is enough to skip the preview. if: >- ${{ (github.event_name == 'workflow_dispatch' && inputs.channel == 'preview') || - (github.event_name == 'workflow_run' - && github.event.workflow_run.conclusion == 'success' - && github.event.workflow_run.event == 'push' - && github.event.workflow_run.head_repository.full_name == github.repository - && github.event.workflow_run.head_commit.author.name != 'acp-release-bot[bot]' - && !startsWith(github.event.workflow_run.head_commit.message, 'chore(main): release ')) + (github.event_name == 'push' + && github.event.head_commit.author.name != 'acp-release-bot[bot]' + && !startsWith(github.event.head_commit.message, 'chore(main): release ')) }} # Same environment as the stable job, so the npm trusted-publisher binding holds. # It carries no required reviewers, so previews never wait for an approval. @@ -128,9 +116,8 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: - # workflow_run runs default to the tip of the default branch, so the commit - # CI actually validated has to be asked for explicitly. - ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.event.workflow_run.head_sha }} + # Publish the exact pushed commit, or the explicitly requested manual ref. + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }} # Brings the tags the version calculation reads as its floor. The repo is a # few megabytes packed, so a full fetch is cheap and sidesteps every # shallow-clone tag caveat. @@ -156,18 +143,13 @@ jobs: # --no-git-tag-version skips every git operation. run: npm version "${{ steps.preview.outputs.version }}" --no-git-tag-version - run: npm run build - # TODO(preview-releases): once one run has proved the trigger, the gate and the - # version calculation on main, drop --dry-run and add - # `echo "published=true" >> "$GITHUB_OUTPUT"` to this step. Nothing else needs - # touching — leaving `published` unset is what keeps the tag and the registry - # dispatch dormant while the publish is only a rehearsal. The workflow_run - # trigger and the `release` environment's protected-branch policy mean this job - # cannot be exercised from a feature branch at all. - name: Publish id: publish # --tag is mandatory: npm publish defaults to `latest` even for a semver # prerelease, which would point every plain `npm install` at a preview. - run: npm publish --dry-run --tag preview + run: | + npm publish --tag preview + echo "published=true" >> "$GITHUB_OUTPUT" outputs: published: ${{ steps.publish.outputs.published }} version: ${{ steps.preview.outputs.version }} diff --git a/docs/RELEASES.md b/docs/RELEASES.md index e881b4b9..cadc4c46 100644 --- a/docs/RELEASES.md +++ b/docs/RELEASES.md @@ -61,9 +61,8 @@ job so that a tag failure can be retried on its own with **Re-run failed jobs** publishing the same one twice fails outright. Both downstream jobs are gated on a `published` output that the publish step -sets, not on whether the publish job went green. That keeps the two concerns -apart — `published` means "npm has this version" and nothing else — and it means -a rehearsal run that only passes `--dry-run` neither tags nor dispatches. +sets only after `npm publish --tag preview` succeeds. This ensures tagging and +the registry update run only after the version has been published to npm. A stable and a preview dispatch can never collide — a release merge publishes stable and skips the preview, every other push does the reverse — so the registry @@ -111,12 +110,11 @@ version _below_ `latest` until the next push lands; that is cosmetic. Release merges are excluded by checking the head commit's author and the subject release-please generates. Both are checked, either is enough, and the cost of a miss is one wasted version number plus a `preview` tag briefly pointing at -already-released code — `latest` is untouched. release-please's own -`releases_created` output would be a sharper signal, but previews hang off the -`CI` workflow finishing rather than off the push, so they run in a different -workflow run from the `release-please` job and cannot read its outputs. +already-released code — `latest` is untouched. Previews start directly on pushes +to `main`, without waiting for CI or the `release-please` job. The commit checks +let previews run independently of release-please's outputs. -To publish a preview by hand — from any commit, bypassing the CI gate: +To publish a preview by hand from any commit: ```sh gh workflow run publish.yml --ref main \