1
-const cp = require('child_process');
1
const ora = require('ora');
2
const path = require('path');
3
const yargs = require('yargs');
5
-const util = require('util');
4
const {hashElement} = require('folder-hash');
5
const promptForOTP = require('./prompt-for-otp');
8
-
9
-const PUBLISHABLE_PACKAGES = [
10
- 'babel-plugin-react-compiler',
11
- 'eslint-plugin-react-compiler',
12
- 'react-compiler-healthcheck',
13
-];
14
-
15
-function _spawn(command, args, options, cb) {
16
- const child = cp.spawn(command, args, options);
17
- child.on('close', exitCode => {
18
- cb(null, exitCode);
19
- });
20
- return child;
21
-}
22
-const spawnHelper = util.promisify(_spawn);
23
-
24
-function execHelper(command, options, streamStdout = false) {
25
- return new Promise((resolve, reject) => {
26
- const proc = cp.exec(command, options, (error, stdout) =>
27
- error ? reject(error) : resolve(stdout.trim())
28
- );
29
- if (streamStdout) {
30
- proc.stdout.pipe(process.stdout);
31
- }
32
- });
33
-}
34
-
35
-async function getDateStringForCommit(commit) {
36
- let dateString = await execHelper(
37
- `git show -s --no-show-signature --format=%cd --date=format:%Y%m%d ${commit}`
38
- );
39
-
40
- // On CI environment, this string is wrapped with quotes '...'s
41
- if (dateString.startsWith("'")) {
42
- dateString = dateString.slice(1, 9);
43
- }
44
-
45
- return dateString;
46
-}
6
+const {PUBLISHABLE_PACKAGES} = require('./shared/packages');
7
+const {
8
+ execHelper,
9
+ getDateStringForCommit,
10
+ spawnHelper,
11
+} = require('./shared/utils');
12
+const {buildPackages} = require('./shared/build-packages');
13
+const {readJson, writeJson} = require('fs-extra');
14
15
/**
16
* Script for publishing PUBLISHABLE_PACKAGES to npm. By default, this runs in tarball mode, meaning
50
type: 'boolean',
51
default: false,
52
})
53
+ .option('ci', {
54
+ description: 'Publish packages via CI',
55
+ type: 'boolean',
56
+ default: false,
57
+ })
58
+ .option('tags', {
59
+ description: 'Tags to publish to npm',
60
+ type: 'choices',
61
+ choices: ['experimental'],
62
+ default: ['experimental'],
63
+ })
64
.help('help')
65
.parseSync();
66
89
- const {packages, forReal, debug} = argv;
90
-
91
- if (debug === false) {
67
+ if (argv.debug === false) {
68
const currBranchName = await execHelper('git rev-parse --abbrev-ref HEAD');
69
const isPristine = (await execHelper('git status --porcelain')) === '';
70
if (currBranchName !== 'main' || isPristine === false) {
74
}
75
}
76
101
- let pkgNames = packages;
102
- if (Array.isArray(packages) === false) {
103
- pkgNames = [packages];
77
+ let pkgNames = argv.packages;
78
+ if (Array.isArray(argv.packages) === false) {
79
+ pkgNames = [argv.packages];
80
}
81
const spinner = ora(
82
`Preparing to publish ${
107
- forReal === true ? '(for real)' : '(dry run)'
108
- } [debug=${debug}]`
83
+ argv.forReal === true ? '(for real)' : '(dry run)'
84
+ } [debug=${argv.debug}]`
85
).info();
86
111
- spinner.info('Building packages');
112
- for (const pkgName of pkgNames) {
113
- const command = `yarn workspace ${pkgName} run build`;
114
- spinner.start(`Running: ${command}\n`);
115
- try {
116
- await execHelper(command);
117
- } catch (e) {
118
- spinner.fail(e.toString());
119
- throw e;
120
- }
121
- spinner.succeed(`Successfully built ${pkgName}`);
122
- }
123
- spinner.stop();
87
+ await buildPackages(pkgNames);
88
125
- if (forReal === false) {
89
+ if (argv.forReal === false) {
90
spinner.info('Dry run: Report tarball contents');
91
for (const pkgName of pkgNames) {
92
console.log(`\n========== ${pkgName} ==========\n`);
107
);
108
}
109
146
- if (forReal === true) {
147
- const otp = await promptForOTP();
110
+ if (argv.forReal === true) {
111
const commit = await execHelper(
112
'git show -s --no-show-signature --format=%h',
113
{
115
}
116
);
117
const dateString = await getDateStringForCommit(commit);
118
+ const otp = argv.ci === false ? await promptForOTP() : null;
119
120
for (const pkgName of pkgNames) {
121
const pkgDir = path.resolve(__dirname, `../../packages/${pkgName}`);
122
+ const pkgJsonPath = path.resolve(
123
+ __dirname,
124
+ `../../packages/${pkgName}/package.json`
125
+ );
126
const {hash} = await hashElement(pkgDir, {
127
encoding: 'hex',
128
folders: {exclude: ['node_modules']},
131
const truncatedHash = hash.slice(0, 7);
132
const newVersion = `0.0.0-experimental-${truncatedHash}-${dateString}`;
133
166
- spinner.start(`Bumping version: ${pkgName}`);
167
- try {
168
- await execHelper(
169
- `yarn version --new-version ${newVersion} --no-git-tag-version`,
170
- {
171
- cwd: pkgDir,
172
- }
173
- );
174
- await execHelper(
175
- `git add package.json && git commit -m "Bump version to ${newVersion}"`,
176
- {
177
- cwd: pkgDir,
178
- }
179
- );
180
- } catch (e) {
181
- spinner.fail(e.toString());
182
- throw e;
183
- }
184
- spinner.succeed(
185
- `Bumped ${pkgName} to ${newVersion} and added a git commit`
134
+ spinner.start(`Writing package.json for ${pkgName}@${newVersion}`);
135
+ await writeJson(
136
+ pkgJsonPath,
137
+ {
138
+ ...(await readJson(pkgJsonPath)),
139
+ version: newVersion,
140
+ },
141
+ {spaces: 2}
142
);
187
- }
143
+ spinner.succeed(`Wrote package.json for ${pkgName}@${newVersion}`);
144
189
- for (const pkgName of pkgNames) {
190
- const pkgDir = path.resolve(__dirname, `../../packages/${pkgName}`);
145
console.log(`\n========== ${pkgName} ==========\n`);
192
- spinner.start(`Publishing ${pkgName} to npm\n`);
146
+ spinner.start(`Publishing ${pkgName}@${newVersion} to npm\n`);
147
194
- const opts = debug === true ? ['publish', '--dry-run'] : ['publish'];
148
+ let opts = [];
149
+ if (argv.debug === true) {
150
+ opts.push('--dry-run');
151
+ }
152
+ if (otp != null) {
153
+ opts.push(`--otp=${otp}`);
154
+ }
155
try {
156
await spawnHelper(
157
'npm',
198
- [...opts, '--registry=https://registry.npmjs.org', `--otp=${otp}`],
158
+ [
159
+ 'publish',
160
+ ...opts,
161
+ '--registry=https://registry.npmjs.org',
162
+ '--tag=experimental',
163
+ ],
164
{
165
cwd: pkgDir,
166
stdio: 'inherit',
172
throw e;
173
}
174
spinner.succeed(`Successfully published ${pkgName} to npm`);
175
+
176
+ spinner.start('Pushing tags to npm');
177
+ for (const tag of argv.tags) {
178
+ try {
179
+ let opts;
180
+ if (otp != null) {
181
+ opts = [
182
+ 'dist-tag',
183
+ 'add',
184
+ `${pkgName}@${newVersion}`,
185
+ tag,
186
+ `--otp=${otp}`,
187
+ ];
188
+ } else {
189
+ opts = ['dist-tag', 'add', `${pkgName}@${newVersion}`, tag];
190
+ }
191
+ if (argv.debug === true) {
192
+ spinner.info(`dry-run: npm ${opts.join(' ')}`);
193
+ } else {
194
+ await spawnHelper('npm', opts);
195
+ }
196
+ } catch (e) {
197
+ spinner.fail(e.toString());
198
+ throw e;
199
+ }
200
+ spinner.succeed(
201
+ `Successfully pushed dist-tag ${tag} for ${pkgName} to npm`
202
+ );
203
+ }
204
}
205
212
- console.log('\n\n✅ All done, please push version bump commits to GitHub');
206
+ console.log('\n\n✅ All done');
207
}
208
}
209