@wpelevator/wp-release 0.4.1 → 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 +136 -6
- 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 +78 -18
- 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/checksums.js +2 -0
- package/dist/commands/command.d.ts +2 -0
- package/dist/commands/sign.js +2 -0
- package/dist/commands/verify.js +61 -12
- package/dist/commands/version-check.js +5 -2
- package/dist/commands/zip.js +7 -7
- package/dist/errors.d.ts +18 -0
- package/dist/errors.js +8 -0
- package/dist/github-actions-writer.d.ts +52 -0
- package/dist/github-actions-writer.js +94 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.js +8 -3
- package/dist/logger.d.ts +88 -16
- package/dist/logger.js +73 -25
- package/dist/package-meta.d.ts +26 -0
- package/dist/package-meta.js +65 -10
- package/dist/report.d.ts +22 -0
- package/dist/report.js +35 -0
- package/dist/summary.d.ts +141 -0
- package/dist/summary.js +287 -0
- package/dist/svn-deploy.d.ts +2 -1
- package/dist/svn-deploy.js +8 -6
- package/dist/version-check.d.ts +39 -1
- package/dist/version-check.js +59 -5
- package/package.json +1 -1
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { access } from 'node:fs/promises';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
12
|
+
import { ValidationError } from "./errors.js";
|
|
13
|
+
/**
|
|
14
|
+
* Return a package.json version descriptor for use as a source or target.
|
|
15
|
+
*
|
|
16
|
+
* @param options Version manifest path.
|
|
17
|
+
* @return Package version descriptor.
|
|
18
|
+
*/
|
|
19
|
+
export function packageJsonVersion(options = {}) {
|
|
20
|
+
return {
|
|
21
|
+
kind: 'package-json',
|
|
22
|
+
file: options.file ?? 'package.json',
|
|
23
|
+
field: 'version',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Return a Composer version descriptor for use as a source or target.
|
|
28
|
+
*
|
|
29
|
+
* @param options Composer manifest path and missing-field behavior.
|
|
30
|
+
* @return Package version descriptor.
|
|
31
|
+
*/
|
|
32
|
+
export function composerJsonVersion(options = {}) {
|
|
33
|
+
return {
|
|
34
|
+
kind: 'composer-json',
|
|
35
|
+
file: options.file ?? 'composer.json',
|
|
36
|
+
field: 'version',
|
|
37
|
+
ifPresent: options.ifPresent ?? true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Return a WordPress plugin header version descriptor.
|
|
42
|
+
*
|
|
43
|
+
* @param options Optional plugin main file path.
|
|
44
|
+
* @return Package version descriptor.
|
|
45
|
+
*/
|
|
46
|
+
export function wordpressPluginVersion(options = {}) {
|
|
47
|
+
return {
|
|
48
|
+
kind: 'wordpress-plugin-header',
|
|
49
|
+
...(options.file ? { file: options.file } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Return a WordPress theme style.css version descriptor.
|
|
54
|
+
*
|
|
55
|
+
* @param options Optional theme stylesheet path.
|
|
56
|
+
* @return Package version descriptor.
|
|
57
|
+
*/
|
|
58
|
+
export function wordpressThemeVersion(options = {}) {
|
|
59
|
+
return {
|
|
60
|
+
kind: 'wordpress-theme-header',
|
|
61
|
+
...(options.file ? { file: options.file } : {}),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Return a WordPress readme Stable tag version descriptor.
|
|
66
|
+
*
|
|
67
|
+
* @param options Optional readme path.
|
|
68
|
+
* @return Package version descriptor.
|
|
69
|
+
*/
|
|
70
|
+
export function wordpressStableTag(options = {}) {
|
|
71
|
+
return {
|
|
72
|
+
kind: 'wordpress-stable-tag',
|
|
73
|
+
...(options.file ? { file: options.file } : {}),
|
|
74
|
+
...(undefined !== options.ifPresent
|
|
75
|
+
? { ifPresent: options.ifPresent }
|
|
76
|
+
: {}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Return a git tag version descriptor for packages without a version file.
|
|
81
|
+
*
|
|
82
|
+
* @param options Optional tag pattern.
|
|
83
|
+
* @return Package version descriptor.
|
|
84
|
+
*/
|
|
85
|
+
export function gitTagVersion(options = {}) {
|
|
86
|
+
return {
|
|
87
|
+
kind: 'git-tag',
|
|
88
|
+
...(options.pattern ? { pattern: options.pattern } : {}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Return a PHP constant descriptor for use as a version source or target.
|
|
93
|
+
*
|
|
94
|
+
* @param options PHP file and constant name.
|
|
95
|
+
* @return Package version descriptor.
|
|
96
|
+
*/
|
|
97
|
+
export function phpConstantVersion(options) {
|
|
98
|
+
return { kind: 'php-constant', ...options };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Add type checking to a JavaScript wp-release configuration.
|
|
102
|
+
*
|
|
103
|
+
* @param config Repository release configuration.
|
|
104
|
+
* @return The same configuration object.
|
|
105
|
+
*/
|
|
106
|
+
export function defineConfig(config) {
|
|
107
|
+
return config;
|
|
108
|
+
}
|
|
109
|
+
const CONFIG_FILES = [
|
|
110
|
+
'wp-release.config.js',
|
|
111
|
+
'wp-release.config.mjs',
|
|
112
|
+
'wp-release.config.cjs',
|
|
113
|
+
];
|
|
114
|
+
/**
|
|
115
|
+
* Load and validate the repository's JavaScript wp-release configuration.
|
|
116
|
+
*
|
|
117
|
+
* @param input Working directory and optional explicit config path.
|
|
118
|
+
* @return Loaded configuration and its absolute file path, or undefined when absent.
|
|
119
|
+
* @throws {ValidationError} If the module cannot be loaded or its shape is invalid.
|
|
120
|
+
*/
|
|
121
|
+
export async function loadChangesetConfig(input = {}) {
|
|
122
|
+
const cwd = path.resolve(input.cwd ?? process.cwd());
|
|
123
|
+
const configFile = input.configFile
|
|
124
|
+
? path.resolve(cwd, input.configFile)
|
|
125
|
+
: await findConfigFile(cwd);
|
|
126
|
+
if (!configFile) {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
let loaded;
|
|
130
|
+
try {
|
|
131
|
+
loaded = await import(__rewriteRelativeImportExtension(pathToFileURL(configFile).href));
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
135
|
+
throw new ValidationError(`Could not load wp-release config ${configFile}: ${message}`);
|
|
136
|
+
}
|
|
137
|
+
const config = 'object' === typeof loaded && null !== loaded && 'default' in loaded
|
|
138
|
+
? loaded.default
|
|
139
|
+
: undefined;
|
|
140
|
+
validateChangesetConfig(config, configFile);
|
|
141
|
+
return { config, file: configFile };
|
|
142
|
+
}
|
|
143
|
+
async function findConfigFile(cwd) {
|
|
144
|
+
for (const fileName of CONFIG_FILES) {
|
|
145
|
+
const candidate = path.join(cwd, fileName);
|
|
146
|
+
try {
|
|
147
|
+
await access(candidate);
|
|
148
|
+
return candidate;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Try the next conventional filename.
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Validate the supported config shape before commands consume it.
|
|
158
|
+
*
|
|
159
|
+
* @param config Untrusted default export value.
|
|
160
|
+
* @param configFile Config file path for error messages.
|
|
161
|
+
*/
|
|
162
|
+
function validateChangesetConfig(config, configFile) {
|
|
163
|
+
if ('object' !== typeof config ||
|
|
164
|
+
null === config ||
|
|
165
|
+
Array.isArray(config)) {
|
|
166
|
+
throw new ValidationError(`wp-release config ${configFile} must default-export a configuration object.`);
|
|
167
|
+
}
|
|
168
|
+
const candidate = config;
|
|
169
|
+
if (!Array.isArray(candidate.packages)) {
|
|
170
|
+
throw new ValidationError(`wp-release config ${configFile} must define a packages array.`);
|
|
171
|
+
}
|
|
172
|
+
for (const [key, value] of Object.entries({
|
|
173
|
+
baseBranch: candidate.baseBranch,
|
|
174
|
+
changesets: candidate.changesets,
|
|
175
|
+
changelogInsertAfter: candidate.changelogInsertAfter,
|
|
176
|
+
root: candidate.root,
|
|
177
|
+
})) {
|
|
178
|
+
if (undefined !== value && 'string' !== typeof value) {
|
|
179
|
+
throw new ValidationError(`wp-release config ${configFile}.${key} must be a string.`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if ('' === candidate.changelogInsertAfter) {
|
|
183
|
+
throw new ValidationError(`wp-release config ${configFile}.changelogInsertAfter must not be empty.`);
|
|
184
|
+
}
|
|
185
|
+
if (undefined !== candidate.tagFormat &&
|
|
186
|
+
'string' !== typeof candidate.tagFormat) {
|
|
187
|
+
throw new ValidationError(`wp-release config ${configFile}.tagFormat must be a string.`);
|
|
188
|
+
}
|
|
189
|
+
if (undefined !== candidate.readmeChangelog &&
|
|
190
|
+
'boolean' !== typeof candidate.readmeChangelog) {
|
|
191
|
+
throw new ValidationError(`wp-release config ${configFile}.readmeChangelog must be a boolean.`);
|
|
192
|
+
}
|
|
193
|
+
if (undefined !== candidate.nextVersion &&
|
|
194
|
+
'function' !== typeof candidate.nextVersion) {
|
|
195
|
+
throw new ValidationError(`wp-release config ${configFile}.nextVersion must be a function.`);
|
|
196
|
+
}
|
|
197
|
+
candidate.packages.forEach((group, index) => {
|
|
198
|
+
if ('object' !== typeof group ||
|
|
199
|
+
null === group ||
|
|
200
|
+
'object' !== typeof group.version ||
|
|
201
|
+
null === group.version ||
|
|
202
|
+
'object' !== typeof group.version.from ||
|
|
203
|
+
!Array.isArray(group.version.to)) {
|
|
204
|
+
throw new ValidationError(`wp-release config ${configFile} has an invalid packages[${index}] entry.`);
|
|
205
|
+
}
|
|
206
|
+
if (undefined !== group.idFrom &&
|
|
207
|
+
!['path', 'package.json#name', 'composer.json#name'].includes(group.idFrom)) {
|
|
208
|
+
throw new ValidationError(`wp-release config ${configFile} packages[${index}].idFrom is not supported.`);
|
|
209
|
+
}
|
|
210
|
+
if ('string' !== typeof group.glob || !group.glob.trim()) {
|
|
211
|
+
throw new ValidationError(`wp-release config ${configFile} packages[${index}].glob must be a non-empty string.`);
|
|
212
|
+
}
|
|
213
|
+
if ('string' !== typeof group.tagType &&
|
|
214
|
+
undefined !== group.tagType) {
|
|
215
|
+
throw new ValidationError(`wp-release config ${configFile} packages[${index}].tagType must be a string.`);
|
|
216
|
+
}
|
|
217
|
+
if (undefined !== group.exclude &&
|
|
218
|
+
(!Array.isArray(group.exclude) ||
|
|
219
|
+
group.exclude.some((item) => 'string' !== typeof item))) {
|
|
220
|
+
throw new ValidationError(`wp-release config ${configFile} packages[${index}].exclude must be an array of strings.`);
|
|
221
|
+
}
|
|
222
|
+
validateVersionDescriptor(group.version.from, `${configFile}.packages[${index}].version.from`, false);
|
|
223
|
+
group.version.to.forEach((target, targetIndex) => validateVersionDescriptor(target, `${configFile}.packages[${index}].version.to[${targetIndex}]`, true));
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
function validateVersionDescriptor(descriptor, location, isTarget) {
|
|
227
|
+
if ('object' !== typeof descriptor || null === descriptor) {
|
|
228
|
+
throw new ValidationError(`wp-release config ${location} must be an object.`);
|
|
229
|
+
}
|
|
230
|
+
const candidate = descriptor;
|
|
231
|
+
const sourceKinds = [
|
|
232
|
+
'package-json',
|
|
233
|
+
'composer-json',
|
|
234
|
+
'wordpress-plugin-header',
|
|
235
|
+
'wordpress-theme-header',
|
|
236
|
+
'wordpress-stable-tag',
|
|
237
|
+
'php-constant',
|
|
238
|
+
'git-tag',
|
|
239
|
+
];
|
|
240
|
+
const targetKinds = sourceKinds.filter((kind) => 'git-tag' !== kind);
|
|
241
|
+
const kinds = isTarget ? targetKinds : sourceKinds;
|
|
242
|
+
if ('string' !== typeof candidate.kind ||
|
|
243
|
+
!kinds.includes(candidate.kind)) {
|
|
244
|
+
throw new ValidationError(`wp-release config ${location}.kind is not supported.`);
|
|
245
|
+
}
|
|
246
|
+
const needsFile = [
|
|
247
|
+
'package-json',
|
|
248
|
+
'composer-json',
|
|
249
|
+
'php-constant',
|
|
250
|
+
].includes(candidate.kind);
|
|
251
|
+
if (needsFile &&
|
|
252
|
+
('string' !== typeof candidate.file || !candidate.file.trim())) {
|
|
253
|
+
throw new ValidationError(`wp-release config ${location}.file must be a non-empty string.`);
|
|
254
|
+
}
|
|
255
|
+
if (['package-json', 'composer-json'].includes(candidate.kind) &&
|
|
256
|
+
'version' !== candidate.field) {
|
|
257
|
+
throw new ValidationError(`wp-release config ${location}.field must be "version".`);
|
|
258
|
+
}
|
|
259
|
+
if ('php-constant' === candidate.kind &&
|
|
260
|
+
('string' !== typeof candidate.constant ||
|
|
261
|
+
!candidate.constant.trim())) {
|
|
262
|
+
throw new ValidationError(`wp-release config ${location}.constant must be a non-empty string.`);
|
|
263
|
+
}
|
|
264
|
+
if ('git-tag' === candidate.kind &&
|
|
265
|
+
undefined !== candidate.pattern &&
|
|
266
|
+
'string' !== typeof candidate.pattern) {
|
|
267
|
+
throw new ValidationError(`wp-release config ${location}.pattern must be a string.`);
|
|
268
|
+
}
|
|
269
|
+
if (undefined !== candidate.ifPresent &&
|
|
270
|
+
'boolean' !== typeof candidate.ifPresent) {
|
|
271
|
+
throw new ValidationError(`wp-release config ${location}.ifPresent must be a boolean.`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Changeset, ChangesetReleasePlan, PackageRelease } from './changesets.ts';
|
|
2
|
+
export interface ChangesetRepository {
|
|
3
|
+
cwd: string;
|
|
4
|
+
configFile?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ChangesetVersionInput extends ChangesetRepository {
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
date?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ChangesetTagInput extends ChangesetRepository {
|
|
11
|
+
dryRun?: boolean;
|
|
12
|
+
push?: boolean;
|
|
13
|
+
githubRelease?: boolean;
|
|
14
|
+
since?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ChangesetTagResult {
|
|
17
|
+
tags: Array<{
|
|
18
|
+
package: string;
|
|
19
|
+
version: string;
|
|
20
|
+
tag: string;
|
|
21
|
+
created: boolean;
|
|
22
|
+
notes: string;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Discover configured packages, pending changesets, and their proposed versions.
|
|
27
|
+
*
|
|
28
|
+
* @param input Repository root and optional explicit config file.
|
|
29
|
+
* @return A release plan; `undefined` when no config is present.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getChangesetReleasePlan(input: ChangesetRepository): Promise<ChangesetReleasePlan | undefined>;
|
|
32
|
+
/**
|
|
33
|
+
* Create a Changesets-compatible Markdown file.
|
|
34
|
+
*
|
|
35
|
+
* @param input Repository, packages and summary.
|
|
36
|
+
* @return Created file path.
|
|
37
|
+
*/
|
|
38
|
+
export declare function addChangeset(input: ChangesetRepository & {
|
|
39
|
+
packages: Record<string, 'patch' | 'minor' | 'major'>;
|
|
40
|
+
summary: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
}): Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Apply pending package versions and changelogs.
|
|
45
|
+
*
|
|
46
|
+
* @param input Repository and versioning options.
|
|
47
|
+
* @return Planned releases and whether files were changed.
|
|
48
|
+
*/
|
|
49
|
+
export declare function versionChangesets(input: ChangesetVersionInput): Promise<ChangesetReleasePlan & {
|
|
50
|
+
date: string;
|
|
51
|
+
changed: boolean;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Create missing release tags, optionally pushing them to the configured remote.
|
|
55
|
+
*
|
|
56
|
+
* @param input Repository and tag options.
|
|
57
|
+
* @return Per-package tags and release notes.
|
|
58
|
+
*/
|
|
59
|
+
export declare function tagChangesets(input: ChangesetTagInput): Promise<ChangesetTagResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Check whether changed files belong to packages without a changeset.
|
|
62
|
+
*
|
|
63
|
+
* @param input Repository and base git ref.
|
|
64
|
+
* @return Changed packages and missing changeset identifiers.
|
|
65
|
+
*/
|
|
66
|
+
export declare function getChangesetStatus(input: ChangesetRepository & {
|
|
67
|
+
since?: string;
|
|
68
|
+
}): Promise<{
|
|
69
|
+
changesets: Changeset[];
|
|
70
|
+
releases: PackageRelease[];
|
|
71
|
+
changedPackages: string[];
|
|
72
|
+
changedPackageFiles: Record<string, string[]>;
|
|
73
|
+
missingChangesets: string[];
|
|
74
|
+
}>;
|