Skip to content

feat: add page version listing and purge commands#171

Merged
pchuri merged 2 commits into
pchuri:mainfrom
stevenhan2:feat/page-versions
May 6, 2026
Merged

feat: add page version listing and purge commands#171
pchuri merged 2 commits into
pchuri:mainfrom
stevenhan2:feat/page-versions

Conversation

@stevenhan2
Copy link
Copy Markdown
Contributor

Description

Three new commands and matching client methods for managing Confluence page version history:

  • versions <pageId> — list historical versions (read-only)
  • version-delete <pageId> <versionNumber> — delete a single non-current version
  • versions-purge <pageId> — convenience: delete every non-current version, keeping only current

The list and delete calls fall back transparently to the /rest/experimental/ endpoint on a 404 or 405 from the configured /rest/api/ path. Confluence Server/Data Center exposes content versions only at the experimental path; Cloud accepts both. The fallback is sticky for paginated listVersions so long histories don't double their round-trip count.

versions-purge accepts --throttle <seconds> to space the version-delete calls inside one page, useful when the underlying instance has aggressive rate limits.

Type of Change

  • New feature (non-breaking change which adds functionality)

Testing

  • Tests pass locally with my changes (648/648)
  • I have added tests that prove my feature works
  • New and existing unit tests pass locally with my changes

12 new test cases cover:

  • pagination of listVersions
  • 404 and 405 fallback on both list and delete
  • empty results array (no infinite loop)
  • 404 propagation when both modern and experimental return 404 (page-not-found)
  • end-to-end purge through both fallbacks
  • descending-order delete (some Confluence builds renumber when an earlier version is removed)
  • partial-failure tolerance (continues the loop, collects errors)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas (path-strategy explanation in listVersions, descending-order rationale in purgeNonCurrentVersions)
  • I have made corresponding changes to the documentation (3 new rows in the Commands table)
  • My changes generate no new warnings

Additional Context

  • The viaExperimental flag returned by deleteVersion and yielded from purgeNonCurrentVersions's onProgress callback is intended as a debugging signal so a user can see when their instance routed via the fallback path. Happy to drop or rename if you'd prefer it stay implementation-detail.
  • Possible follow-ups (intentionally not in this PR to keep it focused):
    • --dry-run on versions-purge
    • Move the throttle from the CLI's onProgress callback into purgeNonCurrentVersions itself so library consumers can pace without a custom callback
    • CLI-layer validation of versionNumber for friendlier error UX

stevenhan2 added 2 commits May 4, 2026 12:20
Three new CLI commands and matching client methods:

  versions <pageId>                   list historical versions
  version-delete <pageId> <vN> [-y]   delete a single non-current version
  versions-purge <pageId> [-y]        delete every non-current version

The list and delete calls fall back transparently to the
/rest/experimental/ path when /rest/api/ returns 404 or 405, so the
commands work on Confluence Server/Data Center (where the version
endpoints aren't exposed under /rest/api/) as well as Cloud. The
fallback is sticky for paginated listVersions so long histories
don't double their round-trip count.

versions-purge accepts --throttle <seconds> to space the
version-delete calls inside one page.
- README: add Commands-table rows for `versions`, `version-delete`,
  `versions-purge` in the same shape as adjacent entries.
- listVersions: drop the unused `expand=content.version` query param.
  The mapping function only reads top-level fields, so the expand
  was inflating responses without effect.
- bin/confluence.js: drop the use-case-specific second sentence from
  the `versions-purge` block comment so it reads generically.
- tests: add three cases that were missing
    - purgeNonCurrentVersions through both fallbacks (list 404 →
      experimental, deletes 404 → experimental)
    - listVersions returns [] cleanly when results array is empty
    - listVersions propagates 404 when both modern and experimental
      paths return 404 (page-not-found case)
Copy link
Copy Markdown
Owner

@pchuri pchuri left a comment

Choose a reason for hiding this comment

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

Thanks for the thoughtful PR — really appreciate the level of care here. The 12 new test cases, the path-strategy comment in listVersions, and the descending-order rationale in purgeNonCurrentVersions made this very easy to review.

A few things I particularly liked:

  • Sticky fallback in listVersions — flipping useExperimental once and reusing it across paginated requests avoids doubling round-trips on long histories. Nice touch.
  • Descending-order delete with the renumber rationale — exactly the kind of subtlety that bites you in production; glad it's both implemented and documented inline.
  • Partial-failure tolerance — collecting errors and continuing the loop (with a covering test) is the right behavior for a bulk-cleanup tool.
  • Consistent assertWritable usage on both mutating commands.

A few minor suggestions (none blocking — happy to land as-is and address as follow-ups):

  1. Double listVersions call in versions-purge CLIbin/confluence.js calls listVersions for the early-exit checks, then purgeNonCurrentVersions calls it again internally. For pages with long histories this doubles the listing cost. Could pass pre-fetched versions in via options, or move the early-exit logic into the library.
  2. --throttle input validationparseFloat('abc') returns NaN, which silently disables throttling (NaN > 0 is false). A Number.isFinite() guard with a friendly error would catch typos.
  3. versionNumber validation in CLI — currently happens inside deleteVersion, so running version-delete 123 abc shows the prompt as Delete vNaN of page 123? before the validation rejects. Validating in the CLI before the prompt is a small UX win.
  4. README vs. CLI argument names — README documents versions <pageId_or_url> but the CLI registers versions <pageId> (similar for the other two). The behavior is correct since extractPageId accepts both, but --help output won't tell users URLs are accepted. Existing delete <pageIdOrUrl> is the precedent.
  5. viaExperimental in the public API — you flagged this in the PR description; agree it's a nice debugging signal but worth documenting as @unstable or similar so future removal isn't a breaking change for library consumers.
  6. Hardcoded limit: 200 — other paginated methods (e.g. getSpaces) accept a pageSize option via parsePositiveInt. Worth aligning for consistency, though not urgent.

CI note

The failing security check is unrelated to this PR — it's the recent batch of axios advisories (validateStatus prototype pollution, etc.) tripping npm audit --audit-level moderate. The same job fails on main at the latest commit, and this PR doesn't touch package.json or package-lock.json. A separate axios bump PR is needed; please don't let it block this one.

Approving. Thanks again!

@pchuri pchuri merged commit 2bd5c37 into pchuri:main May 6, 2026
5 of 6 checks passed
github-actions Bot pushed a commit that referenced this pull request May 6, 2026
# [2.5.0](v2.4.0...v2.5.0) (2026-05-06)

### Bug Fixes

* **deps:** bump axios to ~1.15.2 to address security advisories ([#174](#174)) ([0a1492b](0a1492b)), closes [GHSA-w9j2-pv#6h63](https://github.com/GHSA-w9j2-pv/issues/6h63) [#173](#173)
* **walker:** preserve attributes on <ul>/<ol>/<li> in markdown→storage ([#170](#170)) ([b5c172a](b5c172a)), closes [#153](#153)

### Features

* add page version listing and purge commands ([#171](#171)) ([2bd5c37](2bd5c37))
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

🎉 This PR is included in version 2.5.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@stevenhan2 stevenhan2 deleted the feat/page-versions branch May 11, 2026 17:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants