UNPKG

4.58 kBJavaScriptView Raw
1import { constants, dependsOn, filter, inquirer, loadSettings, log, R, savePackage, semver, updatePackageRef, formatModuleName, } from '../common';
2import * as listCommand from './ls.cmd';
3export const name = 'bump';
4export const alias = 'b';
5export const description = `Bumps a module version along with it's entire dependency graph.`;
6export const args = {
7 '-i': 'Include ignored modules.',
8 '-d': 'Dry run where no files are saved.',
9 '-l': 'Local versions only. Does not retrieve NPM details.',
10};
11export async function cmd(args) {
12 const options = (args && args.options) || {};
13 await bump({
14 includeIgnored: options.i || false,
15 local: options.l || false,
16 dryRun: options.d || false,
17 });
18}
19export async function bump(options = {}) {
20 const { includeIgnored = false, local = false, dryRun = false } = options;
21 const save = !dryRun;
22 const npm = !local;
23 const settings = await loadSettings({ npm, spinner: npm });
24 if (!settings) {
25 log.warn.yellow(constants.CONFIG_NOT_FOUND_ERROR);
26 return;
27 }
28 const modules = settings.modules.filter((pkg) => filter.includeIgnored(pkg, includeIgnored));
29 const module = await promptForModule(modules);
30 if (!module) {
31 return;
32 }
33 log.info();
34 const dependants = dependsOn(module, modules);
35 listCommand.printTable([module], { includeIgnored: true, dependants });
36 if (dryRun) {
37 log.info.gray(`Dry run...no files will be saved.\n`);
38 }
39 log.info();
40 const release = (await promptForReleaseType(module.version));
41 if (!release) {
42 return;
43 }
44 log.info();
45 const bumped = await bumpModule({
46 release,
47 pkg: module,
48 allModules: modules,
49 save,
50 });
51 log.info();
52 log.info(bumped.log());
53 log.info();
54 if (dryRun) {
55 log.info.gray(`\nNo files were saved.`);
56 }
57 else {
58 log.info();
59 }
60}
61async function bumpModule(options) {
62 const { release, pkg, allModules, save, level = 0, ref } = options;
63 const dependants = dependsOn(pkg, allModules);
64 const version = semver.inc(pkg.latest, release);
65 const isRoot = ref === undefined;
66 if (!version) {
67 throw new Error(`Failed to '${release}' the semver ${pkg.latest}.`);
68 }
69 const head = ['update', 'module', 'version', 'dependants'].map((title) => log.gray(title));
70 const table = options.table || log.table({ head, border: false });
71 const logPkgUpdate = (args) => {
72 const { release, pkg, version } = args;
73 let msg = '';
74 msg += ` ${log.yellow(release.toUpperCase())} `;
75 msg += `${formatModuleName(pkg.name)} from ${pkg.latest}${log.yellow(version)} `;
76 return log.gray(msg);
77 };
78 if (ref) {
79 table.add([
80 log.yellow(` ${release.toUpperCase()} `),
81 formatModuleName(`${pkg.name} `),
82 log.gray(`${pkg.latest}${log.magenta(version)} `),
83 log.gray(`${formatModuleName(ref.name)} ${ref.fromVersion}${log.magenta(ref.toVersion)}`),
84 ]);
85 }
86 const json = R.clone(pkg.json);
87 json.version = version;
88 if (save) {
89 await savePackage(pkg.dir, json);
90 }
91 if (isRoot && dependants.length > 0) {
92 log.info.gray('\nchanges:');
93 }
94 for (const dependentPkg of dependants) {
95 await updatePackageRef(dependentPkg, pkg.name, version, { save });
96 await bumpModule({
97 release: 'patch',
98 pkg: dependentPkg,
99 allModules,
100 level: level + 1,
101 ref: { name: pkg.name, fromVersion: pkg.latest, toVersion: version },
102 save,
103 table,
104 });
105 }
106 return {
107 table,
108 log() {
109 return `
110${log.info(logPkgUpdate({ release, pkg, version }))}
111
112${table.toString()}
113
114${log.gray('complete')}
115${log.info(logPkgUpdate({ release, pkg, version }))}
116`.substring(1);
117 },
118 };
119}
120async function promptForModule(modules) {
121 const choices = modules.map((pkg) => ({ name: pkg.name, value: pkg.name }));
122 const res = (await inquirer.prompt({
123 type: 'list',
124 name: 'name',
125 message: 'Select a module',
126 choices,
127 pageSize: 30,
128 }));
129 const name = res.name;
130 return modules.find((pkg) => pkg.name === name);
131}
132async function promptForReleaseType(version) {
133 const choices = ['patch', 'minor', 'major'];
134 const res = (await inquirer.prompt({
135 type: 'list',
136 name: 'name',
137 message: 'Release',
138 choices,
139 }));
140 return res.name;
141}