Skip to content

Commit 7eeac07

Browse files
fix: prepare-release should work with latest preid
This commit updates the prepare-release script to work with the `@bitgo` stable relase org as well as the latest preid. The script will use conventional commits for a specific module to generate the next increment to use for the next version. TICKET: WP-6047
1 parent ee3a622 commit 7eeac07

16 files changed

+545
-289
lines changed

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
node-version-file: .nvmrc
2727

2828
- name: Install BitGoJS
29-
run: yarn install --with-frozen-lockfile
29+
run: yarn install --with-frozen-lockfile --ignore-scripts
3030

3131
- name: Set Environment Variable for Alpha
3232
if: github.ref != 'refs/heads/master' # only publish changes if on feature branches

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ modules/**/pack-scoped/
1818
coverage
1919
/.direnv/
2020
.claude/
21+
scripts/cache/

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@typescript-eslint/parser": "^4.23.0",
1717
"babel-loader": "^9.1.0",
1818
"buffer": "^6.0.3",
19+
"conventional-commits-parser": "6.2.0",
1920
"cross-env": "^7.0.3",
2021
"crypto-browserify": "^3.12.0",
2122
"depcheck": "^1.4.3",
@@ -45,6 +46,7 @@
4546
"should": "^13.1.3",
4647
"should-http": "^0.1.1",
4748
"should-sinon": "^0.0.6",
49+
"simple-git": "^3.28.0",
4850
"sinon": "^6.3.5",
4951
"stream-browserify": "^3.0.0",
5052
"stream-http": "^3.2.0",

scripts/pack-scoped.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,20 @@ import execa from 'execa';
99
import mpath from 'path';
1010
import yargs from 'yargs';
1111
import {
12+
LernaModule,
1213
walk,
13-
getLernaModules,
1414
changeScopeInFile,
15-
getDistTagsForModuleNames,
15+
DistTags,
1616
updateModuleNames,
17+
getDistTagsForModuleNames,
1718
setDependencyVersion,
18-
DistTags,
19-
LernaModule,
19+
getLernaModules,
2020
getNewModuleName,
2121
} from './prepareRelease';
2222

2323
/** The directory to pack the module into */
2424
const scopedPackageDir = 'pack-scoped';
25+
const uninitializedModules = process.env.UNINITIALIZED_MODULES ? process.env.UNINITIALIZED_MODULES.split(',') : [];
2526

2627
async function changeModuleScope(dir: string, params: { lernaModules: LernaModule[]; scope: string }) {
2728
console.log(`Changing scope of module at ${dir} to ${params.scope}`);
@@ -43,7 +44,7 @@ async function changeModuleVersions(
4344
}
4445
) {
4546
const newModuleNames = params.moduleNames.map((m) => updateModuleNames(m, params.moduleNames, params.scope));
46-
const { distTagsByModuleName = await getDistTagsForModuleNames(newModuleNames) } = params;
47+
const { distTagsByModuleName = await getDistTagsForModuleNames(newModuleNames, uninitializedModules, 'beta') } = params;
4748
const packageJsonPath = mpath.join(dir, 'package.json');
4849
const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf-8'));
4950
newModuleNames.forEach((m) => {
@@ -104,7 +105,7 @@ async function getDistTagsForModuleNamesCached(
104105
}
105106
}
106107

107-
const distTagsByModuleName = await getDistTagsForModuleNames(newModuleNames);
108+
const distTagsByModuleName = await getDistTagsForModuleNames(newModuleNames, uninitializedModules, 'beta');
108109
if (params.cache) {
109110
console.log(`Caching dist tags to ${params.cache}`);
110111
await fs.promises.writeFile(params.cache, JSON.stringify([...distTagsByModuleName.entries()], null, 2) + '\n');

scripts/prepare-release.ts

Lines changed: 25 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -1,171 +1,27 @@
1-
import assert from 'node:assert';
2-
import { readFileSync, writeFileSync } from 'fs';
3-
import path from 'path';
4-
import { inc, lt } from 'semver';
5-
import yargs from 'yargs';
6-
import { hideBin } from 'yargs/helpers';
7-
8-
import {
9-
walk,
10-
getDistTagsForModules,
11-
getLernaModules,
12-
changeScopeInFile,
13-
setDependencyVersion,
14-
DistTags,
15-
LernaModule,
16-
} from './prepareRelease';
17-
18-
function replacePackageScopes(
19-
rootDir: string,
20-
lernaModules: LernaModule[],
21-
targetScope: string,
22-
): number {
23-
let filesChanged = 0;
24-
// replace all @bitgo packages & source code with alternate SCOPE
25-
const filePaths = [
26-
...walk(path.join(rootDir, 'modules')),
27-
...walk(path.join(rootDir, 'webpack')),
28-
];
29-
const moduleNames = lernaModules.map(({ name }) => name);
30-
31-
filePaths.forEach((file) => {
32-
filesChanged += changeScopeInFile(file, moduleNames, targetScope);
33-
});
34-
return filesChanged;
35-
}
36-
37-
// modules/bitgo is the only package we publish without an `@bitgo` prefix, so
38-
// we must manually set one
39-
function replaceBitGoPackageScope(rootDir: string, targetScope: string): void {
40-
const cwd = path.join(rootDir, 'modules', 'bitgo');
41-
const json = JSON.parse(
42-
readFileSync(path.join(cwd, 'package.json'), { encoding: 'utf-8' }),
43-
);
44-
json.name = `${targetScope}/bitgo`;
45-
writeFileSync(
46-
path.join(cwd, 'package.json'),
47-
JSON.stringify(json, null, 2) + '\n',
48-
);
49-
}
50-
51-
/**
52-
* Read package.json for a module
53-
* @param module The module to read package.json from
54-
* @returns The parsed package.json content
55-
*/
56-
function readModulePackageJson(module: LernaModule): any {
57-
return JSON.parse(
58-
readFileSync(path.join(module.location, 'package.json'), {
59-
encoding: 'utf-8',
60-
}),
61-
);
62-
}
63-
64-
/**
65-
* Write package.json for a module
66-
* @param module The module to write package.json to
67-
* @param json The content to write
68-
*/
69-
function writeModulePackageJson(module: LernaModule, json: any): void {
70-
writeFileSync(
71-
path.join(module.location, 'package.json'),
72-
JSON.stringify(json, null, 2) + '\n',
73-
);
74-
}
75-
761
/**
77-
* Increment the version for a single module based on the preid.
2+
* Usage:
3+
* # to prepare a stable release on the stable channel
4+
* npx tsx ./scripts/prepare-release.ts latest --scope @bitgo
785
*
79-
* @param {String} preid - The prerelease identifier
80-
* @param {LernaModule} module - The module to update
81-
* @param {DistTags|undefined} tags - The dist tags for the module
82-
* @param {LernaModule[]} allModules - All modules for dependency updates
83-
* @returns {String|undefined} - The new version if set, undefined otherwise
6+
* # to prepare a beta release in the beta organization
7+
* npx tsx ./scripts/prepare-release.ts beta --scope @bitgo-beta
8+
*
9+
* # to skip uninitialized modules, set the UNINITIALIZED_MODULES env var
10+
* # if modules are not initialized and are not skipped, they will fail
11+
* UNINITIALIZED_MODULES=@bitgo/sdk-coin-flrp npx tsx ./scripts/prepare-release.ts latest --scope @bitgo
8412
*/
85-
function incrementVersionsForModuleLocation(
86-
preid: string,
87-
module: LernaModule,
88-
tags: DistTags | undefined,
89-
allModules: LernaModule[],
90-
): string | undefined {
91-
const json = readModulePackageJson(module);
92-
93-
let prevTag: string | undefined = undefined;
94-
95-
if (tags) {
96-
if (tags[preid]) {
97-
const version = tags[preid].split('-');
98-
const latest = tags?.latest?.split('-') ?? ['0.0.0'];
99-
prevTag = lt(version[0], latest[0])
100-
? `${tags.latest}-${preid}`
101-
: tags[preid];
102-
} else {
103-
prevTag = `${tags.latest}-${preid}`;
104-
}
105-
}
10613

107-
if (prevTag) {
108-
const next = inc(prevTag, 'prerelease', undefined, preid);
109-
assert(
110-
typeof next === 'string',
111-
`Failed to increment version for ${json.name} prevTag=${prevTag}`,
112-
);
113-
console.log(`Setting next version for ${json.name} to ${next}`);
114-
json.version = next;
115-
writeModulePackageJson(module, json);
116-
117-
// since we're manually setting new versions, we must also reconcile all other lerna packages to use the 'next' version for this module
118-
allModules.forEach((otherModule) => {
119-
// skip it for the current version
120-
if (otherModule.location === module.location) {
121-
return;
122-
}
123-
124-
// Use readModulePackageJson here instead of direct readFileSync
125-
const otherJson = readModulePackageJson(otherModule);
126-
127-
// Check if this module depends on the one we're updating
128-
const otherJsonString = JSON.stringify(otherJson);
129-
if (otherJsonString.includes(json.name)) {
130-
setDependencyVersion(otherJson, json.name, next);
131-
writeModulePackageJson(otherModule, otherJson);
132-
}
133-
});
134-
135-
return next;
136-
}
137-
return undefined;
138-
}
14+
import path from 'path';
15+
import yargs from 'yargs';
16+
import { hideBin } from 'yargs/helpers';
13917

140-
/**
141-
* increment the version based on the preid.
142-
*
143-
* @param {String} preid - The prerelease identifier
144-
* @param {LernaModule[]} lernaModules - The modules to update
145-
*/
146-
async function incrementVersions(
147-
preid: string,
148-
lernaModules: LernaModule[],
149-
): Promise<void> {
150-
const distTags = await getDistTagsForModules(lernaModules);
18+
import { getLernaModules, validateReleaseTransformations } from './prepareRelease';
19+
import { replacePackageScopes } from './prepareRelease/mutateScope';
20+
import { incrementVersions } from './prepareRelease/incrementVersions';
15121

152-
for (const m of lernaModules) {
153-
try {
154-
incrementVersionsForModuleLocation(
155-
preid,
156-
m,
157-
distTags.get(m),
158-
lernaModules,
159-
);
160-
} catch (e) {
161-
// it's not necessarily a blocking error. Let lerna try and publish anyways
162-
console.warn(
163-
`Couldn't set next version for ${m.name} at ${m.location}`,
164-
e,
165-
);
166-
}
167-
}
168-
}
22+
export const uninitializedModules = process.env.UNINITIALIZED_MODULES
23+
? process.env.UNINITIALIZED_MODULES.split(',')
24+
: [];
16925

17026
yargs(hideBin(process.argv))
17127
.command(
@@ -186,9 +42,7 @@ yargs(hideBin(process.argv))
18642
.option('root-dir', {
18743
type: 'string',
18844
description: 'Root directory of the repository',
189-
default:
190-
process.env.BITGO_PREPARE_RELEASE_ROOT_DIR ||
191-
path.join(__dirname, '..'),
45+
default: process.env.BITGO_PREPARE_RELEASE_ROOT_DIR || path.join(__dirname, '..'),
19246
});
19347
},
19448
async (argv) => {
@@ -201,34 +55,19 @@ yargs(hideBin(process.argv))
20155
try {
20256
// Get lerna modules directly
20357
const lernaModules = await getLernaModules();
204-
20558
// Replace package scopes
206-
const filesChanged = replacePackageScopes(
207-
rootDir,
208-
lernaModules,
209-
targetScope,
210-
);
211-
212-
// Replace BitGo package scope
213-
replaceBitGoPackageScope(rootDir, targetScope);
214-
59+
await replacePackageScopes(rootDir, lernaModules, targetScope);
21560
// Increment versions
216-
await incrementVersions(preid, lernaModules);
61+
await incrementVersions(preid, lernaModules, uninitializedModules);
62+
await validateReleaseTransformations(lernaModules, preid, targetScope);
21763

218-
if (filesChanged) {
219-
console.log(`Successfully re-targeted ${filesChanged} files.`);
220-
process.exit(0);
221-
} else {
222-
console.error(
223-
'No files were changed, something must have gone wrong.',
224-
);
225-
process.exit(1);
226-
}
64+
console.log(`Successfully re-targeted module scopes and versions.`);
65+
process.exit(0);
22766
} catch (error) {
22867
console.error('Error in prepare-release script:', error);
22968
process.exit(1);
23069
}
231-
},
70+
}
23271
)
23372
.help()
23473
.alias('help', 'h')

scripts/prepareRelease/changePackageJson.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

scripts/prepareRelease/changeScopeInFile.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)