Skip to content

Commit bcb4494

Browse files
refactor(scripts): restructure prepare-release code for reuse
Extract common functionality from prepare-release script into separate modules, allowing reuse in new pack-as-beta script. Improve organization with dedicated files for specific functions such as scope changes, dependency updates, and file traversal. Issue: BTC-1933
1 parent f174292 commit bcb4494

File tree

8 files changed

+140
-109
lines changed

8 files changed

+140
-109
lines changed

scripts/changePackageScope/index.ts

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

scripts/prepare-release.ts

Lines changed: 15 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,24 @@
1-
import { readdirSync, readFileSync, statSync, writeFileSync } from 'fs';
1+
import * as assert from 'node:assert';
2+
import { readFileSync, writeFileSync } from 'fs';
23
import * as path from 'path';
34
import { inc } from 'semver';
4-
import { changeScopeInFile, getLernaModules } from './changePackageScope';
5+
import {
6+
walk,
7+
getDistTagsForModuleLocations,
8+
getLernaModules,
9+
changeScopeInFile,
10+
setDependencyVersion,
11+
} from './prepareRelease';
512

613
let lernaModules: string[] = [];
714
let lernaModuleLocations: string[] = [];
815
let TARGET_SCOPE = '@bitgo-beta';
916
let filesChanged = 0;
1017

1118
const setLernaModules = async (): Promise<void> => {
12-
({ lernaModules, lernaModuleLocations } = await getLernaModules());
13-
};
14-
15-
const walk = (dir: string): string[] => {
16-
let results: string[] = [];
17-
const ignoredFolders = [/node_modules/];
18-
const list = readdirSync(dir);
19-
list.forEach((file) => {
20-
file = path.join(dir, file);
21-
const stat = statSync(file);
22-
if (stat && stat.isDirectory()) {
23-
if (!ignoredFolders.some((folder) => folder.test(file))) {
24-
results = [...results, ...walk(file)];
25-
}
26-
} else if (['.ts', '.tsx', '.js', '.json'].includes(path.extname(file))) {
27-
// Is a file
28-
results.push(file);
29-
}
30-
});
31-
return results;
19+
const modules = await getLernaModules();
20+
lernaModules = modules.map(({ name }) => name);
21+
lernaModuleLocations = modules.map(({ location }) => location);
3222
};
3323

3424
const replacePackageScopes = () => {
@@ -39,20 +29,6 @@ const replacePackageScopes = () => {
3929
});
4030
};
4131

