# Release flow: # • Actions → Publish → "Run workflow" = rehearse: build, test, optional npm --dry-run (no upload, no release). # • Push tag v* = real publish + GitHub release (uses environment npm-publish). # # Registry upload uses `npx npm@11 publish` only — not the package manager's publish wrapper. # "Re-run" on an old workflow run does NOT pick up edits to this file; start a NEW run (new tag or Run workflow). # # Authentication (pick one): # A) npm Trusted Publishing (recommended): configure OIDC on npmjs.com — no NPM_TOKEN in GitHub. # Requires Node ≥ 22.14 (see https://docs.npmjs.com/trusted-publishers ). # B) Classic token: GitHub → Settings → Environments → npm-publish → Environment secrets # (recommended) OR Settings → Secrets and variables → Actions → Repository secrets — # name NPM_TOKEN. Publish steps set NODE_AUTH_TOKEN when non-empty. # # One-time npm setup for OIDC (repeat per package on npmjs.com): # Package → Settings → Trusted publishers → GitHub Actions # (this repo, workflow publish.yml, Environment name: npm-publish — must match the job below) # # GitHub UI: Settings → Environments (create npm-publish); Secrets and variables → Actions (repo secrets). name: Publish on: push: tags: ['v*'] workflow_dispatch: inputs: npm_dry_run: description: 'Run npm publish --dry-run for both packages (shows packed files; no upload)' type: boolean default: true # Opt JavaScript actions into Node 24 on the runner (see GitHub deprecation notice for Node 20). env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' jobs: rehearse: if: github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest permissions: contents: read id-token: write steps: - uses: actions/checkout@v6.0.2 - uses: pnpm/action-setup@v4 with: version: 9 - uses: actions/setup-node@v6.3.0 with: node-version: 22 registry-url: https://registry.npmjs.org cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm build - run: pnpm test:quick - name: Show package versions (would publish) run: | echo "neozipkit: $(node -p "require('./packages/neozipkit/package.json').name")@$(node -p "require('./packages/neozipkit/package.json').version")" echo "neozip-blockchain: $(node -p "require('./packages/neozip-blockchain/package.json').name")@$(node -p "require('./packages/neozip-blockchain/package.json').version")" - name: Preview neozipkit (npm publish --dry-run) if: inputs.npm_dry_run working-directory: packages/neozipkit run: npm publish --access public --dry-run - name: Preview neozip-blockchain (npm publish --dry-run) if: inputs.npm_dry_run working-directory: packages/neozip-blockchain run: npm publish --access public --dry-run publish: if: github.event_name == 'push' runs-on: ubuntu-latest environment: npm-publish concurrency: group: npm-publish-${{ github.ref }} cancel-in-progress: false permissions: contents: write id-token: write env: NPM_CONFIG_PROVENANCE: 'true' steps: - uses: actions/checkout@v6.0.2 - uses: pnpm/action-setup@v4 with: version: 9 - uses: actions/setup-node@v6.3.0 with: node-version: 22 registry-url: https://registry.npmjs.org cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm build - run: pnpm test:quick - name: Verify tag matches package versions run: | TAG="${GITHUB_REF#refs/tags/v}" VER_KIT=$(node -p "require('./packages/neozipkit/package.json').version") VER_BC=$(node -p "require('./packages/neozip-blockchain/package.json').version") if [ "$TAG" != "$VER_KIT" ] || [ "$TAG" != "$VER_BC" ]; then echo "::error::Tag v$TAG does not match package versions (neozipkit=$VER_KIT, neozip-blockchain=$VER_BC)" exit 1 fi echo "Tag v$TAG matches both package versions." - name: Preflight (npm CLI for publish) run: npx --yes npm@11 --version # Auth: (1) Classic — NPM_TOKEN on npm-publish environment or repo secrets. # (2) OIDC — omit NPM_TOKEN; Trusted Publishing on npm for BOTH packages. - name: Publish neozipkit working-directory: packages/neozipkit env: NPM_TOKEN_FOR_CI: ${{ secrets.NPM_TOKEN }} run: | if [ -n "${NPM_TOKEN_FOR_CI}" ]; then export NODE_AUTH_TOKEN="$NPM_TOKEN_FOR_CI" echo "::notice::Publishing neozipkit with NPM_TOKEN (classic auth)." else echo "::notice::Publishing neozipkit with OIDC (NPM_TOKEN unset — Trusted Publishing on npm required)." fi npx --yes npm@11 publish --access public - name: Publish neozip-blockchain working-directory: packages/neozip-blockchain env: NPM_TOKEN_FOR_CI: ${{ secrets.NPM_TOKEN }} run: | if [ -n "${NPM_TOKEN_FOR_CI}" ]; then export NODE_AUTH_TOKEN="$NPM_TOKEN_FOR_CI" echo "::notice::Publishing neozip-blockchain with NPM_TOKEN (classic auth)." else echo "::notice::Publishing neozip-blockchain with OIDC (NPM_TOKEN unset — Trusted Publishing on npm required)." fi npx --yes npm@11 publish --access public - uses: softprops/action-gh-release@v2 with: generate_release_notes: true