Release release/0.5.8 #36
Workflow file for this run
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
| # Auto-release to npm from version tags or release-branch merges on main. | |
| # | |
| # The workflow publishes in three ways: | |
| # 1. A merged PR from a `release/vX.Y.Z` branch into `main` (the normal | |
| # path — branch name and `package.json` are both validated against | |
| # each other). `gh release create` pushes the tag as a side effect; | |
| # the subsequent tag-push run is short-circuited by the "already on | |
| # npm" check, so there is no infinite loop. | |
| # 2. A `vX.Y.Z` tag push to `main` (escape hatch / re-publish path — | |
| # tag must match `package.json`). | |
| # 3. A manual `workflow_dispatch` (re-publish / same-version dry test). | |
| # | |
| # PR pushes to a `release/v*` branch, force-pushes, and merges of any | |
| # other branch do NOT publish. | |
| # | |
| # Required repo secret: NPM_TOKEN (npm "Automation" access token with publish | |
| # rights for the `orbcode` package). | |
| name: Release | |
| # Per-run title: | |
| # - tag push → "Release v0.3.1" | |
| # - PR merge → "Release release/v0.3.1" | |
| # - dispatch → "Release v0.3.1" if `version` input set, else "Release manual" | |
| # `run-name` only sees github.* and inputs.* — package.json can't be read here. | |
| run-name: >- | |
| Release ${{ | |
| github.event_name == 'push' && github.ref_name || | |
| github.event_name == 'pull_request' && github.event.pull_request.head.ref || | |
| (inputs.version && format('v{0}', inputs.version)) || 'manual' | |
| }} | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| pull_request: | |
| types: | |
| - closed | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to publish (must match package.json). Leave empty to read from package.json." | |
| required: false | |
| type: string | |
| permissions: | |
| contents: write # create the GitHub Release | |
| id-token: write # npm --provenance (requires a public GitHub repo) | |
| concurrency: | |
| group: release | |
| cancel-in-progress: false | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| if: | | |
| (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || | |
| (github.event_name == 'pull_request' | |
| && github.event.pull_request.merged == true | |
| && github.event.pull_request.base.ref == 'main' | |
| && startsWith(github.event.pull_request.head.ref, 'release/v')) || | |
| (github.event_name == 'workflow_dispatch') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| registry-url: https://registry.npmjs.org | |
| cache: npm | |
| - name: Install | |
| run: npm ci | |
| - name: Resolve and verify version | |
| id: version | |
| run: | | |
| set -euo pipefail | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| NAME=$(node -p "require('./package.json').name") | |
| EVENT="${{ github.event_name }}" | |
| if [ "$EVENT" = "push" ]; then | |
| # Tag push: REF is refs/tags/vX.Y.Z | |
| TAG_VERSION=${GITHUB_REF#refs/tags/v} | |
| if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then | |
| echo "::error::Tag v$TAG_VERSION does not match package.json version $PKG_VERSION." | |
| echo "::error::Update package.json (and this tag) to publish a coherent release." | |
| exit 1 | |
| fi | |
| VERSION="$TAG_VERSION" | |
| elif [ "$EVENT" = "pull_request" ]; then | |
| # Merged release branch: derive version from head_ref (release/vX.Y.Z) | |
| # and require it to match the bumped package.json. | |
| HEAD_REF="${{ github.event.pull_request.head.ref }}" | |
| BRANCH_VERSION=${HEAD_REF#release/v} | |
| if [ -z "$BRANCH_VERSION" ] || [ "$BRANCH_VERSION" = "$HEAD_REF" ]; then | |
| echo "::error::PR head ref '$HEAD_REF' is not a release/vX.Y.Z branch." | |
| exit 1 | |
| fi | |
| if [ "$BRANCH_VERSION" != "$PKG_VERSION" ]; then | |
| echo "::error::Branch version $BRANCH_VERSION does not match package.json version $PKG_VERSION." | |
| echo "::error::Rename the branch to release/v$PKG_VERSION (or update package.json) so they agree." | |
| exit 1 | |
| fi | |
| VERSION="$BRANCH_VERSION" | |
| else | |
| # Manual dispatch: prefer the input, fall back to package.json. | |
| VERSION="${{ inputs.version }}" | |
| if [ -z "$VERSION" ]; then | |
| VERSION="$PKG_VERSION" | |
| fi | |
| if [ "$VERSION" != "$PKG_VERSION" ]; then | |
| echo "::error::Input version $VERSION does not match package.json version $PKG_VERSION." | |
| exit 1 | |
| fi | |
| fi | |
| echo "name=$NAME" >> "$GITHUB_OUTPUT" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Typecheck & build | |
| run: | | |
| npm run typecheck | |
| npm run build | |
| - name: Check whether this version is already on npm | |
| id: check | |
| run: | | |
| NAME="${{ steps.version.outputs.name }}" | |
| VERSION="${{ steps.version.outputs.version }}" | |
| if npm view "$NAME@$VERSION" version >/dev/null 2>&1; then | |
| echo "Version $VERSION already published — skipping." | |
| echo "publish=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "publish=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Publish to npm | |
| if: steps.check.outputs.publish == 'true' | |
| # Drop --provenance if the repository is private (provenance needs a | |
| # public repo and a `repository` field in package.json). | |
| run: npm publish --provenance | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Create GitHub Release | |
| if: steps.check.outputs.publish == 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| TARGET_SHA="${{ github.sha }}" | |
| # For tag pushes, also publish from the tagged commit itself. | |
| if [ "${{ github.event_name }}" = "push" ]; then | |
| TARGET_SHA="$GITHUB_REF" | |
| fi | |
| gh release create "v$VERSION" \ | |
| --title "orbcode v$VERSION" \ | |
| --generate-notes \ | |
| --target "$TARGET_SHA" \ | |
| || echo "Release v$VERSION already exists." |