Skip to content

Commit af40c77

Browse files
authored
chore(release): create canary release script (#5723)
* chore(release): create canary release script * chore(release): merge canary release and full release scripts into single workflow keeps related logic together and npm only allows one trusted publisher workflow
1 parent 04a8b6d commit af40c77

File tree

2 files changed

+84
-84
lines changed

2 files changed

+84
-84
lines changed

.github/workflows/release.yml

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ permissions:
2828
jobs:
2929
release:
3030
# Allow only on master, spring*, summer*, winter*;
31-
if: ${{ github.repository_owner == 'salesforce' && (github.ref_name == 'master' || startsWith(github.ref_name, 'spring') || startsWith(github.ref_name, 'summer') || startsWith(github.ref_name, 'winter')) }}
31+
if: ${{ github.repository_owner == 'salesforce' }}
3232
name: Release LWC - ${{ inputs.release_version }} ${{ inputs.bump }}
3333
environment: release
3434
runs-on: ubuntu-latest
@@ -44,8 +44,23 @@ jobs:
4444
exit 1
4545
fi
4646
fi
47-
echo "Resolved input: '$RELEASE_VERSION'"
47+
48+
if [ "$RELEASE_VERSION" = prerelease ]; then
49+
TAG=canary
50+
else
51+
case "$GITHUB_REF_NAME" in
52+
master) TAG=latest;;
53+
winter*) TAG="$GITHUB_REF_NAME";;
54+
spring*) TAG="$GITHUB_REF_NAME";;
55+
summer*) TAG="$GITHUB_REF_NAME";;
56+
*) echo "Could not determine tag for releasing $GITHUB_REF_NAME as v$NEW_VERSION." && exit 1;;
57+
esac
58+
fi
59+
60+
echo "Resolved input: $RELEASE_VERSION"
4861
echo "resolved=$RELEASE_VERSION" >> "$GITHUB_OUTPUT"
62+
echo "Resolved tag: $TAG"
63+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
4964
5065
- name: Checkout
5166
uses: actions/checkout@v5
@@ -66,42 +81,38 @@ jobs:
6681

6782
- name: Update LWC version
6883
id: update_version
84+
env:
85+
VERSION_INPUT: ${{ steps.resolve_input.outputs.resolved }}
6986
run: |
7087
71-
node ./scripts/release/version.js '${{ steps.resolve_input.outputs.resolved }}'
88+
node ./scripts/release/version.js "$VERSION_INPUT"
7289
RESOLVED_VERSION="$(jq -r .version package.json)"
7390
echo "New version: $RESOLVED_VERSION"
7491
echo "new_version=$RESOLVED_VERSION" >> "$GITHUB_OUTPUT"
7592
93+
- name: Build
94+
run: yarn build
95+
7696
- name: Set git identity (Actions bot)
97+
if: ${{ steps.resolve_input.outputs.resolved != "prerelease" }}
7798
run: |
7899
git config user.name "github-actions[bot]"
79100
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
80101
81102
- name: Commit & push
103+
if: ${{ steps.resolve_input.outputs.resolved != "prerelease" }}
82104
uses: actions-js/push@v1.4
83105
with:
84106
github_token: ${{ secrets.WORKFLOW_PAT }}
85107
branch: ${{ github.ref_name }}
86108
message: 'chore: release v${{ steps.update_version.outputs.new_version }}'
87109

88-
- name: Build
89-
run: yarn build
90-
91-
- name: Tag and create GitHub release
92-
env:
93-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
94-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
95-
run: |
96-
VERSION='${{ steps.update_version.outputs.new_version }}'
97-
git tag -a "v$VERSION" -m "Release v$VERSION"
98-
git push origin tag "v$VERSION"
99-
gh release create "v$VERSION" --title "v$VERSION" --generate-notes
100-
101110
- name: Publish to npm
102111
env:
112+
NEW_VERSION: ${{ steps.update_version.outputs.new_version }}
103113
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
104114
NPM_CONFIG_ALWAYS_AUTH: 'true'
115+
TAG: ${{ steps.resolve_input.outputs.tag }}
105116
run: |
106117
# Force both npm and yarn to use npmjs and pick up the token
107118
yarn config set registry https://registry.npmjs.org
@@ -112,5 +123,16 @@ jobs:
112123
echo "yarn registry: $(yarn config get registry)"
113124
echo "npm registry: $(npm config get registry)"
114125
115-
TAG=$([ "$GITHUB_REF_NAME" = "master" ] && echo latest || echo "$GITHUB_REF_NAME")
126+
echo "Publishing $GITHUB_REF_NAME as v$NEW_VERSION using tag $TAG."
116127
yarn nx release publish --yes --tag "$TAG"
128+
129+
- name: Tag and create GitHub release
130+
if: ${{ steps.resolve_input.outputs.resolved != "prerelease" }}
131+
env:
132+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
133+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
134+
VERSION: ${{ steps.update_version.outputs.new_version }}
135+
run: |
136+
git tag -a "v$VERSION" -m "Release v$VERSION"
137+
git push origin tag "v$VERSION"
138+
gh release create "v$VERSION" --title "v$VERSION" --generate-notes

scripts/release/version.js

Lines changed: 45 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,92 +6,70 @@
66
*/
77
import fs from 'node:fs';
88
import path from 'node:path';
9-
import readline from 'node:readline';
109
import semver from 'semver';
1110
import { globSync } from 'glob';
1211

