|
| 1 | +# Tags and publishes an alpha release when its release PR is merged. |
| 2 | +# |
| 3 | +# Triggered when a `release/alpha-*` PR (opened by "Prepare Alpha Release") is |
| 4 | +# merged into `alpha`. It builds, pushes the `v<version>` tag, and publishes |
| 5 | +# @reearth/core to the npm `alpha` dist-tag. |
| 6 | +# |
| 7 | +# Publishing is secured via npm Trusted Publishing (OIDC): no NPM_TOKEN, no PAT, |
| 8 | +# no GitHub App. Auth is a short-lived OIDC handshake and every publish carries |
| 9 | +# a provenance attestation (verify with `npm audit signatures`). |
| 10 | +# |
| 11 | +# Tag + publish are combined into this single job on purpose: a tag pushed by |
| 12 | +# GITHUB_TOKEN does not trigger other workflows, so publishing here (rather than |
| 13 | +# in a separate `on: push: tags` workflow) is what lets us avoid a privileged |
| 14 | +# token entirely. |
| 15 | +# |
| 16 | +# npm Trusted Publisher (one-time, already configured on npmjs.com): |
| 17 | +# @reearth/core -> repo reearth/core, workflow release_alpha.yml, action |
| 18 | +# "npm publish". Keep this file named release_alpha.yml so that stays valid. |
| 19 | +# |
| 20 | +# beta/latest still publish via npm_release.yml + NPM_TOKEN and are unaffected. |
| 21 | + |
| 22 | +name: Release Alpha |
| 23 | + |
1 | 24 | on: |
2 | | - push: |
3 | | - branches: alpha |
4 | | - paths-ignore: |
5 | | - - "package.json" |
6 | | - workflow_dispatch: |
| 25 | + pull_request: |
| 26 | + types: [closed] |
| 27 | + |
| 28 | +permissions: |
| 29 | + contents: write # push the version tag |
| 30 | + id-token: write # OIDC token for npm Trusted Publishing + provenance |
7 | 31 |
|
8 | 32 | jobs: |
9 | | - release: |
10 | | - permissions: |
11 | | - contents: write |
12 | | - uses: reearth/core/.github/workflows/npm_release.yml@beta |
13 | | - with: |
14 | | - branch: alpha |
15 | | - tag: alpha |
16 | | - version-args: --preid alpha prerelease |
17 | | - secrets: |
18 | | - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} |
19 | | - PAT: ${{ secrets.PAT }} |
| 33 | + publish: |
| 34 | + name: Tag and publish alpha |
| 35 | + runs-on: ubuntu-latest |
| 36 | + # Gates the whole job (tag + publish) on a required reviewer approving the |
| 37 | + # npm-publish environment, so a merged PR can't auto-publish unreviewed. |
| 38 | + environment: npm-publish |
| 39 | + # Only for merged release PRs into alpha (not every closed PR). |
| 40 | + if: >- |
| 41 | + github.event.pull_request.merged == true && |
| 42 | + github.event.pull_request.base.ref == 'alpha' && |
| 43 | + startsWith(github.event.pull_request.head.ref, 'release/alpha-') |
| 44 | + steps: |
| 45 | + - uses: actions/checkout@v4 |
| 46 | + with: |
| 47 | + ref: ${{ github.event.pull_request.merge_commit_sha }} |
| 48 | + - uses: actions/setup-node@v4 |
| 49 | + with: |
| 50 | + # Trusted Publishing requires Node >=22.14 and npm >=11.5.1. Pin a |
| 51 | + # concrete >=22.14 version so the floor can't regress via runner |
| 52 | + # installer changes. |
| 53 | + node-version: 22.14.0 |
| 54 | + registry-url: "https://registry.npmjs.org" |
| 55 | + - name: Run install |
| 56 | + run: yarn install --frozen-lockfile |
| 57 | + - name: Build |
| 58 | + run: yarn build |
| 59 | + - name: Verify tag matches package.json version |
| 60 | + id: version |
| 61 | + run: | |
| 62 | + VERSION=$(node -p "require('./package.json').version") |
| 63 | + echo "version=$VERSION" >> "$GITHUB_OUTPUT" |
| 64 | + echo "tag=v$VERSION" >> "$GITHUB_OUTPUT" |
| 65 | + echo "Publishing @reearth/core@$VERSION" |
| 66 | + - name: Create and push tag |
| 67 | + run: | |
| 68 | + TAG="${{ steps.version.outputs.tag }}" |
| 69 | + HEAD_SHA=$(git rev-parse HEAD) |
| 70 | + # Commit the remote tag points to (peel annotated tags via ^{}); empty |
| 71 | + # if the tag does not exist remotely. |
| 72 | + REMOTE_SHA=$(git ls-remote --tags origin "refs/tags/${TAG}^{}" | awk '{print $1}') |
| 73 | + [ -z "$REMOTE_SHA" ] && REMOTE_SHA=$(git ls-remote --tags origin "refs/tags/${TAG}" | awk '{print $1}') |
| 74 | + if [ -n "$REMOTE_SHA" ]; then |
| 75 | + if [ "$REMOTE_SHA" = "$HEAD_SHA" ]; then |
| 76 | + echo "Tag ${TAG} already exists and matches HEAD; skipping tag push." |
| 77 | + else |
| 78 | + echo "::error::Tag ${TAG} already exists but points to ${REMOTE_SHA}, not the release commit ${HEAD_SHA}. Refusing to publish a mismatched build." |
| 79 | + exit 1 |
| 80 | + fi |
| 81 | + else |
| 82 | + git config user.name "github-actions[bot]" |
| 83 | + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" |
| 84 | + git tag -a "${TAG}" -m "${TAG}" |
| 85 | + git push origin "${TAG}" |
| 86 | + fi |
| 87 | + - name: Activate npm via corepack |
| 88 | + # Done AFTER all yarn steps: enabling the corepack npm shim earlier makes |
| 89 | + # it intercept `yarn` and fail. Node 22 ships npm 10.x; Trusted Publishing |
| 90 | + # needs >=11.5.1, so activate it just before publishing. |
| 91 | + run: | |
| 92 | + corepack enable npm |
| 93 | + corepack prepare npm@11.5.1 --activate |
| 94 | + npm --version |
| 95 | + - name: Publish to npm with provenance (OIDC) |
| 96 | + # No NPM_TOKEN: auth is the OIDC handshake configured as a Trusted |
| 97 | + # Publisher on npmjs.com. --access public because @reearth/core is scoped. |
| 98 | + run: npm publish --provenance --access public --tag alpha |
0 commit comments