42-
/**
43-
* Makes an HTTP request to fetch all the dist tags for a given package.
44-
*/
45-
type DistTags = Record<string, string>;
46-
const getDistTags = async (packageName: string): Promise<DistTags> => {
47-
console.log(`Fetching dist tags for ${packageName}`);
48-
const url = `https://registry.npmjs.org/-/package/${packageName}/dist-tags`;
49-
const response = await fetch(url);
50-
if (!response.ok) {
51-
throw new Error(`Failed ${url}: ${response.status} ${response.statusText} ${await response.text()}`);
52-
}
53-
return response.json();
54-
};
55-
5632
// modules/bitgo is the only package we publish without an `@bitgo` prefix, so
5733
// we must manually set one
5834
const replaceBitGoPackageScope = () => {
@@ -92,36 +68,13 @@ function compareversion(version1, version2) {
9268
return result;
9369
}
9470

95-
async function getDistTagsForModules(moduleLocations: string[]): Promise<(DistTags | undefined)[]> {
96-
return await Promise.all(
97-
moduleLocations.map(async (modulePath) => {
98-
const moduleName: string = JSON.parse(
99-
readFileSync(path.join(modulePath, 'package.json'), { encoding: 'utf-8' })
100-
).name;
101-
switch (moduleName) {
102-
case '@bitgo-beta/express':
103-
case '@bitgo-beta/web-demo':
104-
case '@bitgo-beta/sdk-test':
105-
console.warn(`Skipping ${moduleName} as it's not published to npm`);
106-
return undefined;
107-
}
108-
try {
109-
return await getDistTags(moduleName);
110-
} catch (e) {
111-
console.warn(`Failed to fetch dist tags for ${moduleName}`, e);
112-
return undefined;
113-
}
114-
})
115-
);
116-
}
117-
11871
/**
11972
* increment the version based on the preid. default to `beta`
12073
*
12174
* @param {String | undefined} preid
12275
*/
12376
const incrementVersions = async (preid = 'beta') => {
124-
const distTags = await getDistTagsForModules(lernaModuleLocations);
77+
const distTags = await getDistTagsForModuleLocations(lernaModuleLocations);
12578
for (let i = 0; i < lernaModuleLocations.length; i++) {
12679
try {
12780
const modulePath = lernaModuleLocations[i];
@@ -142,6 +95,7 @@ const incrementVersions = async (preid = 'beta') => {
14295

14396
if (prevTag) {
14497
const next = inc(prevTag, 'prerelease', undefined, preid);
98+
assert(typeof next === 'string', `Failed to increment version for ${json.name}`);
14599
console.log(`Setting next version for ${json.name} to ${next}`);
146100
json.version = next;
147101
writeFileSync(path.join(modulePath, 'package.json'), JSON.stringify(json, null, 2) + '\n');
@@ -154,12 +108,7 @@ const incrementVersions = async (preid = 'beta') => {
154108
const otherJsonContent = readFileSync(path.join(otherModulePath, 'package.json'), { encoding: 'utf-8' });
155109
if (otherJsonContent.includes(json.name)) {
156110
const otherJson = JSON.parse(otherJsonContent);
157-
if (otherJson.dependencies && otherJson.dependencies[json.name]) {
158-
otherJson.dependencies[json.name] = next;
159-
}
160-
if (otherJson.devDependencies && otherJson.devDependencies[json.name]) {
161-
otherJson.devDependencies[json.name] = next;
162-
}
111+
setDependencyVersion(otherJson, json.name, next as string);
163112
writeFileSync(path.join(otherModulePath, 'package.json'), JSON.stringify(otherJson, null, 2) + '\n');
164113
}
165114
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export function setDependencyVersion(
2+
packageJson: {
3+
dependencies?: Record<string, string>;
4+
devDependencies?: Record<string, string>;
5+
},
6+
dependencyName: string,
7+
version: string
8+
): void {
9+
if (packageJson.dependencies && packageJson.dependencies[dependencyName]) {
10+
packageJson.dependencies[dependencyName] = version;
11+
}
12+
if (packageJson.devDependencies && packageJson.devDependencies[dependencyName]) {
13+
packageJson.devDependencies[dependencyName] = version;
14+
}
15+
// FIXME: also update the peerDependencies, buildDependencies, etc.
16+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { readFileSync, writeFileSync } from 'fs';
2+
3+
export function updateModuleNames(input: string, lernaModules: string[], targetScope: string): string {
4+
lernaModules.forEach((moduleName) => {
5+
const newName = `${moduleName.replace('@bitgo/', `${targetScope}/`)}`;
6+
input = input.replace(new RegExp(moduleName, 'g'), newName);
7+
});
8+
return input;
9+
}
10+
11+
export function changeScopeInFile(filePath: string, lernaModules: string[], targetScope: string): number {
12+
const oldContent = readFileSync(filePath, { encoding: 'utf8' });
13+
const newContent = updateModuleNames(oldContent, lernaModules, targetScope);
14+
if (newContent !== oldContent) {
15+
writeFileSync(filePath, newContent, { encoding: 'utf-8' });
16+
return 1;
17+
}
18+
return 0;
19+
}

scripts/prepareRelease/distTags.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { readFileSync } from 'fs';
2+
import * as path from 'path';
3+
4+
export type DistTags = Record<string, string>;
5+
6+
/**
7+
* Makes an HTTP request to fetch all the dist tags for a given package.
8+
*/
9+
export async function getDistTags(packageName: string): Promise<DistTags> {
10+
console.log(`Fetching dist tags for ${packageName}`);
11+
const url = `https://registry.npmjs.org/-/package/${packageName}/dist-tags`;
12+
const response = await fetch(url);
13+
if (!response.ok) {
14+
throw new Error(`Failed ${url}: ${response.status} ${response.statusText} ${await response.text()}`);
15+
}
16+
return response.json();
17+
}
18+
19+
export async function getDistTagsForModuleNames(moduleNames: string[]): Promise<(DistTags | undefined)[]> {
20+
return Promise.all(
21+
moduleNames.map(async (moduleName) => {
22+
switch (moduleName) {
23+
case '@bitgo-beta/express':
24+
case '@bitgo-beta/web-demo':
25+
case '@bitgo-beta/sdk-test':
26+
console.warn(`Skipping ${moduleName} as it's not published to npm`);
27+
return undefined;
28+
}
29+
try {
30+
return await getDistTags(moduleName);
31+
} catch (e) {
32+
console.warn(`Failed to fetch dist tags for ${moduleName}`, e);
33+
return undefined;
34+
}
35+
})
36+
);
37+
}
38+
39+
export async function getDistTagsForModuleLocations(moduleLocations: string[]): Promise<(DistTags | undefined)[]> {
40+
return getDistTagsForModuleNames(
41+
moduleLocations.map(
42+
(modulePath) => JSON.parse(readFileSync(path.join(modulePath, 'package.json'), { encoding: 'utf-8' })).name
43+
)
44+
);
45+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as execa from 'execa';
2+
3+
/**
4+
* Create a function which can run lerna commands
5+
* @param {String} lernaPath - path to lerna binary
6+
* @returns {function(string, string[], Object.<string, string>): Promise<string>}
7+
*/
8+
function getLernaRunner(lernaPath: string) {
9+
return async (command: string, args: string[] = [], options = {}) => {
10+
const { stdout } = await execa(lernaPath, [command, ...args], options);
11+
return stdout;
12+
};
13+
}
14+
15+
export async function getLernaModules(): Promise<Array<{ name: string; location: string }>> {
16+
const { stdout: lernaBinary } = await execa('yarn', ['bin', 'lerna'], { cwd: process.cwd() });
17+
const lerna = getLernaRunner(lernaBinary);
18+
return JSON.parse(await lerna('list', ['--loglevel', 'silent', '--json', '--all']));
19+
}

scripts/prepareRelease/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export * from './changeScopeInFile';
2+
export * from './changePackageJson';
3+
export * from './distTags';
4+
export * from './getLernaModules';
5+
export * from './walk';

scripts/prepareRelease/walk.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as path from 'path';
2+
import { readdirSync, statSync } from 'fs';
3+
4+
export const walk = (dir: string): string[] => {
5+
let results: string[] = [];
6+
const ignoredFolders = [/node_modules/];
7+
const list = readdirSync(dir);
8+
list.forEach((file) => {
9+
file = path.join(dir, file);
10+
const stat = statSync(file);
11+
if (stat && stat.isDirectory()) {
12+
if (!ignoredFolders.some((folder) => folder.test(file))) {
13+
results = [...results, ...walk(file)];
14+
}
15+
} else if (['.ts', '.tsx', '.js', '.json'].includes(path.extname(file))) {
16+
// Is a file
17+
results.push(file);
18+
}
19+
});
20+
return results;
21+
};

0 commit comments

Comments
 (0)