UNPKG

48.7 kBJavaScriptView Raw
1'use strict';
2
3var meow = require('meow');
4var errors = require('@changesets/errors');
5var logger = require('@changesets/logger');
6var util = require('util');
7var fs = require('fs-extra');
8var path = require('path');
9var getPackages = require('@manypkg/get-packages');
10var getDependentsGraph = require('@changesets/get-dependents-graph');
11var config = require('@changesets/config');
12var chalk = require('chalk');
13var child_process = require('child_process');
14var termSize = require('term-size');
15var enquirer = require('enquirer');
16var externalEditor = require('external-editor');
17var git = require('@changesets/git');
18var writeChangeset = require('@changesets/write');
19var semver = require('semver');
20var boxen = require('boxen');
21var outdent = require('outdent');
22var applyReleasePlan = require('@changesets/apply-release-plan');
23var readChangesets = require('@changesets/read');
24var assembleReleasePlan = require('@changesets/assemble-release-plan');
25var pre$1 = require('@changesets/pre');
26var pLimit = require('p-limit');
27var preferredPM = require('preferred-pm');
28var spawn = require('spawndamnit');
29var isCI$1 = require('is-ci');
30var table = require('tty-table');
31var getReleasePlan = require('@changesets/get-release-plan');
32
33function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
34
35var meow__default = /*#__PURE__*/_interopDefault(meow);
36var fs__default = /*#__PURE__*/_interopDefault(fs);
37var path__default = /*#__PURE__*/_interopDefault(path);
38var chalk__default = /*#__PURE__*/_interopDefault(chalk);
39var termSize__default = /*#__PURE__*/_interopDefault(termSize);
40var writeChangeset__default = /*#__PURE__*/_interopDefault(writeChangeset);
41var semver__default = /*#__PURE__*/_interopDefault(semver);
42var boxen__default = /*#__PURE__*/_interopDefault(boxen);
43var outdent__default = /*#__PURE__*/_interopDefault(outdent);
44var applyReleasePlan__default = /*#__PURE__*/_interopDefault(applyReleasePlan);
45var readChangesets__default = /*#__PURE__*/_interopDefault(readChangesets);
46var assembleReleasePlan__default = /*#__PURE__*/_interopDefault(assembleReleasePlan);
47var pLimit__default = /*#__PURE__*/_interopDefault(pLimit);
48var preferredPM__default = /*#__PURE__*/_interopDefault(preferredPM);
49var spawn__default = /*#__PURE__*/_interopDefault(spawn);
50var isCI__default = /*#__PURE__*/_interopDefault(isCI$1);
51var table__default = /*#__PURE__*/_interopDefault(table);
52var getReleasePlan__default = /*#__PURE__*/_interopDefault(getReleasePlan);
53
54const pkgPath = path__default['default'].dirname(require.resolve("@changesets/cli/package.json"));
55async function init(cwd) {
56 const changesetBase = path__default['default'].resolve(cwd, ".changeset");
57
58 if (fs__default['default'].existsSync(changesetBase)) {
59 if (!fs__default['default'].existsSync(path__default['default'].join(changesetBase, "config.json"))) {
60 if (fs__default['default'].existsSync(path__default['default'].join(changesetBase, "config.js"))) {
61 logger.error("It looks like you're using the version 1 `.changeset/config.js` file");
62 logger.error("The format of the config object has significantly changed in v2 as well");
63 logger.error(" - we thoroughly recommend looking at the changelog for this package for what has changed");
64 logger.error("Changesets will write the defaults for the new config, remember to transfer your options into the new config at `.changeset/config.json`");
65 } else {
66 logger.error("It looks like you don't have a config file");
67 logger.info("The default config file will be written at `.changeset/config.json`");
68 }
69
70 await fs__default['default'].writeFile(path__default['default'].resolve(changesetBase, "config.json"), JSON.stringify(config.defaultWrittenConfig, null, 2));
71 } else {
72 logger.warn("It looks like you already have changesets initialized. You should be able to run changeset commands no problems.");
73 }
74 } else {
75 await fs__default['default'].copy(path__default['default'].resolve(pkgPath, "./default-files"), changesetBase);
76 await fs__default['default'].writeFile(path__default['default'].resolve(changesetBase, "config.json"), JSON.stringify(config.defaultWrittenConfig, null, 2));
77 logger.log(chalk__default['default']`Thanks for choosing {green changesets} to help manage your versioning and publishing\n`);
78 logger.log("You should be set up to start using changesets now!\n");
79 logger.info("We have added a `.changeset` folder, and a couple of files to help you out:");
80 logger.info(chalk__default['default']`- {blue .changeset/README.md} contains information about using changesets`);
81 logger.info(chalk__default['default']`- {blue .changeset/config.json} is our default config`);
82 }
83}
84
85function _defineProperty(obj, key, value) {
86 if (key in obj) {
87 Object.defineProperty(obj, key, {
88 value: value,
89 enumerable: true,
90 configurable: true,
91 writable: true
92 });
93 } else {
94 obj[key] = value;
95 }
96
97 return obj;
98}
99
100function ownKeys(object, enumerableOnly) {
101 var keys = Object.keys(object);
102
103 if (Object.getOwnPropertySymbols) {
104 var symbols = Object.getOwnPropertySymbols(object);
105 if (enumerableOnly) symbols = symbols.filter(function (sym) {
106 return Object.getOwnPropertyDescriptor(object, sym).enumerable;
107 });
108 keys.push.apply(keys, symbols);
109 }
110
111 return keys;
112}
113
114function _objectSpread2(target) {
115 for (var i = 1; i < arguments.length; i++) {
116 var source = arguments[i] != null ? arguments[i] : {};
117
118 if (i % 2) {
119 ownKeys(Object(source), true).forEach(function (key) {
120 _defineProperty(target, key, source[key]);
121 });
122 } else if (Object.getOwnPropertyDescriptors) {
123 Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
124 } else {
125 ownKeys(Object(source)).forEach(function (key) {
126 Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
127 });
128 }
129 }
130
131 return target;
132}
133
134// @ts-ignore it's not worth writing a TS declaration file in this repo for a tiny module we use once like this
135// so we can make type assertions using them because `enquirer` types do no support `prefix` right now
136
137/* Notes on using inquirer:
138 * Each question needs a key, as inquirer is assembling an object behind-the-scenes.
139 * At each call, the entire responses object is returned, so we need a unique
140 * identifier for the name every time. This is why we are using serial IDs
141 */
142const serialId = function () {
143 let id = 0;
144 return () => id++;
145}();
146
147const limit = Math.max(termSize__default['default']().rows - 5, 10);
148
149let cancelFlow = () => {
150 logger.success("Cancelled... 👋 ");
151 process.exit();
152};
153
154async function askCheckboxPlus(message, choices, format) {
155 const name = `CheckboxPlus-${serialId()}`;
156 return enquirer.prompt({
157 type: "autocomplete",
158 name,
159 message,
160 prefix: logger.prefix,
161 multiple: true,
162 choices,
163 format,
164 limit,
165 onCancel: cancelFlow
166 }).then(responses => responses[name]).catch(err => {
167 logger.error(err);
168 });
169}
170
171async function askQuestion(message) {
172 const name = `Question-${serialId()}`;
173 return enquirer.prompt([{
174 type: "input",
175 message,
176 name,
177 prefix: logger.prefix,
178 onCancel: cancelFlow
179 }]).then(responses => responses[name]).catch(err => {
180 logger.error(err);
181 });
182}
183
184function askQuestionWithEditor(message) {
185 const response = externalEditor.edit(message, {
186 postfix: ".md"
187 });
188 return response.replace(/^#.*\n?/gm, "").replace(/\n+$/g, "").trim();
189}
190
191async function askConfirm(message) {
192 const name = `Confirm-${serialId()}`;
193 return enquirer.prompt([{
194 message,
195 name,
196 prefix: logger.prefix,
197 type: "confirm",
198 initial: true,
199 onCancel: cancelFlow
200 }]).then(responses => responses[name]).catch(err => {
201 logger.error(err);
202 });
203}
204
205async function askList(message, choices) {
206 const name = `List-${serialId()}`;
207 return enquirer.prompt([{
208 choices,
209 message,
210 name,
211 prefix: logger.prefix,
212 type: "select",
213 onCancel: cancelFlow
214 }]).then(responses => responses[name]).catch(err => {
215 logger.error(err);
216 });
217}
218
219const {
220 green,
221 yellow,
222 red,
223 bold,
224 blue,
225 cyan
226} = chalk__default['default'];
227
228async function confirmMajorRelease(pkgJSON) {
229 if (semver__default['default'].lt(pkgJSON.version, "1.0.0")) {
230 // prettier-ignore
231 logger.log(yellow(`WARNING: Releasing a major version for ${green(pkgJSON.name)} will be its ${red('first major release')}.`));
232 logger.log(yellow(`If you are unsure if this is correct, contact the package's maintainers ${red("before committing this changeset")}.`));
233 let shouldReleaseFirstMajor = await askConfirm(bold(`Are you sure you want still want to release the ${red("first major release")} of ${pkgJSON.name}?`));
234 return shouldReleaseFirstMajor;
235 }
236
237 return true;
238}
239
240async function getPackagesToRelease(changedPackages, allPackages) {
241 function askInitialReleaseQuestion(defaultChoiceList) {
242 return askCheckboxPlus( // TODO: Make this wording better
243 // TODO: take objects and be fancy with matching
244 `Which packages would you like to include?`, defaultChoiceList, x => {
245 // this removes changed packages and unchanged packages from the list
246 // of packages shown after selection
247 if (Array.isArray(x)) {
248 return x.filter(x => x !== "changed packages" && x !== "unchanged packages").map(x => cyan(x)).join(", ");
249 }
250
251 return x;
252 });
253 }
254
255 if (allPackages.length > 1) {
256 const unchangedPackagesNames = allPackages.map(({
257 packageJson
258 }) => packageJson.name).filter(name => !changedPackages.includes(name));
259 const defaultChoiceList = [{
260 name: "changed packages",
261 choices: changedPackages
262 }, {
263 name: "unchanged packages",
264 choices: unchangedPackagesNames
265 }].filter(({
266 choices
267 }) => choices.length !== 0);
268 let packagesToRelease = await askInitialReleaseQuestion(defaultChoiceList);
269
270 if (packagesToRelease.length === 0) {
271 do {
272 logger.error("You must select at least one package to release");
273 logger.error("(You most likely hit enter instead of space!)");
274 packagesToRelease = await askInitialReleaseQuestion(defaultChoiceList);
275 } while (packagesToRelease.length === 0);
276 }
277
278 return packagesToRelease.filter(pkgName => pkgName !== "changed packages" && pkgName !== "unchanged packages");
279 }
280
281 return [allPackages[0].packageJson.name];
282}
283
284function formatPkgNameAndVersion(pkgName, version) {
285 return `${bold(pkgName)}@${bold(version)}`;
286}
287
288async function createChangeset(changedPackages, allPackages) {
289 const releases = [];
290
291 if (allPackages.length > 1) {
292 const packagesToRelease = await getPackagesToRelease(changedPackages, allPackages);
293 let pkgJsonsByName = new Map(allPackages.map(({
294 packageJson
295 }) => [packageJson.name, packageJson]));
296 let pkgsLeftToGetBumpTypeFor = new Set(packagesToRelease);
297 let pkgsThatShouldBeMajorBumped = (await askCheckboxPlus(bold(`Which packages should have a ${red("major")} bump?`), [{
298 name: "all packages",
299 choices: packagesToRelease.map(pkgName => {
300 return {
301 name: pkgName,
302 message: formatPkgNameAndVersion(pkgName, pkgJsonsByName.get(pkgName).version)
303 };
304 })
305 }], x => {
306 // this removes changed packages and unchanged packages from the list
307 // of packages shown after selection
308 if (Array.isArray(x)) {
309 return x.filter(x => x !== "all packages").map(x => cyan(x)).join(", ");
310 }
311
312 return x;
313 })).filter(x => x !== "all packages");
314
315 for (const pkgName of pkgsThatShouldBeMajorBumped) {
316 // for packages that are under v1, we want to make sure major releases are intended,
317 // as some repo-wide sweeping changes have mistakenly release first majors
318 // of packages.
319 let pkgJson = pkgJsonsByName.get(pkgName);
320 let shouldReleaseFirstMajor = await confirmMajorRelease(pkgJson);
321
322 if (shouldReleaseFirstMajor) {
323 pkgsLeftToGetBumpTypeFor.delete(pkgName);
324 releases.push({
325 name: pkgName,
326 type: "major"
327 });
328 }
329 }
330
331 if (pkgsLeftToGetBumpTypeFor.size !== 0) {
332 let pkgsThatShouldBeMinorBumped = (await askCheckboxPlus(bold(`Which packages should have a ${green("minor")} bump?`), [{
333 name: "all packages",
334 choices: [...pkgsLeftToGetBumpTypeFor].map(pkgName => {
335 return {
336 name: pkgName,
337 message: formatPkgNameAndVersion(pkgName, pkgJsonsByName.get(pkgName).version)
338 };
339 })
340 }], x => {
341 // this removes changed packages and unchanged packages from the list
342 // of packages shown after selection
343 if (Array.isArray(x)) {
344 return x.filter(x => x !== "all packages").map(x => cyan(x)).join(", ");
345 }
346
347 return x;
348 })).filter(x => x !== "all packages");
349
350 for (const pkgName of pkgsThatShouldBeMinorBumped) {
351 pkgsLeftToGetBumpTypeFor.delete(pkgName);
352 releases.push({
353 name: pkgName,
354 type: "minor"
355 });
356 }
357 }
358
359 if (pkgsLeftToGetBumpTypeFor.size !== 0) {
360 logger.log(`The following packages will be ${blue("patch")} bumped:`);
361 pkgsLeftToGetBumpTypeFor.forEach(pkgName => {
362 logger.log(formatPkgNameAndVersion(pkgName, pkgJsonsByName.get(pkgName).version));
363 });
364
365 for (const pkgName of pkgsLeftToGetBumpTypeFor) {
366 releases.push({
367 name: pkgName,
368 type: "patch"
369 });
370 }
371 }
372 } else {
373 let pkg = allPackages[0];
374 let type = await askList(`What kind of change is this for ${green(pkg.packageJson.name)}? (current version is ${pkg.packageJson.version})`, ["patch", "minor", "major"]);
375
376 if (type === "major") {
377 let shouldReleaseAsMajor = await confirmMajorRelease(pkg.packageJson);
378
379 if (!shouldReleaseAsMajor) {
380 throw new errors.ExitError(1);
381 }
382 }
383
384 releases.push({
385 name: pkg.packageJson.name,
386 type
387 });
388 }
389
390 logger.log("Please enter a summary for this change (this will be in the changelogs). Submit empty line to open external editor");
391 let summary = await askQuestion("Summary");
392
393 if (summary.length === 0) {
394 try {
395 summary = askQuestionWithEditor("\n\n# Please enter a summary for your changes.\n# An empty message aborts the editor.");
396
397 if (summary.length > 0) {
398 return {
399 confirmed: true,
400 summary,
401 releases
402 };
403 }
404 } catch (err) {
405 logger.log("An error happened using external editor. Please type your summary here:");
406 }
407
408 summary = await askQuestion("");
409
410 while (summary.length === 0) {
411 summary = await askQuestion("\n\n# A summary is required for the changelog! 😪");
412 }
413 }
414
415 return {
416 confirmed: false,
417 summary,
418 releases
419 };
420}
421
422function printConfirmationMessage(changeset, repoHasMultiplePackages) {
423 function getReleasesOfType(type) {
424 return changeset.releases.filter(release => release.type === type).map(release => release.name);
425 }
426
427 logger.log("=== Releasing the following packages ===");
428 const majorReleases = getReleasesOfType("major");
429 const minorReleases = getReleasesOfType("minor");
430 const patchReleases = getReleasesOfType("patch");
431 if (majorReleases.length > 0) logger.log(`${chalk__default['default'].green("[Major]")}\n ${majorReleases.join(", ")}`);
432 if (minorReleases.length > 0) logger.log(`${chalk__default['default'].green("[Minor]")}\n ${minorReleases.join(", ")}`);
433 if (patchReleases.length > 0) logger.log(`${chalk__default['default'].green("[Patch]")}\n ${patchReleases.join(", ")}`);
434
435 if (repoHasMultiplePackages) {
436 const message = outdent__default['default']`
437 ${chalk__default['default'].red("========= NOTE ========")}
438 All dependents of these packages that will be incompatible with the new version will be ${chalk__default['default'].red("patch bumped")} when this changeset is applied.`;
439 const prettyMessage = boxen__default['default'](message, {
440 borderStyle: "double",
441 align: "center"
442 });
443 logger.log(prettyMessage);
444 }
445}
446
447async function add(cwd, {
448 empty,
449 open
450}, config) {
451 const packages = await getPackages.getPackages(cwd);
452 const changesetBase = path__default['default'].resolve(cwd, ".changeset");
453 let newChangeset;
454
455 if (empty) {
456 newChangeset = {
457 confirmed: true,
458 releases: [],
459 summary: ``
460 };
461 } else {
462 const changedPackages = await git.getChangedPackagesSinceRef({
463 cwd,
464 ref: config.baseBranch
465 });
466 const changePackagesName = changedPackages.filter(a => a).map(pkg => pkg.packageJson.name);
467 newChangeset = await createChangeset(changePackagesName, packages.packages);
468 printConfirmationMessage(newChangeset, packages.packages.length > 1);
469
470 if (!newChangeset.confirmed) {
471 newChangeset = _objectSpread2(_objectSpread2({}, newChangeset), {}, {
472 confirmed: await askConfirm("Is this your desired changeset?")
473 });
474 }
475 }
476
477 if (newChangeset.confirmed) {
478 const changesetID = await writeChangeset__default['default'](newChangeset, cwd);
479
480 if (config.commit) {
481 await git.add(path__default['default'].resolve(changesetBase, `${changesetID}.md`), cwd);
482 await git.commit(`docs(changeset): ${newChangeset.summary}`, cwd);
483 logger.log(chalk__default['default'].green(`${empty ? "Empty " : ""}Changeset added and committed`));
484 } else {
485 logger.log(chalk__default['default'].green(`${empty ? "Empty " : ""}Changeset added! - you can now commit it\n`));
486 }
487
488 let hasMajorChange = [...newChangeset.releases].find(c => c.type === "major");
489
490 if (hasMajorChange) {
491 logger.warn("This Changeset includes a major change and we STRONGLY recommend adding more information to the changeset:");
492 logger.warn("WHAT the breaking change is");
493 logger.warn("WHY the change was made");
494 logger.warn("HOW a consumer should update their code");
495 } else {
496 logger.log(chalk__default['default'].green("If you want to modify or expand on the changeset summary, you can find it here"));
497 }
498
499 const changesetPath = path__default['default'].resolve(changesetBase, `${changesetID}.md`);
500 logger.info(chalk__default['default'].blue(changesetPath));
501
502 if (open) {
503 // this is really a hack to reuse the logic embedded in `external-editor` related to determining the editor
504 const externalEditor$1 = new externalEditor.ExternalEditor();
505 externalEditor$1.cleanup();
506 child_process.spawn(externalEditor$1.editor.bin, externalEditor$1.editor.args.concat([changesetPath]), {
507 detached: true,
508 stdio: "inherit"
509 });
510 }
511 }
512}
513
514// folder, and tidy up the subfolders
515// THIS SHOULD BE REMOVED WHEN SUPPORT FOR CHANGESETS FROM V1 IS DROPPED
516
517const removeEmptyFolders = async folderPath => {
518 const dirContents = fs__default['default'].readdirSync(folderPath);
519 return Promise.all(dirContents.map(async contentPath => {
520 const singleChangesetPath = path__default['default'].resolve(folderPath, contentPath);
521
522 try {
523 if ((await fs__default['default'].readdir(singleChangesetPath)).length < 1) {
524 await fs__default['default'].rmdir(singleChangesetPath);
525 }
526 } catch (err) {
527 if (err.code !== "ENOTDIR") {
528 throw err;
529 }
530 }
531 }));
532};
533
534let importantSeparator = chalk__default['default'].red("===============================IMPORTANT!===============================");
535let importantEnd = chalk__default['default'].red("----------------------------------------------------------------------");
536async function version(cwd, options, config) {
537 const releaseConfig = _objectSpread2(_objectSpread2({}, config), {}, {
538 // Disable committing when in snapshot mode
539 commit: options.snapshot ? false : config.commit
540 });
541
542 const [changesets, preState] = await Promise.all([readChangesets__default['default'](cwd), pre$1.readPreState(cwd), removeEmptyFolders(path__default['default'].resolve(cwd, ".changeset"))]);
543
544 if ((preState === null || preState === void 0 ? void 0 : preState.mode) === "pre") {
545 logger.warn(importantSeparator);
546
547 if (options.snapshot !== undefined) {
548 logger.error("Snapshot release is not allowed in pre mode");
549 logger.log("To resolve this exit the pre mode by running `changeset pre exit`");
550 throw new errors.ExitError(1);
551 } else {
552 logger.warn("You are in prerelease mode");
553 logger.warn("If you meant to do a normal release you should revert these changes and run `changeset pre exit`");
554 logger.warn("You can then run `changeset version` again to do a normal release");
555 }
556
557 logger.warn(importantEnd);
558 }
559
560 if (changesets.length === 0 && (preState === undefined || preState.mode !== "exit")) {
561 logger.warn("No unreleased changesets found, exiting.");
562 return;
563 }
564
565 let packages = await getPackages.getPackages(cwd);
566 let releasePlan = assembleReleasePlan__default['default'](changesets, packages, releaseConfig, preState, options.snapshot);
567 await applyReleasePlan__default['default'](releasePlan, packages, releaseConfig, options.snapshot);
568
569 if (releaseConfig.commit) {
570 logger.log("All files have been updated and committed. You're ready to publish!");
571 } else {
572 logger.log("All files have been updated. Review them and commit at your leisure");
573 }
574}
575
576// @ts-ignore
577var isCI = !!(isCI__default['default'] || process.env.GITHUB_ACTIONS);
578
579const npmRequestLimit = pLimit__default['default'](40);
580const npmPublishLimit = pLimit__default['default'](10);
581
582function jsonParse(input) {
583 try {
584 return JSON.parse(input);
585 } catch (err) {
586 if (err instanceof SyntaxError) {
587 console.error("error parsing json:", input);
588 }
589
590 throw err;
591 }
592}
593
594function getCorrectRegistry(packageJson) {
595 var _packageJson$publishC, _packageJson$publishC2;
596
597 const registry = (_packageJson$publishC = packageJson === null || packageJson === void 0 ? void 0 : (_packageJson$publishC2 = packageJson.publishConfig) === null || _packageJson$publishC2 === void 0 ? void 0 : _packageJson$publishC2.registry) !== null && _packageJson$publishC !== void 0 ? _packageJson$publishC : process.env.npm_config_registry;
598 return !registry || registry === "https://registry.yarnpkg.com" ? "https://registry.npmjs.org" : registry;
599}
600
601async function getPublishTool(cwd) {
602 const pm = await preferredPM__default['default'](cwd);
603 if (!pm || pm.name !== "pnpm") return {
604 name: "npm"
605 };
606
607 try {
608 let result = await spawn__default['default']("pnpm", ["--version"], {
609 cwd
610 });
611 let version = result.stdout.toString().trim();
612 let parsed = semver__default['default'].parse(version);
613 return {
614 name: "pnpm",
615 shouldAddNoGitChecks: (parsed === null || parsed === void 0 ? void 0 : parsed.major) === undefined ? false : parsed.major >= 5
616 };
617 } catch (e) {
618 return {
619 name: "pnpm",
620 shouldAddNoGitChecks: false
621 };
622 }
623}
624
625async function getTokenIsRequired() {
626 // Due to a super annoying issue in yarn, we have to manually override this env variable
627 // See: https://github.com/yarnpkg/yarn/issues/2935#issuecomment-355292633
628 const envOverride = {
629 npm_config_registry: getCorrectRegistry()
630 };
631 let result = await spawn__default['default']("npm", ["profile", "get", "--json"], {
632 env: Object.assign({}, process.env, envOverride)
633 });
634 let json = jsonParse(result.stdout.toString());
635
636 if (json.error || !json.tfa || !json.tfa.mode) {
637 return false;
638 }
639
640 return json.tfa.mode === "auth-and-writes";
641}
642function getPackageInfo(packageJson) {
643 return npmRequestLimit(async () => {
644 logger.info(`npm info ${packageJson.name}`); // Due to a couple of issues with yarnpkg, we also want to override the npm registry when doing
645 // npm info.
646 // Issues: We sometimes get back cached responses, i.e old data about packages which causes
647 // `publish` to behave incorrectly. It can also cause issues when publishing private packages
648 // as they will always give a 404, which will tell `publish` to always try to publish.
649 // See: https://github.com/yarnpkg/yarn/issues/2935#issuecomment-355292633
650
651 let result = await spawn__default['default']("npm", ["info", packageJson.name, "--registry", getCorrectRegistry(packageJson), "--json"]); // Github package registry returns empty string when calling npm info
652 // for a non-existant package instead of a E404
653
654 if (result.stdout.toString() === "") {
655 return {
656 error: {
657 code: "E404"
658 }
659 };
660 }
661
662 return jsonParse(result.stdout.toString());
663 });
664}
665async function infoAllow404(packageJson) {
666 var _pkgInfo$error;
667
668 let pkgInfo = await getPackageInfo(packageJson);
669
670 if (((_pkgInfo$error = pkgInfo.error) === null || _pkgInfo$error === void 0 ? void 0 : _pkgInfo$error.code) === "E404") {
671 logger.warn(`Received 404 for npm info ${chalk__default['default'].cyan(`"${packageJson.name}"`)}`);
672 return {
673 published: false,
674 pkgInfo: {}
675 };
676 }
677
678 if (pkgInfo.error) {
679 logger.error(`Received an unknown error code: ${pkgInfo.error.code} for npm info ${chalk__default['default'].cyan(`"${packageJson.name}"`)}`);
680 logger.error(pkgInfo.error.summary);
681 if (pkgInfo.error.detail) logger.error(pkgInfo.error.detail);
682 throw new errors.ExitError(1);
683 }
684
685 return {
686 published: true,
687 pkgInfo
688 };
689}
690let otpAskLimit = pLimit__default['default'](1);
691
692let askForOtpCode = twoFactorState => otpAskLimit(async () => {
693 if (twoFactorState.token !== null) return twoFactorState.token;
694 logger.info("This operation requires a one-time password from your authenticator.");
695 let val = await askQuestion("Enter one-time password:");
696 twoFactorState.token = val;
697 return val;
698});
699
700let getOtpCode = async twoFactorState => {
701 if (twoFactorState.token !== null) {
702 return twoFactorState.token;
703 }
704
705 return askForOtpCode(twoFactorState);
706}; // we have this so that we can do try a publish again after a publish without
707// the call being wrapped in the npm request limit and causing the publishes to potentially never run
708
709async function internalPublish(pkgName, opts, twoFactorState) {
710 let publishTool = await getPublishTool(opts.cwd);
711 let publishFlags = opts.access ? ["--access", opts.access] : [];
712 publishFlags.push("--tag", opts.tag);
713
714 if ((await twoFactorState.isRequired) && !isCI) {
715 let otpCode = await getOtpCode(twoFactorState);
716 publishFlags.push("--otp", otpCode);
717 }
718
719 if (publishTool.name === "pnpm" && publishTool.shouldAddNoGitChecks) {
720 publishFlags.push("--no-git-checks");
721 } // Due to a super annoying issue in yarn, we have to manually override this env variable
722 // See: https://github.com/yarnpkg/yarn/issues/2935#issuecomment-355292633
723
724
725 const envOverride = {
726 npm_config_registry: getCorrectRegistry()
727 };
728 let {
729 stdout
730 } = await spawn__default['default'](publishTool.name, ["publish", opts.cwd, "--json", ...publishFlags], {
731 env: Object.assign({}, process.env, envOverride)
732 }); // New error handling. NPM's --json option is included alongside the `prepublish and
733 // `postpublish` contents in terminal. We want to handle this as best we can but it has
734 // some struggles
735 // Note that both pre and post publish hooks are printed before the json out, so this works.
736
737 let json = jsonParse(stdout.toString().replace(/[^{]*/, ""));
738
739 if (json.error) {
740 // The first case is no 2fa provided, the second is when the 2fa is wrong (timeout or wrong words)
741 if ((json.error.code === "EOTP" || json.error.code === "E401" && json.error.detail.includes("--otp=<code>")) && !isCI) {
742 if (twoFactorState.token !== null) {
743 // the current otp code must be invalid since it errored
744 twoFactorState.token = null;
745 } // just in case this isn't already true
746
747
748 twoFactorState.isRequired = Promise.resolve(true);
749 return internalPublish(pkgName, opts, twoFactorState);
750 }
751
752 logger.error(`an error occurred while publishing ${pkgName}: ${json.error.code}`, json.error.summary, json.error.detail ? "\n" + json.error.detail : "");
753 return {
754 published: false
755 };
756 }
757
758 return {
759 published: true
760 };
761}
762
763function publish(pkgName, opts, twoFactorState) {
764 // If there are many packages to be published, it's better to limit the
765 // concurrency to avoid unwanted errors, for example from npm.
766 return npmRequestLimit(() => npmPublishLimit(() => internalPublish(pkgName, opts, twoFactorState)));
767}
768
769function getReleaseTag(pkgInfo, preState, tag) {
770 if (tag) return tag;
771
772 if (preState !== undefined && pkgInfo.publishedState !== "only-pre") {
773 return preState.tag;
774 }
775
776 return "latest";
777}
778
779const isCustomRegistry = registry => !!registry && registry !== "https://registry.npmjs.org" && registry !== "https://registry.yarnpkg.com";
780
781const getTwoFactorState = ({
782 otp,
783 publicPackages
784}) => {
785 if (otp) {
786 return {
787 token: otp,
788 isRequired: Promise.resolve(true)
789 };
790 }
791
792 if (isCI || publicPackages.some(pkg => {
793 var _pkg$packageJson$publ;
794
795 return isCustomRegistry((_pkg$packageJson$publ = pkg.packageJson.publishConfig) === null || _pkg$packageJson$publ === void 0 ? void 0 : _pkg$packageJson$publ.registry);
796 }) || isCustomRegistry(process.env.npm_config_registry)) {
797 return {
798 token: null,
799 isRequired: Promise.resolve(false)
800 };
801 }
802
803 return {
804 token: null,
805 // note: we're not awaiting this here, we want this request to happen in parallel with getUnpublishedPackages
806 isRequired: getTokenIsRequired()
807 };
808};
809
810async function publishPackages({
811 packages,
812 access,
813 otp,
814 preState,
815 tag
816}) {
817 const packagesByName = new Map(packages.map(x => [x.packageJson.name, x]));
818 const publicPackages = packages.filter(pkg => !pkg.packageJson.private);
819 const twoFactorState = getTwoFactorState({
820 otp,
821 publicPackages
822 });
823 const unpublishedPackagesInfo = await getUnpublishedPackages(publicPackages, preState);
824
825 if (unpublishedPackagesInfo.length === 0) {
826 logger.warn("No unpublished packages to publish");
827 }
828
829 return Promise.all(unpublishedPackagesInfo.map(pkgInfo => {
830 let pkg = packagesByName.get(pkgInfo.name);
831 return publishAPackage(pkg, access, twoFactorState, getReleaseTag(pkgInfo, preState, tag));
832 }));
833}
834
835async function publishAPackage(pkg, access, twoFactorState, tag) {
836 const {
837 name,
838 version,
839 publishConfig
840 } = pkg.packageJson;
841 const localAccess = publishConfig === null || publishConfig === void 0 ? void 0 : publishConfig.access;
842 logger.info(`Publishing ${chalk__default['default'].cyan(`"${name}"`)} at ${chalk__default['default'].green(`"${version}"`)}`);
843 const publishDir = (publishConfig === null || publishConfig === void 0 ? void 0 : publishConfig.directory) ? path.join(pkg.dir, publishConfig.directory) : pkg.dir;
844 const publishConfirmation = await publish(name, {
845 cwd: publishDir,
846 access: localAccess || access,
847 tag
848 }, twoFactorState);
849 return {
850 name,
851 newVersion: version,
852 published: publishConfirmation.published
853 };
854}
855
856async function getUnpublishedPackages(packages, preState) {
857 const results = await Promise.all(packages.map(async ({
858 packageJson
859 }) => {
860 const response = await infoAllow404(packageJson);
861 let publishedState = "never";
862
863 if (response.published) {
864 publishedState = "published";
865
866 if (preState !== undefined) {
867 if (response.pkgInfo.versions && response.pkgInfo.versions.every(version => semver__default['default'].parse(version).prerelease[0] === preState.tag)) {
868 publishedState = "only-pre";
869 }
870 }
871 }
872
873 return {
874 name: packageJson.name,
875 localVersion: packageJson.version,
876 publishedState: publishedState,
877 publishedVersions: response.pkgInfo.versions || []
878 };
879 }));
880 const packagesToPublish = [];
881
882 for (const pkgInfo of results) {
883 const {
884 name,
885 publishedState,
886 localVersion,
887 publishedVersions
888 } = pkgInfo;
889
890 if (!publishedVersions.includes(localVersion)) {
891 packagesToPublish.push(pkgInfo);
892 logger.info(`${name} is being published because our local version (${localVersion}) has not been published on npm`);
893
894 if (preState !== undefined && publishedState === "only-pre") {
895 logger.info(`${name} is being published to ${chalk__default['default'].cyan("latest")} rather than ${chalk__default['default'].cyan(preState.tag)} because there has not been a regular release of it yet`);
896 }
897 } else {
898 // If the local version is behind npm, something is wrong, we warn here, and by not getting published later, it will fail
899 logger.warn(`${name} is not being published because version ${localVersion} is already published on npm`);
900 }
901 }
902
903 return packagesToPublish;
904}
905
906function logReleases(pkgs) {
907 const mappedPkgs = pkgs.map(p => `${p.name}@${p.newVersion}`).join("\n");
908 logger.log(mappedPkgs);
909}
910
911let importantSeparator$1 = chalk__default['default'].red("===============================IMPORTANT!===============================");
912let importantEnd$1 = chalk__default['default'].red("----------------------------------------------------------------------");
913
914function showNonLatestTagWarning(tag, preState) {
915 logger.warn(importantSeparator$1);
916
917 if (preState) {
918 logger.warn(`You are in prerelease mode so packages will be published to the ${chalk__default['default'].cyan(preState.tag)}
919 dist tag except for packages that have not had normal releases which will be published to ${chalk__default['default'].cyan("latest")}`);
920 } else if (tag !== "latest") {
921 logger.warn(`Packages will be released under the ${tag} tag`);
922 }
923
924 logger.warn(importantEnd$1);
925}
926
927async function run(cwd, {
928 otp,
929 tag
930}, config) {
931 const releaseTag = tag && tag.length > 0 ? tag : undefined;
932 let preState = await pre$1.readPreState(cwd);
933
934 if (releaseTag && preState && preState.mode === "pre") {
935 logger.error("Releasing under custom tag is not allowed in pre mode");
936 logger.log("To resolve this exit the pre mode by running `changeset pre exit`");
937 throw new errors.ExitError(1);
938 }
939
940 if (releaseTag || preState) {
941 showNonLatestTagWarning(tag, preState);
942 }
943
944 const {
945 packages,
946 tool
947 } = await getPackages.getPackages(cwd);
948 const response = await publishPackages({
949 packages,
950 // if not public, we wont pass the access, and it works as normal
951 access: config.access,
952 otp,
953 preState,
954 tag: releaseTag
955 });
956 const successful = response.filter(p => p.published);
957 const unsuccessful = response.filter(p => !p.published);
958
959 if (successful.length > 0) {
960 logger.success("packages published successfully:");
961 logReleases(successful); // We create the tags after the push above so that we know that HEAD wont change and that pushing
962 // wont suffer from a race condition if another merge happens in the mean time (pushing tags wont
963 // fail if we are behind the base branch).
964
965 logger.log(`Creating git tag${successful.length > 1 ? "s" : ""}...`);
966
967 if (tool !== "root") {
968 for (const pkg of successful) {
969 const tag = `${pkg.name}@${pkg.newVersion}`;
970 logger.log("New tag: ", tag);
971 await git.tag(tag, cwd);
972 }
973 } else {
974 const tag = `v${successful[0].newVersion}`;
975 logger.log("New tag: ", tag);
976 await git.tag(tag, cwd);
977 }
978 }
979
980 if (unsuccessful.length > 0) {
981 logger.error("packages failed to publish:");
982 logReleases(unsuccessful);
983 throw new errors.ExitError(1);
984 }
985}
986
987async function getStatus(cwd, {
988 sinceMaster,
989 since,
990 verbose,
991 output
992}, config) {
993 if (sinceMaster) {
994 logger.warn("--sinceMaster is deprecated and will be removed in a future major version");
995 logger.warn("Use --since=master instead");
996 }
997
998 const sinceBranch = since === undefined ? sinceMaster ? "master" : undefined : since;
999 const releasePlan = await getReleasePlan__default['default'](cwd, sinceBranch, config);
1000 const {
1001 changesets,
1002 releases
1003 } = releasePlan;
1004 const changedPackages = await git.getChangedPackagesSinceRef({
1005 cwd,
1006 ref: sinceBranch || config.baseBranch
1007 });
1008
1009 if (changedPackages.length > 0 && changesets.length === 0) {
1010 logger.error("Some packages have been changed but no changesets were found. Run `changeset add` to resolve this error.");
1011 logger.error("If this change doesn't need a release, run `changeset add --empty`.");
1012 process.exit(1);
1013 }
1014
1015 if (output) {
1016 await fs__default['default'].writeFile(path__default['default'].join(cwd, output), JSON.stringify(releasePlan, undefined, 2));
1017 return;
1018 }
1019
1020 const print = verbose ? verbosePrint : SimplePrint;
1021 print("patch", releases);
1022 logger.log("---");
1023 print("minor", releases);
1024 logger.log("---");
1025 print("major", releases);
1026 return releasePlan;
1027}
1028
1029function SimplePrint(type, releases) {
1030 const packages = releases.filter(r => r.type === type);
1031
1032 if (packages.length) {
1033 logger.info(chalk__default['default']`Packages to be bumped at {green ${type}}:\n`);
1034 const pkgs = packages.map(({
1035 name
1036 }) => `- ${name}`).join("\n");
1037 logger.log(chalk__default['default'].green(pkgs));
1038 } else {
1039 logger.info(chalk__default['default']`{red NO} packages to be bumped at {green ${type}}`);
1040 }
1041}
1042
1043function verbosePrint(type, releases) {
1044 const packages = releases.filter(r => r.type === type);
1045
1046 if (packages.length) {
1047 logger.info(chalk__default['default']`Packages to be bumped at {green ${type}}`);
1048 const columns = packages.map(({
1049 name,
1050 newVersion: version,
1051 changesets
1052 }) => [chalk__default['default'].green(name), version, changesets.map(c => chalk__default['default'].blue(` .changeset/${c}/changes.md`)).join(" +")]);
1053 const t1 = table__default['default']([{
1054 value: "Package Name",
1055 width: 20
1056 }, {
1057 value: "New Version",
1058 width: 20
1059 }, {
1060 value: "Related Changeset Summaries",
1061 width: 70
1062 }], columns, {
1063 paddingLeft: 1,
1064 paddingRight: 0,
1065 headerAlign: "center",
1066 align: "left"
1067 });
1068 logger.log(t1.render() + "\n");
1069 } else {
1070 logger.info(chalk__default['default']`Running release would release {red NO} packages as a {green ${type}}`);
1071 }
1072}
1073
1074async function pre(cwd, options) {
1075 if (options.command === "enter") {
1076 try {
1077 await pre$1.enterPre(cwd, options.tag);
1078 logger.success(`Entered pre mode with tag ${chalk__default['default'].cyan(options.tag)}`);
1079 logger.info("Run `changeset version` to version packages with prerelease versions");
1080 } catch (err) {
1081 if (err instanceof errors.PreEnterButInPreModeError) {
1082 logger.error("`changeset pre enter` cannot be run when in pre mode");
1083 logger.info("If you're trying to exit pre mode, run `changeset pre exit`");
1084 throw new errors.ExitError(1);
1085 }
1086
1087 throw err;
1088 }
1089 } else {
1090 try {
1091 await pre$1.exitPre(cwd);
1092 logger.success(`Exited pre mode`);
1093 logger.info("Run `changeset version` to version packages with normal versions");
1094 } catch (err) {
1095 if (err instanceof errors.PreExitButNotInPreModeError) {
1096 logger.error("`changeset pre exit` can only be run when in pre mode");
1097 logger.info("If you're trying to enter pre mode, run `changeset pre enter`");
1098 throw new errors.ExitError(1);
1099 }
1100
1101 throw err;
1102 }
1103 }
1104}
1105
1106async function run$1(cwd) {
1107 const {
1108 packages,
1109 tool
1110 } = await getPackages.getPackages(cwd);
1111 const allExistingTags = await git.getAllTags(cwd);
1112
1113 for (const pkg of packages) {
1114 const tag = tool !== "root" ? `${pkg.packageJson.name}@${pkg.packageJson.version}` : `v${pkg.packageJson.version}`;
1115
1116 if (allExistingTags.has(tag)) {
1117 logger.log("Skipping tag (already exists): ", tag);
1118 } else {
1119 logger.log("New tag: ", tag);
1120 await git.tag(tag, cwd);
1121 }
1122 }
1123}
1124
1125async function run$2(input, flags, cwd) {
1126 if (input[0] === "init") {
1127 await init(cwd);
1128 return;
1129 }
1130
1131 if (!fs__default['default'].existsSync(path__default['default'].resolve(cwd, ".changeset"))) {
1132 logger.error("There is no .changeset folder. ");
1133 logger.error("If this is the first time `changesets` have been used in this project, run `yarn changeset init` to get set up.");
1134 logger.error("If you expected there to be changesets, you should check git history for when the folder was removed to ensure you do not lose any configuration.");
1135 throw new errors.ExitError(1);
1136 }
1137
1138 const packages = await getPackages.getPackages(cwd);
1139 let config$1;
1140
1141 try {
1142 config$1 = await config.read(cwd, packages);
1143 } catch (e) {
1144 let oldConfigExists = await fs__default['default'].pathExists(path__default['default'].resolve(cwd, ".changeset/config.js"));
1145
1146 if (oldConfigExists) {
1147 logger.error("It looks like you're using the version 1 `.changeset/config.js` file");
1148 logger.error("You'll need to convert it to a `.changeset/config.json` file");
1149 logger.error("The format of the config object has significantly changed in v2 as well");
1150 logger.error(" - we thoroughly recommend looking at the changelog for this package for what has changed");
1151 throw new errors.ExitError(1);
1152 } else {
1153 throw e;
1154 }
1155 }
1156
1157 if (input.length < 1) {
1158 const {
1159 empty,
1160 open
1161 } = flags; // @ts-ignore if this is undefined, we have already exited
1162
1163 await add(cwd, {
1164 empty,
1165 open
1166 }, config$1);
1167 } else if (input[0] !== "pre" && input.length > 1) {
1168 logger.error("Too many arguments passed to changesets - we only accept the command name as an argument");
1169 } else {
1170 const {
1171 sinceMaster,
1172 since,
1173 verbose,
1174 output,
1175 otp,
1176 empty,
1177 ignore,
1178 snapshot,
1179 tag,
1180 open
1181 } = flags;
1182 const deadFlags = ["updateChangelog", "isPublic", "skipCI", "commit"];
1183 deadFlags.forEach(flag => {
1184 if (flags[flag]) {
1185 logger.error(`the flag ${flag} has been removed from changesets for version 2`);
1186 logger.error(`Please encode the desired value into your config`);
1187 logger.error(`See our changelog for more details`);
1188 throw new errors.ExitError(1);
1189 }
1190 }); // Command line options need to be undefined, otherwise their
1191 // default value overrides the user's provided config in their
1192 // config file. For this reason, we only assign them to this
1193 // object as and when they exist.
1194
1195 switch (input[0]) {
1196 case "add":
1197 {
1198 // @ts-ignore if this is undefined, we have already exited
1199 await add(cwd, {
1200 empty,
1201 open
1202 }, config$1);
1203 return;
1204 }
1205
1206 case "version":
1207 {
1208 let ignoreArrayFromCmd;
1209
1210 if (typeof ignore === "string") {
1211 ignoreArrayFromCmd = [ignore];
1212 } else {
1213 // undefined or an array
1214 ignoreArrayFromCmd = ignore;
1215 } // Validate that items in ignoreArrayFromCmd are valid project names
1216
1217
1218 let pkgNames = new Set(packages.packages.map(({
1219 packageJson
1220 }) => packageJson.name));
1221 const messages = [];
1222
1223 for (const pkgName of ignoreArrayFromCmd || []) {
1224 if (!pkgNames.has(pkgName)) {
1225 messages.push(`The package "${pkgName}" is passed to the \`--ignore\` option but it is not found in the project. You may have misspelled the package name.`);
1226 }
1227 }
1228
1229 if (config$1.ignore.length > 0 && ignoreArrayFromCmd) {
1230 messages.push(`It looks like you are trying to use the \`--ignore\` option while ignore is defined in the config file. This is currently not allowed, you can only use one of them at a time.`);
1231 } else if (ignoreArrayFromCmd) {
1232 // use the ignore flags from cli
1233 config$1.ignore = ignoreArrayFromCmd;
1234 } // Validate that all dependents of ignored packages are listed in the ignore list
1235
1236
1237 const dependentsGraph = getDependentsGraph.getDependentsGraph(packages, {
1238 bumpVersionsWithWorkspaceProtocolOnly: config$1.bumpVersionsWithWorkspaceProtocolOnly
1239 });
1240
1241 for (const ignoredPackage of config$1.ignore) {
1242 const dependents = dependentsGraph.get(ignoredPackage) || [];
1243
1244 for (const dependent of dependents) {
1245 if (!config$1.ignore.includes(dependent)) {
1246 messages.push(`The package "${dependent}" depends on the ignored package "${ignoredPackage}", but "${dependent}" is not being ignored. Please pass "${dependent}" to the \`--ignore\` flag.`);
1247 }
1248 }
1249 }
1250
1251 if (messages.length > 0) {
1252 logger.error(messages.join("\n"));
1253 throw new errors.ExitError(1);
1254 }
1255
1256 await version(cwd, {
1257 snapshot
1258 }, config$1);
1259 return;
1260 }
1261
1262 case "publish":
1263 {
1264 await run(cwd, {
1265 otp,
1266 tag
1267 }, config$1);
1268 return;
1269 }
1270
1271 case "status":
1272 {
1273 await getStatus(cwd, {
1274 sinceMaster,
1275 since,
1276 verbose,
1277 output
1278 }, config$1);
1279 return;
1280 }
1281
1282 case "tag":
1283 {
1284 await run$1(cwd);
1285 return;
1286 }
1287
1288 case "pre":
1289 {
1290 let command = input[1];
1291
1292 if (command !== "enter" && command !== "exit") {
1293 logger.error("`enter`, `exit` or `snapshot` must be passed after prerelease");
1294 throw new errors.ExitError(1);
1295 }
1296
1297 let tag = input[2];
1298
1299 if (command === "enter" && typeof tag !== "string") {
1300 logger.error(`A tag must be passed when using prerelese enter`);
1301 throw new errors.ExitError(1);
1302 } // @ts-ignore
1303
1304
1305 await pre(cwd, {
1306 command,
1307 tag
1308 });
1309 return;
1310 }
1311
1312 case "bump":
1313 {
1314 logger.error('In version 2 of changesets, "bump" has been renamed to "version" - see our changelog for an explanation');
1315 logger.error("To fix this, use `changeset version` instead, and update any scripts that use changesets");
1316 throw new errors.ExitError(1);
1317 }
1318
1319 case "release":
1320 {
1321 logger.error('In version 2 of changesets, "release" has been renamed to "publish" - see our changelog for an explanation');
1322 logger.error("To fix this, use `changeset publish` instead, and update any scripts that use changesets");
1323 throw new errors.ExitError(1);
1324 }
1325
1326 default:
1327 {
1328 logger.error(`Invalid command ${input[0]} was provided`);
1329 throw new errors.ExitError(1);
1330 }
1331 }
1332 }
1333}
1334
1335const {
1336 input,
1337 flags
1338} = meow__default['default'](`
1339 Usage
1340 $ changesets [command]
1341 Commands
1342 init
1343 add [--empty] [--open]
1344 version [--ignore]
1345 publish [--otp=code]
1346 status [--since <branch>] [--verbose] [--output=JSON_FILE.json]
1347 pre <enter|exit> <tag>
1348 tag
1349 `, {
1350 flags: {
1351 sinceMaster: {
1352 type: "boolean"
1353 },
1354 verbose: {
1355 type: "boolean",
1356 alias: "v"
1357 },
1358 output: {
1359 type: "string",
1360 alias: "o"
1361 },
1362 otp: {
1363 type: "string"
1364 },
1365 empty: {
1366 type: "boolean"
1367 },
1368 since: {
1369 type: "string"
1370 },
1371 ignore: {
1372 type: "string",
1373 isMultiple: true
1374 },
1375 tag: {
1376 type: "string"
1377 },
1378 open: {
1379 type: "boolean"
1380 }
1381 }
1382});
1383const cwd = process.cwd();
1384run$2(input, flags, cwd).catch(err => {
1385 if (err instanceof errors.InternalError) {
1386 logger.error("The following error is an internal unexpected error, these should never happen.");
1387 logger.error("Please open an issue with the following link");
1388 logger.error(`https://github.com/atlassian/changesets/issues/new?title=${encodeURIComponent(`Unexpected error during ${input[0] || "add"} command`)}&body=${encodeURIComponent(`## Error
1389
1390\`\`\`
1391${util.format("", err).replace(process.cwd(), "<cwd>")}
1392\`\`\`
1393
1394## Versions
1395
1396- @changesets/cli@${// eslint-disable-next-line import/no-extraneous-dependencies
1397 require("@changesets/cli/package.json").version}
1398- node@${process.version}
1399
1400## Extra details
1401
1402<!-- Add any extra details of what you were doing, ideas you have about what might have caused the error and reproduction steps if possible. If you have a repository we can look at that would be great. 😁 -->
1403`)}`);
1404 }
1405
1406 if (err instanceof errors.ExitError) {
1407 return process.exit(err.code);
1408 }
1409
1410 logger.error(err);
1411 process.exit(1);
1412});