Skip to content

fix(sdk): enforce single source of truth for SDK package versioning#35110

Draft
fmontes wants to merge 1 commit intomainfrom
35109-sdk-single-version-source
Draft

fix(sdk): enforce single source of truth for SDK package versioning#35110
fmontes wants to merge 1 commit intomainfrom
35109-sdk-single-version-source

Conversation

@fmontes
Copy link
Member

@fmontes fmontes commented Mar 24, 2026

What

Replaces the SDK publish action's version detection logic with a single VERSION file at core-web/libs/sdk/VERSION.

Why

The old system scanned NPM dist-tags across all packages at publish time and picked the highest version globally. This broke in two ways:

  1. Package drift@dotcms/react had next=1.2.6-next.3 while all others were at next=1.2.5-next.7. The base version mismatch caused the suffix counter to reset to .1, colliding with an already-published version → 403 on every trunk run.
  2. New packages — adding create-app with version=1.0.0 in its package.json triggered the same collision because it had never been published and the action couldn't reconcile its version with the rest.

Changes

  • core-web/libs/sdk/VERSION — new file, set to 1.2.6 (current highest published stable). This is the single source of truth.
  • deploy-javascript-sdk/action.yml — removed ~150 lines of NPM-scanning/version-calculation logic. Now reads from VERSION, calculates next version in ~30 lines. The next tag suffix uses GITHUB_RUN_NUMBER instead of an incrementing counter — unique by definition, no collision possible.
  • cicd_manual-release-sdks.yml — bumps VERSION file and commits it to git before publishing. Version bumps are now visible in git history.

Result

  • Adding a new package to libs/sdk/ works automatically — no manual version syncing needed.
  • next tag will never collide with an existing published version.
  • To release a new stable version, just run the manual workflow with the desired increment type.

Closes #35109

…35109)

- Add core-web/libs/sdk/VERSION as the single version source
- Replace ~150 lines of fragile NPM-scanning version detection with a
  simple read from VERSION file
- Use GITHUB_RUN_NUMBER as next tag suffix — guaranteed unique, no collision
- Manual release workflow now bumps VERSION file and commits it to git
- New packages added to libs/sdk/ work automatically without manual sync

Fixes recurring 403 publish failures caused by packages drifting out of
version sync (e.g. react at 1.2.6-next.3 while others at 1.2.5-next.7).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@fmontes fmontes requested a review from a team as a code owner March 24, 2026 20:32
@github-actions github-actions bot added Area : CI/CD PR changes GitHub Actions/workflows Area : Frontend PR changes Angular/TypeScript frontend code Area : SDK PR changes SDK libraries labels Mar 24, 2026
@claude
Copy link
Contributor

claude bot commented Mar 24, 2026

Claude finished @fmontes's task in 2m 6s —— View job


PR Review

  • Gather context
  • Read changed files
  • Analyze and post review

Summary

The simplification is welcome and the core idea is sound, but there is one critical logic bug and a few other issues worth addressing before merging.


Critical: Double-Increment in Manual Release

cicd_manual-release-sdks.yml lines 59–90 + action.yml lines 112–125

The manual workflow:

  1. Bumps VERSION file (e.g., 1.2.61.2.7 for a patch bump)
  2. Commits and pushes it
  3. Calls the deploy action with version-type: patch

The deploy action then:

  1. Checks out the branch (now has VERSION=1.2.7)
  2. Reads BASE_VERSION=1.2.7
  3. Since VERSION_TYPE=patch, increments againLATEST_VERSION=1.2.8
  4. Publishes 1.2.8 to NPM

Result: git has 1.2.7, NPM has 1.2.8. After this, every trunk run would publish 1.2.7-next.X, which is lower in semver than the published stable 1.2.8.

The fix is to either pass version-type: auto from the workflow to the action (since the file is already bumped), or have the workflow not bump and let only the action do it. The custom type escapes this because the action's custom path uses CUSTOM_VERSION input directly — but major/minor/patch all double-increment.

Fix this →


Significant: next semver is lower than stable after a release

