Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
369f58f
feat(spec): add issue resolution specification for SDK packaging vers…
KevinDavilaDotCMS Sep 8, 2026
a7a2ee5
Address PR review: name the exact READMEs and add @dotcms/types to th…
KevinDavilaDotCMS Sep 9, 2026
67d3fa8
Add SDK package.json shape validator; retire dead bump-sdk-versions.js
KevinDavilaDotCMS Sep 9, 2026
aaa9e86
Expand Defect B2 scope: main has 6 examples, not 4
KevinDavilaDotCMS Sep 9, 2026
c83292c
Merge spec branch: expand Defect B2 to 6 main examples
KevinDavilaDotCMS Sep 9, 2026
adf9b37
Normalize SDK release version to valid semver (Defect A)
KevinDavilaDotCMS Sep 9, 2026
864c375
Move sibling SDK deps to peerDependencies with 0.0.0 sentinel (Defect…
KevinDavilaDotCMS Sep 9, 2026
d861ba1
Fix main example pins to latest, document Evergreen assumption (Defec…
KevinDavilaDotCMS Sep 9, 2026
4b3a63f
Wire the SDK package.json shape guardrail into CI (AC-007)
KevinDavilaDotCMS Sep 9, 2026
593f852
Resolve LTS pin: 26.9.3-1 verified against a real server, not 1.2.0
KevinDavilaDotCMS Sep 9, 2026
1cbbb94
Merge spec branch: resolve LTS pin to 26.9.3-1
KevinDavilaDotCMS Sep 9, 2026
397d2d4
Add root-cause fix: auto-pin examples at release-branch-cut time (AC-…
KevinDavilaDotCMS Sep 9, 2026
9a9146b
Merge spec branch: root-cause fix for release-branch-cut pinning
KevinDavilaDotCMS Sep 9, 2026
74ba3c1
Root-cause fix: pin example app deps at release-branch-cut time (AC-010)
KevinDavilaDotCMS Sep 9, 2026
1bb7cc0
Correct LTS pin: 1.2.0, not 26.9.3-1 -- static schema check beats liv…
KevinDavilaDotCMS Sep 9, 2026
8b4b15e
Merge spec branch: correct LTS pin to 1.2.0
KevinDavilaDotCMS Sep 9, 2026
6eb36c4
Close out Defect B3: _v16 backport verified and opened (PR #37476)
KevinDavilaDotCMS Sep 9, 2026
19c5eda
Merge spec branch: close out Defect B3 with _v16 backport
KevinDavilaDotCMS Sep 9, 2026
2047c5e
Commit the verified package.json shape contract to PR2
KevinDavilaDotCMS Sep 9, 2026
ebeca08
Merge branch 'main' into 36891-sdk-packaging-version-fix-impl-v2
KevinDavilaDotCMS Sep 9, 2026
dc1ac04
fix(cicd): address CI/CD review on SDK packaging fix (#36891)
KevinDavilaDotCMS Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ inputs:
outputs:
npm-package-version:
description: 'SDK libs - NPM package version that was published'
value: ${{ inputs.version }}
value: ${{ steps.update-versions.outputs.normalized_version }}
published:
description: 'SDK libs - Published (true if all packages published successfully)'
value: ${{ steps.deployment_status.outputs.published }}
Expand All @@ -58,6 +58,7 @@ runs:
node-version-file: 'core-web/.nvmrc'

- name: 'Update package.json versions'
id: update-versions
working-directory: ${{ github.workspace }}/core-web/libs/sdk/
env:
RELEASE_VERSION: ${{ inputs.version }}
Expand All @@ -66,23 +67,60 @@ runs:
set -euo pipefail
echo "::group::Update package.json versions"

# ADR-0019 requires the published SDK version to be valid, ordered npm SemVer —
# e.g. "2026.6.24", not "2026.06.24" — but the dotCMS release tag this value comes
# from is zero-padded (yy.mm.dd-##), so strip leading zeros from each numeric
# segment before writing it anywhere. This is the single point of normalization;
# every jq call below, and the idempotency check in the publish step, must use
# this normalized value, not the raw $RELEASE_VERSION input.
#
# Walk the string segment by segment, PRESERVING the original separators and every
# trailing segment. Splitting on [.-] and rebuilding from only $1..$4 silently
# truncates the `-next.<run_number>` suffix cicd_3-trunk.yml appends to the version
# it passes in (26.9.3-1-next.2632 -> 26.9.3-1), which would make every `next`
# publish collide with the stable release version. Non-numeric segments (`next`)
# pass through untouched. POSIX awk, no gawk dependency.
RELEASE_VERSION=$(echo "$RELEASE_VERSION" | awk '{
s = $0; out = ""
while (match(s, /[.-]/)) {
seg = substr(s, 1, RSTART - 1); sep = substr(s, RSTART, 1)
if (seg ~ /^[0-9]+$/) { sub(/^0+/, "", seg); if (seg == "") seg = "0" }
out = out seg sep
s = substr(s, RSTART + 1)
}
if (s ~ /^[0-9]+$/) { sub(/^0+/, "", s); if (s == "") s = "0" }
print out s
}')
echo "Normalized release version: $RELEASE_VERSION"
echo "normalized_version=$RELEASE_VERSION" >> "$GITHUB_OUTPUT"

sdk_packages=($(find . -maxdepth 1 -mindepth 1 -type d -exec basename {} \;))
echo "Found SDK packages: ${sdk_packages[*]}"

# Each sibling's OWN published name, resolved once up front. Never
# "@dotcms/<directory>": libs/sdk/cli publishes as the UNSCOPED `dotcms`, so a
# hardcoded scope can never match it and would silently leave a literal "latest" in
# a published manifest — Defect B1 all over again. Same reason the publish step
# below reads .name rather than assuming the scope.
sdk_package_names=()
for dep in "${sdk_packages[@]}"; do
sdk_package_names+=("$(jq -r '.name' "$dep/package.json" 2>/dev/null || echo "@dotcms/$dep")")
done
echo "Resolved SDK package names: ${sdk_package_names[*]}"

for sdk in "${sdk_packages[@]}"; do
pkg="$sdk/package.json"
if [ -f "$pkg" ]; then
jq --arg v "$RELEASE_VERSION" '.version = $v' "$pkg" > tmp.$$.json && mv tmp.$$.json "$pkg"
echo " ✅ $sdk -> $RELEASE_VERSION"

# Update dependencies/peerDependencies that reference other SDK packages.
# Pinned exact (no caret): sibling SDK packages always publish in lockstep at
# the same version, so a range only reintroduces the ambiguity ADR-0019 removes.
for dep in "${sdk_packages[@]}"; do
# Same reason as the publish step: resolve the sibling's real name rather than
# assuming the @dotcms/ scope, so an unscoped package is still repointed.
dep_name=$(jq -r '.name' "$dep/package.json" 2>/dev/null || echo "@dotcms/$dep")
for field in dependencies peerDependencies; do
# Update dependencies/peerDependencies/devDependencies that reference other SDK
# packages. Pinned exact (no caret): sibling SDK packages always publish in
# lockstep at the same version, so a range only reintroduces the ambiguity
# ADR-0019 removes. devDependencies is included so @dotcms/types (a dev-only
# dependency in every SDK lib) no longer ships with an unmasked "latest".
for dep_name in "${sdk_package_names[@]}"; do
for field in dependencies peerDependencies devDependencies; do
if jq -e ".${field}[\"$dep_name\"]" "$pkg" >/dev/null 2>&1; then
jq --arg field "$field" --arg dep "$dep_name" --arg v "$RELEASE_VERSION" \
'.[$field][$dep] = $v' "$pkg" > tmp.$$.json && mv tmp.$$.json "$pkg"
Expand All @@ -93,12 +131,15 @@ runs:
fi
done

# Update example projects
# Update example projects. Exact pin, no caret: a `^` range drifts forward exactly
# the way Defect B3 did on the LTS branches, and validate-sdk-package-shapes rejects
# ranges on any non-trunk branch — the release pipeline must never emit a shape its
# own guardrail would fail.
if [ -d "$EXAMPLES_PATH" ]; then
while IFS= read -r pkg_json; do
for dep in "${sdk_packages[@]}"; do
if jq -e ".dependencies[\"@dotcms/$dep\"]" "$pkg_json" >/dev/null 2>&1; then
jq --arg dep "@dotcms/$dep" --arg v "^$RELEASE_VERSION" \
for dep_name in "${sdk_package_names[@]}"; do
if jq -e ".dependencies[\"$dep_name\"]" "$pkg_json" >/dev/null 2>&1; then
jq --arg dep "$dep_name" --arg v "$RELEASE_VERSION" \
'.dependencies[$dep] = $v' "$pkg_json" > tmp.$$.json && mv tmp.$$.json "$pkg_json"
fi
done
Expand Down Expand Up @@ -161,7 +202,9 @@ runs:
id: publish_packages
working-directory: ${{ github.workspace }}/core-web/dist/libs/sdk/
env:
RELEASE_VERSION: ${{ inputs.version }}
# Normalized by the "Update package.json versions" step above — must match exactly
# what was written into each package.json, not the raw (possibly zero-padded) input.
RELEASE_VERSION: ${{ steps.update-versions.outputs.normalized_version }}
NPM_AUTH_TOKEN: ${{ inputs.npm-token }}
NPM_TAG: ${{ inputs.npm-tag }}
run: |
Expand Down
11 changes: 11 additions & 0 deletions .github/filters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ cli: &cli
sdk_libs:
- 'core-web/libs/sdk/**'

examples:
- 'examples/**'

# The package.json shape guardrail's own source. Deliberately NOT folded into sdk_libs:
# that filter also gates the trunk npm publish job (cicd_3-trunk.yml), and touching the
# validator must not trigger an SDK release. Without this key the job that runs the
# validator is not triggered by changes to the validator — you could break the guardrail
# and keep a green build.
sdk_package_shapes:
- '.github/scripts/validate-sdk-package-shapes/**'

# PR area labeling filters
# These are separate from test-triggering filters to avoid false positives
# (e.g., workflow changes should trigger backend tests but shouldn't label PR as "Area : Backend")
Expand Down
7 changes: 7 additions & 0 deletions .github/scripts/validate-sdk-package-shapes/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
testMatch: ['**/*.test.ts'],
};
Loading
Loading