Skip to content

fix(rpk-docs): never delete pages for plugins absent from the tree - #221

Closed
JakeSCahill wants to merge 5 commits into
mainfrom
fix/protect-failed-plugin-pages
Closed

fix(rpk-docs): never delete pages for plugins absent from the tree#221
JakeSCahill wants to merge 5 commits into
mainfrom
fix/protect-failed-plugin-pages

Conversation

@JakeSCahill

@JakeSCahill JakeSCahill commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Problem

The rpk-docs automation deleted the rpk k8s multicluster reference pages in redpanda-data/docs#1831. Root cause, verified in an isolated environment with the v26.2.1-rc2 binary:

  • rpk core ships only a shim (install/uninstall/upgrade) for managed plugins. multicluster and version come from the separately published k8s plugin.
  • The CI generation environment has no plugin installed, and during pre-GA windows it can't install one: the plugin publisher's stableVersionRe only promotes pure X.Y.Z releases, so unpinned rpk k8s install fails until GA.
  • With the plugin absent from --print-tree, the generator treated its pages and nav entries as stale and removed them. ai, check, and connect are equally exposed (all shim-only in a plugin-less tree).

Fix

Auto-detect known plugins whose command subtree is absent or shim-only in the current run's tree and preserve their existing pages and nav entries (deduplicating nav lines against entries regenerated in the same run). Callers can also pass protectedPlugins explicitly. The source-build path now records failed plugin installs in the log.

Second fix: help-text underlines and column headers

Command help text underlines section titles with =/- runs and uses ALL-CAPS column-header rows in aligned sample output. The section parser left the underlines in section content, where a run of 4+ = is an AsciiDoc example-block delimiter — producing an unterminated block on the generated rpk cluster brokers decommission-status page (and its rpk redpanda admin predecessor) — and promoted multi-space column-header rows (PARTITION REASON) to section headings, splitting sample tables. The parser now consumes an underline that directly follows a section header, treats multi-space lines as content, and warns if a bare delimiter run still reaches content. Verified by regenerating all 355 pages from the v26.2.1-rc2 tree: zero bare delimiter runs outside code fences (the only matches are legitimate [tabs] block delimiters from overrides).

Verification

Ran generateRpkDocs against a copy of the docs repo's beta rpk reference using a clean-environment v26.2.1-rc2 tree (no plugins): all four shim-only plugin directories preserved with a log line each, 26 plugin nav entries kept (including the four multicluster entries #1831 dropped), zero plugin pages deleted, and non-plugin regeneration proceeded normally. node --check passes on both changed files.

🤖 Generated with Claude Code

