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