Skip to content

Commit e2b1065

Browse files
committed
ci workflow changes for release branches
1 parent 356da43 commit e2b1065

7 files changed

Lines changed: 241 additions & 228 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ on:
55
branches:
66
- main
77
- 'renovate/**'
8+
- 'release/**'
89
pull_request:
910
branches:
1011
- main
12+
- 'release/**'
1113

1214
permissions:
1315
contents: read

.github/workflows/deploy-docs.yml

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,17 @@ jobs:
5454
- name: Get latest release tag
5555
id: release
5656
run: |
57-
# Find the most recent package tag and docs tag
58-
PKG_TAG=$(git describe --tags --abbrev=0 --match '@salesforce/*' 2>/dev/null || echo "")
59-
DOCS_TAG=$(git describe --tags --abbrev=0 --match 'docs@*' 2>/dev/null || echo "")
57+
# Find the most recent package tag and docs tag across all branches
58+
# (git describe only finds ancestor tags; git tag --list finds all)
59+
PKG_TAG=$(git tag --list '@salesforce/*' --sort=-creatordate | head -n1)
60+
DOCS_TAG=$(git tag --list 'docs@*' --sort=-creatordate | head -n1)
6061
61-
# Pick whichever tag is closer to HEAD (fewer commits behind)
62+
# Pick whichever tag was created most recently
6263
LATEST_TAG=""
6364
if [[ -n "$PKG_TAG" && -n "$DOCS_TAG" ]]; then
64-
PKG_DISTANCE=$(git rev-list --count "${PKG_TAG}..HEAD")
65-
DOCS_DISTANCE=$(git rev-list --count "${DOCS_TAG}..HEAD")
66-
if [[ "$DOCS_DISTANCE" -le "$PKG_DISTANCE" ]]; then
65+
PKG_TS=$(git for-each-ref --format='%(creatordate:unix)' "refs/tags/${PKG_TAG}")
66+
DOCS_TS=$(git for-each-ref --format='%(creatordate:unix)' "refs/tags/${DOCS_TAG}")
67+
if [[ "$DOCS_TS" -ge "$PKG_TS" ]]; then
6768
LATEST_TAG="$DOCS_TAG"
6869
else
6970
LATEST_TAG="$PKG_TAG"
@@ -77,15 +78,9 @@ jobs:
7778
echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT
7879
echo "exists=$([[ -n $LATEST_TAG ]] && echo true || echo false)" >> $GITHUB_OUTPUT
7980
80-
- name: Read CLI version for display
81-
id: cli-version
82-
run: |
83-
CLI_VERSION=$(node -p "require('./packages/b2c-cli/package.json').version")
84-
echo "version=$CLI_VERSION" >> $GITHUB_OUTPUT
85-
8681
- name: Build dev documentation
8782
run: |
88-
IS_DEV_BUILD=true RELEASE_VERSION=${{ steps.cli-version.outputs.version }} pnpm run docs:build
83+
IS_DEV_BUILD=true pnpm run docs:build
8984
mv docs/.vitepress/dist docs/.vitepress/dist-dev
9085
9186
- name: Build stable documentation from release tag
@@ -114,7 +109,7 @@ jobs:
114109
# Build at release tag with main's config (no IS_DEV_BUILD = stable at root)
115110
pnpm install --frozen-lockfile
116111
pnpm -r run build
117-
RELEASE_VERSION=${{ steps.cli-version.outputs.version }} pnpm run docs:build
112+
pnpm run docs:build
118113
119114
# Combine: stable at root, dev in /dev/
120115
mv docs/.vitepress/dist-dev docs/.vitepress/dist/dev

.github/workflows/publish.yml

Lines changed: 115 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
name: Publish to npm
22

33
on:
4+
workflow_run:
5+
workflows: ["CI"]
6+
types: [completed]
7+
branches: ['release/**']
48
schedule:
59
- cron: '0 2 * * 1-5' # Weekdays at 2 AM UTC (Mon-Fri)
610
workflow_dispatch:
711
inputs:
812
release_type:
9-
description: 'Release type'
13+
description: 'Release type (ignored for release branch workflow_run — always stable)'
1014
required: true
1115
default: 'nightly'
1216
type: choice
@@ -21,44 +25,96 @@ jobs:
2125
publish:
2226
name: Publish
2327
runs-on: ubuntu-latest
28+
if: >-
29+
github.event_name != 'workflow_run' ||
30+
github.event.workflow_run.conclusion == 'success'
2431
permissions:
2532
contents: write # For creating GitHub releases and tags
2633
id-token: write # Required for npm OIDC trusted publishers
34+
pull-requests: write # For creating merge-back PRs
2735
steps:
2836
- name: Checkout
2937
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3038
with:
39+
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || '' }}
3140
fetch-depth: 0 # Needed for docs tag detection
3241

3342
- name: Determine release type
3443
id: release-type
3544
run: |
36-
if [[ "${{ github.event.inputs.release_type }}" == "stable" ]]; then
45+
if [[ "${{ github.event.inputs.release_type }}" == "stable" ]] || [[ "${{ github.event_name }}" == "workflow_run" ]]; then
3746
echo "type=stable" >> $GITHUB_OUTPUT
3847
echo "tag=latest" >> $GITHUB_OUTPUT
3948
else
4049
echo "type=nightly" >> $GITHUB_OUTPUT
4150
echo "tag=nightly" >> $GITHUB_OUTPUT
4251
fi
4352
53+
- name: Check for pending changesets
54+
if: steps.release-type.outputs.type == 'stable'
55+
id: changesets
56+
run: |
57+
PENDING=$(find .changeset -name '*.md' ! -name 'README.md' 2>/dev/null | wc -l | tr -d ' ')
58+
if [[ "$PENDING" -gt 0 ]]; then
59+
echo "skip=true" >> $GITHUB_OUTPUT
60+
echo "::notice::Found $PENDING pending changeset(s) — skipping publish"
61+
else
62+
echo "skip=false" >> $GITHUB_OUTPUT
63+
fi
64+
65+
- name: Quick version check
66+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true'
67+
id: quick-check
68+
run: |
69+
HAS_CHANGES=false
70+
for spec in "@salesforce/b2c-tooling-sdk:packages/b2c-tooling-sdk" \
71+
"@salesforce/b2c-cli:packages/b2c-cli" \
72+
"@salesforce/b2c-dx-mcp:packages/b2c-dx-mcp"; do
73+
PKG_NAME="${spec%%:*}"
74+
PKG_PATH="${spec##*:}"
75+
LOCAL=$(node -p "require('./${PKG_PATH}/package.json').version")
76+
NPM=$(npm view "$PKG_NAME" version 2>/dev/null || echo "0.0.0")
77+
if [ "$LOCAL" != "$NPM" ]; then
78+
HAS_CHANGES=true
79+
break
80+
fi
81+
done
82+
# Also check docs tag
83+
if [ "$HAS_CHANGES" = "false" ]; then
84+
DOCS_VERSION=$(node -p "require('./docs/package.json').version")
85+
if ! git rev-parse "docs@${DOCS_VERSION}" >/dev/null 2>&1; then
86+
HAS_CHANGES=true
87+
fi
88+
fi
89+
if [ "$HAS_CHANGES" = "false" ]; then
90+
echo "skip=true" >> $GITHUB_OUTPUT
91+
echo "::notice::All package versions match npm — nothing to publish"
92+
else
93+
echo "skip=false" >> $GITHUB_OUTPUT
94+
fi
95+
4496
- name: Setup pnpm
97+
if: steps.release-type.outputs.type == 'nightly' || (steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true')
4598
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
4699

47100
- name: Setup Node.js
101+
if: steps.release-type.outputs.type == 'nightly' || (steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true')
48102
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
49103
with:
50104
node-version: 22
51105
cache: 'pnpm'
52106
registry-url: 'https://registry.npmjs.org'
53107

54108
- name: Upgrade npm for trusted publishing
109+
if: steps.release-type.outputs.type == 'nightly' || (steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true')
55110
run: npm install -g npm@latest
56111

57112
- name: Install dependencies
113+
if: steps.release-type.outputs.type == 'nightly' || (steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true')
58114
run: pnpm install --frozen-lockfile
59115

60116
- name: Determine packages to publish
61-
if: steps.release-type.outputs.type == 'stable'
117+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true'
62118
id: packages
63119
run: |
64120
check_package() {
@@ -74,6 +130,19 @@ jobs:
74130
if [ "$LOCAL_VERSION" != "$NPM_VERSION" ]; then
75131
echo "publish_${output_key}=true" >> $GITHUB_OUTPUT
76132
echo "version_${output_key}=${LOCAL_VERSION}" >> $GITHUB_OUTPUT
133+
134+
# Determine appropriate npm dist-tag via semver comparison
135+
IS_NEWER=$(node -e "
136+
const [a,b,c] = '${LOCAL_VERSION}'.split('.').map(Number);
137+
const [x,y,z] = '${NPM_VERSION}'.split('.').map(Number);
138+
console.log(a>x||(a===x&&(b>y||(b===y&&c>z))));
139+
")
140+
if [ "$IS_NEWER" = "true" ]; then
141+
echo "tag_${output_key}=latest" >> $GITHUB_OUTPUT
142+
else
143+
MINOR=$(echo "$LOCAL_VERSION" | sed 's/\.[0-9]*$//')
144+
echo "tag_${output_key}=release-${MINOR}" >> $GITHUB_OUTPUT
145+
fi
77146
else
78147
echo "publish_${output_key}=false" >> $GITHUB_OUTPUT
79148
fi
@@ -109,25 +178,33 @@ jobs:
109178
echo "Set snapshot version: $SNAPSHOT"
110179
111180
- name: Build packages
181+
if: steps.release-type.outputs.type == 'nightly' || (steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true')
112182
run: pnpm run build
113183

114184
- name: Run tests
185+
if: steps.release-type.outputs.type == 'nightly' || (steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true')
115186
run: pnpm --filter '!b2c-vs-extension' run test
116187

117188
- name: Publish SDK to npm
118189
if: steps.release-type.outputs.type == 'nightly' || steps.packages.outputs.publish_sdk == 'true'
119-
run: pnpm --filter @salesforce/b2c-tooling-sdk publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
190+
run: >-
191+
pnpm --filter @salesforce/b2c-tooling-sdk publish --provenance --no-git-checks
192+
--tag ${{ steps.release-type.outputs.type == 'nightly' && 'nightly' || steps.packages.outputs.tag_sdk }}
120193
121194
- name: Publish CLI to npm
122195
if: steps.release-type.outputs.type == 'nightly' || steps.packages.outputs.publish_cli == 'true'
123-
run: pnpm --filter @salesforce/b2c-cli publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
196+
run: >-
197+
pnpm --filter @salesforce/b2c-cli publish --provenance --no-git-checks
198+
--tag ${{ steps.release-type.outputs.type == 'nightly' && 'nightly' || steps.packages.outputs.tag_cli }}
124199
125200
- name: Publish MCP to npm
126201
if: steps.release-type.outputs.type == 'nightly' || steps.packages.outputs.publish_mcp == 'true'
127-
run: pnpm --filter @salesforce/b2c-dx-mcp publish --provenance --no-git-checks --tag ${{ steps.release-type.outputs.tag }}
202+
run: >-
203+
pnpm --filter @salesforce/b2c-dx-mcp publish --provenance --no-git-checks
204+
--tag ${{ steps.release-type.outputs.type == 'nightly' && 'nightly' || steps.packages.outputs.tag_mcp }}
128205
129206
- name: Create git tags
130-
if: steps.release-type.outputs.type == 'stable'
207+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true'
131208
run: |
132209
git config user.name "github-actions[bot]"
133210
git config user.email "github-actions[bot]@users.noreply.github.com"
@@ -160,15 +237,15 @@ jobs:
160237
fi
161238
162239
- name: Create docs tag if version changed
163-
if: steps.release-type.outputs.type == 'stable' && steps.packages.outputs.publish_docs == 'true'
240+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true' && steps.packages.outputs.publish_docs == 'true'
164241
run: |
165242
DOCS_TAG="docs@${{ steps.packages.outputs.version_docs }}"
166243
git tag "$DOCS_TAG"
167244
git push origin "$DOCS_TAG"
168245
echo "Created docs tag: $DOCS_TAG"
169246
170247
- name: Extract changelogs for release
171-
if: steps.release-type.outputs.type == 'stable'
248+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true'
172249
run: |
173250
# Function to extract the latest version section from a changelog
174251
extract_latest() {
@@ -210,7 +287,7 @@ jobs:
210287
} > /tmp/release-notes.md
211288
212289
- name: Create GitHub Release
213-
if: steps.release-type.outputs.type == 'stable'
290+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true'
214291
run: |
215292
# Determine the release tag — prefer CLI as the user-facing product
216293
if [[ "${{ steps.packages.outputs.publish_cli }}" == "true" ]]; then
@@ -231,7 +308,7 @@ jobs:
231308
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
232309

233310
- name: Package skills artifacts
234-
if: steps.release-type.outputs.type == 'stable'
311+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true'
235312
run: |
236313
# Create b2c-skills.zip containing skills/b2c/skills/
237314
cd skills/b2c && zip -r ../../b2c-skills.zip skills/
@@ -243,7 +320,7 @@ jobs:
243320
ls -la *.zip
244321
245322
- name: Upload skills to release
246-
if: steps.release-type.outputs.type == 'stable'
323+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true'
247324
run: |
248325
# Determine the release tag (same logic as Create GitHub Release)
249326
if [[ "${{ steps.packages.outputs.publish_cli }}" == "true" ]]; then
@@ -262,7 +339,32 @@ jobs:
262339
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
263340

264341
- name: Trigger documentation deployment
265-
if: steps.release-type.outputs.type == 'stable'
342+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true'
266343
run: gh workflow run deploy-docs.yml
267344
env:
268345
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
346+
347+
- name: Create PR to merge version bumps back to main
348+
if: github.event_name == 'workflow_run'
349+
run: |
350+
if [[ "${{ steps.packages.outputs.publish_sdk }}" == "true" ]] || \
351+
[[ "${{ steps.packages.outputs.publish_cli }}" == "true" ]] || \
352+
[[ "${{ steps.packages.outputs.publish_mcp }}" == "true" ]] || \
353+
[[ "${{ steps.packages.outputs.publish_docs }}" == "true" ]]; then
354+
BRANCH="${{ github.event.workflow_run.head_branch }}"
355+
gh pr create --base main --head "$BRANCH" \
356+
--title "Merge version bumps from ${BRANCH}" \
357+
--body "$(cat <<'EOF'
358+
Auto-created after hotfix publish from `'"${BRANCH}"'`.
359+
360+
Merges version bump commits back to main to prevent version collisions on the next regular release.
361+
362+
**Review checklist:**
363+
- [ ] Version bumps in package.json files look correct
364+
- [ ] CHANGELOG entries are accurate
365+
- [ ] No merge conflicts with pending changesets on main
366+
EOF
367+
)" || echo "::warning::PR already exists or could not be created"
368+
fi
369+
env:
370+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ Add a changeset when your PR includes changes that users should know about:
7474
- Breaking changes
7575
- Significant improvements
7676

77+
For **documentation-only changes** (new guides, restructured content, significant improvements) that should be deployed before the next package release, create a changeset targeting `@salesforce/b2c-dx-docs`. This triggers a doc-only release and rebuild. Routine doc fixes (typos, minor clarifications) that can wait for the next package release don't need a changeset.
78+
7779
You **don't need** a changeset for:
78-
- Documentation-only changes
7980
- Internal refactoring
8081
- Test improvements
8182
- CI/build changes
@@ -102,6 +103,7 @@ You **don't need** a changeset for:
102103

103104
- Changesets are optional - maintainers can add them later if needed
104105
- Multiple changesets can exist for separate changes
106+
- For **hotfix releases** (urgent patches while unrelated changesets are pending on `main`), maintainers use release branches — see [PUBLISHING.md](./PUBLISHING.md#hotfix-release) for details
105107
- See [PUBLISHING.md](./PUBLISHING.md) for full release process details
106108

107109
# Creating a Pull Request

0 commit comments

Comments
 (0)