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