UNPKG

36.5 kBJavaScriptView Raw
1"use strict";
2
3function _interopDefault(ex) {
4 return ex && "object" == typeof ex && "default" in ex ? ex.default : ex;
5}
6
7var meow = _interopDefault(require("meow")), errors = require("@changesets/errors"), logger = require("@changesets/logger"), util = require("util"), fs = _interopDefault(require("fs-extra")), path = require("path"), path__default = _interopDefault(path), getPackages = require("@manypkg/get-packages"), getDependentsGraph = require("@changesets/get-dependents-graph"), config = require("@changesets/config"), chalk = _interopDefault(require("chalk")), termSize = _interopDefault(require("term-size")), enquirer = require("enquirer"), externalEditor = require("external-editor"), git = require("@changesets/git"), writeChangeset = _interopDefault(require("@changesets/write")), semver = _interopDefault(require("semver")), boxen = _interopDefault(require("boxen")), outdent = _interopDefault(require("outdent")), applyReleasePlan = _interopDefault(require("@changesets/apply-release-plan")), readChangesets = _interopDefault(require("@changesets/read")), assembleReleasePlan = _interopDefault(require("@changesets/assemble-release-plan")), pre$1 = require("@changesets/pre"), pLimit = _interopDefault(require("p-limit")), preferredPM = _interopDefault(require("preferred-pm")), spawn = _interopDefault(require("spawndamnit")), isCI$1 = _interopDefault(require("is-ci")), table = _interopDefault(require("tty-table")), getReleasePlan = _interopDefault(require("@changesets/get-release-plan"));
8
9const pkgPath = path__default.dirname(require.resolve("@changesets/cli/package.json"));
10
11async function init(cwd) {
12 const changesetBase = path__default.resolve(cwd, ".changeset");
13 fs.existsSync(changesetBase) ? fs.existsSync(path__default.join(changesetBase, "config.json")) ? logger.warn("It looks like you already have changesets initialized. You should be able to run changeset commands no problems.") : (fs.existsSync(path__default.join(changesetBase, "config.js")) ? (logger.error("It looks like you're using the version 1 `.changeset/config.js` file"),
14 logger.error("The format of the config object has significantly changed in v2 as well"),
15 logger.error(" - we thoroughly recommend looking at the changelog for this package for what has changed"),
16 logger.error("Changesets will write the defaults for the new config, remember to transfer your options into the new config at `.changeset/config.json`")) : (logger.error("It looks like you don't have a config file"),
17 logger.info("The default config file will be written at `.changeset/config.json`")),
18 await fs.writeFile(path__default.resolve(changesetBase, "config.json"), JSON.stringify(config.defaultWrittenConfig, null, 2))) : (await fs.copy(path__default.resolve(pkgPath, "./default-files"), changesetBase),
19 await fs.writeFile(path__default.resolve(changesetBase, "config.json"), JSON.stringify(config.defaultWrittenConfig, null, 2)),
20 logger.log(chalk`Thanks for choosing {green changesets} to help manage your versioning and publishing\n`),
21 logger.log("You should be set up to start using changesets now!\n"), logger.info("We have added a `.changeset` folder, and a couple of files to help you out:"),
22 logger.info(chalk`- {blue .changeset/README.md} contains information about using changesets`),
23 logger.info(chalk`- {blue .changeset/config.json} is our default config`));
24}
25
26const serialId = function() {
27 let id = 0;
28 return () => id++;
29}(), limit = Math.max(termSize().rows - 5, 10);
30
31let cancelFlow = () => {
32 logger.success("Cancelled... 👋 "), process.exit();
33};
34
35async function askCheckboxPlus(message, choices, format) {
36 const name = `CheckboxPlus-${serialId()}`;
37 return enquirer.prompt({
38 type: "autocomplete",
39 name: name,
40 message: message,
41 prefix: logger.prefix,
42 multiple: !0,
43 choices: choices,
44 format: format,
45 limit: limit,
46 onCancel: cancelFlow
47 }).then(responses => responses[name]).catch(err => {
48 logger.error(err);
49 });
50}
51
52async function askQuestion(message) {
53 const name = `Question-${serialId()}`;
54 return enquirer.prompt([ {
55 type: "input",
56 message: message,
57 name: name,
58 prefix: logger.prefix,
59 onCancel: cancelFlow
60 } ]).then(responses => responses[name]).catch(err => {
61 logger.error(err);
62 });
63}
64
65function askQuestionWithEditor(message) {
66 return externalEditor.edit(message, {
67 postfix: ".md"
68 }).replace(/^#.*\n?/gm, "").replace(/\n+$/g, "").trim();
69}
70
71async function askConfirm(message) {
72 const name = `Confirm-${serialId()}`;
73 return enquirer.prompt([ {
74 message: message,
75 name: name,
76 prefix: logger.prefix,
77 type: "confirm",
78 initial: !0,
79 onCancel: cancelFlow
80 } ]).then(responses => responses[name]).catch(err => {
81 logger.error(err);
82 });
83}
84
85async function askList(message, choices) {
86 const name = `List-${serialId()}`;
87 return enquirer.prompt([ {
88 choices: choices,
89 message: message,
90 name: name,
91 prefix: logger.prefix,
92 type: "select",
93 onCancel: cancelFlow
94 } ]).then(responses => responses[name]).catch(err => {
95 logger.error(err);
96 });
97}
98
99const {green: green, yellow: yellow, red: red, bold: bold, blue: blue, cyan: cyan} = chalk;
100
101async function confirmMajorRelease(pkgJSON) {
102 if (semver.lt(pkgJSON.version, "1.0.0")) {
103 return logger.log(yellow(`WARNING: Releasing a major version for ${green(pkgJSON.name)} will be its ${red("first major release")}.`)),
104 logger.log(yellow(`If you are unsure if this is correct, contact the package's maintainers ${red("before committing this changeset")}.`)),
105 await askConfirm(bold(`Are you sure you want still want to release the ${red("first major release")} of ${pkgJSON.name}?`));
106 }
107 return !0;
108}
109
110async function getPackagesToRelease(changedPackages, allPackages) {
111 function askInitialReleaseQuestion(defaultChoiceList) {
112 return askCheckboxPlus("Which packages would you like to include?", defaultChoiceList, x => Array.isArray(x) ? x.filter(x => "changed packages" !== x && "unchanged packages" !== x).map(x => cyan(x)).join(", ") : x);
113 }
114 if (allPackages.length > 1) {
115 const unchangedPackagesNames = allPackages.map(({packageJson: packageJson}) => packageJson.name).filter(name => !changedPackages.includes(name)), defaultChoiceList = [ {
116 name: "changed packages",
117 choices: changedPackages
118 }, {
119 name: "unchanged packages",
120 choices: unchangedPackagesNames
121 } ].filter(({choices: choices}) => 0 !== choices.length);
122 let packagesToRelease = await askInitialReleaseQuestion(defaultChoiceList);
123 if (0 === packagesToRelease.length) do {
124 logger.error("You must select at least one package to release"), logger.error("(You most likely hit enter instead of space!)"),
125 packagesToRelease = await askInitialReleaseQuestion(defaultChoiceList);
126 } while (0 === packagesToRelease.length);
127 return packagesToRelease.filter(pkgName => "changed packages" !== pkgName && "unchanged packages" !== pkgName);
128 }
129 return [ allPackages[0].packageJson.name ];
130}
131
132function formatPkgNameAndVersion(pkgName, version) {
133 return `${bold(pkgName)}@${bold(version)}`;
134}
135
136async function createChangeset(changedPackages, allPackages) {
137 const releases = [];
138 if (allPackages.length > 1) {
139 const packagesToRelease = await getPackagesToRelease(changedPackages, allPackages);
140 let pkgJsonsByName = new Map(allPackages.map(({packageJson: packageJson}) => [ packageJson.name, packageJson ])), pkgsLeftToGetBumpTypeFor = new Set(packagesToRelease), pkgsThatShouldBeMajorBumped = (await askCheckboxPlus(bold(`Which packages should have a ${red("major")} bump?`), [ {
141 name: "all packages",
142 choices: packagesToRelease.map(pkgName => ({
143 name: pkgName,
144 message: formatPkgNameAndVersion(pkgName, pkgJsonsByName.get(pkgName).version)
145 }))
146 } ], x => Array.isArray(x) ? x.filter(x => "all packages" !== x).map(x => cyan(x)).join(", ") : x)).filter(x => "all packages" !== x);
147 for (const pkgName of pkgsThatShouldBeMajorBumped) {
148 let pkgJson = pkgJsonsByName.get(pkgName);
149 await confirmMajorRelease(pkgJson) && (pkgsLeftToGetBumpTypeFor.delete(pkgName),
150 releases.push({
151 name: pkgName,
152 type: "major"
153 }));
154 }
155 if (0 !== pkgsLeftToGetBumpTypeFor.size) {
156 let pkgsThatShouldBeMinorBumped = (await askCheckboxPlus(bold(`Which packages should have a ${green("minor")} bump?`), [ {
157 name: "all packages",
158 choices: [ ...pkgsLeftToGetBumpTypeFor ].map(pkgName => ({
159 name: pkgName,
160 message: formatPkgNameAndVersion(pkgName, pkgJsonsByName.get(pkgName).version)
161 }))
162 } ], x => Array.isArray(x) ? x.filter(x => "all packages" !== x).map(x => cyan(x)).join(", ") : x)).filter(x => "all packages" !== x);
163 for (const pkgName of pkgsThatShouldBeMinorBumped) pkgsLeftToGetBumpTypeFor.delete(pkgName),
164 releases.push({
165 name: pkgName,
166 type: "minor"
167 });
168 }
169 if (0 !== pkgsLeftToGetBumpTypeFor.size) {
170 logger.log(`The following packages will be ${blue("patch")} bumped:`), pkgsLeftToGetBumpTypeFor.forEach(pkgName => {
171 logger.log(formatPkgNameAndVersion(pkgName, pkgJsonsByName.get(pkgName).version));
172 });
173 for (const pkgName of pkgsLeftToGetBumpTypeFor) releases.push({
174 name: pkgName,
175 type: "patch"
176 });
177 }
178 } else {
179 let pkg = allPackages[0], type = await askList(`What kind of change is this for ${green(pkg.packageJson.name)}? (current version is ${pkg.packageJson.version})`, [ "patch", "minor", "major" ]);
180 if (console.log(type), "major" === type) {
181 if (!await confirmMajorRelease(pkg.packageJson)) throw new errors.ExitError(1);
182 }
183 releases.push({
184 name: pkg.packageJson.name,
185 type: type
186 });
187 }
188 logger.log("Please enter a summary for this change (this will be in the changelogs). Submit empty line to open external editor");
189 let summary = await askQuestion("Summary");
190 0 === summary.length && (summary = askQuestionWithEditor(""));
191 try {
192 for (;0 === summary.length; ) summary = await askQuestionWithEditor("\n\n# A summary is required for the changelog! 😪");
193 } catch (err) {
194 for (logger.log("An error happened using external editor. Please type your summary here:"),
195 summary = await askQuestion(""); 0 === summary.length; ) summary = await askQuestion("\n\n# A summary is required for the changelog! 😪");
196 }
197 return {
198 summary: summary,
199 releases: releases
200 };
201}
202
203function printConfirmationMessage(changeset, repoHasMultiplePackages) {
204 function getReleasesOfType(type) {
205 return changeset.releases.filter(release => release.type === type).map(release => release.name);
206 }
207 logger.log("=== Releasing the following packages ===");
208 const majorReleases = getReleasesOfType("major"), minorReleases = getReleasesOfType("minor"), patchReleases = getReleasesOfType("patch");
209 if (majorReleases.length > 0 && logger.log(`${chalk.green("[Major]")}\n ${majorReleases.join(", ")}`),
210 minorReleases.length > 0 && logger.log(`${chalk.green("[Minor]")}\n ${minorReleases.join(", ")}`),
211 patchReleases.length > 0 && logger.log(`${chalk.green("[Patch]")}\n ${patchReleases.join(", ")}`),
212 repoHasMultiplePackages) {
213 const message = outdent`
214 ${chalk.red("========= NOTE ========")}
215 All dependents of these packages that will be incompatible with the new version will be ${chalk.red("patch bumped")} when this changeset is applied.`, prettyMessage = boxen(message, {
216 borderStyle: "double",
217 align: "center"
218 });
219 logger.log(prettyMessage);
220 }
221}
222
223async function add(cwd, {empty: empty}, config) {
224 const packages = await getPackages.getPackages(cwd), changesetBase = path__default.resolve(cwd, ".changeset");
225 let newChangeset, confirmChangeset;
226 if (empty) newChangeset = {
227 releases: [],
228 summary: ""
229 }, confirmChangeset = !0; else {
230 const changePackagesName = (await git.getChangedPackagesSinceRef({
231 cwd: cwd,
232 ref: config.baseBranch
233 })).filter(a => a).map(pkg => pkg.packageJson.name);
234 newChangeset = await createChangeset(changePackagesName, packages.packages), printConfirmationMessage(newChangeset, packages.packages.length > 1),
235 confirmChangeset = await askConfirm("Is this your desired changeset?");
236 }
237 if (confirmChangeset) {
238 const changesetID = await writeChangeset(newChangeset, cwd);
239 config.commit ? (await git.add(path__default.resolve(changesetBase, `${changesetID}.md`), cwd),
240 await git.commit(`docs(changeset): ${newChangeset.summary}`, cwd), logger.log(chalk.green(`${empty ? "Empty " : ""}Changeset added and committed`))) : logger.log(chalk.green(`${empty ? "Empty " : ""}Changeset added! - you can now commit it\n`)),
241 [ ...newChangeset.releases ].find(c => "major" === c.type) ? (logger.warn("This Changeset includes a major change and we STRONGLY recommend adding more information to the changeset:"),
242 logger.warn("WHAT the breaking change is"), logger.warn("WHY the change was made"),
243 logger.warn("HOW a consumer should update their code")) : logger.log(chalk.green("If you want to modify or expand on the changeset summary, you can find it here")),
244 logger.info(chalk.blue(path__default.resolve(changesetBase, `${changesetID}.md`)));
245 }
246}
247
248const removeEmptyFolders = async folderPath => {
249 const dirContents = fs.readdirSync(folderPath);
250 return Promise.all(dirContents.map(async contentPath => {
251 const singleChangesetPath = path__default.resolve(folderPath, contentPath);
252 try {
253 (await fs.readdir(singleChangesetPath)).length < 1 && await fs.rmdir(singleChangesetPath);
254 } catch (err) {
255 if ("ENOTDIR" !== err.code) throw err;
256 }
257 }));
258};
259
260function ownKeys(object, enumerableOnly) {
261 var keys = Object.keys(object);
262 if (Object.getOwnPropertySymbols) {
263 var symbols = Object.getOwnPropertySymbols(object);
264 enumerableOnly && (symbols = symbols.filter((function(sym) {
265 return Object.getOwnPropertyDescriptor(object, sym).enumerable;
266 }))), keys.push.apply(keys, symbols);
267 }
268 return keys;
269}
270
271function _objectSpread(target) {
272 for (var i = 1; i < arguments.length; i++) {
273 var source = null != arguments[i] ? arguments[i] : {};
274 i % 2 ? ownKeys(Object(source), !0).forEach((function(key) {
275 _defineProperty(target, key, source[key]);
276 })) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach((function(key) {
277 Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
278 }));
279 }
280 return target;
281}
282
283function _defineProperty(obj, key, value) {
284 return key in obj ? Object.defineProperty(obj, key, {
285 value: value,
286 enumerable: !0,
287 configurable: !0,
288 writable: !0
289 }) : obj[key] = value, obj;
290}
291
292let importantSeparator = chalk.red("===============================IMPORTANT!==============================="), importantEnd = chalk.red("----------------------------------------------------------------------");
293
294async function version(cwd, options, config) {
295 const releaseConfig = _objectSpread(_objectSpread({}, config), {}, {
296 commit: !options.snapshot && config.commit
297 }), [changesets, preState] = await Promise.all([ readChangesets(cwd), pre$1.readPreState(cwd), removeEmptyFolders(path__default.resolve(cwd, ".changeset")) ]);
298 if ("pre" === (null == preState ? void 0 : preState.mode)) {
299 if (logger.warn(importantSeparator), void 0 !== options.snapshot) throw logger.error("Snapshot release is not allowed in pre mode"),
300 logger.log("To resolve this exit the pre mode by running `changeset pre exit`"),
301 new errors.ExitError(1);
302 logger.warn("You are in prerelease mode"), logger.warn("If you meant to do a normal release you should revert these changes and run `changeset pre exit`"),
303 logger.warn("You can then run `changeset version` again to do a normal release"),
304 logger.warn(importantEnd);
305 }
306 if (0 === changesets.length && (void 0 === preState || "exit" !== preState.mode)) return void logger.warn("No unreleased changesets found, exiting.");
307 let packages = await getPackages.getPackages(cwd), releasePlan = assembleReleasePlan(changesets, packages, releaseConfig, preState, options.snapshot);
308 await applyReleasePlan(releasePlan, packages, releaseConfig, options.snapshot),
309 releaseConfig.commit ? logger.log("All files have been updated and committed. You're ready to publish!") : logger.log("All files have been updated. Review them and commit at your leisure");
310}
311
312var isCI = !(!isCI$1 && !process.env.GITHUB_ACTIONS);
313
314const npmRequestLimit = pLimit(40);
315
316function jsonParse(input) {
317 try {
318 return JSON.parse(input);
319 } catch (err) {
320 throw err instanceof SyntaxError && console.error("error parsing json:", input),
321 err;
322 }
323}
324
325function getCorrectRegistry() {
326 return "https://registry.yarnpkg.com" === process.env.npm_config_registry ? void 0 : process.env.npm_config_registry;
327}
328
329async function getPublishTool(cwd) {
330 const pm = await preferredPM(cwd);
331 if (!pm || "pnpm" !== pm.name) return {
332 name: "npm"
333 };
334 try {
335 let version = (await spawn("pnpm", [ "--version" ], {
336 cwd: cwd
337 })).stdout.toString().trim(), parsed = semver.parse(version);
338 return {
339 name: "pnpm",
340 shouldAddNoGitChecks: void 0 !== (null == parsed ? void 0 : parsed.major) && parsed.major >= 5
341 };
342 } catch (e) {
343 return {
344 name: "pnpm",
345 shouldAddNoGitChecks: !1
346 };
347 }
348}
349
350async function getTokenIsRequired() {
351 const envOverride = {
352 npm_config_registry: getCorrectRegistry()
353 };
354 let json = jsonParse((await spawn("npm", [ "profile", "get", "--json" ], {
355 env: Object.assign({}, process.env, envOverride)
356 })).stdout.toString());
357 return !(json.error || !json.tfa || !json.tfa.mode) && "auth-and-writes" === json.tfa.mode;
358}
359
360function getPackageInfo(pkgName) {
361 return npmRequestLimit(async () => {
362 logger.info(`npm info ${pkgName}`);
363 const envOverride = {
364 npm_config_registry: getCorrectRegistry()
365 };
366 return jsonParse((await spawn("npm", [ "info", pkgName, "--json" ], {
367 env: Object.assign({}, process.env, envOverride)
368 })).stdout.toString());
369 });
370}
371
372async function infoAllow404(pkgName) {
373 let pkgInfo = await getPackageInfo(pkgName);
374 if (pkgInfo.error && "E404" === pkgInfo.error.code) return logger.warn(`Received 404 for npm info ${chalk.cyan(`"${pkgName}"`)}`),
375 {
376 published: !1,
377 pkgInfo: {}
378 };
379 if (pkgInfo.error) throw logger.error(`Received an unknown error code: ${pkgInfo.error.code} for npm info ${chalk.cyan(`"${pkgName}"`)}`),
380 logger.error(pkgInfo.error.summary), pkgInfo.error.detail && logger.error(pkgInfo.error.detail),
381 new errors.ExitError(1);
382 return {
383 published: !0,
384 pkgInfo: pkgInfo
385 };
386}
387
388let otpAskLimit = pLimit(1), askForOtpCode = twoFactorState => otpAskLimit(async () => {
389 if (null !== twoFactorState.token) return twoFactorState.token;
390 logger.info("This operation requires a one-time password from your authenticator.");
391 let val = await askQuestion("Enter one-time password:");
392 return twoFactorState.token = val, val;
393}), getOtpCode = async twoFactorState => null !== twoFactorState.token ? twoFactorState.token : askForOtpCode(twoFactorState);
394
395async function internalPublish(pkgName, opts, twoFactorState) {
396 let publishTool = await getPublishTool(opts.cwd), publishFlags = opts.access ? [ "--access", opts.access ] : [];
397 if (publishFlags.push("--tag", opts.tag), await twoFactorState.isRequired && !isCI) {
398 let otpCode = await getOtpCode(twoFactorState);
399 publishFlags.push("--otp", otpCode);
400 }
401 "pnpm" === publishTool.name && publishTool.shouldAddNoGitChecks && publishFlags.push("--no-git-checks");
402 const envOverride = {
403 npm_config_registry: getCorrectRegistry()
404 };
405 let {stdout: stdout} = await spawn(publishTool.name, [ "publish", "--json", ...publishFlags ], {
406 cwd: opts.cwd,
407 env: Object.assign({}, process.env, envOverride)
408 }), json = jsonParse(stdout.toString().replace(/[^{]*/, ""));
409 return json.error ? ("EOTP" === json.error.code || "E401" === json.error.code && json.error.detail.includes("--otp=<code>")) && !isCI ? (null !== twoFactorState.token && (twoFactorState.token = null),
410 twoFactorState.isRequired = Promise.resolve(!0), internalPublish(pkgName, opts, twoFactorState)) : (logger.error(`an error occurred while publishing ${pkgName}: ${json.error.code}`, json.error.summary, json.error.detail ? "\n" + json.error.detail : ""),
411 {
412 published: !1
413 }) : {
414 published: !0
415 };
416}
417
418function publish(pkgName, opts, twoFactorState) {
419 return npmRequestLimit(() => internalPublish(pkgName, opts, twoFactorState));
420}
421
422function getReleaseTag(pkgInfo, preState, tag) {
423 return tag || (void 0 !== preState && "only-pre" !== pkgInfo.publishedState ? preState.tag : "latest");
424}
425
426async function publishPackages({packages: packages, access: access, otp: otp, preState: preState, tag: tag}) {
427 const packagesByName = new Map(packages.map(x => [ x.packageJson.name, x ])), publicPackages = packages.filter(pkg => !pkg.packageJson.private);
428 let twoFactorState = void 0 === otp ? {
429 token: null,
430 isRequired: isCI || publicPackages.some(x => x.packageJson.publishConfig && x.packageJson.publishConfig.registry && "https://registry.npmjs.org" !== x.packageJson.publishConfig.registry && "https://registry.yarnpkg.com" !== x.packageJson.publishConfig.registry) || void 0 !== process.env.npm_config_registry && "https://registry.npmjs.org" !== process.env.npm_config_registry && "https://registry.yarnpkg.com" !== process.env.npm_config_registry ? Promise.resolve(!1) : getTokenIsRequired()
431 } : {
432 token: otp,
433 isRequired: Promise.resolve(!0)
434 };
435 const unpublishedPackagesInfo = await getUnpublishedPackages(publicPackages, preState);
436 0 === unpublishedPackagesInfo.length && logger.warn("No unpublished packages to publish");
437 let promises = [];
438 for (let pkgInfo of unpublishedPackagesInfo) {
439 let pkg = packagesByName.get(pkgInfo.name);
440 promises.push(publishAPackage(pkg, access, twoFactorState, getReleaseTag(pkgInfo, preState, tag)));
441 }
442 return Promise.all(promises);
443}
444
445async function publishAPackage(pkg, access, twoFactorState, tag) {
446 const {name: name, version: version, publishConfig: publishConfig} = pkg.packageJson, localAccess = publishConfig && publishConfig.access;
447 logger.info(`Publishing ${chalk.cyan(`"${name}"`)} at ${chalk.green(`"${version}"`)}`);
448 const publishDir = publishConfig && publishConfig.directory ? path.join(pkg.dir, publishConfig.directory) : pkg.dir;
449 return {
450 name: name,
451 newVersion: version,
452 published: (await publish(name, {
453 cwd: publishDir,
454 access: localAccess || access,
455 tag: tag
456 }, twoFactorState)).published
457 };
458}
459
460async function getUnpublishedPackages(packages, preState) {
461 const results = await Promise.all(packages.map(async pkg => {
462 const config = pkg.packageJson, response = await infoAllow404(config.name);
463 let publishedState = "never";
464 return response.published && (publishedState = "published", void 0 !== preState && response.pkgInfo.versions && response.pkgInfo.versions.every(version => semver.parse(version).prerelease[0] === preState.tag) && (publishedState = "only-pre")),
465 {
466 name: config.name,
467 localVersion: config.version,
468 publishedState: publishedState,
469 publishedVersions: response.pkgInfo.versions || []
470 };
471 })), packagesToPublish = [];
472 for (const pkgInfo of results) {
473 const {name: name, publishedState: publishedState, localVersion: localVersion, publishedVersions: publishedVersions} = pkgInfo;
474 publishedVersions.includes(localVersion) ? logger.warn(`${name} is not being published because version ${localVersion} is already published on npm`) : (packagesToPublish.push(pkgInfo),
475 logger.info(`${name} is being published because our local version (${localVersion}) has not been published on npm`),
476 void 0 !== preState && "only-pre" === publishedState && logger.info(`${name} is being published to ${chalk.cyan("latest")} rather than ${chalk.cyan(preState.tag)} because there has not been a regular release of it yet`));
477 }
478 return packagesToPublish;
479}
480
481function logReleases(pkgs) {
482 const mappedPkgs = pkgs.map(p => `${p.name}@${p.newVersion}`).join("\n");
483 logger.log(mappedPkgs);
484}
485
486let importantSeparator$1 = chalk.red("===============================IMPORTANT!==============================="), importantEnd$1 = chalk.red("----------------------------------------------------------------------");
487
488function showNonLatestTagWarning(tag, preState) {
489 logger.warn(importantSeparator$1), preState ? logger.warn(`You are in prerelease mode so packages will be published to the ${chalk.cyan(preState.tag)}\n dist tag except for packages that have not had normal releases which will be published to ${chalk.cyan("latest")}`) : "latest" !== tag && logger.warn(`Packages will be released under the ${tag} tag`),
490 logger.warn(importantEnd$1);
491}
492
493async function run(cwd, {otp: otp, tag: tag}, config) {
494 const releaseTag = tag && tag.length > 0 ? tag : void 0;
495 let preState = await pre$1.readPreState(cwd);
496 if (releaseTag && preState && "pre" === preState.mode) throw logger.error("Releasing under custom tag is not allowed in pre mode"),
497 logger.log("To resolve this exit the pre mode by running `changeset pre exit`"),
498 new errors.ExitError(1);
499 (releaseTag || preState) && showNonLatestTagWarning(tag, preState);
500 const {packages: packages, tool: tool} = await getPackages.getPackages(cwd), response = await publishPackages({
501 packages: packages,
502 access: config.access,
503 otp: otp,
504 preState: preState,
505 tag: releaseTag
506 }), successful = response.filter(p => p.published), unsuccessful = response.filter(p => !p.published);
507 if (successful.length > 0) if (logger.success("packages published successfully:"),
508 logReleases(successful), logger.log(`Creating git tag${successful.length > 1 ? "s" : ""}...`),
509 "root" !== tool) for (const pkg of successful) {
510 const tag = `${pkg.name}@${pkg.newVersion}`;
511 logger.log("New tag: ", tag), await git.tag(tag, cwd);
512 } else {
513 const tag = `v${successful[0].newVersion}`;
514 logger.log("New tag: ", tag), await git.tag(tag, cwd);
515 }
516 if (unsuccessful.length > 0) throw logger.error("packages failed to publish:"),
517 logReleases(unsuccessful), new errors.ExitError(1);
518}
519
520async function getStatus(cwd, {sinceMaster: sinceMaster, since: since, verbose: verbose, output: output}, config) {
521 sinceMaster && (logger.warn("--sinceMaster is deprecated and will be removed in a future major version"),
522 logger.warn("Use --since=master instead"));
523 const releasePlan = await getReleasePlan(cwd, void 0 === since ? sinceMaster ? "master" : void 0 : since, config), {changesets: changesets, releases: releases} = releasePlan;
524 if (changesets.length < 1 && (logger.error("No changesets present"), process.exit(1)),
525 output) return void await fs.writeFile(path__default.join(cwd, output), JSON.stringify(releasePlan, void 0, 2));
526 const print = verbose ? verbosePrint : SimplePrint;
527 return print("patch", releases), logger.log("---"), print("minor", releases), logger.log("---"),
528 print("major", releases), releasePlan;
529}
530
531function SimplePrint(type, releases) {
532 const packages = releases.filter(r => r.type === type);
533 if (packages.length) {
534 logger.info(chalk`Packages to be bumped at {green ${type}}:\n`);
535 const pkgs = packages.map(({name: name}) => `- ${name}`).join("\n");
536 logger.log(chalk.green(pkgs));
537 } else logger.info(chalk`{red NO} packages to be bumped at {green ${type}}`);
538}
539
540function verbosePrint(type, releases) {
541 const packages = releases.filter(r => r.type === type);
542 if (packages.length) {
543 logger.info(chalk`Packages to be bumped at {green ${type}}`);
544 const columns = packages.map(({name: name, newVersion: version, changesets: changesets}) => [ chalk.green(name), version, changesets.map(c => chalk.blue(` .changeset/${c}/changes.md`)).join(" +") ]), t1 = table([ {
545 value: "Package Name",
546 width: 20
547 }, {
548 value: "New Version",
549 width: 20
550 }, {
551 value: "Related Changeset Summaries",
552 width: 70
553 } ], columns, {
554 paddingLeft: 1,
555 paddingRight: 0,
556 headerAlign: "center",
557 align: "left"
558 });
559 logger.log(t1.render() + "\n");
560 } else logger.info(chalk`Running release would release {red NO} packages as a {green ${type}}`);
561}
562
563async function pre(cwd, options) {
564 if ("enter" === options.command) try {
565 await pre$1.enterPre(cwd, options.tag), logger.success(`Entered pre mode with tag ${chalk.cyan(options.tag)}`),
566 logger.info("Run `changeset version` to version packages with prerelease versions");
567 } catch (err) {
568 if (err instanceof errors.PreEnterButInPreModeError) throw logger.error("`changeset pre enter` cannot be run when in pre mode"),
569 logger.info("If you're trying to exit pre mode, run `changeset pre exit`"), new errors.ExitError(1);
570 throw err;
571 } else try {
572 await pre$1.exitPre(cwd), logger.success("Exited pre mode"), logger.info("Run `changeset version` to version packages with normal versions");
573 } catch (err) {
574 if (err instanceof errors.PreExitButNotInPreModeError) throw logger.error("`changeset pre exit` can only be run when in pre mode"),
575 logger.info("If you're trying to enter pre mode, run `changeset pre enter`"), new errors.ExitError(1);
576 throw err;
577 }
578}
579
580async function run$1(input, flags, cwd) {
581 if ("init" === input[0]) return void await init(cwd);
582 if (!fs.existsSync(path__default.resolve(cwd, ".changeset"))) throw logger.error("There is no .changeset folder. "),
583 logger.error("If this is the first time `changesets` have been used in this project, run `yarn changeset init` to get set up."),
584 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."),
585 new errors.ExitError(1);
586 const packages = await getPackages.getPackages(cwd);
587 let config$1;
588 try {
589 config$1 = await config.read(cwd, packages);
590 } catch (e) {
591 throw await fs.pathExists(path__default.resolve(cwd, ".changeset/config.js")) ? (logger.error("It looks like you're using the version 1 `.changeset/config.js` file"),
592 logger.error("You'll need to convert it to a `.changeset/config.json` file"), logger.error("The format of the config object has significantly changed in v2 as well"),
593 logger.error(" - we thoroughly recommend looking at the changelog for this package for what has changed"),
594 new errors.ExitError(1)) : e;
595 }
596 if (input.length < 1) {
597 const {empty: empty} = flags;
598 await add(cwd, {
599 empty: empty
600 }, config$1);
601 } else if ("pre" !== input[0] && input.length > 1) logger.error("Too many arguments passed to changesets - we only accept the command name as an argument"); else {
602 const {sinceMaster: sinceMaster, since: since, verbose: verbose, output: output, otp: otp, empty: empty, ignore: ignore, snapshot: snapshot, tag: tag} = flags;
603 switch ([ "updateChangelog", "isPublic", "skipCI", "commit" ].forEach(flag => {
604 if (flags[flag]) throw logger.error(`the flag ${flag} has been removed from changesets for version 2`),
605 logger.error("Please encode the desired value into your config"), logger.error("See our changelog for more details"),
606 new errors.ExitError(1);
607 }), input[0]) {
608 case "add":
609 return void await add(cwd, {
610 empty: empty
611 }, config$1);
612
613 case "version":
614 {
615 let ignoreArrayFromCmd;
616 ignoreArrayFromCmd = "string" == typeof ignore ? [ ignore ] : ignore;
617 let pkgNames = new Set(packages.packages.map(({packageJson: packageJson}) => packageJson.name));
618 const messages = [];
619 for (const pkgName of ignoreArrayFromCmd || []) pkgNames.has(pkgName) || 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.`);
620 config$1.ignore.length > 0 && ignoreArrayFromCmd ? 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.") : ignoreArrayFromCmd && (config$1.ignore = ignoreArrayFromCmd);
621 const dependentsGraph = getDependentsGraph.getDependentsGraph(packages);
622 for (const ignoredPackage of config$1.ignore) {
623 const dependents = dependentsGraph.get(ignoredPackage) || [];
624 for (const dependent of dependents) config$1.ignore.includes(dependent) || messages.push(`The package "${dependent}" depends on the ignored package "${ignoredPackage}", but "${dependent}" is not being ignored. Please pass "${dependent}" to the \`--ignore\` flag.`);
625 }
626 if (messages.length > 0) throw logger.error(messages.join("\n")), new errors.ExitError(1);
627 return void await version(cwd, {
628 snapshot: snapshot
629 }, config$1);
630 }
631
632 case "publish":
633 return void await run(cwd, {
634 otp: otp,
635 tag: tag
636 }, config$1);
637
638 case "status":
639 return void await getStatus(cwd, {
640 sinceMaster: sinceMaster,
641 since: since,
642 verbose: verbose,
643 output: output
644 }, config$1);
645
646 case "pre":
647 {
648 let command = input[1];
649 if ("enter" !== command && "exit" !== command) throw logger.error("`enter`, `exit` or `snapshot` must be passed after prerelease"),
650 new errors.ExitError(1);
651 let tag = input[2];
652 if ("enter" === command && "string" != typeof tag) throw logger.error("A tag must be passed when using prerelese enter"),
653 new errors.ExitError(1);
654 return void await pre(cwd, {
655 command: command,
656 tag: tag
657 });
658 }
659
660 case "bump":
661 throw logger.error('In version 2 of changesets, "bump" has been renamed to "version" - see our changelog for an explanation'),
662 logger.error("To fix this, use `changeset version` instead, and update any scripts that use changesets"),
663 new errors.ExitError(1);
664
665 case "release":
666 throw logger.error('In version 2 of changesets, "release" has been renamed to "publish" - see our changelog for an explanation'),
667 logger.error("To fix this, use `changeset publish` instead, and update any scripts that use changesets"),
668 new errors.ExitError(1);
669
670 default:
671 throw logger.error(`Invalid command ${input[0]} was provided`), new errors.ExitError(1);
672 }
673 }
674}
675
676const {input: input, flags: flags} = meow("\n Usage\n $ changesets [command]\n Commands\n init\n add [--empty]\n version [--ignore]\n publish [--otp=code]\n status [--since-master --verbose --output=JSON_FILE.json]\n prerelease <tag>\n ", {
677 flags: {
678 sinceMaster: {
679 type: "boolean"
680 },
681 verbose: {
682 type: "boolean",
683 alias: "v"
684 },
685 output: {
686 type: "string",
687 alias: "o"
688 },
689 otp: {
690 type: "string",
691 default: void 0
692 },
693 empty: {
694 type: "boolean"
695 },
696 since: {
697 type: "string",
698 default: void 0
699 },
700 ignore: {
701 type: "string",
702 default: void 0,
703 isMultiple: !0
704 },
705 tag: {
706 type: "string"
707 }
708 }
709}), cwd = process.cwd();
710
711run$1(input, flags, cwd).catch(err => {
712 if (err instanceof errors.InternalError && (logger.error("The following error is an internal unexpected error, these should never happen."),
713 logger.error("Please open an issue with the following link"), logger.error(`https://github.com/atlassian/changesets/issues/new?title=${encodeURIComponent(`Unexpected error during ${input[0] || "add"} command`)}&body=${encodeURIComponent(`## Error\n\n\`\`\`\n${util.format("", err).replace(process.cwd(), "<cwd>")}\n\`\`\`\n\n## Versions\n\n- @changesets/cli@${require("@changesets/cli/package.json").version}\n- node@${process.version}\n\n## Extra details\n\n\x3c!-- 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. 😁 --\x3e\n`)}`)),
714 err instanceof errors.ExitError) return process.exit(err.code);
715 logger.error(err), process.exit(1);
716});