diff --git a/.github/workflows/cut-versions.yml b/.github/workflows/cut-versions.yml new file mode 100644 index 0000000..172b8a2 --- /dev/null +++ b/.github/workflows/cut-versions.yml @@ -0,0 +1,97 @@ +name: Auto-cut Stable versions + +# Checks every versioned tool for a newer tag upstream (see +# scripts/auto-cut-versions.js) and, if one exists, cuts Stable and +# re-cuts Previous versions via scripts/cut-version.js, then merges the +# result straight to main — see "Cutting Stable or Previous versions" in +# docs/contribute/versioning.mdx. Fully automatic end to end: a newer tag +# existing upstream is itself the only signal this waits for, and the +# build + test run below is the gate, not a human. Runs on a schedule so +# nobody has to remember to run that script by hand after a release, and +# nobody has to click merge either. + +on: + schedule: + - cron: '0 6 * * *' # daily, 06:00 UTC + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +concurrency: + group: auto-cut-versions + cancel-in-progress: false + +jobs: + auto-cut: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + # See the matching comment in ci.yml for why both are needed. + - name: Install Doxygen and Graphviz + run: sudo apt-get update && sudo apt-get install -y doxygen graphviz + + - name: Check for new tags and cut Stable + run: node scripts/auto-cut-versions.js + + - name: Determine whether anything was cut + id: check + run: | + if [ -f cut-version-summary.md ]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + else + echo "changed=false" >> "$GITHUB_OUTPUT" + fi + + # A cut is never pushed unverified — build/test have to pass on the + # actual result before a PR is opened or updated with it. + - name: Build + if: steps.check.outputs.changed == 'true' + run: npm run build + + - name: Test + if: steps.check.outputs.changed == 'true' + run: npm test + + # One fixed branch, force-pushed each run — a run the next day with + # no further upstream changes has nothing new to add, and a run + # while an earlier auto-cut PR somehow still exists updates that + # same PR in place instead of opening a duplicate (normally there + # is none: the merge below closes it out the same run it's opened). + # Still goes through a PR (not a direct push to main) so the cut + # has a normal commit/PR record — merging it is what's automatic + # here, not the record-keeping. + - name: Open, then merge, the PR + if: steps.check.outputs.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + BRANCH="automated/cut-versions" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -B "$BRANCH" + git add -A -- '*_versioned_docs' '*_versioned_sidebars' '*_versions.json' versioned-tools-stable.json + git commit -m "$(printf 'Auto-cut Stable version(s)\n\n%s' "$(cat cut-version-summary.md)")" + git push --force origin "$BRANCH" + if [ -z "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number')" ]; then + gh pr create --title "Auto-cut Stable version(s)" --body-file cut-version-summary.md --head "$BRANCH" --base main + else + gh pr edit "$BRANCH" --body-file cut-version-summary.md + fi + # Build + Test above already validated this exact commit, so + # merge immediately rather than waiting on anything further — + # if branch protection on main blocks this (e.g. it requires + # its own separate status checks or reviews), this fails loudly + # here and the PR is left open for a human, rather than merging + # partway or silently doing nothing. + gh pr merge "$BRANCH" --merge --delete-branch diff --git a/.gitignore b/.gitignore index 46d89ac..69afc83 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,10 @@ versioned-tools/**/*.md /doxygen2docusaurus.json /scripts/generated/ +# scripts/auto-cut-versions.js's own scratch output — read by +# .github/workflows/cut-versions.yml, never committed itself. +/cut-version-summary.md + # Editor / machine-specific .vscode/ diff --git a/adaptive-grippers-cpp_versioned_docs/version-previous-versions/_readme.md b/adaptive-grippers-cpp_versioned_docs/version-previous-versions/_readme.md deleted file mode 100644 index a9c3674..0000000 --- a/adaptive-grippers-cpp_versioned_docs/version-previous-versions/_readme.md +++ /dev/null @@ -1,14 +0,0 @@ - - -C++ driver with functions to control `Robotiq` Adaptive Grippers: 2F85, 2F140 and Hand-E. It allows high communication frequency. - -:::note -With the default baudrate of the gripper the maximum achievable communication -frequency is 250Hz. The communication frequency is set with the -`ConnectionConfig::connectionFrequency` parameter, which defaults to 100Hz. -::: - -Cross-platform: Linux, Windows, macOS — and freestanding/RTOS targets such -as STM32 microcontrollers. - - diff --git a/adaptive-grippers-cpp_versioned_docs/version-stable/docs/index.mdx b/adaptive-grippers-cpp_versioned_docs/version-stable/docs/index.mdx new file mode 100644 index 0000000..ad6a4ad --- /dev/null +++ b/adaptive-grippers-cpp_versioned_docs/version-stable/docs/index.mdx @@ -0,0 +1,15 @@ +--- +title: Introduction guides +sidebar_label: Introduction guides +--- + +import Readme from '../_readme.md'; + + + +## Contents + +{/* AUTO-GENERATED-GUIDES-TABLE:START */} + +{/* AUTO-GENERATED-GUIDES-TABLE:END */} + diff --git a/adaptive-grippers-cpp_versioned_docs/version-stable/index.mdx b/adaptive-grippers-cpp_versioned_docs/version-stable/index.mdx index 929d4eb..ad17b43 100644 --- a/adaptive-grippers-cpp_versioned_docs/version-stable/index.mdx +++ b/adaptive-grippers-cpp_versioned_docs/version-stable/index.mdx @@ -15,6 +15,14 @@ import Readme from './_readme.md'; +## Get started + +{/* AUTO-GENERATED-SUBPAGES-TABLE:START */} +
+ Introduction guides +
+{/* AUTO-GENERATED-SUBPAGES-TABLE:END */} + ## Source Code GitHub Repository diff --git a/adaptive-grippers-cpp_versioned_sidebars/version-previous-versions-sidebars.json b/adaptive-grippers-cpp_versioned_sidebars/version-previous-versions-sidebars.json index 8505830..a8402c3 100644 --- a/adaptive-grippers-cpp_versioned_sidebars/version-previous-versions-sidebars.json +++ b/adaptive-grippers-cpp_versioned_sidebars/version-previous-versions-sidebars.json @@ -14,9 +14,13 @@ "label": "Libraries", "items": [ { - "type": "doc", - "id": "index", - "label": "C++" + "type": "category", + "label": "C++", + "link": { + "type": "doc", + "id": "index" + }, + "items": [] }, { "type": "link", diff --git a/adaptive-grippers-cpp_versioned_sidebars/version-stable-sidebars.json b/adaptive-grippers-cpp_versioned_sidebars/version-stable-sidebars.json index 8505830..f7b12a9 100644 --- a/adaptive-grippers-cpp_versioned_sidebars/version-stable-sidebars.json +++ b/adaptive-grippers-cpp_versioned_sidebars/version-stable-sidebars.json @@ -14,9 +14,23 @@ "label": "Libraries", "items": [ { - "type": "doc", - "id": "index", - "label": "C++" + "type": "category", + "label": "C++", + "link": { + "type": "doc", + "id": "index" + }, + "items": [ + { + "type": "category", + "label": "Introduction guides", + "link": { + "type": "doc", + "id": "docs/index" + }, + "items": [] + } + ] }, { "type": "link", diff --git a/adaptive-grippers-cpp_versions.json b/adaptive-grippers-cpp_versions.json index 402035e..47ba807 100644 --- a/adaptive-grippers-cpp_versions.json +++ b/adaptive-grippers-cpp_versions.json @@ -1,4 +1,4 @@ [ - "stable", - "previous-versions" + "previous-versions", + "stable" ] diff --git a/docs/contribute/versioning.mdx b/docs/contribute/versioning.mdx index 1d42c5d..6fdfecc 100644 --- a/docs/contribute/versioning.mdx +++ b/docs/contribute/versioning.mdx @@ -204,106 +204,84 @@ also swizzled shorter, to one line (`src/theme/DocVersionBanner/index.jsx`) — unrelated to any of the above, just bundled into the same theme-swizzling work. -## Cutting Stable or Previous versions by hand - -There's no CI automation for this yet — every version cut is a manual, -local operation, run once and committed. `scripts/list-submodule-tags.js` -finds the current tags directly off each submodule's remote (`git -ls-remote --tags`, not the local checkout, which can go stale): - -```bash -node scripts/list-submodule-tags.js -``` - -**To cut (or re-cut) Stable at the newest tag:** +## Cutting Stable or Previous versions + +`.github/workflows/cut-versions.yml` runs this daily for every tool +already tracking a Stable tag, fully automatically — end to end, not +just the cut itself: it checks each one's submodule for a newer tag +(`scripts/auto-cut-versions.js`), and if there is one, that's the only +signal it waits for; it cuts it, validates the result with a full build +and test run, and merges straight to `main` through a PR it opens and +merges itself. Nobody needs to remember to run this after a release, and +nobody needs to click merge either. There's no filtering on tag name yet +(e.g. skipping a pre-release/beta tag) — every tool currently opted into +versioning only ever tags real releases, so "newest tag" already means +"newest release" for all of them; a name-based filter is a deliberate, +not-yet-needed follow-up for the day that stops being true. + +Cutting by hand (a new tool's first cut, before it's in +`versioned-tools-stable.json` for the automation to find; re-cutting a +specific non-newest tag; or just running it locally instead of waiting +for the schedule) is one command each, via `scripts/cut-version.js`: ```bash -cd external/ -git checkout -cd ../.. -SKIP_SUBMODULE_RESET=1 node scripts/sync-external-docs.js -npm run docusaurus -- docs:version: stable -cd external/ && git checkout main && cd ../.. -SKIP_SUBMODULE_RESET=1 node scripts/sync-external-docs.js # restore Development (main)'s own content -``` - -`SKIP_SUBMODULE_RESET=1` is required — `sync-external-docs.js` runs `git -submodule update --init --force` on every normal invocation, which would -silently revert the manual `git checkout ` right back to the pinned -commit before the sync even ran. - -**Rewrite any `main`-branch source links to the tag, before cutting.** -Content synced from the submodule (its README, guides) routinely links -back to its own source on GitHub — `tree/main/...`, `blob/main/...` — which -is correct for Development but wrong once that same text is frozen into a -Stable snapshot: the file at `main` can already differ from what shipped -in the tag Stable is supposed to represent. Rewrite every such link to -`tree//...` / `blob//...` in the checked-out content *before* -running `docs:version:`, and do the same for any hand-authored "Source -Code" button/CTA on the tool's own wrapper page -(`https://github.com//` → `https://github.com///tree/`). -There's no automation for this yet — grep the synced content for -`/main/` under `github.com/robotiq/` before cutting, and check by hand. - -**Watch for stale-content contamination.** `sync-external-docs.js` never -deletes a previously-written folder (e.g. a tool's `docs/` guides or -generated `API/`) just because the currently-checked-out tag's job skips -(no `Doxyfile` yet at that tag, no `docs/` folder yet, ...) — it only -writes what the current job list produces. If `versioned-tools///` -already has content left over from a *different* (usually newer) checkout -when you cut a version, that stale content gets captured into the -snapshot too. Before cutting a version that should be sparse (an early -tag that predates a guide folder, or a `previous-versions` signpost that -should hold only its own hand-written `index.mdx`), move anything the -current tag's own sync wouldn't produce out of the way first, cut, then -restore it afterward for Development's own benefit. Verify with a plain -`find _versioned_docs/version- -type f` before trusting the -cut — skipping this step is an easy way to leak a stale `docs`/`API` tree -into what should have been a two-file signpost. - -**Writing the `Previous versions` signpost.** It's a hand-authored -`index.mdx`, temporarily written over the live wrapper page (back it up -first), cut with `docs:version: previous-versions`, then -restored: - -```mdx ---- -title: C++ -sidebar_label: C++ ---- - -**Stable** currently tracks ``'s newest release, **vX.Y.Z**. - -We only host **Development (main)** and **Stable** here — older releases -aren't archived on this site. Browse their own tag in the source -repository instead: - -- **vA.B.C** — [browse source](https://github.com/robotiq//tree/vA.B.C) -``` - -**List only tags OLDER than the one Stable tracks — never re-list Stable's -own tag.** A tool with only one tag total has *nothing* to list here yet; -say so explicitly ("there are no older releases archived here yet") rather -than reusing another tool's list shape unchanged. "Exclude whatever Stable -tracks" is the actual rule, not "list every tag that isn't literally the -newest" — those only coincide once a tool has 2+ tags, so copying a -multi-tag tool's signpost as a template for a single-tag one silently -re-lists Stable's own tag as if it were archived separately. Check each -tool's actual tag count before authoring its signpost; don't assume the -same shape applies. - -**Make the Stable tag visible.** Nothing on a Stable page itself ever -prints which tag it is — without a visible marker, the only tag a visitor -ever sees named anywhere is whatever the `Previous versions` page lists, -which reads as "only 1 of N releases is on this site" even when Stable -silently *is* the newest one. Label it in `docusaurus.config.js`'s -`versions` config: - -```js -stable: { label: 'Stable (v2.0.0)', path: '' }, +node scripts/cut-version.js stable [] # defaults to the newest +node scripts/cut-version.js previous-versions ``` -Update this by hand every time Stable is re-cut to a newer tag. +`` is one of the ids registered in `scripts/versioned-tools.js` +(`tactile-cpp`, `tactile-python`, `adaptive-grippers-cpp`, ...). Cut +`stable` before `previous-versions` for a tool that needs both — the +`previous-versions` signpost excludes whichever tag `stable` currently +tracks, so that has to already be current. + +The script runs the whole procedure that used to be done by hand, in +order, and undoes every step's own side effects even if a later step +fails: + +- Finds the target tag off the submodule's remote + (`scripts/list-submodule-tags.js`, `git ls-remote --tags` — not the + local checkout, which can go stale) and checks it out. +- Re-syncs the tool's docs at that tag (`sync-external-docs.js`, with + `SKIP_SUBMODULE_RESET` so the checkout isn't immediately reverted). +- Clears any content and generated-sidebar cache left over from a + *different* checkout before syncing, so a tag that predates a guide + folder or a Doxyfile ends up genuinely sparse rather than inheriting + another checkout's leftovers (`scripts/lib/prune.js`'s + `pruneLegacyFolder`, plus wiping `scripts/generated/`). +- Prunes any `AUTO-GENERATED-*-TABLE` sub-page link that wouldn't + actually exist in this cut (`pruneDanglingSubpageLinks`). +- Rewrites the synced content's `tree/main/...` / `blob/main/...` + GitHub links (READMEs, guides, the wrapper page's own "Source Code" + button) to point at the tag instead (`rewriteMainLinksToTag`) — the + file at `main` can already differ from what shipped in the tag Stable + represents. +- Strips the "Use a released version" admonition that's real content on + Development but wrong once frozen into Stable itself + (`stripDevelopmentOnlyAdmonition`). +- For `previous-versions`, replaces the wrapper page with a generated + signpost (`buildSignpost`) listing every tag older than the one Stable + tracks, or saying so explicitly when there aren't any — the live + sub-pages are backed up first and restored after, since this cut must + hold only that one page. +- Runs `docs:version:` into a scratch version name first, then renames it + into place — `docusaurus.config.js`'s `lastVersion`/`versions` config + has to keep resolving to an existing version for the entire duration of + *any* `docusaurus` CLI invocation, including the cut itself, so + deleting-then-recutting the real name directly trips + `lastVersion: ... is invalid`. +- Restores the submodule's actual pinned commit and Development's own + synced content, regardless of whether the cut itself succeeded. +- Records the cut tag in `versioned-tools-stable.json` (for `stable`), + which `docusaurus.config.js` reads to build the `Stable (vX.Y.Z)` + switcher label — no by-hand label edit needed. +- Regenerates every versioned sidebar snapshot against the current live + site nav tree (`regenerate-versioned-sidebars.mjs`), so this cut (and + any earlier one) reflects the site's current navigation shape. + +Review the resulting diff and run a full `npm run build` before +committing — the script prints this reminder itself. Unit tests for its +pure helpers live in `test/cut-version.test.js`. ## Checklist: adding versioning to a new tool @@ -316,33 +294,60 @@ Assuming the tool already has its own wrapper page and a 2. Move the tool's existing content (its wrapper `index.mdx`, and any other hand-authored files) from `docs/drivers////` to `versioned-tools////`. -3. Add a new `@docusaurus/plugin-content-docs` entry to +3. Add a `:::tip Use a released version` admonition to that wrapper + `index.mdx` — see any existing versioned tool's wrapper page for the + exact text, and [API Stability Policy](/docs/api-stability). This page + is what becomes Development's own content once the plugin instance + below exists, so it needs the same "this documents unreleased `main`" + nudge every other versioned tool's wrapper page already has. If the + tool also gets a generated API reference (a `doxygen2docusaurus` job), + nothing extra is needed there — `injectExperimentalNotice` in + `sync-external-docs.js` already adds the matching notice to every page + that pipeline produces, for any tool. +4. Add a new `@docusaurus/plugin-content-docs` entry to `docusaurus.config.js`'s `plugins` array — copy `tactile-cpp`'s or `adaptive-grippers-cpp`'s as a starting point depending on whether the - tool is a single page or split into guides/API. -4. In `sidebars.js`, replace the tool's doc-id sidebar entry with a + tool is a single page or split into guides/API. See + [Which version the root URL serves](#which-version-the-root-url-serves) + above for the `versions` config shape once the tool has a tag (skip + `versions`/`lastVersion` entirely until then, matching `isaac-sim`). +5. In `sidebars.js`, replace the tool's doc-id sidebar entry with a `{ type: 'link', href: encodeURI('/docs/drivers///') }` item (see any existing versioned tool's entry there for the exact shape) — it no longer belongs to the default instance. -5. Create `sidebars..js`, calling +6. Create `sidebars..js`, calling `buildInstanceSidebar('', activeItem)` from `scripts/site-nav-tree.mjs` — `activeItem` is a single `{type: 'doc', id: 'index', label: ''}` for a one-page tool, or a nested category for a tool split into guides/API (see - `sidebars.adaptive-grippers-cpp.js`). -6. Add the tool's `versioned` node (`{ label, tool: '' }`) to + `sidebars.adaptive-grippers-cpp.js`). For a split tool, guard *every* + category whose `link` targets content that might not exist yet (a + `previous-versions` cut is a pure signpost with no `docs/`, and an + early tag can predate a guide folder or a Doxyfile) — check the real + file exists on disk before including that category at all, the same + way `sidebars.adaptive-grippers-cpp.js`'s `doxygenApiCategory` and + `guidesCategory` both do. Skipping this leaves a category whose `link` + points at a doc id that doesn't exist in that version at all, which + only Docusaurus's own build-time `checkSidebarsDocIds` catches — not + the cut itself, which reports success. +7. Add the tool's `versioned` node (`{ label, tool: '' }`) to `scripts/site-nav-tree.mjs`'s `SITE_TREE`, replacing whatever `leaf(...)` entry described it before, and add its path to `VERSIONED_TOOL_PATHS`. -7. If the tool already has a tag, cut `stable` (and `previous-versions`, - if it has 2+ tags) following [Cutting Stable or Previous versions by - hand](#cutting-stable-or-previous-versions-by-hand) above, and add the - matching `versions`/`lastVersion` config plus a +8. Register the tool in `scripts/versioned-tools.js` (submodule, repo URL, + sidebar key, `toolPath`) — `scripts/cut-version.js` needs this entry to + cut `stable`/`previous-versions` for it. +9. If the tool already has a tag, cut `stable` (and `previous-versions`, + if it has 2+ tags) following [Cutting Stable or Previous + versions](#cutting-stable-or-previous-versions) above, and add a `custom-scopedVersionDropdown` navbar item. If it has no tags yet, skip - this step entirely — leave `includeCurrentVersion: true` with no - `versions` config, matching `isaac-sim`, and come back to it once a tag - exists. -8. Run a full clean rebuild (`rm -rf .doxygen2docusaurus-staging build + this step entirely and come back to it once a tag exists. +10. Run a full clean rebuild (`rm -rf .doxygen2docusaurus-staging build .docusaurus scripts/generated node_modules/.cache && npm run build`) - and check the tool's `