Skip to content

Backoffice: Preserve prerelease tag when hoisting peer dependencies#22841

Merged
AndyButland merged 1 commit into
mainfrom
v18/bugfix/preserve-prerelease-in-hoisted-peer-deps
May 13, 2026
Merged

Backoffice: Preserve prerelease tag when hoisting peer dependencies#22841
AndyButland merged 1 commit into
mainfrom
v18/bugfix/preserve-prerelease-in-hoisted-peer-deps

Conversation

@iOvergaard

Copy link
Copy Markdown
Contributor

Summary

The publish-time cleanse step that rewrites workspace dependencies into the published peerDependencies of @umbraco-cms/backoffice was stripping the prerelease suffix from version ranges. ^2.0.0-rc.1 (the version @umbraco-backoffice/uui declares for @umbraco-ui/uui) was being collapsed to ^2.0.0, which no published @umbraco-ui/uui version satisfies — only 2.0.0-rc.0/-rc.1 are on npm so far. The result was that @umbraco-cms/backoffice@18.0.0-beta1+ (which is what extension developers are installing) listed an unresolvable peer dep and npm install failed:

Can't update extensions to @umbraco-cms/backoffice@18.0.0-beta1 because it depends on @umbraco-ui/uui@2.0.0 and that's not published.

Cause: looseVersionRange() in devops/publish/cleanse-pkg.js read semver.minVersion(...).major/minor/patch and discarded the .prerelease array when rebuilding the range string.

Fix: include the prerelease suffix when present, so ^2.0.0-rc.1 round-trips as ^2.0.0-rc.1 and accepts 2.0.0-rc.1, future RCs/betas, and the eventual stable 2.x.

Verified with semver semantics:

^2.0.0-rc.1 → ^2.0.0-rc.1     (was: ^2.0.0)
^3.3.1      → ^3.3.1          (unchanged)
^0.85.0     → >=0.85.0 <1.0.0 (unchanged)

satisfies('2.0.0-rc.1', '^2.0.0-rc.1') → true
satisfies('2.0.0',      '^2.0.0-rc.1') → true
satisfies('2.0.1',      '^2.0.0-rc.1') → true
satisfies('3.0.0',      '^2.0.0-rc.1') → false

The only workspace currently affected is src/external/uui (@umbraco-ui/uui@^2.0.0-rc.1). All other external workspace deps already use stable ranges and produce the same output as before.

Test plan

  • Cherry-pick to release/18.0 so the fix lands in the next 18.0.0-beta/rc package
  • Run npm run build:for:cms and npm pack in src/Umbraco.Web.UI.Client, inspect the peerDependencies of the resulting tarball — @umbraco-ui/uui should be ^2.0.0-rc.1, not ^2.0.0
  • npm install @umbraco-cms/backoffice@<new-build> in an extension project resolves cleanly

🤖 Generated with Claude Code

The publish cleanse step strips the prerelease suffix from hoisted dependency
ranges via `semver.minVersion(...).major/minor/patch`. For `^2.0.0-rc.1`
this produced `^2.0.0`, which no published `@umbraco-ui/uui` version
currently satisfies, breaking extension installs against
`@umbraco-cms/backoffice@18.0.0-beta1`+.

Use the full SemVer (including any prerelease) as the floor so
`^2.0.0-rc.1` stays satisfiable by the actual published rc.
Copilot AI review requested due to automatic review settings May 13, 2026 14:34
@claude

claude Bot commented May 13, 2026

Copy link
Copy Markdown

Claude finished @iOvergaard's task in 1m 41s —— View job


PR Review

Target: origin/main · Based on commit: c2e7c152

Fixes a publish-time regression where looseVersionRange() discarded the prerelease identifier when rebuilding the peer dependency range — causing ^2.0.0-rc.1 to collapse to ^2.0.0, an unsatisfiable range since no stable @umbraco-ui/uui@2.x exists on npm yet.

  • Other changes: Published peerDependencies for @umbraco-ui/uui in @umbraco-cms/backoffice will now correctly read ^2.0.0-rc.1 instead of ^2.0.0, resolving the install failure for extension developers.

Suggestions

  • devops/publish/cleanse-pkg.js: No automated tests exist for looseVersionRange(), and none are added here. The devops directory has no test infrastructure today, so this is not a blocker — but the function now has meaningful branching logic (stable vs. prerelease, 0.x.y vs. major ≥ 1) that would benefit from a small unit test suite (e.g., a Node.js --test or Vitest file alongside the script). The verification table in the PR description would be an ideal starting point.

Approved

The fix is correct and minimal. semver.SemVer.prerelease is ReadonlyArray<string | number>, prerelease.join('.') produces the right suffix (e.g., rc.1), and the destructuring change keeps the diff clean. All existing stable-version code paths are unaffected — they just pick up an empty prereleaseSuffix. Good work, this was a genuinely tricky publish-time bug to track down.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Suggestion] No automated tests exist for looseVersionRange(), and none are added in this PR. The devops directory has no test infrastructure today, so this isn't a blocker — but this function now has meaningful branching logic (stable vs. prerelease, 0.x.y vs. major≥1) that would benefit from a small unit test suite (e.g., a Node.js --test or Vitest file in devops/publish/). The PR description's manual verification table would be a good starting point for test cases.

@claude claude Bot added the area/frontend label May 13, 2026

Copilot AI 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.

Pull request overview

Fixes the publish-time package cleansing step for @umbraco-cms/backoffice so that prerelease version ranges aren’t rewritten into unsatisfiable stable ranges, preventing npm install failures for extension developers consuming 18.x beta/rc packages.

Changes:

  • Updates looseVersionRange() to preserve prerelease suffixes when reconstructing the “floor” version from semver.minVersion(...).
  • Ensures both ^... ranges and 0.x.y ranges keep prerelease tags (e.g. ^2.0.0-rc.1 remains ^2.0.0-rc.1).

@AndyButland AndyButland 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.

Looks good. Checking the entry in npm/umbraco-cms-backoffice-18.1.0-rc.g4df33a6.tgz/package.json from this build I see:

"@umbraco-ui/uui": "^2.0.0-rc.1",

But from umbraco-cms-backoffice-18.0.0-beta1.tgz/package.json for release-18.0.0-beta1 we have:

"@umbraco-ui/uui": "^2.0.0",

@AndyButland AndyButland merged commit 3e7c1fa into main May 13, 2026
37 checks passed
@AndyButland AndyButland deleted the v18/bugfix/preserve-prerelease-in-hoisted-peer-deps branch May 13, 2026 20:51
AndyButland pushed a commit that referenced this pull request May 13, 2026
…22841)

The publish cleanse step strips the prerelease suffix from hoisted dependency
ranges via `semver.minVersion(...).major/minor/patch`. For `^2.0.0-rc.1`
this produced `^2.0.0`, which no published `@umbraco-ui/uui` version
currently satisfies, breaking extension installs against
`@umbraco-cms/backoffice@18.0.0-beta1`+.

Use the full SemVer (including any prerelease) as the floor so
`^2.0.0-rc.1` stays satisfiable by the actual published rc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants