Skip to content

Commit e8e4417

Browse files
authored
chore: switch to independent per-package versioning (#116)
Remove linked versioning so each package (b2c-cli, b2c-tooling-sdk, b2c-dx-mcp) versions independently based on its own changesets. The publish pipeline now compares each package's local version against npm and only publishes packages that have actually changed.
1 parent 9cd4bcc commit e8e4417

File tree

6 files changed

+147
-64
lines changed

6 files changed

+147
-64
lines changed

.changeset/config.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
],
77
"commit": false,
88
"fixed": [],
9-
"linked": [
10-
["@salesforce/b2c-cli", "@salesforce/b2c-tooling-sdk", "@salesforce/b2c-dx-mcp"]
11-
],
9+
"linked": [],
1210
"access": "public",
1311
"baseBranch": "main",
1412
"updateInternalDependencies": "patch",

.github/workflows/changesets.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
permissions:
1717
contents: write
1818
pull-requests: write
19+
actions: write
1920
steps:
2021
- name: Checkout
2122
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
@@ -33,10 +34,17 @@ jobs:
3334
run: pnpm install --frozen-lockfile
3435

3536
- name: Create Release PR
37+
id: changesets
3638
uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1.5.3
3739
with:
3840
version: pnpm changeset version
3941
title: 'Next Release: changelog and version packages'
4042
commit: 'chore: version packages'
4143
env:
4244
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
45+
46+
- name: Trigger publish workflow
47+
if: steps.changesets.outputs.hasChangesets == 'false'
48+
run: gh workflow run publish.yml -f release_type=stable
49+
env:
50+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/publish.yml

Lines changed: 125 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
name: Publish to npm
22

33
on:
4-
push:
5-
tags:
6-
- 'v[0-9]+.[0-9]+.[0-9]+' # Stable releases: v1.0.0, v2.1.3
7-
- 'v[0-9]+.[0-9]+.[0-9]+-*' # Pre-releases: v1.0.0-beta.1, v1.0.0-rc.1
84
schedule:
95
- cron: '0 2 * * 1-5' # Weekdays at 2 AM UTC (Mon-Fri)
106
workflow_dispatch:
@@ -16,6 +12,7 @@ on:
1612
type: choice
1713
options:
1814
- nightly
15+
- stable
1916

2017
env:
2118
SFCC_DISABLE_TELEMETRY: ${{ vars.SFCC_DISABLE_TELEMETRY }}
@@ -25,7 +22,7 @@ jobs:
2522
name: Publish
2623
runs-on: ubuntu-latest
2724
permissions:
28-
contents: write # For creating GitHub releases
25+
contents: write # For creating GitHub releases and tags
2926
id-token: write # Required for npm OIDC trusted publishers
3027
steps:
3128
- name: Checkout
@@ -34,30 +31,12 @@ jobs:
3431
- name: Determine release type
3532
id: release-type
3633
run: |
37-
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref_type }}" == "tag" ]]; then
34+
if [[ "${{ github.event.inputs.release_type }}" == "stable" ]]; then
3835
echo "type=stable" >> $GITHUB_OUTPUT
39-
# Pre-release versions (v1.0.0-beta.1) publish to @next, stable to @latest
40-
if [[ "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-.+ ]]; then
41-
echo "tag=next" >> $GITHUB_OUTPUT
42-
echo "prerelease=true" >> $GITHUB_OUTPUT
43-
else
44-
echo "tag=latest" >> $GITHUB_OUTPUT
45-
echo "prerelease=false" >> $GITHUB_OUTPUT
46-
fi
36+
echo "tag=latest" >> $GITHUB_OUTPUT
4737
else
4838
echo "type=nightly" >> $GITHUB_OUTPUT
4939
echo "tag=nightly" >> $GITHUB_OUTPUT
50-
echo "prerelease=false" >> $GITHUB_OUTPUT
51-
fi
52-
53-
- name: Validate tag matches package version
54-
if: steps.release-type.outputs.type == 'stable'
55-
run: |
56-
TAG_VERSION="${GITHUB_REF_NAME#v}"
57-
PKG_VERSION=$(node -p "require('./packages/b2c-tooling-sdk/package.json').version")
58-
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
59-
echo "Error: Tag version ($TAG_VERSION) does not match package version ($PKG_VERSION)"
60-
exit 1
6140
fi
6241
6342
- name: Setup pnpm
@@ -76,6 +55,32 @@ jobs:
7655
- name: Install dependencies
7756
run: pnpm install --frozen-lockfile
7857

58+
- name: Determine packages to publish
59+
if: steps.release-type.outputs.type == 'stable'
60+
id: packages
61+
run: |
62+
check_package() {
63+
local pkg_name=$1
64+
local pkg_path=$2
65+
local output_key=$3
66+
67+
LOCAL_VERSION=$(node -p "require('./${pkg_path}/package.json').version")
68+
NPM_VERSION=$(npm view "$pkg_name" version 2>/dev/null || echo "0.0.0")
69+
70+
echo "${pkg_name}: local=${LOCAL_VERSION} npm=${NPM_VERSION}"
71+
72+
if [ "$LOCAL_VERSION" != "$NPM_VERSION" ]; then
73+
echo "publish_${output_key}=true" >> $GITHUB_OUTPUT
74+
echo "version_${output_key}=${LOCAL_VERSION}" >> $GITHUB_OUTPUT
75+
else
76+
echo "publish_${output_key}=false" >> $GITHUB_OUTPUT
77+
fi
78+
}
79+
80+
check_package "@salesforce/b2c-tooling-sdk" "packages/b2c-tooling-sdk" "sdk"
81+
check_package "@salesforce/b2c-cli" "packages/b2c-cli" "cli"
82+
check_package "@salesforce/b2c-dx-mcp" "packages/b2c-dx-mcp" "mcp"
83+
7984
- name: Create snapshot versions
8085
if: steps.release-type.outputs.type == 'nightly'
8186
run: |
@@ -97,48 +102,102 @@ jobs:
97102
- name: Run tests
98103
run: pnpm run test
99104

100-
- name: Publish to npm
101-
run: |
102-
pnpm --filter @salesforce/b2c-tooling-sdk publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
103-
pnpm --filter @salesforce/b2c-cli publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
104-
# pnpm --filter @salesforce/b2c-dx-mcp publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
105+
- name: Publish SDK to npm
106+
if: steps.release-type.outputs.type == 'nightly' || steps.packages.outputs.publish_sdk == 'true'
107+
run: pnpm --filter @salesforce/b2c-tooling-sdk publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
108+
109+
- name: Publish CLI to npm
110+
if: steps.release-type.outputs.type == 'nightly' || steps.packages.outputs.publish_cli == 'true'
111+
run: pnpm --filter @salesforce/b2c-cli publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
112+
113+
- name: Publish MCP to npm
114+
if: steps.release-type.outputs.type == 'nightly' || steps.packages.outputs.publish_mcp == 'true'
115+
run: pnpm --filter @salesforce/b2c-dx-mcp publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
105116

106-
- name: Extract changelog for release
117+
- name: Create git tags
107118
if: steps.release-type.outputs.type == 'stable'
108119
run: |
109-
VERSION="${GITHUB_REF_NAME#v}"
120+
git config user.name "github-actions[bot]"
121+
git config user.email "github-actions[bot]@users.noreply.github.com"
110122
111-
# Function to extract version section from a changelog
112-
extract_version() {
113-
awk -v ver="$1" '
114-
/^## / { if (found) exit; if ($2 == ver) found=1; next }
123+
TAGS_CREATED=""
124+
125+
if [[ "${{ steps.packages.outputs.publish_sdk }}" == "true" ]]; then
126+
TAG="@salesforce/b2c-tooling-sdk@${{ steps.packages.outputs.version_sdk }}"
127+
git tag "$TAG"
128+
TAGS_CREATED="$TAGS_CREATED $TAG"
129+
fi
130+
131+
if [[ "${{ steps.packages.outputs.publish_cli }}" == "true" ]]; then
132+
TAG="@salesforce/b2c-cli@${{ steps.packages.outputs.version_cli }}"
133+
git tag "$TAG"
134+
TAGS_CREATED="$TAGS_CREATED $TAG"
135+
fi
136+
137+
if [[ "${{ steps.packages.outputs.publish_mcp }}" == "true" ]]; then
138+
TAG="@salesforce/b2c-dx-mcp@${{ steps.packages.outputs.version_mcp }}"
139+
git tag "$TAG"
140+
TAGS_CREATED="$TAGS_CREATED $TAG"
141+
fi
142+
143+
if [ -n "$TAGS_CREATED" ]; then
144+
git push origin $TAGS_CREATED
145+
echo "Created tags:$TAGS_CREATED"
146+
else
147+
echo "No tags to create"
148+
fi
149+
150+
- name: Extract changelogs for release
151+
if: steps.release-type.outputs.type == 'stable'
152+
run: |
153+
# Function to extract the latest version section from a changelog
154+
extract_latest() {
155+
awk '
156+
/^## / { if (found) exit; found=1; next }
115157
found { print }
116-
' "$2"
158+
' "$1"
117159
}
118160
119-
# Build combined release notes
161+
# Build combined release notes for published packages
120162
{
121-
echo "## @salesforce/b2c-cli"
122-
echo ""
123-
extract_version "$VERSION" packages/b2c-cli/CHANGELOG.md
124-
echo ""
125-
echo "## @salesforce/b2c-dx-mcp"
126-
echo ""
127-
extract_version "$VERSION" packages/b2c-dx-mcp/CHANGELOG.md
128-
echo ""
129-
echo "## @salesforce/b2c-tooling-sdk"
130-
echo ""
131-
extract_version "$VERSION" packages/b2c-tooling-sdk/CHANGELOG.md
163+
if [[ "${{ steps.packages.outputs.publish_cli }}" == "true" ]]; then
164+
echo "## @salesforce/b2c-cli@${{ steps.packages.outputs.version_cli }}"
165+
echo ""
166+
extract_latest packages/b2c-cli/CHANGELOG.md
167+
echo ""
168+
fi
169+
170+
if [[ "${{ steps.packages.outputs.publish_mcp }}" == "true" ]]; then
171+
echo "## @salesforce/b2c-dx-mcp@${{ steps.packages.outputs.version_mcp }}"
172+
echo ""
173+
extract_latest packages/b2c-dx-mcp/CHANGELOG.md
174+
echo ""
175+
fi
176+
177+
if [[ "${{ steps.packages.outputs.publish_sdk }}" == "true" ]]; then
178+
echo "## @salesforce/b2c-tooling-sdk@${{ steps.packages.outputs.version_sdk }}"
179+
echo ""
180+
extract_latest packages/b2c-tooling-sdk/CHANGELOG.md
181+
echo ""
182+
fi
132183
} > /tmp/release-notes.md
133184
134185
- name: Create GitHub Release
135186
if: steps.release-type.outputs.type == 'stable'
136187
run: |
137-
PRERELEASE_FLAG=""
138-
if [[ "${{ steps.release-type.outputs.prerelease }}" == "true" ]]; then
139-
PRERELEASE_FLAG="--prerelease"
188+
# Determine the release tag — prefer CLI as the user-facing product
189+
if [[ "${{ steps.packages.outputs.publish_cli }}" == "true" ]]; then
190+
RELEASE_TAG="@salesforce/b2c-cli@${{ steps.packages.outputs.version_cli }}"
191+
elif [[ "${{ steps.packages.outputs.publish_sdk }}" == "true" ]]; then
192+
RELEASE_TAG="@salesforce/b2c-tooling-sdk@${{ steps.packages.outputs.version_sdk }}"
193+
elif [[ "${{ steps.packages.outputs.publish_mcp }}" == "true" ]]; then
194+
RELEASE_TAG="@salesforce/b2c-dx-mcp@${{ steps.packages.outputs.version_mcp }}"
195+
else
196+
echo "No packages published, skipping release"
197+
exit 0
140198
fi
141-
gh release create "$GITHUB_REF_NAME" --notes-file /tmp/release-notes.md $PRERELEASE_FLAG
199+
200+
gh release create "$RELEASE_TAG" --notes-file /tmp/release-notes.md
142201
env:
143202
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
144203

@@ -157,6 +216,18 @@ jobs:
157216
- name: Upload skills to release
158217
if: steps.release-type.outputs.type == 'stable'
159218
run: |
160-
gh release upload "$GITHUB_REF_NAME" b2c-skills.zip b2c-cli-skills.zip
219+
# Determine the release tag (same logic as Create GitHub Release)
220+
if [[ "${{ steps.packages.outputs.publish_cli }}" == "true" ]]; then
221+
RELEASE_TAG="@salesforce/b2c-cli@${{ steps.packages.outputs.version_cli }}"
222+
elif [[ "${{ steps.packages.outputs.publish_sdk }}" == "true" ]]; then
223+
RELEASE_TAG="@salesforce/b2c-tooling-sdk@${{ steps.packages.outputs.version_sdk }}"
224+
elif [[ "${{ steps.packages.outputs.publish_mcp }}" == "true" ]]; then
225+
RELEASE_TAG="@salesforce/b2c-dx-mcp@${{ steps.packages.outputs.version_mcp }}"
226+
else
227+
echo "No release to upload to"
228+
exit 0
229+
fi
230+
231+
gh release upload "$RELEASE_TAG" b2c-skills.zip b2c-cli-skills.zip
161232
env:
162233
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

AGENTS.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,17 @@ See [testing skill](./.claude/skills/testing/SKILL.md) for patterns on writing t
127127

128128
## Changesets
129129

130-
This project uses [Changesets](https://github.com/changesets/changesets) for version management. When making changes that affect users, create a changeset:
130+
This project uses [Changesets](https://github.com/changesets/changesets) for version management with **independent per-package versioning**. Each package versions independently based on its own changesets.
131+
132+
**How it works:**
133+
- A changeset affecting only the SDK bumps only the SDK version
134+
- Packages that depend on a bumped package get an automatic patch bump (via `updateInternalDependencies: "patch"`) — e.g., if SDK bumps, CLI and MCP auto-get a patch bump because they depend on it
135+
- Only packages with a newer version than what's on npm get published
131136

132137
Changeset guidelines:
133-
- Create a changeset for any user-facing changes (features, bug fixes); typically in new pull requests;
138+
- Create a changeset for any user-facing changes (features, bug fixes); typically in new pull requests
134139
- a pull request can have multiple changesets; separate files for separate changes
140+
- Only list directly-changed packages in changeset frontmatter — do not include dependent packages (they get auto-bumped)
135141
- Select the appropriate semver bump: `patch` (bug fixes) or `minor` (new features)
136142
- This is a pre-1.0 preview release, so there are no `major` breaking change bumps yet
137143
- Good changesets explain:
@@ -151,4 +157,4 @@ create a changeset file directly in `.changeset/` with a unique filename (e.g.,
151157
Description of the change explaining WHAT, WHY, and HOW to update
152158
```
153159

154-
- Include only the packages that were modified
160+
- Include only the packages that were directly modified

docs/.vitepress/config.mts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ function getVersionItems() {
2323
// Use ../ to navigate up to main docs
2424
return [
2525
{ text: 'Development (main)', link: '../' },
26-
{ text: `Release (${releaseVersion})`, link: '/' },
26+
{ text: 'Latest Release', link: '/' },
2727
];
2828
}
2929

3030
// Main build: base is /b2c-developer-tooling/
3131
return [
3232
{ text: 'Development (main)', link: '/' },
33-
{ text: `Release (${releaseVersion})`, link: '/release/' },
33+
{ text: 'Latest Release', link: '/release/' },
3434
];
3535
}
3636

@@ -133,7 +133,7 @@ export default defineConfig({
133133
{ text: 'CLI Reference', link: '/cli/' },
134134
{ text: 'API Reference', link: '/api/' },
135135
{
136-
text: isReleaseBuild ? releaseVersion : 'dev',
136+
text: isReleaseBuild ? 'Latest Release' : 'dev',
137137
items: getVersionItems(),
138138
},
139139
],

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"docs:preview": "vitepress preview docs",
2121
"changeset": "changeset",
2222
"version": "changeset version",
23-
"release": "pnpm run build && pnpm --filter @salesforce/b2c-tooling-sdk --filter @salesforce/b2c-cli --filter @salesforce/b2c-dx-mcp publish --access public"
23+
"release": "echo 'Releases are handled by CI (publish.yml). Use workflow_dispatch for manual releases.' && exit 1"
2424
},
2525
"keywords": [],
2626
"author": "",

0 commit comments

Comments
 (0)