1312
const rootPath = path.resolve(import.meta.dirname, '../../');
1413
const rootPackageJsonPath = `${rootPath}/package.json`;
1514
const rootPackageJson = JSON.parse(fs.readFileSync(rootPackageJsonPath, 'utf-8'));
1615

17-
(async () => {
18-
const rawVersion = await getVersion();
19-
const parsedVersion = await parseVersion(rawVersion);
20-
updatePackages(parsedVersion);
21-
})().catch(console.error);
22-
23-
async function getVersion() {
24-
if (process.argv[2]) {
25-
return process.argv[2];
26-
}
27-
const rl = readline.createInterface({
28-
input: process.stdin,
29-
output: process.stdout,
30-
});
31-
const answer = await new Promise((resolve) =>
32-
rl.question('Enter a new LWC version: ', resolve)
33-
);
34-
rl.close();
35-
return answer;
16+
const rawVersion = process.argv[2];
17+
if (!rawVersion) {
18+
throw new Error('You must specify a version number or bump type.');
3619
}
20+
// Preid defaults to alpha (prereleases are v1.2.3-alpha.0)
21+
const preid = process.argv[3] ?? 'alpha';
22+
const newVersion = parseVersion(rawVersion, preid);
23+
updatePackages(newVersion);
3724

38-
async function parseVersion(rawVersion) {
39-
try {
40-
const current = rootPackageJson.version;
41-
const exact = semver.valid(rawVersion);
42-
if (exact) {
43-
// answer is a semver version
44-
if (semver.gt(exact, current)) {
45-
return exact;
46-
}
47-
throw new Error(`Release version ${rawVersion} is not greater than ${current}.`);
48-
}
49-
const incremented = semver.inc(current, rawVersion);
50-
if (incremented) {
51-
// answer is a semver release type (major/minor/etc.)
52-
return incremented;
25+
function parseVersion(rawVersion, preid) {
26+
const current = rootPackageJson.version;
27+
const exact = semver.valid(rawVersion);
28+
if (exact) {
29+
// answer is a semver version
30+
if (semver.gt(exact, current)) {
31+
return exact;
5332
}
54-
throw new Error(`Invalid release version: ${rawVersion}`);
55-
} catch (error) {
56-
console.error(error);
57-
process.exit(1);
33+
throw new Error(`Release version ${rawVersion} is not greater than ${current}.`);
34+
}
35+
const incremented = semver.inc(current, rawVersion, preid);
36+
if (incremented) {
37+
// answer is a semver release type (major/minor/etc.)
38+
return incremented;
5839
}
40+
throw new Error(`Invalid release version: ${rawVersion}`);
5941
}
6042

6143
function updatePackages(newVersion) {
62-
try {
63-
const packagesToUpdate = getPackagesToUpdate();
64-
const workspacesPackageJson = new Set(
65-
packagesToUpdate.map(({ packageJson }) => packageJson.name)
66-
);
44+
const packagesToUpdate = getPackagesToUpdate();
45+
const workspacesPackageJson = new Set(
46+
packagesToUpdate.map(({ packageJson }) => packageJson.name)
47+
);
6748

68-
for (const { packageJson } of packagesToUpdate) {
69-
packageJson.version = newVersion;
70-
// Look for different types of dependencies
71-
// ex: dependencies, devDependencies, peerDependencies
72-
const pkgDependencyTypes = Object.keys(packageJson).filter((key) =>
73-
key.match(/.*[dD]ependencies/)
74-
);
75-
// Update dependencies in package.json
76-
for (const pkgDependencyType of pkgDependencyTypes) {
77-
for (const pkgDepName of Object.keys(packageJson[pkgDependencyType])) {
78-
if (workspacesPackageJson.has(pkgDepName)) {
79-
// ex: packageJson[devDependencies][@lwc/template-compiler]
80-
packageJson[pkgDependencyType][pkgDepName] = newVersion;
81-
}
49+
for (const { packageJson } of packagesToUpdate) {
50+
packageJson.version = newVersion;
51+
// Look for different types of dependencies
52+
// ex: dependencies, devDependencies, peerDependencies
53+
const pkgDependencyTypes = Object.keys(packageJson).filter((key) =>
54+
key.match(/.*[dD]ependencies/)
55+
);
56+
// Update dependencies in package.json
57+
for (const pkgDependencyType of pkgDependencyTypes) {
58+
for (const pkgDepName of Object.keys(packageJson[pkgDependencyType])) {
59+
if (workspacesPackageJson.has(pkgDepName)) {
60+
// ex: packageJson[devDependencies][@lwc/template-compiler]
61+
packageJson[pkgDependencyType][pkgDepName] = newVersion;
8262
}
8363
}
8464
}
65+
}
8566

86-
// Update package.json files and print updated packges
87-
for (const { originalVersion, packageJson, packageJsonPath } of packagesToUpdate) {
88-
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + '\n');
89-
console.log(
90-
`Updated ${packageJson.name} from ${originalVersion} to ${packageJson.version}`
91-
);
92-
}
93-
} catch (error) {
94-
console.error(error);
67+
// Update package.json files and print updated packges
68+
for (const { originalVersion, packageJson, packageJsonPath } of packagesToUpdate) {
69+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + '\n');
70+
console.log(
71+
`Updated ${packageJson.name} from ${originalVersion} to ${packageJson.version}`
72+
);
9573
}
9674
}
9775

0 commit comments

Comments
 (0)