rpk core ships only an install/uninstall/upgrade shim for managed
plugins. When the generation environment lacks a plugin binary, the
plugin's real commands are missing from --print-tree, and the
generator treated its pages and nav entries as stale and deleted
them. This happens every pre-GA window: the plugin publisher only
promotes stable X.Y.Z releases, so 'rpk <plugin> install' resolves
nothing until GA. The v26.2.1-rc2 regen deleted the five rpk k8s
multicluster pages this way (redpanda-data/docs#1831).

Auto-detect known plugins whose subtree is absent or shim-only and
preserve their existing pages and nav entries, deduplicating against
entries regenerated in the same run. Also track failed plugin
installs in the source-build path for the generation log.

Verified against a copy of the docs beta rpk reference with a
plugin-less v26.2.1-rc2 tree: all four shim-only plugin directories
preserved, 26 plugin nav entries kept, zero plugin pages deleted,
while non-plugin regeneration proceeds normally.
@netlify

netlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploy Preview for docs-extensions-and-macros ready!

Name Link
🔨 Latest commit f2a976a
🔍 Latest deploy log https://app.netlify.com/projects/docs-extensions-and-macros/deploys/6a6b050f7eb8f00008dd5f2a
😎 Deploy Preview https://deploy-preview-221--docs-extensions-and-macros.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 381a7fca-0f71-4476-8690-3b9782108a23

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The rpk documentation generator now accepts and auto-detects protected plugins, preserves their existing navigation entries, and excludes their generated directories from stale-file deletion. The Docker-based plugin installation flow also records plugin names whose installation fails.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: kbatuigas

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: preserving plugin docs when their command tree is absent.
Description check ✅ Passed The description is directly about the same rpk-docs deletion bug and the proposed preservation fix.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/protect-failed-plugin-pages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tools/rpk-docs/generate-rpk-docs.js`:
- Around line 2639-2667: Add regression tests covering auto-protection in the
plugin detection logic around PLUGIN_SHIM_COMMANDS, KNOWN_PLUGIN_NAMES, and
effectiveProtectedPlugins when a known plugin is absent or has only shim
commands. Verify protected plugin directories survive stale-file cleanup, and
verify regenerated navigation does not contain duplicate plugin xrefs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 56f4e31d-1293-450e-8e54-26e666d697d4

📥 Commits

Reviewing files that changed from the base of the PR and between ad02a1f and 86d1fcb.

📒 Files selected for processing (2)
  • tools/rpk-docs/generate-rpk-docs.js
  • tools/rpk-docs/rpk-docs-handler.js

Comment thread tools/rpk-docs/generate-rpk-docs.js Outdated
Command help text often underlines section titles with a run of = or -
characters and uses ALL-CAPS column-header rows in aligned sample
output. The section parser promoted the titles to headings but left
the underline in the content, where a line of 4+ = characters is an
AsciiDoc example-block delimiter, producing an unterminated block
(seen on rpk cluster brokers decommission-status, and previously on
its rpk redpanda admin predecessor). It also promoted multi-space
column-header rows such as 'PARTITION      REASON' to section
headings, splitting sample tables.

Consume the underline when it directly follows a section header, treat
lines containing multi-space runs as content rather than headers, and
warn if any bare delimiter run still reaches section content.

Verified by regenerating all 355 pages from the v26.2.1-rc2 tree: the
decommission-status sections now render with their tables intact, and
no bare delimiter runs remain outside code fences.
…(CodeRabbit)

Covers auto-protection when a known plugin is absent or shim-only,
explicit protectedPlugins, protected plugin directories surviving the
stale-file sweep while genuinely stale pages are still deleted, and
preserved nav entries not duplicating entries that are also present in
the regenerated output.
@JakeSCahill
JakeSCahill requested a review from a team July 30, 2026 07:43
…splacing nav entries

Protection for managed plugins previously only exempted their pages from
the stale-file sweep. Two gaps remained when the tree had a plugin's shim
(install/uninstall/upgrade) but not its real commands:

- Pages under the plugin subtree were still written, so the parent page
  (e.g. rpk-k8s.adoc) was regenerated with a shim-only Subcommands table,
  orphaning the preserved child pages.
- Preserved nav entries were appended after all generated entries, so
  they rendered nested under the wrong parent at the end of the section.

Protection now covers the whole pipeline. Protected plugins are detected
before the write loop (explicit callers merged with shim-only/absent
auto-detection) and generation skips their entire subtree, parent page
included, exactly like the fully-absent case. updateNavFile no longer
generates entries for protected plugins. It preserves each plugin's
previous nav block (parent plus nested children) and splices it back in
at its original position, anchored to the nearest preceding surviving
entry. In the common shim scenario the nav and every plugin page come
out byte-identical to the previous run.

The preservation log line now lists only plugins that actually had nav
entries preserved instead of every protected plugin.
… plugins

fetchRpkTreeFromLinuxSource collected failedPlugins but never used it.
It now returns { tree, failedPlugins } and the handler threads the list
into both generateRpkDocs calls as explicit protectedPlugins, merged
there with auto-detection, so a failed install can never delete or
rewrite that plugin's existing docs even if the shim heuristic changes.

Also drop the handler's duplicate KNOWN_PLUGINS definition and share the
single constant exported by generate-rpk-docs.js (the handler still
re-exports it for existing consumers).
@JakeSCahill

Copy link
Copy Markdown
Contributor Author

Pushed two commits addressing the review blockers, plus the smaller findings from the same review.

Blocker 1: preserved nav entries appended at the end (c2db373)

updateNavFile no longer generates entries for protected plugins and no longer appends preserved entries after the last generated entry. It preserves each protected plugin's previous nav block (parent entry plus nested children) and splices it back in at its original position, anchored to the nearest preceding entry that survives regeneration. In the shim scenario the rebuilt nav is byte-identical to the previous nav, minus only genuinely stale entries elsewhere in the section.

Blocker 2: shim content overwrote the plugin parent page (c2db373)

Protection now covers page writes, not just the deletion sweep. Protected plugins are detected before the write loop (detectProtectedPlugins, explicit callers merged with the shim-only/absent auto-detection) and generation skips the plugin's entire subtree, parent page included. A shim-only run leaves rpk-k8s.adoc and every child page untouched, exactly like the fully-absent case.

Cleanups (f2a976a and c2db373)

  • failedPlugins in the handler is no longer dead code. fetchRpkTreeFromLinuxSource returns { tree, failedPlugins } and both generateRpkDocs calls receive it as explicit protectedPlugins, merged with auto-detection.
  • The duplicate KNOWN_PLUGIN_NAMES list is gone. generate-rpk-docs.js now owns and exports KNOWN_PLUGINS, and the handler imports it (still re-exported from the handler for existing consumers).
  • The "Preserving N nav entries for plugins" log now lists only plugins that actually had entries preserved.

Test evidence

End-to-end harness reproducing the pre-GA shim scenario (seeded full k8s pages and nav, shim-only tree, stale rpk-topic-describe page):

Before this change:

  • rpk-k8s.adoc, rpk-k8s-install/uninstall/upgrade.adoc rewritten (sha256 changed), parent Subcommands table reduced to the shim
  • multicluster nav entries appended after rpk-version at the end of the section, detached from the rpk k8s parent

After this change:

  • all 6 rpk-k8s/ pages byte-identical (sha256 verified)
  • nav k8s block unchanged and in place: parent directly after rpk-iotune, multicluster children nested directly under the parent, rpk-version still follows the block
  • stale non-plugin page rpk-topic-describe.adoc still deleted and its nav entry removed (filesDeleted: 1)

New regression tests: preserved entries spliced in place under the plugin parent (nav byte-identical in the shim case), fully absent plugin block kept in its original position, shim run leaves the parent page content untouched and writes no shim pages under the protected subtree, and a fully installed plugin still regenerates pages and sweeps its stale files as usual. One existing test's comment was updated to match the new preserve-in-place semantics (its assertions were placement-agnostic and still pass).

Full suite: 33 suites, 760 tests passing (npx jest), including all 8 rpk-docs suites.

@JakeSCahill

Copy link
Copy Markdown
Contributor Author

Superseded by #225, now merged: all of this branch's protection commits were folded in (verified — every symbol and all six regression tests are in main via #225).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant