Skip to content

Commit 1e1a8f7

Browse files
committed
NEW @W-17330636@ Implemented SNAPSHOT-based release cycle
1 parent e12463b commit 1e1a8f7

File tree

6 files changed

+616
-26
lines changed

6 files changed

+616
-26
lines changed

.github/workflows/publish-package-to-npm.yml

Lines changed: 321 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,41 @@ name: publish-package-to-npm
22
on:
33
workflow_dispatch:
44
inputs:
5-
package:
6-
description: Package to be published
7-
type: string
8-
required: true
9-
version:
10-
description: Version to be published
11-
type: string
12-
required: true
5+
code-analyzer-core:
6+
description: Should the code-analyzer-core package be released?
7+
type: boolean
8+
required: false
9+
default: false
10+
code-analyzer-engine-api:
11+
description: Should the code-analyzer-engine-api package be released?
12+
type: boolean
13+
required: false
14+
default: false
15+
code-analyzer-eslint-engine:
16+
description: Should the code-analyzer-eslint-engine package be released?
17+
type: boolean
18+
required: false
19+
default: false
20+
code-analyzer-flowtest-engine:
21+
description: Should the code-analyzer-flowtest-engine package be released?
22+
type: boolean
23+
required: false
24+
default: false
25+
code-analyzer-pmd-engine:
26+
description: Should the code-analyzer-pmd-engine package be released?
27+
type: boolean
28+
required: false
29+
default: false
30+
code-analyzer-regex-engine:
31+
description: Should the code-analyzer-regex-engine package be released?
32+
type: boolean
33+
required: false
34+
default: false
35+
code-analyzer-retirejs-engine:
36+
description: Should the code-analyzer-retirejs-engine package be released?
37+
type: boolean
38+
required: false
39+
default: false
1340
dryrun:
1441
description: Add --dry-run to npm publish step? (Uncheck to actually publish)
1542
type: boolean
@@ -21,33 +48,303 @@ defaults:
2148
shell: bash
2249

2350
jobs:
24-
verify-and-publish:
51+
validate-packages-as-releasable:
52+
runs-on: macos-latest
53+
outputs:
54+
packages-to-release: ${{ steps.main.outputs.packages_to_release }}
55+
steps:
56+
- uses: actions/checkout@v4
57+
- uses: actions/setup-node@v4
58+
with:
59+
node-version: 'lts/*'
60+
- name: Verify to-be-released packages are SNAPSHOT-versioned
61+
id: main
62+
run: |
63+
PACKAGES_TO_CHECK=()
64+
if [ "${{ inputs.code-analyzer-core }}" == "true" ]; then
65+
PACKAGES_TO_CHECK+=('code-analyzer-core')
66+
fi
67+
if [ "${{ inputs.code-analyzer-engine-api }}" == "true" ]; then
68+
PACKAGES_TO_CHECK+=('code-analyzer-engine-api')
69+
fi
70+
if [ "${{ inputs.code-analyzer-eslint-engine }}" == "true" ]; then
71+
PACKAGES_TO_CHECK+=('code-analyzer-eslint-engine')
72+
fi
73+
if [ "${{ inputs.code-analyzer-flowtest-engine }}" == "true" ]; then
74+
PACKAGES_TO_CHECK+=('code-analyzer-flowtest-engine')
75+
fi
76+
if [ "${{ inputs.code-analyzer-pmd-engine }}" == "true" ]; then
77+
PACKAGES_TO_CHECK+=('code-analyzer-pmd-engine')
78+
fi
79+
if [ "${{ inputs.code-analyzer-regex-engine }}" == "true" ]; then
80+
PACKAGES_TO_CHECK+=('code-analyzer-regex-engine')
81+
fi
82+
if [ "${{ inputs.code-analyzer-retirejs-engine }}" == "true" ]; then
83+
PACKAGES_TO_CHECK+=('code-analyzer-retirejs-engine')
84+
fi
85+
node ./.github/workflows/publish-package-to-npm/validate-packages-as-releasable.js "$PACKAGES_TO_CHECK"
86+
# Having all of the packages that are going to be released as a single string is helpful later.
87+
echo "packages_to_release=$PACKAGES_TO_CHECK" >> "$GITHUB_OUTPUT
88+
prepare-release-branch:
89+
runs-on: macos-latest
90+
env:
91+
GH_TOKEN: ${{ github.token }}
92+
permissions:
93+
contents: write
94+
needs: validate-packages-as-releasable
95+
outputs:
96+
branch-name: ${{ steps.create-release-branch.outputs.branch_name }}
97+
steps:
98+
- uses: actions/checkout@v4
99+
- uses: actions/setup-node@v4
100+
with:
101+
node-version: 'lts/*'
102+
- name: Create release branch
103+
id: create-release-branch
104+
run: |
105+
NOW_TIMESTAMP=$(date +%s)
106+
git checkout -b release/$NOW_TIMESTAMP
107+
# Immediately push the branch with no changes, so GraphQL can push to it later.
108+
git push --set-upstream origin release/$NOW_TIMESTAMP
109+
# Output the branch name so that it can be used later.
110+
echo "branch_name=release/$NOW_TIMESTAMP" >> "$GITHUB_OUTPUT"
111+
- name: Strip '-SNAPSHOT' from to-be-released package versions
112+
run: |
113+
if [ "${{ inputs.code-analyzer-core }}" == "true" ]; then
114+
cd ./packages/code-analyzer-core
115+
npm --no-git-tag-version version patch # Increments X.Y.Z-SNAPSHOT to X.Y.Z, which is what we want.
116+
cd ../..
117+
fi
118+
if [ "${{ inputs.code-analyzer-engine-api }}" == "true" ]; then
119+
cd ./packages/code-analyzer-engine-api
120+
npm --no-git-tag-version version patch # Increments X.Y.Z-SNAPSHOT to X.Y.Z, which is what we want.
121+
cd ../..
122+
fi
123+
if [ "${{ inputs.code-analyzer-eslint-engine }}" == "true" ]; then
124+
cd ./packages/code-analyzer-eslint-engine
125+
npm --no-git-tag-version version patch # Increments X.Y.Z-SNAPSHOT to X.Y.Z, which is what we want.
126+
cd ../..
127+
fi
128+
if [ "${{ inputs.code-analyzer-flowtest-engine }}" == "true" ]; then
129+
cd ./packages/code-analyzer-flowtest-engine
130+
npm --no-git-tag-version version patch # Increments X.Y.Z-SNAPSHOT to X.Y.Z, which is what we want.
131+
cd ../..
132+
fi
133+
if [ "${{ inputs.code-analyzer-pmd-engine }}" == "true" ]; then
134+
cd ./packages/code-analyzer-pmd-engine
135+
npm --no-git-tag-version version patch # Increments X.Y.Z-SNAPSHOT to X.Y.Z, which is what we want.
136+
cd ../..
137+
fi
138+
if [ "${{ inputs.code-analyzer-regex-engine }}" == "true" ]; then
139+
cd ./packages/code-analyzer-regex-engine
140+
npm --no-git-tag-version version patch # Increments X.Y.Z-SNAPSHOT to X.Y.Z, which is what we want.
141+
cd ../..
142+
fi
143+
if [ "${{ inputs.code-analyzer-retirejs-engine }}" == "true" ]; then
144+
cd ./packages/code-analyzer-retirejs-engine
145+
npm --no-git-tag-version version patch # Increments X.Y.Z-SNAPSHOT to X.Y.Z, which is what we want.
146+
cd ../..
147+
fi
148+
- name: Update inter-package dependencies
149+
run: |
150+
RELEASABLE_PACKAGES=${{ needs.validate-packages-as-releasable.outputs.packages-to-release }}
151+
cd packages
152+
ALL_PACKAGES=`ls`
153+
cd ..
154+
node ./.github/workflows/publish-package-to-npm/update-dependencies-on-released-pacakges.js "$RELEASABLE_PACKAGES" "$ALL_PACKAGES"
155+
- name: Build
156+
run: |
157+
npm install
158+
npm run build
159+
# No need to test; that comes later.
160+
- name: Commit changes to release branch
161+
run: |
162+
# GraphQL needs to know what branch to push to.
163+
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
164+
# GraphQL needs a message for the commit.
165+
MESSAGE="Preparing Core Ecosystem for release"
166+
# GraphQL needs the latest versions of all the package.json files, as Base64 encoded strings.
167+
CORE_PACKAGE_JSON="$(cat packages/code-analyzer-core/package.json | base64)"
168+
API_PACKAGE_JSON="$(cat packages/code-analyzer-engine-api/package.json | base64)"
169+
ESLINT_PACKAGE_JSON="$(cat packages/code-analyzer-eslint-engine/package.json | base64)"
170+
FLOWTEST_PACKAGE_JSON="$(cat packages/code-analyzer-flowtest-engine/package.json | base64)"
171+
PMD_PACKAGE_JSON="$(cat packages/code-analyzer-pmd-engine/package.json | base64)"
172+
REGEX_PACKAGE_JSON="$(cat packages/code-analyzer-regex-engine/package.json | base64)"
173+
RETIREJS_PACKAGE_JSON="$(cat packages/code-analyzer-retirejs-engine/package.json | base64)"
174+
TEMPLATE_PACKAGE_JSON="$(cat packages/T-E-M-P-L-A-T-E/package.json | base64)"
175+
# GraphQL also needs the top-level package-lock.json
176+
PACKAGE_LOCK_JSON="$(cat package-lock.json | base64)"
177+
178+
gh api graphql -F message="$MESSAGE" -F oldOid=`git rev-parse HEAD` -F branch="$BRANCH" \
179+
-F corePackage="$CORE_PACKAGE_JSON" \
180+
-F apiPackage="$API_PACKAGE_JSON" \
181+
-F eslintPackage="$ESLINT_PACKAGE_JSON" \
182+
-F flowtestPackage="$FLOWTEST_PACKAGE_JSON" \
183+
-F pmdPackage="$PMD_PACKAGE_JSON" \
184+
-F regexPackage="$REGEX_PACKAGE_JSON" \
185+
-F retirejsPackage="$RETIREJS_PACKAGE_JSON" \
186+
-F templatePackage="$TEMPLATE_PACKAGE_JSON" \
187+
-F packageLock="$PACKAGE_LOCK_JSON" \
188+
-f query='
189+
mutation ($message: String!, $oldOid: GitObjectID!, $branch: String!,
190+
$corePackage: Base64String!, $apiPackage: Base64String!, $eslintPackage: Base64String!,
191+
$flowtestPackage: Base64String!, $pmdPackage: Base64String!, $regexPackage: Base64String!,
192+
$retirejsPackage: Base64String!, $templatePackage: Base64String!, $packageLock: Base64String!) {
193+
createCommitOnBranch(input: {
194+
branch: {
195+
repositoryNameWithOwner: "forcedotcom/code-analyzer-core",
196+
branchName: $branch
197+
},
198+
message: {
199+
headline: $message
200+
},
201+
fileChanges: {
202+
additions: [
203+
{
204+
path: "packages/code-analyzer-core/package.json",
205+
contents: $corePackage
206+
}, {
207+
path: "packages/code-analyzer-engine-api/package.json",
208+
contents: $apiPackage
209+
}, {
210+
path: "packages/code-analyzer-eslint-engine/package.json",
211+
contents: $eslintPackage
212+
}, {
213+
path: "packages/code-analyzer-flowtest-engine/package.json",
214+
contents: $flowtestPackage
215+
}, {
216+
path: "packages/code-analyzer-pmd-engine/package.json",
217+
contents: $pmdPackage
218+
}, {
219+
path: "packages/code-analyzer-regex-engine/package.json",
220+
contents: $regexPackage
221+
}, {
222+
path: "packages/code-analyzer-retirejs-engine/package.json",
223+
contents: $retirejsPackage
224+
}, {
225+
path: "packages/T-E-M-P-L-A-T-E/package.json",
226+
contents: $templatePackage
227+
}, {
228+
path: "package-lock.json",
229+
contents: $packageLock
230+
}
231+
},
232+
expectedHeadOid: $oldOid
233+
}) {
234+
commit {
235+
id
236+
}
237+
}
238+
}'
239+
build-and-test-and-publish:
25240
runs-on: ubuntu-latest
26-
defaults:
27-
run:
28-
working-directory: ./packages/${{inputs.package}}
241+
needs: prepare-release-branch
29242
steps:
30243
- uses: actions/checkout@v4
244+
with:
245+
ref: ${{ needs.prepare-release-branch.outputs.branch-name }}
31246
- uses: actions/setup-node@v4
32247
with:
33-
node-version: 20
34-
- name: Verify we are using the correct package.json file
35-
run: |
36-
[[ -f package.json ]] || (echo "::error:: ./packages/${{inputs.package}}/package.json does not exist." && exit 1)
37-
PACKAGE_VERSION=`cat package.json | jq '.version' | xargs`
38-
[[ ${{ inputs.version }} == ${PACKAGE_VERSION} ]] || (echo "::error:: Input version ${{ inputs.version }} does not match package.json version ${PACKAGE_VERSION}" && exit 1)
39-
PACKAGE_NAME=`cat package.json | jq '.name' | xargs`
40-
[[ "@salesforce/${{ inputs.package }}" == ${PACKAGE_NAME} ]] || (echo "::error:: Input package "@salesforce/${{ inputs.package }}" does not match package.json name ${PACKAGE_NAME}" && exit 1)
248+
node-version: 'lts/*'
41249
- name: Build and test
42250
run: |
43251
npm install
44252
npm run build
45-
npm run test
46-
- name: publish-to-npm
253+
npm run test # Test here, since we didn't do it elsewhere
254+
- name: Publish Engine API
255+
if: ${{ inputs.code-analyzer-engine-api == 'true' }}
256+
run: |
257+
cd ./packages/code-analyzer-engine-api
258+
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
259+
if [ "${{ inputs.dryrun }}" == "true" ]]; then
260+
npm publish --tag latest-alpha --access public --verbose --dry-run
261+
else
262+
npm publish --tag latest-alpha --access public --verbose
263+
fi
264+
cd ../..
265+
- name: Publish Core
266+
if: ${{ inputs.code-analyzer-core == 'true' }}
267+
run: |
268+
cd ./packages/code-analyzer-core
269+
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
270+
if [ "${{ inputs.dryrun }}" == "true" ]]; then
271+
npm publish --tag latest-alpha --access public --verbose --dry-run
272+
else
273+
npm publish --tag latest-alpha --access public --verbose
274+
fi
275+
cd ../..
276+
- name: Publish ESLint Engine
277+
if: ${{ inputs.code-analyzer-eslint-engine == 'true' }}
278+
run: |
279+
cd ./packages/code-analyzer-eslint-engine
280+
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
281+
if [ "${{ inputs.dryrun }}" == "true" ]]; then
282+
npm publish --tag latest-alpha --access public --verbose --dry-run
283+
else
284+
npm publish --tag latest-alpha --access public --verbose
285+
fi
286+
cd ../..
287+
- name: Publish FlowTest Engine
288+
if: ${{ inputs.code-analyzer-flowtest-engine == 'true' }}
289+
run: |
290+
cd ./packages/code-analyzer-flowtest-engine
291+
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
292+
if [ "${{ inputs.dryrun }}" == "true" ]]; then
293+
npm publish --tag latest-alpha --access public --verbose --dry-run
294+
else
295+
npm publish --tag latest-alpha --access public --verbose
296+
fi
297+
cd ../..
298+
- name: Publish PMD Engine
299+
if: ${{ inputs.code-analyzer-pmd-engine == 'true' }}
300+
run: |
301+
cd ./packages/code-analyzer-pmd-engine
302+
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
303+
if [ "${{ inputs.dryrun }}" == "true" ]]; then
304+
npm publish --tag latest-alpha --access public --verbose --dry-run
305+
else
306+
npm publish --tag latest-alpha --access public --verbose
307+
fi
308+
cd ../..
309+
- name: Publish Regex Engine
310+
if: ${{ inputs.code-analyzer-regex-engine == 'true' }}
47311
run: |
312+
cd ./packages/code-analyzer-regex-engine
48313
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
49-
if [ "${{inputs.dryrun}}" == "true" ]; then
314+
if [ "${{ inputs.dryrun }}" == "true" ]]; then
50315
npm publish --tag latest-alpha --access public --verbose --dry-run
51316
else
52317
npm publish --tag latest-alpha --access public --verbose
53-
fi
318+
fi
319+
cd ../..
320+
- name: Publish RetireJS Engine
321+
if: ${{ inputs.code-analyzer-retirejs-engine == 'true' }}
322+
run: |
323+
cd ./packages/code-analyzer-retirejs-engine
324+
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
325+
if [ "${{ inputs.dryrun }}" == "true" ]]; then
326+
npm publish --tag latest-alpha --access public --verbose --dry-run
327+
else
328+
npm publish --tag latest-alpha --access public --verbose
329+
fi
330+
cd ../..
331+
create-postrelease-pull-request:
332+
runs-on: macos-latest
333+
needs: [prepare-release-branch, build-and-test-and-publish]
334+
if: ${{ inputs.dryrun == 'false' }} # A Dry Run doesn't release, so no PR should be made
335+
permissions:
336+
contents: write
337+
pull-requests: write
338+
steps:
339+
- uses: actions/checkout@v4
340+
with:
341+
ref: ${{ needs.prepare-release-branch.outputs.branch-name }}
342+
- run: |
343+
echo -e "This branch and PR were automatically created as part of a Package Publish.\n\
344+
The branch increments the .version property of published packages from X.Y.Z-SNAPSHOT to X.Y.Z, and updates any\
345+
inter-package dependencies appropriately.\n\
346+
The narrow scope of these changes makes a merge conflict unlikely, but if one does occur, you should consult\
347+
with the author of the conflicting change and decide what to do next. Ultimately it may make sense to not merge\
348+
this pull request at all. Use your judgment." > body.txt
349+
350+
gh pr create -B dev -H ${{ needs.prepare-release-branch.outputs.branch-name }} --title "POSTRELEASE @W-XXXXXXXX@ Merging after ecosystem release" -F body.txt

0 commit comments

Comments
 (0)