-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathindex.js
executable file
·327 lines (298 loc) · 10 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#!/usr/bin/env node
/* eslint-disable max-len, global-require, import/no-dynamic-require, no-console */
import path from 'path';
import { addDefaults, merge } from 'timm';
import program from 'commander';
import initConsole from './utils/initConsole';
import { isObject } from './utils/helpers';
import status from './status';
import bootstrap from './bootstrap';
import clean from './clean';
import addRemoveUpgrade from './addRemoveUpgrade';
import removeAll from './removeAll';
import bump from './bump';
import outdated from './outdated';
import prepublish from './prepublish';
import publish from './publish';
import resetAllVersions from './resetAllVersions';
import all from './all';
import runScript from './runScript';
process.env.YARN_SILENT = 0;
const pkg = require('../package.json');
const monorepoPkg = require(path.resolve('package.json'));
const OAO_CONFIG = monorepoPkg.oao || {};
const DEFAULT_SRC_DIR = OAO_CONFIG.src || 'packages/*';
const DEFAULT_COPY_ATTRS =
'description,keywords,author,license,homepage,bugs,repository';
const DEFAULT_CHANGELOG = 'CHANGELOG.md';
program.version(pkg.version);
// =========================================
// Helpers
// =========================================
const processOptions = options0 => {
let options = options0;
if (options.single) {
options = merge(options, { src: [] });
} else {
// If workspaces are enabled in the monorepo, some configuration is
// overriden by the monorepo package.json
if (monorepoPkg.workspaces) {
let src = monorepoPkg.workspaces;
if (isObject(src)) src = src.packages;
if (!src) {
throw new Error('Could not find correct config for Yarn workspaces');
}
options = merge(options, { src, workspaces: true });
}
// Add extra configuration in the `oao` field of the monorepo package.json
options = addDefaults(options, { ignoreSrc: OAO_CONFIG.ignoreSrc });
}
return options;
};
// Create a command with common options
const createCommand = (syntax, description) =>
program
.command(syntax)
.description(description)
.option(
'-s --src <glob>',
`glob pattern for sub-package paths [${DEFAULT_SRC_DIR}]`,
DEFAULT_SRC_DIR
)
.option(
'-i --ignore-src <glob>',
'glob pattern for sub-package paths that should be ignored'
)
.option(
'-l --link <regex>',
'regex pattern for dependencies that should be linked, not installed'
)
.option('--single', 'no subpackages, just the root one')
.option('--relative-time', 'shorten log dates');
// =========================================
// Commands
// =========================================
createCommand('status', 'Show an overview of the monorepo status').action(
cmd => {
const options = processOptions(cmd.opts());
return status(options);
}
);
createCommand(
'bootstrap',
'Install external dependencies and create internal links'
)
.option(
'--prod --production',
'skip external and internal development-only dependencies (also via NODE_ENV=production)'
)
.option('--no-lockfile', "don't read or generate a lockfile")
.option('--pure-lockfile', "don't generate a lockfile")
.option(
'--frozen-lockfile',
"don't generate a lockfile and fail if an update is needed"
)
.option(
'--no-parallel',
"don't run yarn install in parallel (use it to debug errors, since parallel logs may be hard to read)"
)
.action(cmd => {
const options = processOptions(cmd.opts());
initConsole(options);
return bootstrap(options);
});
createCommand(
'clean',
'Delete all node_modules directories from sub-packages and the root package'
).action(cmd => {
const options = processOptions(cmd.opts());
initConsole(options);
return clean(options);
});
createCommand(
'add <sub-package> <packages...>',
'Add dependencies to a sub-package'
)
.option('-D --dev', 'add to `devDependencies` instead of `dependencies`')
.option('-P --peer', 'add to `peerDependencies` instead of `dependencies`')
.option(
'-O --optional',
'add to `optionalDependencies` instead of `dependencies`'
)
.option('-E --exact', 'install the exact version')
.option(
'-T --tilde',
'install the most recent release with the same minor version'
)
.action((subpackage, deps, cmd) => {
const options = processOptions(cmd.opts());
initConsole(options);
return addRemoveUpgrade(subpackage, 'add', deps, options);
});
createCommand(
'remove <sub-package> <packages...>',
'Remove dependencies from a sub-package'
).action((subpackage, deps, cmd) => {
const options = processOptions(cmd.opts());
initConsole(options);
return addRemoveUpgrade(subpackage, 'remove', deps, options);
});
createCommand(
'remove-all <packages...>',
'Remove one or several dependencies throughout the monorepo'
).action(async (deps, cmd) => {
const options = processOptions(cmd.opts());
initConsole(options);
await removeAll(deps, options);
return bootstrap(options);
});
createCommand(
'upgrade <sub-package> [packages...]',
'Upgrade some/all dependencies of a package'
)
.option('--ignore-engines', 'disregard engines check during upgrade')
.action((subpackage, deps, cmd) => {
const options = processOptions(cmd.opts());
initConsole(options);
return addRemoveUpgrade(subpackage, 'upgrade', deps, options);
});
createCommand(
'bump <packages...>',
'Upgrade one or several dependencies throughout the monorepo (e.g. react@next, timm)'
).action(async (deps, cmd) => {
const options = processOptions(cmd.opts());
initConsole(options);
await bump(deps, options);
return bootstrap(options);
});
createCommand('outdated', 'Check for outdated dependencies').action(cmd => {
const options = processOptions(cmd.opts());
initConsole(options);
return outdated(options);
});
createCommand(
'prepublish',
'Prepare for a release: validate versions, copy READMEs and package.json attrs'
)
.option(
'--copy-attrs <attrs>',
`copy these package.json attrs to sub-packages [${DEFAULT_COPY_ATTRS}]`,
DEFAULT_COPY_ATTRS
)
.action(cmd => {
const options = processOptions(cmd.opts());
initConsole(options);
return prepublish(options);
});
createCommand('publish', 'Publish all (non-private) sub-packages')
.option(
'--no-master',
'allow publishing from a non-master or non-main branch'
)
.option('--no-check-uncommitted', 'skip uncommitted check')
.option('--no-check-unpulled', 'skip unpulled check')
.option('--no-checks', 'skip all pre-publish checks')
.option(
'--no-bump',
'do not increment version numbers (also disables git commit)'
)
.option(
'--bump-dependent-reqs <no|exact|range>',
'bump dependent requirements (inside the monorepo) following this approach: no bumping, exact version, version range (default: range)'
)
.option('--no-confirm', 'do not ask for confirmation before publishing')
.option('--no-git-commit', 'skip the commit-tag-push step before publishing')
.option('--no-npm-publish', 'skip the npm publish step')
.option(
'--new-version <version>',
'use this version for publishing, instead of asking'
)
.option(
'--increment-version-by <major|minor|patch|rc|beta|alpha>',
'increment version by this, instead of asking'
)
.option(
'--publish-tag <tag>',
'publish with a custom tag (instead of `latest`)'
)
.option(
'--changelog-path <path>',
`changelog path [${DEFAULT_CHANGELOG}]`,
DEFAULT_CHANGELOG
)
.option('--no-changelog', 'skip changelog updates')
.option('--otp <code>', 'use 2-factor authentication to publish your package')
.option(
'--access <public|restricted>',
'publish "public" or "restricted" packages'
)
.action(cmd => {
const options = processOptions(cmd.opts());
initConsole(options);
return publish(options);
});
createCommand(
'reset-all-versions <version>',
'Reset all versions (incl. monorepo package) to the specified one'
)
.option('--no-confirm', 'do not ask for confirmation')
.action((version, cmd) => {
const options = processOptions(cmd.opts());
initConsole(options);
return resetAllVersions(version, options);
});
createCommand('all <command>', 'Run a given command on all sub-packages')
.option('--tree', 'follow dependency tree (starting from the tree leaves)')
.option('--parallel', 'run command in parallel on all sub-packages')
.option(
'--no-parallel-logs',
'use chronological logging, even in parallel mode'
)
.option('--parallel-limit <#processes>', 'max number of processes to launch')
.option(
'--ignore-errors',
'do not stop even if there are errors in some packages'
)
.action((command, cmd) => {
// Extract arguments following the first separator (`--`) and
// add them to the command to be executed
const { rawArgs } = cmd.parent;
const idxSeparator = rawArgs.indexOf('--');
const finalCommand =
idxSeparator >= 0
? [command].concat(rawArgs.slice(idxSeparator + 1)).join(' ')
: command;
// Run the `all` command
const options = processOptions(cmd.opts());
initConsole(options);
return all(finalCommand, options);
});
createCommand('run-script <command>', 'Run a given script on all sub-packages')
.option('--tree', 'follow dependency tree (starting from the tree leaves)')
.option('--parallel', 'run script in parallel on all sub-packages')
.option(
'--no-parallel-logs',
'use chronological logging, even in parallel mode'
)
.option('--parallel-limit <#processes>', 'max number of processes to launch')
.option(
'--ignore-errors',
'do not stop even if there are errors in some packages'
)
.action((command, cmd) => {
const options = processOptions(cmd.opts());
initConsole(options);
return runScript(command, options);
});
process.on('unhandledRejection', err => {
console.error(err); // eslint-disable-line
process.exit(1);
});
process.on('SIGINT', () => {
process.exit(0);
});
// Syntax error -> show CLI help
program.command('*', '', { noHelp: true }).action(() => program.outputHelp());
if (process.argv.length <= 2) program.outputHelp();
// Let's go!
program.parse(process.argv);