@wpelevator/wp-release 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -6
- package/dist/changeset-config.d.ts +86 -2
- package/dist/changeset-config.js +101 -6
- package/dist/changeset-dependents.d.ts +19 -8
- package/dist/changeset-dependents.js +96 -34
- package/dist/changeset-files.d.ts +6 -5
- package/dist/changeset-files.js +7 -5
- package/dist/changeset-packages.d.ts +45 -8
- package/dist/changeset-packages.js +73 -14
- package/dist/changeset-prompt.d.ts +119 -0
- package/dist/changeset-prompt.js +203 -0
- package/dist/changeset-release.d.ts +38 -3
- package/dist/changeset-release.js +88 -11
- package/dist/changesets.d.ts +6 -2
- package/dist/changesets.js +18 -12
- package/dist/cli.d.ts +7 -1
- package/dist/cli.js +18 -5
- package/dist/commands/changeset-add.d.ts +5 -2
- package/dist/commands/changeset-add.js +108 -9
- package/dist/commands/changeset-args.d.ts +24 -5
- package/dist/commands/changeset-args.js +57 -14
- package/dist/commands/changeset-status.d.ts +2 -0
- package/dist/commands/changeset-tag.js +2 -1
- package/dist/commands/changeset-version.d.ts +6 -0
- package/dist/commands/changeset-version.js +15 -3
- package/dist/commands/command.d.ts +3 -0
- package/dist/commands/deploy-git.d.ts +24 -4
- package/dist/commands/deploy-git.js +56 -3
- package/dist/commands/deploy-svn.d.ts +24 -4
- package/dist/commands/deploy-svn.js +56 -2
- package/dist/commands/package-deploys.d.ts +78 -0
- package/dist/commands/package-deploys.js +108 -0
- package/dist/git-deploy.d.ts +32 -0
- package/dist/git-deploy.js +57 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +2 -1
- package/dist/package-deploy.d.ts +105 -0
- package/dist/package-deploy.js +288 -0
- package/dist/release-repository.d.ts +14 -2
- package/dist/release-repository.js +46 -7
- package/dist/release-tags.d.ts +3 -1
- package/dist/release-tags.js +5 -2
- package/dist/tag-format.d.ts +3 -3
- package/dist/tag-format.js +1 -1
- package/dist/version-files.d.ts +2 -1
- package/dist/version-files.js +12 -7
- package/dist/versions.d.ts +28 -3
- package/dist/versions.js +84 -9
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { getVersionedReleases, prependChangelog } from "./changelog.js";
|
|
|
3
3
|
import { loadChangesetConfig } from "./changeset-config.js";
|
|
4
4
|
import { applyDependents, assertDependentsSourcesReleased, collectPinDriftWarnings, expandDependentsPlan, findBundledPinChanges, hasChangeset, selectReleasePlan, stripDependentsPlan, updateDependencyDeclaration, } from "./changeset-dependents.js";
|
|
5
5
|
import { consumeChangeset, readChangesets, readChangesetsSince, writeChangeset, } from "./changeset-files.js";
|
|
6
|
-
import {
|
|
6
|
+
import { discoverPackages, getChangedPackages, resolvePackageNames, toChangesetPackage, } from "./changeset-packages.js";
|
|
7
7
|
import { getChangesetBump, getNextVersion } from "./changesets.js";
|
|
8
8
|
import { ValidationError } from "./errors.js";
|
|
9
9
|
import { FileJournal } from "./file-journal.js";
|
|
@@ -11,7 +11,7 @@ import { getPreviousTag, getReleaseNotes, getTagVersion, selectTagPackages, } fr
|
|
|
11
11
|
import { ReleaseRepository } from "./release-repository.js";
|
|
12
12
|
import { formatTag } from "./tag-format.js";
|
|
13
13
|
import { verifyVersionTargets, writeVersion } from "./version-files.js";
|
|
14
|
-
import { isPrerelease } from "./versions.js";
|
|
14
|
+
import { getPrereleaseVersion, getSnapshotVersion, isPrerelease, } from "./versions.js";
|
|
15
15
|
const MISSING_CONFIG = 'No wp-release config found. Add wp-release.config.js or pass --config <path>.';
|
|
16
16
|
/**
|
|
17
17
|
* Changeset releases of a repository: recording changesets, versioning the
|
|
@@ -67,8 +67,17 @@ export class ChangesetRelease {
|
|
|
67
67
|
async add(options) {
|
|
68
68
|
const config = await this.requireConfig();
|
|
69
69
|
const packages = await discoverPackages(this.repository, config);
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
const entries = Object.entries(options.packages);
|
|
71
|
+
const names = resolvePackageNames(packages, entries.map(([name]) => name));
|
|
72
|
+
const resolved = {};
|
|
73
|
+
entries.forEach(([, bump], index) => {
|
|
74
|
+
const name = names[index] ?? '';
|
|
75
|
+
if (Object.hasOwn(resolved, name)) {
|
|
76
|
+
throw new ValidationError(`Package "${name}" was passed more than once.`);
|
|
77
|
+
}
|
|
78
|
+
resolved[name] = bump;
|
|
79
|
+
});
|
|
80
|
+
return writeChangeset(this.getChangesetDirectory(config), resolved, options.summary, options.name);
|
|
72
81
|
}
|
|
73
82
|
/**
|
|
74
83
|
* Apply pending package versions and changelogs. A failed run restores
|
|
@@ -82,9 +91,12 @@ export class ChangesetRelease {
|
|
|
82
91
|
const context = await this.requireContext();
|
|
83
92
|
const { config, packages } = context;
|
|
84
93
|
const withDependents = options.dependents ?? true;
|
|
94
|
+
const selected = options.packages
|
|
95
|
+
? resolvePackageNames(packages, options.packages)
|
|
96
|
+
: undefined;
|
|
85
97
|
let releasePlan = context.plan;
|
|
86
|
-
if (
|
|
87
|
-
releasePlan = expandDependentsPlan(await selectReleasePlan(context.plan, packages,
|
|
98
|
+
if (selected) {
|
|
99
|
+
releasePlan = expandDependentsPlan(await selectReleasePlan(context.plan, packages, selected, config, withDependents));
|
|
88
100
|
}
|
|
89
101
|
else if (!withDependents) {
|
|
90
102
|
releasePlan = stripDependentsPlan(context.plan);
|
|
@@ -96,10 +108,31 @@ export class ChangesetRelease {
|
|
|
96
108
|
if (withDependents && config.dependents) {
|
|
97
109
|
await assertDependentsSourcesReleased(releasePlan, context.plan, packages, config);
|
|
98
110
|
}
|
|
111
|
+
if (undefined !== options.prerelease &&
|
|
112
|
+
undefined !== options.snapshot) {
|
|
113
|
+
throw new ValidationError('A release cannot be both a pre-release and a snapshot.');
|
|
114
|
+
}
|
|
115
|
+
if (undefined !== options.snapshot) {
|
|
116
|
+
const id = options.snapshot;
|
|
117
|
+
const time = options.snapshotTime ?? new Date();
|
|
118
|
+
releasePlan = {
|
|
119
|
+
...releasePlan,
|
|
120
|
+
releases: releasePlan.releases.map((release) => ({
|
|
121
|
+
...release,
|
|
122
|
+
nextVersion: getSnapshotVersion(release.nextVersion, id, time),
|
|
123
|
+
})),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (undefined !== options.prerelease) {
|
|
127
|
+
releasePlan = {
|
|
128
|
+
...releasePlan,
|
|
129
|
+
releases: await this.toPrereleases(context, releasePlan.releases, options.prerelease),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
99
132
|
const date = options.date ?? new Date().toISOString().slice(0, 10);
|
|
100
133
|
const releases = await getVersionedReleases(this.repository, config, releasePlan.releases, this.getChangesetDirectory(config));
|
|
101
134
|
if (!options.dryRun) {
|
|
102
|
-
await this.writeReleases(context, releasePlan, releases, date,
|
|
135
|
+
await this.writeReleases(context, releasePlan, releases, date, selected);
|
|
103
136
|
}
|
|
104
137
|
return {
|
|
105
138
|
changesets: releasePlan.changesets,
|
|
@@ -124,7 +157,7 @@ export class ChangesetRelease {
|
|
|
124
157
|
throw new ValidationError('Listing untagged releases cannot be combined with pushing tags.');
|
|
125
158
|
}
|
|
126
159
|
const context = await this.requireContext();
|
|
127
|
-
const selected = selectTagPackages(context.packages, options.packages ?? [], options.version);
|
|
160
|
+
const selected = selectTagPackages(context.packages, resolvePackageNames(context.packages, options.packages ?? []), options.version);
|
|
128
161
|
const packages = options.since
|
|
129
162
|
? (await getChangedPackages(this.repository, selected, options.since)).packages
|
|
130
163
|
: selected;
|
|
@@ -185,14 +218,23 @@ export class ChangesetRelease {
|
|
|
185
218
|
const since = options.since ??
|
|
186
219
|
(config.baseBranch ? `origin/${config.baseBranch}` : undefined);
|
|
187
220
|
const changed = since
|
|
188
|
-
? await getChangedPackages(this.repository, packages, since)
|
|
221
|
+
? await getChangedPackages(this.repository, packages, since, options.uncommitted)
|
|
189
222
|
: { packages: [], filesByPackage: {} };
|
|
190
223
|
const changedPackages = changed.packages.map((pkg) => pkg.name);
|
|
191
224
|
const changesetsInDiff = since
|
|
192
|
-
? await readChangesetsSince(this.repository, this.getChangesetDirectory(config), changesets, since)
|
|
225
|
+
? await readChangesetsSince(this.repository, this.getChangesetDirectory(config), changesets, since, options.uncommitted)
|
|
193
226
|
: [];
|
|
194
227
|
const hasEmptyChangeset = changesetsInDiff.some((changeset) => 0 === Object.keys(changeset.packages).length);
|
|
195
|
-
const bundled =
|
|
228
|
+
const bundled = since
|
|
229
|
+
? await findBundledPinChanges({
|
|
230
|
+
changed,
|
|
231
|
+
changesetsInDiff,
|
|
232
|
+
packages,
|
|
233
|
+
config,
|
|
234
|
+
repository: this.repository,
|
|
235
|
+
since,
|
|
236
|
+
})
|
|
237
|
+
: new Set();
|
|
196
238
|
const missingChangesets = hasEmptyChangeset
|
|
197
239
|
? []
|
|
198
240
|
: changedPackages.filter((name) => !hasChangeset(changesetsInDiff, name) &&
|
|
@@ -203,6 +245,7 @@ export class ChangesetRelease {
|
|
|
203
245
|
? await collectPinDriftWarnings(config, packages)
|
|
204
246
|
: [];
|
|
205
247
|
return {
|
|
248
|
+
...(since ? { since } : {}),
|
|
206
249
|
changesets,
|
|
207
250
|
releases,
|
|
208
251
|
changedPackages,
|
|
@@ -211,6 +254,40 @@ export class ChangesetRelease {
|
|
|
211
254
|
warnings,
|
|
212
255
|
};
|
|
213
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Turn the next versions of releases into pre-releases, like 1.3.0-rc.1
|
|
259
|
+
* for 1.3.0, numbered from the existing tags of each package. Dependents
|
|
260
|
+
* become pre-releases too, so they bundle the pre-releases of their sources.
|
|
261
|
+
*
|
|
262
|
+
* @param context Release context.
|
|
263
|
+
* @param releases Releases with their stable next versions.
|
|
264
|
+
* @param prerelease Pre-release identifier with an optional number, like rc or rc.1.
|
|
265
|
+
* @return Releases with their pre-release next versions.
|
|
266
|
+
* @throws {ValidationError} For an invalid pre-release or an existing version.
|
|
267
|
+
*/
|
|
268
|
+
async toPrereleases(context, releases, prerelease) {
|
|
269
|
+
const tagFormat = context.config.tagFormat ?? '{path}/{version}';
|
|
270
|
+
return Promise.all(releases.map(async (release) => {
|
|
271
|
+
const configured = context.packages.find((pkg) => pkg.name === release.package.name);
|
|
272
|
+
const versions = configured
|
|
273
|
+
? await this.listTaggedVersions(formatTag(tagFormat, configured, ''))
|
|
274
|
+
: [];
|
|
275
|
+
return {
|
|
276
|
+
...release,
|
|
277
|
+
nextVersion: getPrereleaseVersion(release.nextVersion, prerelease, versions),
|
|
278
|
+
};
|
|
279
|
+
}));
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* List the versions of the tags with a prefix.
|
|
283
|
+
*
|
|
284
|
+
* @param prefix Tag prefix of a package, like `plugins/alpha/`.
|
|
285
|
+
* @return Tagged versions.
|
|
286
|
+
*/
|
|
287
|
+
async listTaggedVersions(prefix) {
|
|
288
|
+
const tags = await this.repository.listTags(prefix);
|
|
289
|
+
return tags.map((tag) => tag.slice(prefix.length));
|
|
290
|
+
}
|
|
214
291
|
/**
|
|
215
292
|
* Write the versions, dependency specs and changelogs of the releases and
|
|
216
293
|
* consume the applied changesets, restoring every changed file when a
|
package/dist/changesets.d.ts
CHANGED
|
@@ -83,11 +83,15 @@ export declare function formatChangelogList(entries: string[]): string;
|
|
|
83
83
|
*/
|
|
84
84
|
export declare function getChangesetBump(changesets: Changeset[], packageName: string): ChangesetBump | undefined;
|
|
85
85
|
/**
|
|
86
|
-
* Calculate the next stable
|
|
86
|
+
* Calculate the next stable version using literal SemVer bump rules. Besides
|
|
87
|
+
* x.y.z, it accepts the x.y and x.y.z.w versions common in WordPress plugins:
|
|
88
|
+
* the bumped part is raised, the parts after it reset to 0, and the version
|
|
89
|
+
* keeps its number of parts, so a minor bump of 2.1 is 2.2 and of 1.2.3.4 is
|
|
90
|
+
* 1.3.0.0. A patch bump of x.y adds the third part, so 2.1 becomes 2.1.1.
|
|
87
91
|
*
|
|
88
92
|
* @param currentVersion Current package version.
|
|
89
93
|
* @param bump Requested bump.
|
|
90
94
|
* @return Next version.
|
|
91
|
-
* @throws {ValidationError} If currentVersion is not a stable x.y.z version.
|
|
95
|
+
* @throws {ValidationError} If currentVersion is not a stable x.y, x.y.z or x.y.z.w version.
|
|
92
96
|
*/
|
|
93
97
|
export declare function getNextVersion(currentVersion: string, bump: ChangesetBump): string;
|
package/dist/changesets.js
CHANGED
|
@@ -99,26 +99,32 @@ export function getChangesetBump(changesets, packageName) {
|
|
|
99
99
|
return bumps.sort((a, b) => BUMP_RANK[b] - BUMP_RANK[a])[0];
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
|
-
* Calculate the next stable
|
|
102
|
+
* Calculate the next stable version using literal SemVer bump rules. Besides
|
|
103
|
+
* x.y.z, it accepts the x.y and x.y.z.w versions common in WordPress plugins:
|
|
104
|
+
* the bumped part is raised, the parts after it reset to 0, and the version
|
|
105
|
+
* keeps its number of parts, so a minor bump of 2.1 is 2.2 and of 1.2.3.4 is
|
|
106
|
+
* 1.3.0.0. A patch bump of x.y adds the third part, so 2.1 becomes 2.1.1.
|
|
103
107
|
*
|
|
104
108
|
* @param currentVersion Current package version.
|
|
105
109
|
* @param bump Requested bump.
|
|
106
110
|
* @return Next version.
|
|
107
|
-
* @throws {ValidationError} If currentVersion is not a stable x.y.z version.
|
|
111
|
+
* @throws {ValidationError} If currentVersion is not a stable x.y, x.y.z or x.y.z.w version.
|
|
108
112
|
*/
|
|
109
113
|
export function getNextVersion(currentVersion, bump) {
|
|
110
114
|
if (!CHANGESET_BUMPS.includes(bump)) {
|
|
111
115
|
throw new ValidationError(`Invalid bump "${bump}"; expected patch, minor or major.`);
|
|
112
116
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
throw new ValidationError(`Cannot bump "${currentVersion}": expected a stable semantic version in x.y.z format.`);
|
|
117
|
+
if (!/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){1,3}$/.test(currentVersion)) {
|
|
118
|
+
throw new ValidationError(`Cannot bump "${currentVersion}": expected a stable version in x.y, x.y.z or x.y.z.w format.`);
|
|
116
119
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
const parts = currentVersion.split('.').map(Number);
|
|
121
|
+
const index = { major: 0, minor: 1, patch: 2 }[bump];
|
|
122
|
+
const length = Math.max(parts.length, index + 1);
|
|
123
|
+
return Array.from({ length }, (_, position) => {
|
|
124
|
+
const part = parts[position] ?? 0;
|
|
125
|
+
if (position === index) {
|
|
126
|
+
return part + 1;
|
|
127
|
+
}
|
|
128
|
+
return position < index ? part : 0;
|
|
129
|
+
}).join('.');
|
|
124
130
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -6,7 +6,13 @@ import type { ChangesetVersionResult } from './commands/changeset-version.ts';
|
|
|
6
6
|
import { Logger } from './logger.ts';
|
|
7
7
|
import type { OutputStream } from './logger.ts';
|
|
8
8
|
import type { Command, CommandOutcome } from './commands/command.ts';
|
|
9
|
+
/** Input stream that interactive prompts read from in a terminal. */
|
|
10
|
+
export type InputStream = NodeJS.ReadableStream & {
|
|
11
|
+
isTTY?: boolean;
|
|
12
|
+
};
|
|
9
13
|
export interface CliIo {
|
|
14
|
+
/** Input for interactive prompts, used when it and stdout are a terminal. */
|
|
15
|
+
stdin?: InputStream;
|
|
10
16
|
/** Stream for regular output. */
|
|
11
17
|
stdout?: OutputStream;
|
|
12
18
|
/** Stream for errors. */
|
|
@@ -74,7 +80,7 @@ export declare function execute<Name extends keyof CommandResults>(name: Name, a
|
|
|
74
80
|
* Run the CLI.
|
|
75
81
|
*
|
|
76
82
|
* @param args CLI arguments without the node and script paths.
|
|
77
|
-
* @param io
|
|
83
|
+
* @param io Input and output streams and working directory.
|
|
78
84
|
* @return Exit code.
|
|
79
85
|
*/
|
|
80
86
|
export declare function run(args: string[], io?: CliIo): Promise<number>;
|
package/dist/cli.js
CHANGED
|
@@ -176,11 +176,11 @@ function getGitHubOutputFile(values) {
|
|
|
176
176
|
*
|
|
177
177
|
* @param command Command definition with options and run().
|
|
178
178
|
* @param args Arguments after the command name.
|
|
179
|
-
* @param io
|
|
179
|
+
* @param io Input and output streams and working directory.
|
|
180
180
|
* @return Exit code.
|
|
181
181
|
*/
|
|
182
182
|
async function runCommand(command, args, io) {
|
|
183
|
-
const { stdout, stderr, cwd } = io;
|
|
183
|
+
const { stdin, stdout, stderr, cwd } = io;
|
|
184
184
|
let logger = new Logger({ writer: new TextWriter({ stdout, stderr }) });
|
|
185
185
|
try {
|
|
186
186
|
const { values, positionals } = parseArgs({
|
|
@@ -198,12 +198,20 @@ async function runCommand(command, args, io) {
|
|
|
198
198
|
quiet: getBoolean(values, 'quiet') || getBoolean(values, 'json'),
|
|
199
199
|
verbose: getBoolean(values, 'verbose'),
|
|
200
200
|
});
|
|
201
|
+
// Prompts need a person at a terminal, and would corrupt JSON output.
|
|
202
|
+
const interactive = true === stdin.isTTY &&
|
|
203
|
+
true === stdout.isTTY &&
|
|
204
|
+
!getBoolean(values, 'json') &&
|
|
205
|
+
!githubOutputFile;
|
|
201
206
|
const { exitCode, result } = await command.run({
|
|
202
207
|
values,
|
|
203
208
|
positionals,
|
|
204
209
|
cwd,
|
|
205
210
|
...(configFile ? { configFile } : {}),
|
|
206
211
|
logger,
|
|
212
|
+
...(interactive
|
|
213
|
+
? { terminal: { input: stdin, output: stdout } }
|
|
214
|
+
: {}),
|
|
207
215
|
});
|
|
208
216
|
if (getBoolean(values, 'json')) {
|
|
209
217
|
stdout.write(JSON.stringify(result, null, '\t') + '\n');
|
|
@@ -259,11 +267,11 @@ export async function execute(name, args, context) {
|
|
|
259
267
|
* Run the CLI.
|
|
260
268
|
*
|
|
261
269
|
* @param args CLI arguments without the node and script paths.
|
|
262
|
-
* @param io
|
|
270
|
+
* @param io Input and output streams and working directory.
|
|
263
271
|
* @return Exit code.
|
|
264
272
|
*/
|
|
265
273
|
export async function run(args, io = {}) {
|
|
266
|
-
const { stdout = process.stdout, stderr = process.stderr, cwd = process.cwd(), } = io;
|
|
274
|
+
const { stdin = process.stdin, stdout = process.stdout, stderr = process.stderr, cwd = process.cwd(), } = io;
|
|
267
275
|
const wantsHelp = args.includes('--help') || args.includes('-h');
|
|
268
276
|
const command = findCommand(args);
|
|
269
277
|
if (command && wantsHelp) {
|
|
@@ -271,7 +279,12 @@ export async function run(args, io = {}) {
|
|
|
271
279
|
return EXIT_SUCCESS;
|
|
272
280
|
}
|
|
273
281
|
if (command) {
|
|
274
|
-
return runCommand(command, args.slice(1), {
|
|
282
|
+
return runCommand(command, args.slice(1), {
|
|
283
|
+
stdin,
|
|
284
|
+
stdout,
|
|
285
|
+
stderr,
|
|
286
|
+
cwd,
|
|
287
|
+
});
|
|
275
288
|
}
|
|
276
289
|
if (0 === args.length || wantsHelp || 'help' === args[0]) {
|
|
277
290
|
stdout.write(getHelp() + '\n');
|
|
@@ -22,15 +22,18 @@ declare const _default: {
|
|
|
22
22
|
readonly empty: {
|
|
23
23
|
readonly type: "boolean";
|
|
24
24
|
};
|
|
25
|
+
readonly since: {
|
|
26
|
+
readonly type: "string";
|
|
27
|
+
};
|
|
25
28
|
readonly name: {
|
|
26
29
|
readonly type: "string";
|
|
27
30
|
};
|
|
28
31
|
};
|
|
29
|
-
run({ values, cwd, configFile, logger }: import("./command.ts").CommandContext): Promise<{
|
|
32
|
+
run({ values, cwd, configFile, logger, terminal }: import("./command.ts").CommandContext): Promise<{
|
|
30
33
|
exitCode: number;
|
|
31
34
|
result: {
|
|
32
35
|
file: string;
|
|
33
|
-
packages:
|
|
36
|
+
packages: any;
|
|
34
37
|
};
|
|
35
38
|
}>;
|
|
36
39
|
};
|
|
@@ -1,34 +1,133 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolvePackageNames } from "../changeset-packages.js";
|
|
2
|
+
import { ChangesetPrompt } from "../changeset-prompt.js";
|
|
3
|
+
import { ChangesetRelease } from "../changeset-release.js";
|
|
4
|
+
import { ValidationError } from "../errors.js";
|
|
2
5
|
import { parseChangesetAddArgs, changesetAddArgs } from "./changeset-args.js";
|
|
6
|
+
/**
|
|
7
|
+
* Get the bumps of the changed packages that have no changeset yet.
|
|
8
|
+
*
|
|
9
|
+
* @param release Changeset release of the repository.
|
|
10
|
+
* @param input Parsed options with the base ref.
|
|
11
|
+
* @param bump Bump of the changed packages.
|
|
12
|
+
* @return Bump of each changed package.
|
|
13
|
+
* @throws {ValidationError} If no changed package needs a changeset.
|
|
14
|
+
*/
|
|
15
|
+
async function getChangedPackageBumps(release, input, bump) {
|
|
16
|
+
const status = await release.getStatus({
|
|
17
|
+
...(input.since ? { since: input.since } : {}),
|
|
18
|
+
uncommitted: true,
|
|
19
|
+
});
|
|
20
|
+
if (!status.missingChangesets.length) {
|
|
21
|
+
const since = status.since ? ` since ${status.since}` : '';
|
|
22
|
+
throw new ValidationError(`No package changed${since} without a changeset. Pass --package <name> to choose the packages.`);
|
|
23
|
+
}
|
|
24
|
+
return Object.fromEntries(status.missingChangesets.map((name) => [name, bump]));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Ask for the changeset, preselecting the changed packages without one.
|
|
28
|
+
*
|
|
29
|
+
* @param release Changeset release of the repository.
|
|
30
|
+
* @param input Parsed options with the base ref and release note.
|
|
31
|
+
* @param terminal Terminal to ask in.
|
|
32
|
+
* @return Package bumps and release note.
|
|
33
|
+
*/
|
|
34
|
+
async function askChangeset(release, input, terminal) {
|
|
35
|
+
const packages = await release.getPackages();
|
|
36
|
+
const status = await release.getStatus({
|
|
37
|
+
...(input.since ? { since: input.since } : {}),
|
|
38
|
+
uncommitted: true,
|
|
39
|
+
});
|
|
40
|
+
const prompt = new ChangesetPrompt(terminal);
|
|
41
|
+
try {
|
|
42
|
+
return await prompt.ask({
|
|
43
|
+
packages,
|
|
44
|
+
changed: status.missingChangesets,
|
|
45
|
+
...(status.since ? { since: status.since } : {}),
|
|
46
|
+
...(input.summary ? { summary: input.summary } : {}),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
prompt.close();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the package bumps and release note from the options, the changed
|
|
55
|
+
* packages or the prompts.
|
|
56
|
+
*
|
|
57
|
+
* @param release Changeset release of the repository.
|
|
58
|
+
* @param input Parsed options.
|
|
59
|
+
* @param terminal Terminal to ask in, when the CLI runs in one.
|
|
60
|
+
* @return Package bumps, empty for no release, and release note.
|
|
61
|
+
* @throws {ValidationError} Without packages outside a terminal.
|
|
62
|
+
*/
|
|
63
|
+
async function getChangeset(release, input, terminal) {
|
|
64
|
+
const summary = input.summary ?? '';
|
|
65
|
+
let changeset;
|
|
66
|
+
if (input.empty) {
|
|
67
|
+
changeset = { packages: {}, summary };
|
|
68
|
+
}
|
|
69
|
+
else if (Object.keys(input.packages).length) {
|
|
70
|
+
changeset = { packages: input.packages, summary };
|
|
71
|
+
}
|
|
72
|
+
else if (input.bump) {
|
|
73
|
+
changeset = {
|
|
74
|
+
packages: await getChangedPackageBumps(release, input, input.bump),
|
|
75
|
+
summary,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
else if (terminal) {
|
|
79
|
+
changeset = await askChangeset(release, input, terminal);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
throw new ValidationError('Pass matching repeated --package <name> and --bump <patch|minor|major> options, a single --bump for the changed packages, or --empty.');
|
|
83
|
+
}
|
|
84
|
+
return changeset;
|
|
85
|
+
}
|
|
3
86
|
export default {
|
|
4
87
|
name: 'changeset-add',
|
|
5
|
-
usage: 'changeset-add
|
|
88
|
+
usage: 'changeset-add [--empty | --package <name> --bump <bump> ... | --bump <bump>] [options]',
|
|
6
89
|
summary: 'Add a package release note for the next release PR.',
|
|
7
90
|
help: `Options:
|
|
8
|
-
--package <name> Package identifier
|
|
91
|
+
--package <name> Package identifier, or its path under the configured
|
|
92
|
+
root (repeatable)
|
|
9
93
|
--bump <bump> patch, minor or major (repeatable, in package order)
|
|
10
94
|
--summary <text> Customer-facing release note
|
|
11
95
|
--empty Record that this change does not need a release
|
|
96
|
+
--since <ref> Compare changed files with this git ref (default:
|
|
97
|
+
origin/<baseBranch>)
|
|
12
98
|
--name <name> Changeset filename (default: random identifier)
|
|
13
99
|
|
|
14
100
|
Use --package and --bump pairs for package releases, or --empty for changes
|
|
15
|
-
that should pass the status check without producing a release
|
|
101
|
+
that should pass the status check without producing a release. A single
|
|
102
|
+
--bump without --package releases the packages that changed since the base
|
|
103
|
+
ref, including uncommitted files, and have no changeset yet. Without
|
|
104
|
+
--package and --bump in a terminal, the command asks for the packages, with
|
|
105
|
+
the changed ones preselected, their bumps and the release note.`,
|
|
16
106
|
options: changesetAddArgs,
|
|
17
|
-
async run({ values, cwd, configFile, logger }) {
|
|
107
|
+
async run({ values, cwd, configFile, logger, terminal }) {
|
|
18
108
|
const input = parseChangesetAddArgs(values);
|
|
19
|
-
const
|
|
109
|
+
const release = new ChangesetRelease({
|
|
20
110
|
cwd,
|
|
21
111
|
...(configFile ? { configFile } : {}),
|
|
22
|
-
|
|
23
|
-
|
|
112
|
+
});
|
|
113
|
+
const changeset = await getChangeset(release, input, terminal);
|
|
114
|
+
// Adding resolves the package paths and rejects a package passed twice.
|
|
115
|
+
const file = await release.add({
|
|
116
|
+
packages: changeset.packages,
|
|
117
|
+
summary: changeset.summary,
|
|
24
118
|
...(input.name ? { name: input.name } : {}),
|
|
25
119
|
});
|
|
120
|
+
const names = resolvePackageNames(await release.getPackages(), Object.keys(changeset.packages));
|
|
121
|
+
const packages = Object.fromEntries(Object.values(changeset.packages).map((bump, index) => [
|
|
122
|
+
names[index],
|
|
123
|
+
bump,
|
|
124
|
+
]));
|
|
26
125
|
logger.info(`Created ${file}.`);
|
|
27
126
|
return {
|
|
28
127
|
exitCode: 0,
|
|
29
128
|
result: {
|
|
30
129
|
file,
|
|
31
|
-
packages
|
|
130
|
+
packages,
|
|
32
131
|
},
|
|
33
132
|
};
|
|
34
133
|
},
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import type { ChangesetPackages } from '../changesets.ts';
|
|
1
|
+
import type { ChangesetBump, ChangesetPackages } from '../changesets.ts';
|
|
2
2
|
import type { ParsedValues } from './command.ts';
|
|
3
3
|
/** Parsed input for `changeset-add`. */
|
|
4
4
|
export interface ChangesetAddArgs {
|
|
5
|
+
/** Bump of each package passed with --package, by identifier or path. */
|
|
5
6
|
packages: ChangesetPackages;
|
|
6
|
-
|
|
7
|
+
/** Bump for the changed packages without a changeset, passed without --package. */
|
|
8
|
+
bump?: ChangesetBump;
|
|
9
|
+
summary?: string;
|
|
7
10
|
empty: boolean;
|
|
11
|
+
since?: string;
|
|
8
12
|
name?: string;
|
|
9
13
|
}
|
|
10
14
|
/** Parse-args options for `changeset-add`. */
|
|
@@ -23,16 +27,21 @@ export declare const changesetAddArgs: {
|
|
|
23
27
|
readonly empty: {
|
|
24
28
|
readonly type: "boolean";
|
|
25
29
|
};
|
|
30
|
+
readonly since: {
|
|
31
|
+
readonly type: "string";
|
|
32
|
+
};
|
|
26
33
|
readonly name: {
|
|
27
34
|
readonly type: "string";
|
|
28
35
|
};
|
|
29
36
|
};
|
|
30
37
|
/**
|
|
31
|
-
* Parse and validate the `changeset-add` options.
|
|
38
|
+
* Parse and validate the `changeset-add` options. Without --package, a
|
|
39
|
+
* single --bump applies to the changed packages without a changeset, and
|
|
40
|
+
* without --bump either the command asks for the changeset in a terminal.
|
|
32
41
|
*
|
|
33
42
|
* @param values Parsed CLI options.
|
|
34
43
|
* @return Normalized changeset input.
|
|
35
|
-
* @throws {ValidationError} If
|
|
44
|
+
* @throws {ValidationError} If options are conflicting or incomplete.
|
|
36
45
|
*/
|
|
37
46
|
export declare function parseChangesetAddArgs(values: ParsedValues): ChangesetAddArgs;
|
|
38
47
|
/** Parse-args options for `changeset-status`. */
|
|
@@ -68,6 +77,12 @@ export declare const changesetVersionArgs: {
|
|
|
68
77
|
readonly 'no-dependents': {
|
|
69
78
|
readonly type: "boolean";
|
|
70
79
|
};
|
|
80
|
+
readonly prerelease: {
|
|
81
|
+
readonly type: "string";
|
|
82
|
+
};
|
|
83
|
+
readonly snapshot: {
|
|
84
|
+
readonly type: "string";
|
|
85
|
+
};
|
|
71
86
|
};
|
|
72
87
|
/** Parsed input for `changeset-version`. */
|
|
73
88
|
export interface ChangesetVersionArgs {
|
|
@@ -76,6 +91,10 @@ export interface ChangesetVersionArgs {
|
|
|
76
91
|
packages?: string[];
|
|
77
92
|
/** Whether the selected sources release their configured dependents; defaults to true. */
|
|
78
93
|
dependents: boolean;
|
|
94
|
+
/** Pre-release identifier with an optional number, like rc or rc.1. */
|
|
95
|
+
prerelease?: string;
|
|
96
|
+
/** Snapshot identifier, like pr-251. */
|
|
97
|
+
snapshot?: string;
|
|
79
98
|
}
|
|
80
99
|
/**
|
|
81
100
|
* Validate and normalize a release date option.
|
|
@@ -90,7 +109,7 @@ export declare function parseChangesetDate(value: string | undefined): string |
|
|
|
90
109
|
*
|
|
91
110
|
* @param values Parsed CLI options.
|
|
92
111
|
* @return Normalized versioning input.
|
|
93
|
-
* @throws {ValidationError} If --date is invalid.
|
|
112
|
+
* @throws {ValidationError} If --date is invalid, or an option is empty or conflicting.
|
|
94
113
|
*/
|
|
95
114
|
export declare function parseChangesetVersionArgs(values: ParsedValues): ChangesetVersionArgs;
|
|
96
115
|
/** Parse-args options for `changeset-tag`. */
|