@wpelevator/wp-release 0.5.0 → 0.6.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 +67 -0
- package/dist/changeset-config.d.ts +189 -0
- package/dist/changeset-config.js +273 -0
- package/dist/changeset-release.d.ts +74 -0
- package/dist/changeset-release.js +829 -0
- package/dist/changesets.d.ts +72 -0
- package/dist/changesets.js +103 -0
- package/dist/cli.d.ts +12 -5
- package/dist/cli.js +28 -7
- package/dist/commands/changeset-add.d.ts +37 -0
- package/dist/commands/changeset-add.js +35 -0
- package/dist/commands/changeset-args.d.ts +114 -0
- package/dist/commands/changeset-args.js +139 -0
- package/dist/commands/changeset-status.d.ts +43 -0
- package/dist/commands/changeset-status.js +65 -0
- package/dist/commands/changeset-tag.d.ts +25 -0
- package/dist/commands/changeset-tag.js +27 -0
- package/dist/commands/changeset-version.d.ts +38 -0
- package/dist/commands/changeset-version.js +39 -0
- package/dist/commands/command.d.ts +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type { ChangesetConfig } from './changeset-config.ts';
|
|
2
|
+
export declare const CHANGESET_BUMPS: readonly ["patch", "minor", "major"];
|
|
3
|
+
export type ChangesetBump = (typeof CHANGESET_BUMPS)[number];
|
|
4
|
+
export type ChangesetPackages = Record<string, ChangesetBump>;
|
|
5
|
+
/** A parsed Changesets-compatible Markdown file. */
|
|
6
|
+
export interface Changeset {
|
|
7
|
+
/** File name relative to .changeset/, including the .md extension. */
|
|
8
|
+
fileName: string;
|
|
9
|
+
/** Package names and their requested version bumps; empty for a no-release changeset. */
|
|
10
|
+
packages: ChangesetPackages;
|
|
11
|
+
/** Customer-facing release note. */
|
|
12
|
+
summary: string;
|
|
13
|
+
}
|
|
14
|
+
export type ChangesetPackageType = 'plugin' | 'theme' | 'npm' | 'other';
|
|
15
|
+
/** A package discovered from repository configuration and its version files. */
|
|
16
|
+
export interface ChangesetPackage {
|
|
17
|
+
/** Changeset-facing identifier (package.json name or configured path id). */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Absolute package directory. */
|
|
20
|
+
directory: string;
|
|
21
|
+
/** Package path relative to the configured root. */
|
|
22
|
+
path: string;
|
|
23
|
+
type: ChangesetPackageType;
|
|
24
|
+
/** Version read from the package's authoritative version source. */
|
|
25
|
+
currentVersion: string;
|
|
26
|
+
}
|
|
27
|
+
/** One package's proposed release in a release plan. */
|
|
28
|
+
export interface PackageRelease {
|
|
29
|
+
package: ChangesetPackage;
|
|
30
|
+
bump: ChangesetBump;
|
|
31
|
+
currentVersion: string;
|
|
32
|
+
nextVersion: string;
|
|
33
|
+
changesets: Changeset[];
|
|
34
|
+
}
|
|
35
|
+
/** Deterministic release plan assembled from pending changesets. */
|
|
36
|
+
export interface ChangesetReleasePlan {
|
|
37
|
+
changesets: Changeset[];
|
|
38
|
+
releases: PackageRelease[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parse the supported subset of Changesets' Markdown format.
|
|
42
|
+
*
|
|
43
|
+
* @param contents Markdown contents.
|
|
44
|
+
* @param fileName File name relative to .changeset/.
|
|
45
|
+
* @return Parsed changeset.
|
|
46
|
+
* @throws {ValidationError} If the frontmatter or package bumps are invalid.
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseChangeset(contents: string, fileName?: string): Changeset;
|
|
49
|
+
/**
|
|
50
|
+
* Serialize a changeset using the standard Markdown frontmatter format.
|
|
51
|
+
*
|
|
52
|
+
* @param changeset Parsed changeset values.
|
|
53
|
+
* @return Markdown contents with a trailing newline.
|
|
54
|
+
*/
|
|
55
|
+
export declare function formatChangeset(changeset: Omit<Changeset, 'fileName'>): string;
|
|
56
|
+
/**
|
|
57
|
+
* Return the strongest bump requested for a package across changesets.
|
|
58
|
+
*
|
|
59
|
+
* @param changesets Pending changesets.
|
|
60
|
+
* @param packageName Package identifier.
|
|
61
|
+
* @return Highest bump, or undefined when no changeset mentions the package.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getChangesetBump(changesets: Changeset[], packageName: string): ChangesetBump | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Calculate the next stable semantic version using literal SemVer bump rules.
|
|
66
|
+
*
|
|
67
|
+
* @param currentVersion Current package version.
|
|
68
|
+
* @param bump Requested bump.
|
|
69
|
+
* @return Next version.
|
|
70
|
+
* @throws {ValidationError} If currentVersion is not a stable x.y.z version.
|
|
71
|
+
*/
|
|
72
|
+
export declare function getNextVersion(currentVersion: string, bump: ChangesetBump): string;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { ValidationError } from "./errors.js";
|
|
2
|
+
export const CHANGESET_BUMPS = ['patch', 'minor', 'major'];
|
|
3
|
+
const BUMP_RANK = {
|
|
4
|
+
patch: 0,
|
|
5
|
+
minor: 1,
|
|
6
|
+
major: 2,
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Parse the supported subset of Changesets' Markdown format.
|
|
10
|
+
*
|
|
11
|
+
* @param contents Markdown contents.
|
|
12
|
+
* @param fileName File name relative to .changeset/.
|
|
13
|
+
* @return Parsed changeset.
|
|
14
|
+
* @throws {ValidationError} If the frontmatter or package bumps are invalid.
|
|
15
|
+
*/
|
|
16
|
+
export function parseChangeset(contents, fileName = 'changeset.md') {
|
|
17
|
+
const lines = contents.replace(/^\uFEFF/, '').split(/\r?\n/);
|
|
18
|
+
if ('---' !== lines[0]) {
|
|
19
|
+
throw new ValidationError(`Changeset ${fileName} must start with YAML frontmatter (---).`);
|
|
20
|
+
}
|
|
21
|
+
const closingLine = lines.indexOf('---', 1);
|
|
22
|
+
if (-1 === closingLine) {
|
|
23
|
+
throw new ValidationError(`Changeset ${fileName} is missing the closing frontmatter delimiter.`);
|
|
24
|
+
}
|
|
25
|
+
const packages = {};
|
|
26
|
+
const frontmatter = lines.slice(1, closingLine);
|
|
27
|
+
frontmatter.forEach((line, index) => {
|
|
28
|
+
if (line.trim()) {
|
|
29
|
+
const match = /^\s*(?:"((?:[^"\\]|\\.)+)"|'([^']+)'|([^:#]+))\s*:\s*(patch|minor|major)\s*$/.exec(line);
|
|
30
|
+
if (!match) {
|
|
31
|
+
throw new ValidationError(`Invalid package bump on line ${index + 2} of changeset ${fileName}.`);
|
|
32
|
+
}
|
|
33
|
+
const name = (match[1] ?? match[2] ?? match[3] ?? '')
|
|
34
|
+
.replaceAll('\\"', '"')
|
|
35
|
+
.trim();
|
|
36
|
+
if (!name) {
|
|
37
|
+
throw new ValidationError(`Package name is empty on line ${index + 2} of changeset ${fileName}.`);
|
|
38
|
+
}
|
|
39
|
+
if (Object.hasOwn(packages, name)) {
|
|
40
|
+
throw new ValidationError(`Package "${name}" appears more than once in changeset ${fileName}.`);
|
|
41
|
+
}
|
|
42
|
+
packages[name] = match[4];
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
fileName,
|
|
47
|
+
packages,
|
|
48
|
+
summary: lines
|
|
49
|
+
.slice(closingLine + 1)
|
|
50
|
+
.join('\n')
|
|
51
|
+
.trim(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Serialize a changeset using the standard Markdown frontmatter format.
|
|
56
|
+
*
|
|
57
|
+
* @param changeset Parsed changeset values.
|
|
58
|
+
* @return Markdown contents with a trailing newline.
|
|
59
|
+
*/
|
|
60
|
+
export function formatChangeset(changeset) {
|
|
61
|
+
const entries = Object.entries(changeset.packages).sort((a, b) => a[0].localeCompare(b[0]));
|
|
62
|
+
const frontmatter = entries
|
|
63
|
+
.map(([name, bump]) => `${JSON.stringify(name)}: ${bump}`)
|
|
64
|
+
.join('\n');
|
|
65
|
+
return `---\n${frontmatter}\n---\n\n${changeset.summary.trim()}\n`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Return the strongest bump requested for a package across changesets.
|
|
69
|
+
*
|
|
70
|
+
* @param changesets Pending changesets.
|
|
71
|
+
* @param packageName Package identifier.
|
|
72
|
+
* @return Highest bump, or undefined when no changeset mentions the package.
|
|
73
|
+
*/
|
|
74
|
+
export function getChangesetBump(changesets, packageName) {
|
|
75
|
+
const bumps = changesets
|
|
76
|
+
.map((changeset) => changeset.packages[packageName])
|
|
77
|
+
.filter((bump) => Boolean(bump));
|
|
78
|
+
return bumps.sort((a, b) => BUMP_RANK[b] - BUMP_RANK[a])[0];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Calculate the next stable semantic version using literal SemVer bump rules.
|
|
82
|
+
*
|
|
83
|
+
* @param currentVersion Current package version.
|
|
84
|
+
* @param bump Requested bump.
|
|
85
|
+
* @return Next version.
|
|
86
|
+
* @throws {ValidationError} If currentVersion is not a stable x.y.z version.
|
|
87
|
+
*/
|
|
88
|
+
export function getNextVersion(currentVersion, bump) {
|
|
89
|
+
if (!CHANGESET_BUMPS.includes(bump)) {
|
|
90
|
+
throw new ValidationError(`Invalid bump "${bump}"; expected patch, minor or major.`);
|
|
91
|
+
}
|
|
92
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(currentVersion);
|
|
93
|
+
if (!match) {
|
|
94
|
+
throw new ValidationError(`Cannot bump "${currentVersion}": expected a stable semantic version in x.y.z format.`);
|
|
95
|
+
}
|
|
96
|
+
if ('major' === bump) {
|
|
97
|
+
return `${Number(match[1]) + 1}.0.0`;
|
|
98
|
+
}
|
|
99
|
+
if ('minor' === bump) {
|
|
100
|
+
return `${match[1]}.${Number(match[2]) + 1}.0`;
|
|
101
|
+
}
|
|
102
|
+
return `${match[1]}.${match[2]}.${Number(match[3]) + 1}`;
|
|
103
|
+
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ChecksumsResult } from './commands/checksums.ts';
|
|
2
2
|
import type { SignResult } from './commands/sign.ts';
|
|
3
3
|
import type { ZipResult } from './commands/zip.ts';
|
|
4
|
+
import type { ChangesetVersionResult } from './commands/changeset-version.ts';
|
|
4
5
|
import { Logger } from './logger.ts';
|
|
5
6
|
import type { OutputStream } from './logger.ts';
|
|
6
7
|
import type { Command, CommandOutcome } from './commands/command.ts';
|
|
@@ -43,23 +44,29 @@ export interface CommandResults {
|
|
|
43
44
|
zip: ZipResult;
|
|
44
45
|
checksums: ChecksumsResult;
|
|
45
46
|
sign: SignResult;
|
|
47
|
+
'changeset-add': import('./commands/changeset-add.ts').ChangesetAddResult;
|
|
48
|
+
'changeset-status': import('./commands/changeset-status.ts').ChangesetStatusResult;
|
|
49
|
+
'changeset-version': ChangesetVersionResult;
|
|
50
|
+
'changeset-tag': import('./changeset-release.ts').ChangesetTagResult;
|
|
46
51
|
}
|
|
47
52
|
/**
|
|
48
53
|
* Run a command by name with the given arguments, for wrappers like the
|
|
49
54
|
* GitHub Actions that need the result and the thrown errors instead of an
|
|
50
55
|
* exit code.
|
|
51
56
|
*
|
|
52
|
-
* @param name
|
|
53
|
-
* @param args
|
|
54
|
-
* @param context
|
|
55
|
-
* @param context.cwd
|
|
56
|
-
* @param context.
|
|
57
|
+
* @param name Command name, such as zip.
|
|
58
|
+
* @param args Arguments after the command name.
|
|
59
|
+
* @param context Working directory and logger.
|
|
60
|
+
* @param context.cwd Working directory that relative paths resolve against.
|
|
61
|
+
* @param context.configFile Explicit config file path, when supplied by a wrapper.
|
|
62
|
+
* @param context.logger Logger for the command output.
|
|
57
63
|
* @return Exit code and result of the command.
|
|
58
64
|
* @throws {Error} If the command is unknown, the arguments are invalid or the command fails.
|
|
59
65
|
*/
|
|
60
66
|
export declare function execute<Name extends keyof CommandResults>(name: Name, args: string[], context: {
|
|
61
67
|
cwd: string;
|
|
62
68
|
logger: Logger;
|
|
69
|
+
configFile?: string;
|
|
63
70
|
}): Promise<CommandOutcome<CommandResults[Name]>>;
|
|
64
71
|
/**
|
|
65
72
|
* Run the CLI.
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,10 @@ import { getBoolean, getString } from "./commands/command.js";
|
|
|
10
10
|
import { ValidationError } from "./errors.js";
|
|
11
11
|
import { GitHubActionsWriter } from "./github-actions-writer.js";
|
|
12
12
|
import { logError } from "./report.js";
|
|
13
|
+
import changesetAdd from "./commands/changeset-add.js";
|
|
14
|
+
import changesetStatus from "./commands/changeset-status.js";
|
|
15
|
+
import changesetVersion from "./commands/changeset-version.js";
|
|
16
|
+
import changesetTag from "./commands/changeset-tag.js";
|
|
13
17
|
export const EXIT_SUCCESS = 0;
|
|
14
18
|
export const EXIT_FAILURE = 1;
|
|
15
19
|
export const EXIT_INVALID = 2;
|
|
@@ -20,6 +24,10 @@ export const commands = [
|
|
|
20
24
|
verify,
|
|
21
25
|
versionCheck,
|
|
22
26
|
deploySvn,
|
|
27
|
+
changesetAdd,
|
|
28
|
+
changesetStatus,
|
|
29
|
+
changesetVersion,
|
|
30
|
+
changesetTag,
|
|
23
31
|
];
|
|
24
32
|
const globalArgs = {
|
|
25
33
|
help: { type: 'boolean', short: 'h' },
|
|
@@ -28,6 +36,7 @@ const globalArgs = {
|
|
|
28
36
|
'log-format': { type: 'string' },
|
|
29
37
|
ci: { type: 'boolean' },
|
|
30
38
|
json: { type: 'boolean' },
|
|
39
|
+
config: { type: 'string' },
|
|
31
40
|
};
|
|
32
41
|
const globalOptions = `Global options:
|
|
33
42
|
-h, --help Show help for the command
|
|
@@ -37,7 +46,8 @@ const globalOptions = `Global options:
|
|
|
37
46
|
annotations and job summaries (default: github
|
|
38
47
|
when GITHUB_ACTIONS=true, otherwise text)
|
|
39
48
|
--ci Same as --log-format github
|
|
40
|
-
--json Print the result as JSON
|
|
49
|
+
--json Print the result as JSON
|
|
50
|
+
--config <path> Path to a JavaScript release config file`;
|
|
41
51
|
/**
|
|
42
52
|
* Get the top-level help text listing all commands.
|
|
43
53
|
*
|
|
@@ -155,6 +165,10 @@ async function runCommand(command, args, io) {
|
|
|
155
165
|
options: { ...globalArgs, ...command.options },
|
|
156
166
|
allowPositionals: true,
|
|
157
167
|
});
|
|
168
|
+
const configFile = getString(values, 'config');
|
|
169
|
+
if ('' === configFile?.trim()) {
|
|
170
|
+
throw new ValidationError('--config <path> must not be empty.');
|
|
171
|
+
}
|
|
158
172
|
logger = new Logger({
|
|
159
173
|
writer: createLogWriter(values, { stdout, stderr }),
|
|
160
174
|
quiet: getBoolean(values, 'quiet') || getBoolean(values, 'json'),
|
|
@@ -164,6 +178,7 @@ async function runCommand(command, args, io) {
|
|
|
164
178
|
values,
|
|
165
179
|
positionals,
|
|
166
180
|
cwd,
|
|
181
|
+
...(configFile ? { configFile } : {}),
|
|
167
182
|
logger,
|
|
168
183
|
});
|
|
169
184
|
if (getBoolean(values, 'json')) {
|
|
@@ -181,11 +196,12 @@ async function runCommand(command, args, io) {
|
|
|
181
196
|
* GitHub Actions that need the result and the thrown errors instead of an
|
|
182
197
|
* exit code.
|
|
183
198
|
*
|
|
184
|
-
* @param name
|
|
185
|
-
* @param args
|
|
186
|
-
* @param context
|
|
187
|
-
* @param context.cwd
|
|
188
|
-
* @param context.
|
|
199
|
+
* @param name Command name, such as zip.
|
|
200
|
+
* @param args Arguments after the command name.
|
|
201
|
+
* @param context Working directory and logger.
|
|
202
|
+
* @param context.cwd Working directory that relative paths resolve against.
|
|
203
|
+
* @param context.configFile Explicit config file path, when supplied by a wrapper.
|
|
204
|
+
* @param context.logger Logger for the command output.
|
|
189
205
|
* @return Exit code and result of the command.
|
|
190
206
|
* @throws {Error} If the command is unknown, the arguments are invalid or the command fails.
|
|
191
207
|
*/
|
|
@@ -196,14 +212,19 @@ export async function execute(name, args, context) {
|
|
|
196
212
|
}
|
|
197
213
|
const { values, positionals } = parseArgs({
|
|
198
214
|
args,
|
|
199
|
-
options: command.options,
|
|
215
|
+
options: { ...globalArgs, ...command.options },
|
|
200
216
|
allowPositionals: true,
|
|
201
217
|
});
|
|
218
|
+
const configFile = getString(values, 'config') ?? context.configFile;
|
|
219
|
+
if ('' === configFile?.trim()) {
|
|
220
|
+
throw new ValidationError('--config <path> must not be empty.');
|
|
221
|
+
}
|
|
202
222
|
// The command table is keyed by name, so the result matches CommandResults.
|
|
203
223
|
return command.run({
|
|
204
224
|
values,
|
|
205
225
|
positionals,
|
|
206
226
|
...context,
|
|
227
|
+
...(configFile ? { configFile } : {}),
|
|
207
228
|
});
|
|
208
229
|
}
|
|
209
230
|
/**
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface ChangesetAddResult {
|
|
2
|
+
file: string;
|
|
3
|
+
packages: Record<string, string>;
|
|
4
|
+
}
|
|
5
|
+
declare const _default: {
|
|
6
|
+
name: string;
|
|
7
|
+
usage: string;
|
|
8
|
+
summary: string;
|
|
9
|
+
help: string;
|
|
10
|
+
options: {
|
|
11
|
+
readonly package: {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
readonly multiple: true;
|
|
14
|
+
};
|
|
15
|
+
readonly bump: {
|
|
16
|
+
readonly type: "string";
|
|
17
|
+
readonly multiple: true;
|
|
18
|
+
};
|
|
19
|
+
readonly summary: {
|
|
20
|
+
readonly type: "string";
|
|
21
|
+
};
|
|
22
|
+
readonly empty: {
|
|
23
|
+
readonly type: "boolean";
|
|
24
|
+
};
|
|
25
|
+
readonly name: {
|
|
26
|
+
readonly type: "string";
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
run({ values, cwd, configFile, logger }: import("./command.ts").CommandContext): Promise<{
|
|
30
|
+
exitCode: number;
|
|
31
|
+
result: {
|
|
32
|
+
file: string;
|
|
33
|
+
packages: import("../changesets.ts").ChangesetPackages;
|
|
34
|
+
};
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
export default _default;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { addChangeset } from "../changeset-release.js";
|
|
2
|
+
import { parseChangesetAddArgs, changesetAddArgs } from "./changeset-args.js";
|
|
3
|
+
export default {
|
|
4
|
+
name: 'changeset-add',
|
|
5
|
+
usage: 'changeset-add (--empty | --package <name> --bump <bump> ...) [options]',
|
|
6
|
+
summary: 'Add a package release note for the next release PR.',
|
|
7
|
+
help: `Options:
|
|
8
|
+
--package <name> Package identifier (repeatable)
|
|
9
|
+
--bump <bump> patch, minor or major (repeatable, in package order)
|
|
10
|
+
--summary <text> Customer-facing release note
|
|
11
|
+
--empty Record that this change does not need a release
|
|
12
|
+
--name <name> Changeset filename (default: random identifier)
|
|
13
|
+
|
|
14
|
+
Use --package and --bump pairs for package releases, or --empty for changes
|
|
15
|
+
that should pass the status check without producing a release.`,
|
|
16
|
+
options: changesetAddArgs,
|
|
17
|
+
async run({ values, cwd, configFile, logger }) {
|
|
18
|
+
const input = parseChangesetAddArgs(values);
|
|
19
|
+
const file = await addChangeset({
|
|
20
|
+
cwd,
|
|
21
|
+
...(configFile ? { configFile } : {}),
|
|
22
|
+
packages: input.packages,
|
|
23
|
+
summary: input.summary,
|
|
24
|
+
...(input.name ? { name: input.name } : {}),
|
|
25
|
+
});
|
|
26
|
+
logger.info(`Created ${file}.`);
|
|
27
|
+
return {
|
|
28
|
+
exitCode: 0,
|
|
29
|
+
result: {
|
|
30
|
+
file,
|
|
31
|
+
packages: input.packages,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { ChangesetPackages } from '../changesets.ts';
|
|
2
|
+
import type { ParsedValues } from './command.ts';
|
|
3
|
+
/** Parsed input for `changeset-add`. */
|
|
4
|
+
export interface ChangesetAddArgs {
|
|
5
|
+
packages: ChangesetPackages;
|
|
6
|
+
summary: string;
|
|
7
|
+
empty: boolean;
|
|
8
|
+
name?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Parse-args options for `changeset-add`. */
|
|
11
|
+
export declare const changesetAddArgs: {
|
|
12
|
+
readonly package: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly multiple: true;
|
|
15
|
+
};
|
|
16
|
+
readonly bump: {
|
|
17
|
+
readonly type: "string";
|
|
18
|
+
readonly multiple: true;
|
|
19
|
+
};
|
|
20
|
+
readonly summary: {
|
|
21
|
+
readonly type: "string";
|
|
22
|
+
};
|
|
23
|
+
readonly empty: {
|
|
24
|
+
readonly type: "boolean";
|
|
25
|
+
};
|
|
26
|
+
readonly name: {
|
|
27
|
+
readonly type: "string";
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Parse and validate the `changeset-add` options.
|
|
32
|
+
*
|
|
33
|
+
* @param values Parsed CLI options.
|
|
34
|
+
* @return Normalized changeset input.
|
|
35
|
+
* @throws {ValidationError} If required options are missing or conflicting.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseChangesetAddArgs(values: ParsedValues): ChangesetAddArgs;
|
|
38
|
+
/** Parse-args options for `changeset-status`. */
|
|
39
|
+
export declare const changesetStatusArgs: {
|
|
40
|
+
readonly since: {
|
|
41
|
+
readonly type: "string";
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/** Parsed input for `changeset-status`. */
|
|
45
|
+
export interface ChangesetStatusArgs {
|
|
46
|
+
since?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Parse the `changeset-status` options.
|
|
50
|
+
*
|
|
51
|
+
* @param values Parsed CLI options.
|
|
52
|
+
* @return Normalized status input.
|
|
53
|
+
* @throws {ValidationError} If --since is empty.
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseChangesetStatusArgs(values: ParsedValues): ChangesetStatusArgs;
|
|
56
|
+
/** Parse-args options for `changeset-version`. */
|
|
57
|
+
export declare const changesetVersionArgs: {
|
|
58
|
+
readonly 'dry-run': {
|
|
59
|
+
readonly type: "boolean";
|
|
60
|
+
};
|
|
61
|
+
readonly date: {
|
|
62
|
+
readonly type: "string";
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
/** Parsed input for `changeset-version`. */
|
|
66
|
+
export interface ChangesetVersionArgs {
|
|
67
|
+
dryRun: boolean;
|
|
68
|
+
date?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Validate and normalize a release date option.
|
|
72
|
+
*
|
|
73
|
+
* @param value Value from --date.
|
|
74
|
+
* @return A validated ISO date or undefined.
|
|
75
|
+
* @throws {ValidationError} If the date is not a real YYYY-MM-DD date.
|
|
76
|
+
*/
|
|
77
|
+
export declare function parseChangesetDate(value: string | undefined): string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Parse the `changeset-version` options.
|
|
80
|
+
*
|
|
81
|
+
* @param values Parsed CLI options.
|
|
82
|
+
* @return Normalized versioning input.
|
|
83
|
+
* @throws {ValidationError} If --date is invalid.
|
|
84
|
+
*/
|
|
85
|
+
export declare function parseChangesetVersionArgs(values: ParsedValues): ChangesetVersionArgs;
|
|
86
|
+
/** Parse-args options for `changeset-tag`. */
|
|
87
|
+
export declare const changesetTagArgs: {
|
|
88
|
+
readonly push: {
|
|
89
|
+
readonly type: "boolean";
|
|
90
|
+
};
|
|
91
|
+
readonly 'dry-run': {
|
|
92
|
+
readonly type: "boolean";
|
|
93
|
+
};
|
|
94
|
+
readonly 'github-release': {
|
|
95
|
+
readonly type: "boolean";
|
|
96
|
+
};
|
|
97
|
+
readonly since: {
|
|
98
|
+
readonly type: "string";
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
/** Parsed input for `changeset-tag`. */
|
|
102
|
+
export interface ChangesetTagArgs {
|
|
103
|
+
push: boolean;
|
|
104
|
+
dryRun: boolean;
|
|
105
|
+
githubRelease: boolean;
|
|
106
|
+
since?: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Parse the `changeset-tag` options.
|
|
110
|
+
*
|
|
111
|
+
* @param values Parsed CLI options.
|
|
112
|
+
* @return Normalized tag input.
|
|
113
|
+
*/
|
|
114
|
+
export declare function parseChangesetTagArgs(values: ParsedValues): ChangesetTagArgs;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { ValidationError } from "../errors.js";
|
|
2
|
+
import { CHANGESET_BUMPS } from "../changesets.js";
|
|
3
|
+
import { getBoolean, getString, getStrings } from "./command.js";
|
|
4
|
+
/** Parse-args options for `changeset-add`. */
|
|
5
|
+
export const changesetAddArgs = {
|
|
6
|
+
package: { type: 'string', multiple: true },
|
|
7
|
+
bump: { type: 'string', multiple: true },
|
|
8
|
+
summary: { type: 'string' },
|
|
9
|
+
empty: { type: 'boolean' },
|
|
10
|
+
name: { type: 'string' },
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Parse and validate the `changeset-add` options.
|
|
14
|
+
*
|
|
15
|
+
* @param values Parsed CLI options.
|
|
16
|
+
* @return Normalized changeset input.
|
|
17
|
+
* @throws {ValidationError} If required options are missing or conflicting.
|
|
18
|
+
*/
|
|
19
|
+
export function parseChangesetAddArgs(values) {
|
|
20
|
+
const names = getStrings(values, 'package');
|
|
21
|
+
const bumps = getStrings(values, 'bump');
|
|
22
|
+
const summary = getString(values, 'summary')?.trim();
|
|
23
|
+
const empty = getBoolean(values, 'empty');
|
|
24
|
+
const name = getString(values, 'name');
|
|
25
|
+
if (empty && (names.length || bumps.length || summary)) {
|
|
26
|
+
throw new ValidationError('--empty cannot be combined with --package, --bump or --summary.');
|
|
27
|
+
}
|
|
28
|
+
if (!empty && (!names.length || names.length !== bumps.length)) {
|
|
29
|
+
throw new ValidationError('Pass matching repeated --package <name> and --bump <patch|minor|major> options, or use --empty.');
|
|
30
|
+
}
|
|
31
|
+
if (!empty && !summary) {
|
|
32
|
+
throw new ValidationError('--summary <text> is required unless --empty is set.');
|
|
33
|
+
}
|
|
34
|
+
if (name && !/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name)) {
|
|
35
|
+
throw new ValidationError('--name must contain only letters, numbers, dots, underscores or hyphens.');
|
|
36
|
+
}
|
|
37
|
+
const packages = {};
|
|
38
|
+
names.forEach((packageName, index) => {
|
|
39
|
+
const bump = bumps[index];
|
|
40
|
+
if (Object.hasOwn(packages, packageName)) {
|
|
41
|
+
throw new ValidationError(`Package "${packageName}" was passed more than once.`);
|
|
42
|
+
}
|
|
43
|
+
if (!CHANGESET_BUMPS.includes(bump)) {
|
|
44
|
+
throw new ValidationError(`Invalid bump "${bump}" for package "${packageName}"; expected patch, minor or major.`);
|
|
45
|
+
}
|
|
46
|
+
packages[packageName] = bump;
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
packages,
|
|
50
|
+
summary: summary ?? '',
|
|
51
|
+
empty,
|
|
52
|
+
...(name ? { name } : {}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Parse-args options for `changeset-status`. */
|
|
56
|
+
export const changesetStatusArgs = {
|
|
57
|
+
since: { type: 'string' },
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Parse the `changeset-status` options.
|
|
61
|
+
*
|
|
62
|
+
* @param values Parsed CLI options.
|
|
63
|
+
* @return Normalized status input.
|
|
64
|
+
* @throws {ValidationError} If --since is empty.
|
|
65
|
+
*/
|
|
66
|
+
export function parseChangesetStatusArgs(values) {
|
|
67
|
+
const since = getString(values, 'since');
|
|
68
|
+
if ('' === since?.trim()) {
|
|
69
|
+
throw new ValidationError('--since <ref> must not be empty.');
|
|
70
|
+
}
|
|
71
|
+
return since ? { since } : {};
|
|
72
|
+
}
|
|
73
|
+
/** Parse-args options for `changeset-version`. */
|
|
74
|
+
export const changesetVersionArgs = {
|
|
75
|
+
'dry-run': { type: 'boolean' },
|
|
76
|
+
date: { type: 'string' },
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Validate and normalize a release date option.
|
|
80
|
+
*
|
|
81
|
+
* @param value Value from --date.
|
|
82
|
+
* @return A validated ISO date or undefined.
|
|
83
|
+
* @throws {ValidationError} If the date is not a real YYYY-MM-DD date.
|
|
84
|
+
*/
|
|
85
|
+
export function parseChangesetDate(value) {
|
|
86
|
+
if (undefined === value) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
90
|
+
const parsed = new Date(`${value}T00:00:00.000Z`);
|
|
91
|
+
if (!match ||
|
|
92
|
+
Number.isNaN(parsed.getTime()) ||
|
|
93
|
+
parsed.toISOString().slice(0, 10) !== value) {
|
|
94
|
+
throw new ValidationError(`Invalid release date "${value}"; expected a real date in YYYY-MM-DD format.`);
|
|
95
|
+
}
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Parse the `changeset-version` options.
|
|
100
|
+
*
|
|
101
|
+
* @param values Parsed CLI options.
|
|
102
|
+
* @return Normalized versioning input.
|
|
103
|
+
* @throws {ValidationError} If --date is invalid.
|
|
104
|
+
*/
|
|
105
|
+
export function parseChangesetVersionArgs(values) {
|
|
106
|
+
const date = parseChangesetDate(getString(values, 'date'));
|
|
107
|
+
return {
|
|
108
|
+
dryRun: getBoolean(values, 'dry-run'),
|
|
109
|
+
...(date ? { date } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** Parse-args options for `changeset-tag`. */
|
|
113
|
+
export const changesetTagArgs = {
|
|
114
|
+
push: { type: 'boolean' },
|
|
115
|
+
'dry-run': { type: 'boolean' },
|
|
116
|
+
'github-release': { type: 'boolean' },
|
|
117
|
+
since: { type: 'string' },
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Parse the `changeset-tag` options.
|
|
121
|
+
*
|
|
122
|
+
* @param values Parsed CLI options.
|
|
123
|
+
* @return Normalized tag input.
|
|
124
|
+
*/
|
|
125
|
+
export function parseChangesetTagArgs(values) {
|
|
126
|
+
const args = {
|
|
127
|
+
push: getBoolean(values, 'push'),
|
|
128
|
+
dryRun: getBoolean(values, 'dry-run'),
|
|
129
|
+
githubRelease: getBoolean(values, 'github-release'),
|
|
130
|
+
since: getString(values, 'since'),
|
|
131
|
+
};
|
|
132
|
+
if ('' === args.since?.trim()) {
|
|
133
|
+
throw new ValidationError('--since <ref> must not be empty.');
|
|
134
|
+
}
|
|
135
|
+
if (args.githubRelease && !args.push) {
|
|
136
|
+
throw new ValidationError('--github-release requires --push.');
|
|
137
|
+
}
|
|
138
|
+
return args;
|
|
139
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface ChangesetStatusResult {
|
|
2
|
+
changesets: Array<{
|
|
3
|
+
fileName: string;
|
|
4
|
+
packages: Record<string, string>;
|
|
5
|
+
summary: string;
|
|
6
|
+
}>;
|
|
7
|
+
releases: Array<{
|
|
8
|
+
package: string;
|
|
9
|
+
bump: string;
|
|
10
|
+
currentVersion: string;
|
|
11
|
+
nextVersion: string;
|
|
12
|
+
}>;
|
|
13
|
+
changedPackages: string[];
|
|
14
|
+
changedPackageFiles: Record<string, string[]>;
|
|
15
|
+
missingChangesets: string[];
|
|
16
|
+
}
|
|
17
|
+
declare const _default: {
|
|
18
|
+
name: string;
|
|
19
|
+
usage: string;
|
|
20
|
+
summary: string;
|
|
21
|
+
help: string;
|
|
22
|
+
options: {
|
|
23
|
+
readonly since: {
|
|
24
|
+
readonly type: "string";
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
run({ values, cwd, configFile, logger }: import("./command.ts").CommandContext): Promise<{
|
|
28
|
+
exitCode: number;
|
|
29
|
+
result: {
|
|
30
|
+
releases: {
|
|
31
|
+
package: string;
|
|
32
|
+
bump: "patch" | "minor" | "major";
|
|
33
|
+
currentVersion: string;
|
|
34
|
+
nextVersion: string;
|
|
35
|
+
}[];
|
|
36
|
+
changesets: import("../changesets.ts").Changeset[];
|
|
37
|
+
changedPackages: string[];
|
|
38
|
+
changedPackageFiles: Record<string, string[]>;
|
|
39
|
+
missingChangesets: string[];
|
|
40
|
+
};
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
export default _default;
|