@@ -2,14 +2,41 @@ name: publish-package-to-npm
22on :
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
2350jobs :
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