Skip to content

Commit 6d87bd9

Browse files
committed
Update bump-demo-script.ts
1 parent ff2da74 commit 6d87bd9

File tree

1 file changed

+116
-142
lines changed

1 file changed

+116
-142
lines changed

scripts/bump-demo-packages.ts

Lines changed: 116 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,209 +1,183 @@
1+
import { Command, type OptionValues } from 'commander';
2+
import { promises as fs } from 'fs';
3+
import path from 'path';
4+
import inquirer from 'inquirer';
15
import { findWorkspacePackages } from '@pnpm/workspace.find-packages';
2-
import { spawnSync } from 'child_process';
3-
import * as fs from 'fs';
4-
import * as path from 'path';
5-
import * as process from 'process';
66

7-
enum ResultType {
7+
enum ProcessStatus {
88
SUCCESS,
99
WARNING,
10-
FAILED
10+
ERROR
1111
}
1212

1313
type ProcessResult =
1414
| {
1515
demoName: string;
16-
resultType: ResultType.SUCCESS;
16+
status: ProcessStatus.SUCCESS;
1717
}
1818
| {
1919
demoName: string;
20-
resultType: ResultType.WARNING;
21-
message: string;
20+
status: ProcessStatus.WARNING;
21+
errors: string[];
2222
}
2323
| {
2424
demoName: string;
25-
resultType: ResultType.FAILED;
26-
message: string;
25+
status: ProcessStatus.ERROR;
26+
errors: string[];
2727
};
2828

29-
type Flags = {
30-
'--ignore-workspace': boolean;
31-
'--pattern': boolean;
32-
'--dry-run': boolean;
29+
const displayStatus = (status: ProcessStatus): string => {
30+
switch (status) {
31+
case ProcessStatus.SUCCESS:
32+
return '✅ Success';
33+
case ProcessStatus.WARNING:
34+
return '🚧 Warning';
35+
case ProcessStatus.ERROR:
36+
return '🚫 Error ';
37+
}
3338
};
3439

35-
const DEMOS_DIR = 'demos';
40+
const displayResults = (results: ProcessResult[]) => {
41+
let errored = false;
42+
43+
const data = results.map((r) => {
44+
errored = errored || r.status === ProcessStatus.ERROR;
45+
const errors: string | null =
46+
r.status === ProcessStatus.SUCCESS ? null : r.errors.map((e) => e.slice(0, 40)).join('\n');
47+
return {
48+
demo: r.demoName,
49+
status: displayStatus(r.status),
50+
errors
51+
};
52+
});
53+
54+
console.table(data, ['status', 'demo', 'errors']);
55+
56+
return errored;
57+
};
3658

3759
const workspacePackages = await findWorkspacePackages(path.resolve('.'), {
3860
patterns: ['./packages/*']
3961
});
4062

41-
const defaultFlags = (): Flags => {
42-
return {
43-
'--ignore-workspace': false,
44-
'--pattern': false,
45-
'--dry-run': false
46-
};
63+
const resolveDemos = async (): Promise<string[]> => {
64+
const demos = await fs.readdir('./demos');
65+
return demos.sort();
4766
};
4867

49-
const parseArgs = (processArgs: string[]): [string, string[], Flags] => {
50-
// processArgs[0] == 'node'
51-
// processArgs[1] == 'bump-demo-package.ts'
52-
const name: string = processArgs[1];
53-
const args: string[] = [];
54-
const flags: Flags = defaultFlags();
55-
56-
// Boolean flags
57-
for (const arg of processArgs.slice(2)) {
58-
if (arg in flags) {
59-
flags[arg] = true;
60-
} else {
61-
args.push(arg);
68+
const chooseDemos = async (demos: string[]): Promise<string[]> => {
69+
const choices = demos.map((d) => ({ name: d, value: d }));
70+
const result = await inquirer.prompt({
71+
type: 'checkbox',
72+
message: 'Select the demos you want to version',
73+
name: 'demos',
74+
loop: false,
75+
choices
76+
});
77+
return result.demos;
78+
};
79+
80+
const processDemos = async (demos: string[], options: OptionValues): Promise<ProcessResult[]> => {
81+
const results = [];
82+
for (const demo of demos) {
83+
console.log(`\n> \x1b[1m${demo}\x1b[0m`);
84+
85+
const result = await processDemo(demo, options);
86+
if (result.status !== ProcessStatus.SUCCESS) {
87+
const prefix =
88+
result.status === ProcessStatus.WARNING ? '\x1b[1;33m[WARNING]\x1b[0m: ' : '\x1b[1;31m[ERROR]\x1b[0m: ';
89+
result.errors.forEach((e) => console.error(prefix + e));
6290
}
91+
results.push(result);
6392
}
6493

65-
return [name, args, flags];
94+
return results;
6695
};
6796

68-
let [_programName, programArgs, programOpts]: [string, string[], Flags] = parseArgs(process.argv);
97+
const processDemo = async (demoName: string, options: OptionValues): Promise<ProcessResult> => {
98+
const demoSrc = path.resolve(path.join('demos', demoName));
6999

70-
const processDemo = (demoPath: string): ProcessResult => {
71-
const demoName = path.basename(demoPath);
72-
const demoSrc = path.resolve(demoPath);
73-
74-
console.log(`Processing ${demoName}`);
75-
if (!fs.lstatSync(demoSrc).isDirectory()) {
100+
if (!(await fs.lstat(demoSrc)).isDirectory()) {
76101
return {
77102
demoName,
78-
resultType: ResultType.WARNING,
79-
message: `'${demoSrc}' is not a directory.`
103+
status: ProcessStatus.ERROR,
104+
errors: [`./demos/${demoName} is not a directory.`]
80105
};
81106
}
82107

83108
const packageJsonPath = path.join(demoSrc, 'package.json');
84109
let packageJson: any;
85110

86111
try {
87-
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
112+
packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
88113
} catch (e) {
89-
if (e instanceof SyntaxError) {
90-
return {
91-
demoName,
92-
resultType: ResultType.FAILED,
93-
message: `Error parsing package.json: ${e.message}`
94-
};
95-
}
96-
97-
if (!('code' in e)) {
98-
return {
99-
demoName,
100-
resultType: ResultType.FAILED,
101-
message: `Unknown error: ${e}`
102-
};
103-
}
104-
105114
return {
106115
demoName,
107-
resultType: ResultType.FAILED,
108-
message: `Error reading package.json: ${e.message}`
116+
status: ProcessStatus.ERROR,
117+
errors: [`Error reading package.json: ${e}`]
109118
};
110119
}
111120

112-
let result: ProcessResult = {
113-
demoName,
114-
resultType: ResultType.SUCCESS
115-
};
116-
const processDeps = (deps: [string, string][]) => {
117-
for (const workspacePackage of workspacePackages) {
118-
const packageName = workspacePackage.manifest.name!;
119-
if (packageName in deps) {
120-
const originalVersion = deps[packageName];
121-
const latestVersion = '^' + workspacePackage.manifest.version!;
122-
123-
if (result.resultType !== ResultType.WARNING && originalVersion.startsWith('workspace')) {
124-
if (!programOpts['--ignore-workspace']) {
125-
result = {
126-
demoName,
127-
resultType: ResultType.WARNING,
128-
message: `Package '${packageName}' had version '${originalVersion}' which is unexpected.`
129-
};
130-
}
131-
}
132-
133-
console.log(`> ${packageName}: ${originalVersion} => ${latestVersion}`);
134-
deps[packageName] = latestVersion;
135-
}
136-
}
137-
};
121+
let packagesFound = 0;
122+
const processDeps = (deps: { [_: string]: string }) => {
123+
workspacePackages.forEach((pkg) => {
124+
const pkgName = pkg.manifest.name!;
125+
if (!(pkgName in deps)) return;
126+
packagesFound++;
138127

139-
if (packageJson.dependencies) {
140-
processDeps(packageJson.dependencies);
141-
}
128+
const currentVersion = deps[pkgName];
129+
const latestVersion = '^' + pkg.manifest.version!;
142130

143-
if (packageJson.peerDependencies) {
144-
processDeps(packageJson.peerDependencies);
145-
}
131+
console.log(`${pkgName}: ${currentVersion} => ${latestVersion}`);
132+
deps[pkgName] = latestVersion;
133+
});
134+
};
135+
136+
if (packageJson.dependencies) processDeps(packageJson.dependencies);
137+
if (packageJson.devDependencies) processDeps(packageJson.devDependencies);
146138

147-
if (packageJson.devDependencies) {
148-
processDeps(packageJson.devDependencies);
139+
if (packagesFound === 0) {
140+
return {
141+
demoName,
142+
status: ProcessStatus.WARNING,
143+
errors: [`No workspace packages found`]
144+
};
149145
}
150146

151-
if (!programOpts['--dry-run']) {
147+
if (!options.dryRun) {
152148
try {
153-
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
149+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
154150
} catch (e) {
155-
result = {
151+
return {
156152
demoName,
157-
resultType: ResultType.FAILED,
158-
message: `Error writing package.json: ${e.message}`
153+
status: ProcessStatus.ERROR,
154+
errors: [`Failed to write package.json: ${e}`]
159155
};
160156
}
161157
}
162158

163-
console.log('Done\n');
164-
return result;
159+
return {
160+
demoName,
161+
status: ProcessStatus.SUCCESS
162+
};
165163
};
166164

167-
const main = () => {
168-
let demos: string[] = [];
169-
170-
if (programOpts['--pattern']) {
171-
const pattern = programArgs.join(' ');
172-
console.log(`Finding demos using pattern '${pattern}'`);
173-
174-
const process = spawnSync('find', [DEMOS_DIR, '-maxdepth', '1', '-name', pattern], {
175-
encoding: 'utf8'
176-
});
177-
demos = process.stdout.split('\n').filter((d) => d.trim().length > 0);
178-
179-
console.log('Done\n');
180-
} else {
181-
const allDemos = fs.readdirSync(path.resolve('./demos'));
182-
const givenDemos = programArgs;
183-
184-
if (givenDemos.length > 0) {
185-
console.log('Bumping given demos');
186-
demos = givenDemos;
187-
} else {
188-
console.log('Bumping all demos');
189-
demos = allDemos;
190-
}
191-
192-
demos = demos.map((d) => path.join(DEMOS_DIR, d));
193-
}
194-
195-
const results = demos.map((demo) => processDemo(demo));
196-
197-
const warnings = results.filter((r) => r.resultType == ResultType.WARNING);
198-
const errors = results.filter((r) => r.resultType == ResultType.FAILED);
165+
const main = async () => {
166+
const program = new Command();
167+
program.option('--dry-run', 'resolve version changes without applying', false);
168+
program.parse();
169+
const options = program.opts();
199170

200-
if (warnings.length > 0) {
201-
console.log('Warnings:');
202-
}
171+
const allDemos = await resolveDemos();
172+
const userDemos = await chooseDemos(allDemos);
203173

204-
if (errors.length > 0) {
205-
console.log('Failures:');
174+
const results = await processDemos(userDemos, options);
175+
const failed = displayResults(results);
176+
if (failed) {
177+
console.error('Not all demos succeeded.');
178+
process.exit(1);
206179
}
180+
console.log('All demos succeeded.');
207181
};
208182

209183
main();

0 commit comments

Comments
 (0)