Pull docs from the website repo on a schedule - #2387
Open
dividedmind wants to merge 4 commits into
Open
Conversation
The `::set-output` workflow command has been deprecated since 2022; `yarn_install` was the last user of it in this repo. Replace it with `$GITHUB_OUTPUT`. Also bump the actions used in main.yml to match the versions .github/actions/setup-node already pins: actions/checkout v3 -> v6 and actions/cache v3 -> v5. Assisted-by: Claude:claude-opus-5
Contributor
There was a problem hiding this comment.
Pull request overview
This PR replaces the old push-based documentation sync with a scheduled pull-based mirror from getappmap/applandinc.github.io, ensuring docs/ stays an exact (Markdown-only) help corpus for appmap navie help and preventing stale-base CI failures and corpus drift.
Changes:
- Added a Node-based, unit-tested
scripts/sync-docs.mjsmirroring implementation (including delete/prune semantics and an exclude list) and wired it into Yarn scripts. - Added a scheduled
.github/workflows/sync-docs.ymlworkflow that checks out the website’s_docsvia a GitHub App token and opens/updates a long-lived sync PR. - Updated CI to detect docs-only PRs and skip expensive jobs while always running
test_cli; updatedpackages/clibuild:docto reuse the same mirror logic.
Reviewed changes
Copilot reviewed 48 out of 50 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/sync-docs.test.mjs | Adds unit tests for the docs mirroring behavior (copy/update/delete/prune/exclude/dry-run). |
| scripts/sync-docs.mjs | Introduces the cross-platform, explicit docs mirroring implementation and CLI wrapper. |
| packages/cli/package.json | Switches build:doc from rsync to the shared sync-docs script. |
| package.json | Adds test:scripts and sync-docs entry points at the repo root. |
| docs/using-navie-ai/navie-user-interface.md | Removed from this repo’s mirrored corpus (upstream no longer publishes it). |
| docs/unused_for_now_index.html | Removes non-Markdown asset from the mirrored corpus. |
| docs/TODO-review2.md | Removes local-only TODO from the mirrored corpus (retained in history). |
| docs/reference/appmap-python.md | Updates mirrored docs content (log file behavior section). |
| docs/reference/appmap-client-cli.md | Updates mirrored docs content (adds/extends sanitize documentation). |
| docs/navie/using-navie.md | Removes superseded Navie doc page from corpus. |
| docs/navie/index.md | Removes superseded Navie index page from corpus. |
| docs/navie/how-to-open-navie.md | Removes superseded Navie doc page from corpus. |
| docs/navie/how-navie-works.md | Removes superseded Navie doc page from corpus. |
| docs/navie/bring-your-own-model.md | Removes superseded Navie doc page from corpus. |
| docs/navie-reference/navie-user-interface.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/navie-pre-built-libraries-for-appmap-data.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/navie-options.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/navie-openai-key-management.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/navie-how-it-works.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/navie-github-repository.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/navie-commands.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/navie-bring-your-own-model-examples.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/navie-accessing-logs.md | Removes superseded Navie reference page from corpus. |
| docs/navie-reference/index.md | Removes superseded Navie reference index page from corpus. |
| docs/navie-reference.md | Removes monolithic Navie reference page from corpus. |
| docs/integrations/smartbear-swaggerhub.md | Removes superseded integrations doc page from corpus. |
| docs/integrations/readme.md | Removes superseded integrations doc page from corpus. |
| docs/integrations/postman.md | Removes superseded integrations doc page from corpus. |
| docs/integrations/plantuml.md | Removes superseded integrations doc page from corpus. |
| docs/integrations/mermaid.md | Removes superseded integrations doc page from corpus. |
| docs/integrations/index.md | Removes superseded integrations index page from corpus. |
| docs/integrations/docker.md | Removes superseded integrations doc page from corpus. |
| docs/integrations/circle-ci.md | Removes superseded integrations doc page from corpus. |
| docs/integrations/atlassian-confluence.md | Removes superseded integrations doc page from corpus. |
| docs/integrations/atlassian-compass.md | Removes superseded integrations doc page from corpus. |
| docs/guides/using-appmap-diagrams.md | Removes superseded guide page from corpus. |
| docs/guides/using-appmap-analysis.md | Removes superseded guide page from corpus. |
| docs/guides/reverse-engineering.md | Removes superseded guide page from corpus. |
| docs/guides/refine-appmap-data.md | Removes superseded guide page from corpus. |
| docs/guides/reading-sql-in-appmap-diagrams.md | Removes superseded guide page from corpus. |
| docs/guides/openapi.md | Removes superseded guide page from corpus. |
| docs/guides/navigating-code-objects.md | Removes superseded guide page from corpus. |
| docs/guides/index.md | Removes superseded guides index page from corpus. |
| docs/guides/handling-large-appmap-diagrams.md | Removes superseded guide page from corpus. |
| docs/guides/exporting-appmap-diagrams.md | Removes superseded guide page from corpus. |
| docs/analysis/rules-reference.html | Removes non-Markdown redirect artifact from corpus. |
| .github/workflows/sync-docs.yml | Adds scheduled pull-based sync workflow using GitHub App auth and a single long-lived PR. |
| .github/workflows/main.yml | Adds docs-only gating and runs yarn test:scripts; modernizes job dependencies after removing the old install gate. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
dividedmind
force-pushed
the
build/doc-updates
branch
from
August 15, 2026 12:21
829e80e to
063706a
Compare
dividedmind
marked this pull request as ready for review
August 15, 2026 12:35
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 48 out of 50 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
scripts/sync-docs.mjs:94
syncDocsis exported, but when called with missing/undefinedsourceortargetit will currently throw a NodeTypeErrorfromexistsSync/path handling rather than a clear usage error. Adding explicit argument validation here makes failures easier to diagnose and prevents confusing stack traces.
docs/ is the help corpus that `appmap navie help` indexes and that packages/cli bundles into its published artifacts. The website repo getappmap/applandinc.github.io owns the content, and until now it pushed updates here: a workflow there opened a pull request against the `next-doc` staging branch on every push to master. That had three problems. The base branch was never refreshed, so every sync PR carried a tree frozen at 2024-12-20 and ran CI against it. Being push-triggered and fire-and-forget, a failed run was invisible to the people who own the consumer — hence the 17-month gap between syncs, and the manual rescue in dfa7ef0. And the rsync used a globbed source, so --delete never pruned top-level entries the website had retired: docs/ had grown to 95 markdown files against 57 upstream, with superseded copies of reorganized pages still in the search index. Invert it. A scheduled workflow here pulls instead, which is self-healing (a missed run is fixed by the next), surfaces failures in this repo, cuts its branch from main so the base cannot go stale, and needs only *read* access to the website rather than write access here. The pull request gate is kept, so a human still reviews what ships. The mirror itself is a plain script with no git or network in it, so it can be unit tested and run by hand onto any branch: yarn sync-docs --source ../applandinc.github.io/_docs It deletes what the website no longer publishes, mirrors only the *.md files the indexer actually consumes, and takes an exclude list — which gives build:doc's post-hoc `rm -f` of the retired appmap-agent-js docs a proper home. build:doc now reuses the same script, so there is one mirror implementation instead of two and the build no longer needs rsync. The website is read with a read-only deploy key rather than a token from the appmap-releasebot app. An app declares its permissions app-wide rather than per repository, so installing releasebot on the website would let every holder of its private key — appmap-ruby, appmap-node, appmap-intellij-plugin — mint write access there. Requesting a downscoped token would not help either, since the key material in the job can always ask for more. The app token is still used to open the pull request, because GitHub suppresses workflow runs for events GITHUB_TOKEN authors and a sync PR with no checks would defeat the point of opening one. Both third-party actions are pinned by commit SHA rather than by mutable tag, since they run in the same job that reads the app's private key. The version comments keep them legible and let Dependabot or Renovate still propose bumps. They are pinned at the current majors, create-pull-request v8.1.1 and create-github-app-token v3.2.0. Neither major bump affects this workflow: both moved to Node 24, which only constrains self-hosted runners, and create-github-app-token v2 dropped the snake_case `app_id`/`private_key` inputs this workflow never used. Its `app-id` input is deprecated in favour of `client-id` as of v3.1.0, so the client ID is used from the start rather than warning on every run. Finally, gate the heavy CI jobs on a docs_only check so a docs-only pull request runs test_cli — which builds the help index over docs/, and so can legitimately catch an upstream reorganization — without also running the component, chromatic, scanner and native suites. Assisted-by: Claude:claude-opus-5
Mirrors _docs from getappmap/applandinc.github.io@65f25d96 via `yarn sync-docs`, bringing docs/ to 57 markdown files — an exact match for what the website publishes. Most of this is the backlog the old push-based sync could not express. Its rsync never pruned top-level entries, so pages the website reorganized away in 2024 were still being indexed by `appmap navie help` and cited with permalinks to URLs that no longer resolve: docs/navie/ is the superseded ancestor of docs/using-navie-ai/, and docs/guides/ and docs/integrations/ moved under docs/reference/. Also drops non-Markdown assets the indexer never reads, and TODO-review2.md, which was added here rather than upstream and is preserved in history. Assisted-by: Claude:claude-opus-5
yarn_install saved its Yarn and node_modules caches under
`${{ runner.os }}-yarn-<lock hash>` and
`${{ runner.os }}-node-modules-<lock hash>`. Every job that consumes a
dependency cache does so through .github/actions/setup-node, which
keys on `${{ github.job }}-...` instead — and `github.job` inside a
composite action resolves to the calling job, never to yarn_install.
So nothing has been reading what yarn_install wrote: it ran a full
`yarn install` on every CI run into cache entries with no consumers,
and serialized six jobs behind itself via `needs:`.
Remove it. Each job continues to populate and restore its own cache
via setup-node, and they now start in parallel instead of waiting.
The trade-off is that a cold cache costs one install per job rather
than one per run; sharing a single cache across jobs would mean
unifying setup-node's keys, which is a separate change.
Assisted-by: Claude:claude-opus-5
dividedmind
force-pushed
the
build/doc-updates
branch
from
August 15, 2026 12:52
063706a to
cfbd98b
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the push-based docs sync from
getappmap/applandinc.github.iowith a scheduled pull, and cleans up the corpus drift the old mechanism accumulated.Started from a CI failure on a docs sync PR —
sequenceDiagram.spec.tsdying withNo usable sandbox!from Chromium. That turned out to be a symptom, not a bug: the PNG test has been skipped and--no-sandboxhas been passed since 2025-01-08. The sync PR was running a tree frozen at 2024-12-20.Why
The website repo owns the content of
docs/, which is not repo documentation — it is the help corpus thatappmap navie helpindexes (packages/cli/src/cmds/navie/help.ts) and thatpackages/clibundles into its published npm tarball and native binaries. Until now the website pushed updates here: a workflow there rsynced_docsand opened a PR against thenext-docstaging branch on every push to master.Three things were wrong with that.
The base was never refreshed.
next-doc's code is frozen at82d7ef9f1(2024-12-20,chore(release): 3.180.1); the only 12 commits since are doc syncs andmainhas never been merged in — 477 commits behind.create-pull-requestcuts its branch from the base, not from the checked-out ref, so every sync PR carried that Dec-2024 tree and ran the full CI suite against it. (Proof it used the base: had the head branch beenmain-based, merging #2370 intonext-docin July 2026 would have pulled main's 477 commits in. It didn't.)Push-triggered and fire-and-forget. Real sync events: several in Dec 2024, then 2025-01-03, 01-24, 02-07 — then nothing until 2026-07-02. A 17-month gap during which every shipped CLI carried a stale help corpus.
dfa7ef0f7("Manually sync the docs since the PR didn't open") shows it failed silently, and structurally it had to: the job ran in the website repo, so failures surfaced to people who don't own the consumer.The rsync was not a mirror.
rsync -av --delete _docs/* docs— the shell expands the glob, sodocs/itself is never a synced directory, only its children are.--deletetherefore pruned inside subdirectories that still existed upstream but never removed top-level entries the website had retired.docs/had grown to 95 markdown files against 57 upstream.That last one was a product bug, not hygiene.
docs/navie/{using-navie,bring-your-own-model,how-navie-works,how-to-open-navie}.mdare the superseded ancestors of upstreamusing-navie-ai/{navie-workflow,choose-llm-provider,navie-architecture,navie-opening}.md, anddocs/guides/anddocs/integrations/moved underdocs/reference/— both generations sat in the lunr index. Sincehelp.tsstamps every snippet with ahttps://appmap.io/docs/<path>permalink, Navie could answer from documentation retired ~18 months ago and cite URLs that no longer resolve.What changed
c7c59f353ci:modernize deprecated workflow syntax and action versions02a0b1d16feat:pull docs from the website repo on a scheduledecb4bd8bchore:sync docs from applandinc.github.io829e80e48ci:drop the vestigialyarn_installjobscripts/sync-docs.mjs— the mirror, with no git and no network in it, so it is unit testable and runnable by hand onto any branch:Implemented in Node rather than shelling to rsync: the bug being fixed was rsync flag semantics, so mirror behavior is now explicit and asserted — and it works on Windows. Mirrors only the
*.mdfiles the indexer consumes, deletes what the website no longer publishes, prunes emptied directories, and takes an exclude list — which givesbuild:doc's post-hocrm -fof the retired appmap-agent-js docs a proper home. 13 tests vianode --test(no new deps), wired asyarn test:scriptsand run in CI fromtest_the_rest..github/workflows/sync-docs.yml— weekly (Mon 06:00 UTC) +workflow_dispatch+ arepository_dispatch: [sync-docs]hook, neverpull_request. Sparse-checks-out_docsonly, and opens a single long-livedchore/sync-docsPR withadd-paths: docs. Records the upstream SHA in the commit and PR body for provenance.Pulling beats fixing the push in place: a schedule is self-healing (a missed run is fixed by the next), the branch is cut from
maineach run so the base cannot go stale, failures surface in the repo that owns the consumer, and the credential direction inverts — this repo reads the website, where the website previously held a cross-repo write PAT. The PR gate is preserved, so a human still reviews what ships in the CLI.Two credentials, deliberately
The website is read with a read-only deploy key (
DOCS_REPO_SSH_KEY), not with anappmap-releasebottoken. A GitHub App declares its permissions app-wide, not per repository, so installing releasebot on the website would let every holder of its private key —appmap-ruby,appmap-node,appmap-intellij-plugin— mint write access to it. Requesting a downscoped token viapermission-contents: readwould not fix that either: it is a request made by the same job that holds the key, so it guards against accidents, not against anything adversarial. A deploy key is scoped to one repository and read-only by construction, so nothing in this job can write to the website.The pull request is opened with an app token, scoped to this repository and minted immediately before the step that uses it. That part is load-bearing rather than hygiene: GitHub suppresses workflow runs for
GITHUB_TOKEN-authored events, so a sync PR created with it would arrive with zero checks — andtest_clibuilding the help index overdocs/is the whole reason for opening one.packages/clibuild:docnow reuses the same script, so there is one mirror implementation instead of two and the build no longer needs rsync.CI
docs_onlygate — a checkout-freechangesjob uses the PR files API to detect docs-only PRs and skipstest_components,test_chromatic,test_scanner,test_nativeandtest_the_restfor them.test_clialways runs, becauseHelpIndex.spec.tsbuilds the index over the realdocs/and asserts a['java', 'maven']search returns snippets containing both terms — an upstream reorganization can legitimately break search, and that is exactly the check worth keeping on a sync PR. The filter applies only topull_request, sorelease'sneeds:are never skipped.yarn_installremoved. It saved caches under${{ runner.os }}-{yarn,node-modules}-<hash>, but the only consumer of a dependency cache in the repo is.github/actions/setup-node, keyed${{ github.job }}-…— and inside a compositeaction
github.jobresolves to the calling job, never toyarn_install. Nothing has been reading what it wrote: it ran a fullyarn installevery CI run into orphaned cache entries while serializing six jobs behind itself. Trade-off: a coldcache now costs one install per job rather than one per run, but jobs start in parallel. Sharing one cache across jobs would mean unifying
setup-node's keys — deliberately left as a separate change.Reviewing the docs commit
decb4bd8bis 44 files, −4519 lines. It is mechanical, and you can confirm it:docs/is now 57 markdown files, exactly matching upstream. Also dropped: the non-Markdown assets the indexer never reads (two PDFs, two stray HTML files), andTODO-review2.md, which was added here rather than upstream — preserved in history.Verification
yarn verifyOKHelpIndex.spec.tspasses against the trimmed corpusbuild:docproduces 57 files and is idempotent--checkreports the mirror cleanCI on this PR runs everything (it touches workflows and scripts, so it is not docs-only) — which exercises both the new
changesjob and the gate's default path. The app-token path andadd-paths: docscan only be exercised by a real run; seebelow.
Before merge
Three secrets, none of which exist here yet:
RELEASE_BOT_CLIENT_IDandRELEASE_BOT_PRIVATE_KEY. The app is installed with the needed permissions, but secrets are per-repo.Note the Client ID, not the App ID —
create-github-app-tokendeprecatedapp-idin favour ofclient-idin v3.1.0, and new code shouldn't start on a deprecated input. It's a different value (Iv23li…), on the app's settings page just under the App ID. The other repos using this app (appmap-ruby,appmap-node,appmap-intellij-plugin) are still onapp-idwith@v1; these are org-level secrets, added the client ID there to let them migrate later without another secret.DOCS_REPO_SSH_KEY— the private half of a read-only deploy key:Add
docs-sync-key.pubas a deploy key onapplandinc.github.iowith write access unchecked, anddocs-sync-keyhere asDOCS_REPO_SSH_KEY.Coordination
Pairs with https://github.com/getappmap/applandinc.github.io/pull/1581, which removes the push side.
Merge this one first, so there is never a window without a working sync path. If someone pushes to the website's master in between, the old workflow may open one more stale
feat/sync-docs-*PR againstnext-doc— just close it.After merge
workflow_dispatchthe sync once rather than waiting for Monday. Expect0 added, 0 updated, 0 deletedand no PR — a clean signal that both the mirror and the app token work.next-docbranch. Nothing targets it now, and its only value was the staging hop that caused the stale-base bug.DOC_SYNC_TOKENfrom the website repo's secrets — the cross-repo write credential is no longer used by anything.Not in scope
sequenceDiagram.spec.tsstays skipped; re-enabling it needs a browser on the runner, sincePUPPETEER_SKIP_DOWNLOADis set globally. Verified locally that it passes both with the bundled Chromium 110 and with a system Chromium 150 viaPUPPETEER_EXECUTABLE_PATH, so puppeteer 19's CDP usage here tolerates the version skew — the gap is browser provisioning, not the renderer.setup-node's cache keys so jobs share one entry.releasestill authenticating with theGH_TOKENPAT — anotherappmap-releasebotcandidate.