From c2ab4cf279c843e640399dfe936373c4ef7d9470 Mon Sep 17 00:00:00 2001 From: Howard Askew <19271569+howaskew@users.noreply.github.com> Date: Mon, 19 Oct 2026 14:14:23 +0100 Subject: [PATCH] ci: Make the npm publish safe to rerun and switch to the GitHub App - Push the version bump before publishing, so a rejected push stops the run before anything reaches npm. Previously npm could be ahead of GitHub, as happened to data-model-validator on 5 August 2026. - Remove the postpublish git push, and make publish-patch push before publishing too. - Use the OpenActive GitHub App token for checkout, push and dispatch instead of the PUBLIC_REPO_ACCESS_TOKEN personal access token. - Loop guard: skip runs started by openactive[bot], and add a skip-CI marker to the bump commit, so the guard no longer depends on email strings. - Scope the dispatch token to the target repository; without owner and repositories the App token only covers this repository. - Publish with NPM_TOKEN2, a repo-level token (the org NPM_TOKEN is rejected by npm). - Run one publish at a time, and update checkout, setup-node and repository-dispatch to current major versions. Supersedes #206 and #207. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/npm-test.yml | 4 +-- .github/workflows/publish-to-npm.yml | 50 +++++++++++++++++++++------- package.json | 3 +- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/.github/workflows/npm-test.yml b/.github/workflows/npm-test.yml index c661ff6a..2f47c522 100644 --- a/.github/workflows/npm-test.yml +++ b/.github/workflows/npm-test.yml @@ -10,9 +10,9 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Use Node.js 18.17.1 - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: 18.17.1 - name: Install diff --git a/.github/workflows/publish-to-npm.yml b/.github/workflows/publish-to-npm.yml index f02db902..f4c6180f 100644 --- a/.github/workflows/publish-to-npm.yml +++ b/.github/workflows/publish-to-npm.yml @@ -4,22 +4,37 @@ on: push: branches: [ master ] +# Never run two publishes at once; a second merge waits for the first to finish +concurrency: + group: publish-to-npm + cancel-in-progress: false + +permissions: + contents: read + jobs: publish: runs-on: ubuntu-latest - if: ${{ !contains(github.event.head_commit.author.email, 'openactive-bot@users.noreply.github.com') }} + # Loop guard: the version bump commit below is pushed by the OpenActive GitHub App, and also carries [skip ci] + if: ${{ github.actor != 'openactive[bot]' }} steps: + - name: Generate GitHub App Token + uses: actions/create-github-app-token@v1 + id: generate-token + with: + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: - token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + token: ${{ steps.generate-token.outputs.token }} - name: Identify run: | - git config user.name openactive-bot - git config user.email openactive-bot@users.noreply.github.com + git config --global user.name "openactive[bot]" + git config --global user.email 207210293+openactive[bot]@users.noreply.github.com - name: Use Node.js 18.17.1 - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: 18.17.1 registry-url: https://registry.npmjs.org/ @@ -28,24 +43,35 @@ jobs: - name: Test run: npm test - name: Increment Version - run: npm version patch + run: npm version patch -m "%s [skip ci]" + # Push before publishing: if the push is rejected, nothing is published, so npm can never get ahead of GitHub + - name: Push version update + run: git push origin HEAD:master - name: Publish to npm run: npm publish env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - - name: Push version update - run: git push + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN2 }} dispatch: needs: publish strategy: + fail-fast: false matrix: repo: ['OpenActive.NET', 'OpenActive.DatasetSite.NET', 'models-php', 'models-ruby', 'models-ts', 'data-model-validator-site', 'openactive.github.io', 'developer-documentation', 'openactive-test-suite'] runs-on: ubuntu-latest steps: + # Without owner and repositories, the token only covers this repository and cannot dispatch to others + - name: Generate GitHub App Token + uses: actions/create-github-app-token@v1 + id: generate-token + with: + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + owner: openactive + repositories: ${{ matrix.repo }} - name: Trigger tooling update - uses: peter-evans/repository-dispatch@v1 + uses: peter-evans/repository-dispatch@v3 with: - token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + token: ${{ steps.generate-token.outputs.token }} repository: openactive/${{ matrix.repo }} event-type: data-models-update diff --git a/package.json b/package.json index dd5537e1..a356744e 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "test": "npm run test-no-lint", "test-no-lint": "jasmine", "test-debug": "node --inspect-brk -i ./node_modules/jasmine/bin/jasmine.js", - "postpublish": "git push", - "publish-patch": "npm test && git pull && git push && npm version patch && npm publish" + "publish-patch": "npm test && git pull && npm version patch && git push && npm publish" } }