cli-released #6
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
| name: Sync CLI User Guide | |
| # Regenerates the CLI User Guide (src/org/cli/*.md) from @imqueue/cli's wiki/ | |
| # and commits the result to master — which deploys the site. It runs when the | |
| # cli repo signals a release (repository_dispatch, see the snippet at the bottom | |
| # of this file), and can also be triggered by hand. | |
| on: | |
| repository_dispatch: | |
| types: [cli-released] | |
| workflow_dispatch: | |
| inputs: | |
| ref: | |
| description: "@imqueue/cli git ref (tag/branch) to sync from" | |
| default: master | |
| # Never let two syncs race on a push to master. | |
| concurrency: | |
| group: sync-cli-guide | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| # For `gh workflow run indexnow.yml` in the last step. contents:write alone | |
| # cannot dispatch a workflow. | |
| actions: write | |
| jobs: | |
| sync: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout imqueue.com | |
| uses: actions/checkout@v7 | |
| with: | |
| # REQUIRED by the verify step. check:dates reads git history | |
| # (`git log --follow --diff-filter=A`) for every page's publication | |
| # date; the default shallow fetch has one commit, so every file looks | |
| # as though that commit added it and the check fails on every run. | |
| # Same reason refresh-api-docs.yml sets it. | |
| fetch-depth: 0 | |
| - name: Resolve cli ref | |
| id: ref | |
| run: echo "ref=${{ github.event.client_payload.ref || github.event.inputs.ref || 'master' }}" >> "$GITHUB_OUTPUT" | |
| - name: Checkout @imqueue/cli wiki source | |
| uses: actions/checkout@v7 | |
| with: | |
| repository: imqueue/cli | |
| ref: ${{ steps.ref.outputs.ref }} | |
| path: .cli-src | |
| sparse-checkout: wiki | |
| # Only needed if imqueue/cli is private. For a public repo the default | |
| # token is enough and you can delete this line (and the secret). | |
| token: ${{ secrets.CLI_SYNC_TOKEN || github.token }} | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| # The sync script itself needs no dependencies, but everything after it | |
| # does — and `npm ci` also runs `prepare`, which points core.hooksPath at | |
| # .githooks. | |
| - run: npm ci | |
| - name: Regenerate CLI User Guide from the wiki | |
| run: node scripts/sync-cli-wiki.js --wiki .cli-src/wiki | |
| - name: Anything to do? | |
| id: changed | |
| run: | | |
| if [ -z "$(git status --porcelain -- src/org/cli)" ]; then | |
| echo "No changes — the guide is already in sync." | |
| echo "any=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "any=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Commit the guide | |
| if: steps.changed.outputs.any == 'true' | |
| env: | |
| REF: ${{ steps.ref.outputs.ref }} | |
| run: | | |
| git config user.name "imqueue-bot" | |
| git config user.email "bot@imqueue.com" | |
| # An explicit path, not `git add -A`: this working tree also holds | |
| # .cli-src/ from the sparse checkout above, plus (on a self-hosted | |
| # runner) the untracked local-only promotion/ and *-PLAN.md material. | |
| git add -- src/org/cli | |
| # --no-verify here and below on purpose: the "Verify" step is the gate, | |
| # and it runs on the exact tree that gets pushed. Letting the hook run | |
| # would execute the same suite three times for one sync, and on the | |
| # first of those runs a BRAND-NEW guide page is staged-but-uncommitted, | |
| # so gen-page-dates reports it untracked and check:dates cannot see it | |
| # either way. | |
| git commit --no-verify -m "docs(cli): sync CLI User Guide from @imqueue/cli@${REF}" | |
| - name: Record dates for new or changed guide pages | |
| if: steps.changed.outputs.any == 'true' | |
| # AFTER the commit, never before. gen-page-dates derives `published` from | |
| # the commit that ADDED a file (`git log --diff-filter=A`), so a page that | |
| # is only staged resolves to null and is omitted from pageDates.json — and | |
| # then check:dates fails on the *next* commit with "has no entry — it would | |
| # render with no date". Running it here, then amending, is what keeps a | |
| # newly synced page from shipping with no datePublished at all. | |
| run: | | |
| npm run gen-page-dates | |
| if [ -n "$(git status --porcelain -- src/_data/pageDates.json)" ]; then | |
| git add -- src/_data/pageDates.json | |
| git commit --no-verify --amend --no-edit | |
| echo "Folded pageDates.json into the sync commit." | |
| else | |
| echo "pageDates.json unchanged." | |
| fi | |
| - name: Verify — redirects, analytics, dates, links, sitemap | |
| if: steps.changed.outputs.any == 'true' | |
| # This is the gate, and it has to be here. A push made with GITHUB_TOKEN | |
| # does not trigger other workflows, so checks.yml will NOT run for the | |
| # commit this job creates — while Cloudflare Pages deploys from the git | |
| # push itself. Without this step an unverified guide goes straight to | |
| # production. Same reasoning as refresh-api-docs.yml. | |
| run: npm test | |
| - name: Push | |
| if: steps.changed.outputs.any == 'true' | |
| run: git push | |
| - name: Announce the new guide to IndexNow | |
| if: steps.changed.outputs.any == 'true' | |
| # indexnow.yml is triggered by `push: branches: [master]`, which a | |
| # GITHUB_TOKEN push does not fire — so a synced guide used to wait for the | |
| # next unrelated human push before Bing/Yandex heard about it. /cli/ pages | |
| # are submitted (only /api/ is excluded, via --exclude=/api/), so there is | |
| # something real to announce. | |
| # | |
| # Dispatching that workflow rather than calling `npm run indexnow:org` | |
| # here: indexnow-ping.js does NOT wait for anything ("Run AFTER a deploy, | |
| # once the new content is actually live"), and the ~12-minute | |
| # built-vs-live sitemap parity gate that makes it correct lives in | |
| # indexnow.yml. Pinging from this job would submit a brand-new guide page | |
| # before Cloudflare Pages had deployed it, and IndexNow would fetch a 404. | |
| # | |
| # workflow_dispatch is one of the two events GitHub explicitly EXEMPTS | |
| # from the "GITHUB_TOKEN cannot trigger workflows" rule (the other is | |
| # repository_dispatch), so this does start a run — which is the whole | |
| # reason it is a dispatch and not a push. | |
| # | |
| # Non-fatal: the sync itself has already landed and the sitemap covers the | |
| # slow path, so a dispatch failure must not fail the sync. | |
| continue-on-error: true | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: gh workflow run indexnow.yml --ref master | |
| # --------------------------------------------------------------------------- | |
| # To fire this automatically on every @imqueue/cli npm publish, add a step to | |
| # the cli repo's release/publish workflow (AFTER the successful `npm publish`): | |
| # | |
| # - name: Notify imqueue.com to refresh the CLI User Guide | |
| # run: | | |
| # curl -sSf -X POST \ | |
| # -H "Authorization: Bearer ${{ secrets.SITE_DISPATCH_TOKEN }}" \ | |
| # -H "Accept: application/vnd.github+json" \ | |
| # https://api.github.com/repos/imqueue/imqueue.com/dispatches \ | |
| # -d "{\"event_type\":\"cli-released\",\"client_payload\":{\"ref\":\"${GITHUB_REF_NAME}\"}}" | |
| # | |
| # SITE_DISPATCH_TOKEN is a fine-grained PAT (or classic PAT with `repo` scope) | |
| # that can send dispatches to imqueue/imqueue.com, stored as a secret in the | |
| # cli repo. That is the only credential you need to create by hand. | |
| # --------------------------------------------------------------------------- |