action.yml line 128:

NEXT_VERSION="${LATEST_VERSION}-next.${RUN_NUMBER}"

When VERSION=1.2.6 (already the published stable), auto trunk runs publish 1.2.6-next.X. In semver, 1.2.6-next.X < 1.2.6 — the next tag would point to versions that are semantically older than the latest stable. This is benign if users always pin to a tag, but confusing if they inspect or compare versions. After a stable release, VERSION should be bumped to the next development version (e.g., 1.2.7) so next publishes 1.2.7-next.X which is clearly ahead of 1.2.6.


Missing permissions: contents: write

cicd_manual-release-sdks.yml — the git push on line 90 needs write access to repository contents. There's no permissions: block in the workflow. If the org/repo default is read, the push will fail with a 403. Should add:

permissions:
  contents: write

Minor: for sdk in $(ls) anti-pattern

action.yml line 229:

for sdk in $(ls)

Word-splitting on ls output breaks with spaces/special chars in directory names. Use for sdk in */ instead (since this runs in the dist/libs/sdk/ directory).


Note: Error handling on partial publish failure

action.yml lines 226–265: if publishing latest fails for one package, the loop continues and publishes others. Packages end up in an inconsistent state before the final exit 1. This was pre-existing behavior, but worth noting since the action is being rewritten anyway. Consider failing fast on first publish error.

@fmontes fmontes marked this pull request as draft March 24, 2026 20:36
@spbolton
Copy link
Member

Architectural concern: VERSION file on main vs release branch pattern

The dotCMS release model keeps main versionless and deterministic:

  • Main/trunk always builds as 1.0.0-SNAPSHOT.mvn/maven.config with a version is actively prevented on main
  • Build output is determined by commit hash — same hash, same output
  • Release branches commit the version to .mvn/maven.config on a tagged release branch
  • The merge queue is the single gateway for changes to main — out-of-band pushes to main force all running merge queue builds to restart, wasting up to 30-90 minutes of compute per interruption

This PR introduces core-web/libs/sdk/VERSION on main. A few concerns:

  1. Determinism — a VERSION bump commit changes no code but alters build output. Two commits with identical code but different VERSION values produce different artifacts, diverging from the commit-hash-determines-output invariant.

  2. Merge queue disruption — the manual release workflow pushes directly to main, bypassing the merge queue. Any push to main outside the merge queue invalidates and restarts all in-flight merge queue builds. Maintaining the merge queue as the only source of changes to main avoids this disruption.

  3. next tag semver ordering — after publishing 1.2.6 as stable, trunk runs publish 1.2.6-next.X. In semver, prereleases are lower than their release (1.2.6-next.X < 1.2.6), so the @next tag would point to versions semantically older than @latest. VERSION would need to be bumped to 1.2.7 immediately after a release to keep next ahead of latest — adding another push to main.

Alternative (aligned with existing model):

  • Trunk runs: publish next tag with ${GITHUB_RUN_NUMBER} suffix (as this PR does — good). Base version derived from the current NPM @latest tag or a fixed value.
  • Manual SDK releases: create a release branch, commit the VERSION file there, publish from that branch. Same pattern as Maven releases with .mvn/maven.config.
  • Main stays versionless: no VERSION file on main. Trunk builds derive what they need without tracked version state.

This is a design question, not a blocker — there may be good reasons the SDK model needs to differ from Maven. But worth a deliberate decision rather than drifting into a different pattern.

Also from the automated review:

  • Double-increment bug: the manual workflow bumps VERSION then passes the same version-type to the action, which increments again. Git ends up with 1.2.7, NPM with 1.2.8. Needs fixing regardless of architectural direction.
  • Missing permissions: contents: write: the git push step will fail without write permissions if the repo default is read-only.

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

Labels

AI: Safe To Rollback Area : CI/CD PR changes GitHub Actions/workflows Area : Frontend PR changes Angular/TypeScript frontend code Area : SDK PR changes SDK libraries

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

fix(sdk): enforce single source of truth for SDK package versioning

2 participants