@wpelevator/wp-release 0.14.0 → 0.16.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 +256 -36
- package/dist/changeset-config.d.ts +3 -0
- package/dist/changeset-release.d.ts +9 -3
- package/dist/changeset-release.js +23 -14
- package/dist/cli.d.ts +17 -7
- package/dist/cli.js +27 -2
- package/dist/commands/args.d.ts +11 -0
- package/dist/commands/args.js +23 -0
- package/dist/commands/artifact-signing.d.ts +20 -0
- package/dist/commands/artifact-signing.js +42 -0
- package/dist/commands/build.d.ts +32 -0
- package/dist/commands/build.js +91 -0
- package/dist/commands/changeset-add.d.ts +55 -6
- package/dist/commands/changeset-add.js +12 -3
- package/dist/commands/changeset-args.js +2 -2
- package/dist/commands/changeset-project-args.d.ts +63 -0
- package/dist/commands/changeset-project-args.js +114 -0
- package/dist/commands/changeset-status.d.ts +50 -1
- package/dist/commands/changeset-status.js +4 -2
- package/dist/commands/changeset-tag.d.ts +55 -6
- package/dist/commands/changeset-tag.js +7 -4
- package/dist/commands/changeset-version.d.ts +55 -6
- package/dist/commands/changeset-version.js +4 -2
- package/dist/commands/checksums.d.ts +4 -1
- package/dist/commands/checksums.js +27 -6
- package/dist/commands/command.d.ts +3 -0
- package/dist/commands/deploy-svn.d.ts +11 -15
- package/dist/commands/deploy-svn.js +25 -5
- package/dist/commands/package-source.d.ts +43 -0
- package/dist/commands/package-source.js +101 -0
- package/dist/commands/sign.d.ts +0 -9
- package/dist/commands/sign.js +10 -47
- package/dist/commands/verify.d.ts +7 -1
- package/dist/commands/verify.js +53 -17
- package/dist/commands/zip.d.ts +25 -2
- package/dist/commands/zip.js +136 -110
- package/dist/index.d.ts +9 -2
- package/dist/index.js +3 -1
- package/dist/integrity.d.ts +33 -0
- package/dist/integrity.js +115 -0
- package/dist/output-files.d.ts +7 -0
- package/dist/output-files.js +25 -0
- package/dist/package-build.d.ts +33 -0
- package/dist/package-build.js +112 -0
- package/dist/package-files.d.ts +25 -0
- package/dist/package-files.js +24 -0
- package/dist/package-zip.d.ts +14 -2
- package/dist/package-zip.js +129 -38
- package/dist/release-tags.js +6 -0
- package/dist/signing.d.ts +36 -0
- package/dist/signing.js +52 -1
- package/dist/single-project.d.ts +32 -0
- package/dist/single-project.js +144 -0
- package/dist/summary.d.ts +9 -0
- package/dist/summary.js +25 -0
- package/dist/zip.d.ts +3 -0
- package/dist/zip.js +16 -6
- package/package.json +6 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { readdir } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { packageJsonVersion, composerJsonVersion, wordpressPluginVersion, wordpressThemeVersion, wordpressStableTag, } from "./changeset-config.js";
|
|
4
|
+
import { ValidationError } from "./errors.js";
|
|
5
|
+
import { readJsonIfExists } from "./json-files.js";
|
|
6
|
+
import { parseFileHeaders, readFileStart } from "./package-meta.js";
|
|
7
|
+
/** CLI names of version descriptor kinds. */
|
|
8
|
+
export const VERSION_KINDS = {
|
|
9
|
+
'package-json': 'package-json',
|
|
10
|
+
'composer-json': 'composer-json',
|
|
11
|
+
'wordpress-plugin': 'wordpress-plugin-header',
|
|
12
|
+
'wordpress-theme': 'wordpress-theme-header',
|
|
13
|
+
'wordpress-stable-tag': 'wordpress-stable-tag',
|
|
14
|
+
'php-constant': 'php-constant',
|
|
15
|
+
'git-tag': 'git-tag',
|
|
16
|
+
};
|
|
17
|
+
function descriptorId(descriptor) {
|
|
18
|
+
if ('git-tag' === descriptor.kind) {
|
|
19
|
+
return descriptor.pattern ?? '';
|
|
20
|
+
}
|
|
21
|
+
return 'php-constant' === descriptor.kind
|
|
22
|
+
? `${descriptor.file}#${descriptor.constant}`
|
|
23
|
+
: descriptor.file ?? '';
|
|
24
|
+
}
|
|
25
|
+
function selectSource(versions, selector) {
|
|
26
|
+
let candidates = versions;
|
|
27
|
+
if (selector) {
|
|
28
|
+
const separator = selector.indexOf(':');
|
|
29
|
+
const kind = separator < 0 ? selector : selector.slice(0, separator);
|
|
30
|
+
const id = separator < 0 ? undefined : selector.slice(separator + 1);
|
|
31
|
+
const descriptorKind = VERSION_KINDS[kind];
|
|
32
|
+
candidates = versions.filter((descriptor) => descriptor.kind === descriptorKind &&
|
|
33
|
+
(undefined === id || descriptorId(descriptor) === id));
|
|
34
|
+
}
|
|
35
|
+
else if (versions.length > 1) {
|
|
36
|
+
// A Stable tag can accompany a unique authoritative version file.
|
|
37
|
+
candidates = versions.filter((descriptor) => 'wordpress-stable-tag' !== descriptor.kind);
|
|
38
|
+
}
|
|
39
|
+
if (candidates.length !== 1) {
|
|
40
|
+
throw new ValidationError('Cannot choose the current version source. Pass --version-from <kind> or --version-from <kind>:<file> (PHP constants use <file>#<constant>), or add a wp-release config.');
|
|
41
|
+
}
|
|
42
|
+
return candidates[0];
|
|
43
|
+
}
|
|
44
|
+
async function detectVersions(cwd) {
|
|
45
|
+
const versions = [];
|
|
46
|
+
const entries = await readdir(cwd, { withFileTypes: true });
|
|
47
|
+
for (const entry of entries
|
|
48
|
+
.filter((item) => item.isFile() &&
|
|
49
|
+
(item.name.endsWith('.php') || 'style.css' === item.name))
|
|
50
|
+
.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
51
|
+
const contents = await readFileStart(path.join(cwd, entry.name));
|
|
52
|
+
const theme = 'style.css' === entry.name;
|
|
53
|
+
const nameHeader = theme ? 'Theme Name' : 'Plugin Name';
|
|
54
|
+
const headers = parseFileHeaders({
|
|
55
|
+
contents: contents ?? '',
|
|
56
|
+
headers: [nameHeader, 'Version'],
|
|
57
|
+
});
|
|
58
|
+
if (headers[nameHeader]) {
|
|
59
|
+
versions.push(theme
|
|
60
|
+
? wordpressThemeVersion({ file: entry.name })
|
|
61
|
+
: wordpressPluginVersion({ file: entry.name }));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const file of ['package.json', 'composer.json']) {
|
|
65
|
+
const manifest = await readJsonIfExists(path.join(cwd, file)).catch((error) => {
|
|
66
|
+
throw new ValidationError(`Could not read ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
|
+
});
|
|
68
|
+
if (manifest && 'package.json' === file && manifest.workspaces) {
|
|
69
|
+
throw new ValidationError('Automatic changeset configuration is for a single root project. Configure workspace packages in a wp-release config or pass explicit --version-* descriptors.');
|
|
70
|
+
}
|
|
71
|
+
if (manifest &&
|
|
72
|
+
'string' === typeof manifest.version &&
|
|
73
|
+
manifest.version.trim()) {
|
|
74
|
+
versions.push('package.json' === file
|
|
75
|
+
? packageJsonVersion()
|
|
76
|
+
: composerJsonVersion());
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (versions.length > 1) {
|
|
80
|
+
throw new ValidationError('Cannot choose among multiple root version sources. Pass explicit --version-* descriptors or add a wp-release config.');
|
|
81
|
+
}
|
|
82
|
+
if (1 === versions.length &&
|
|
83
|
+
'wordpress-plugin-header' === versions[0]?.kind) {
|
|
84
|
+
const readmes = await Promise.all(['readme.txt', 'readme.md'].map(async (file) => {
|
|
85
|
+
const contents = await readFileStart(path.join(cwd, file));
|
|
86
|
+
const headers = parseFileHeaders({
|
|
87
|
+
contents: contents ?? '',
|
|
88
|
+
headers: ['Stable tag'],
|
|
89
|
+
});
|
|
90
|
+
return headers['Stable tag'] ? file : undefined;
|
|
91
|
+
}));
|
|
92
|
+
const readme = readmes.find(Boolean);
|
|
93
|
+
if (readme) {
|
|
94
|
+
versions.push(wordpressStableTag({ file: readme }));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return versions;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Build the root package config, without creating a configuration file.
|
|
101
|
+
*
|
|
102
|
+
* @param cwd Project root directory.
|
|
103
|
+
* @param options Explicit descriptors and shared release settings.
|
|
104
|
+
* @param tagFormat Tag format override, otherwise v{version}.
|
|
105
|
+
* @return Root package config, or undefined without a version source.
|
|
106
|
+
*/
|
|
107
|
+
export async function resolveSingleProjectConfig(cwd, options = {}, tagFormat) {
|
|
108
|
+
const versions = options.versions ?? (await detectVersions(cwd));
|
|
109
|
+
if (!versions.length) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
const ids = versions.map((descriptor) => `${descriptor.kind}:${descriptorId(descriptor)}`);
|
|
113
|
+
if (new Set(ids).size !== ids.length) {
|
|
114
|
+
throw new ValidationError('A version descriptor was supplied more than once. Pass each --version-* file or constant only once.');
|
|
115
|
+
}
|
|
116
|
+
const from = selectSource(versions, options.versionFrom);
|
|
117
|
+
const to = versions.filter((descriptor) => 'git-tag' !== descriptor.kind);
|
|
118
|
+
// Composer targets preserve the existing optional-version convention.
|
|
119
|
+
const targets = to.map((descriptor) => 'composer-json' === descriptor.kind
|
|
120
|
+
? { ...descriptor, ifPresent: descriptor.ifPresent ?? true }
|
|
121
|
+
: descriptor);
|
|
122
|
+
let idFrom = 'path';
|
|
123
|
+
if ('package-json' === from.kind && 'package.json' === from.file) {
|
|
124
|
+
idFrom = 'package.json#name';
|
|
125
|
+
}
|
|
126
|
+
else if ('composer-json' === from.kind &&
|
|
127
|
+
'composer.json' === from.file) {
|
|
128
|
+
idFrom = 'composer.json#name';
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
...(options.baseBranch ? { baseBranch: options.baseBranch } : {}),
|
|
132
|
+
...(options.remote ? { remote: options.remote } : {}),
|
|
133
|
+
...(undefined !== options.readmeChangelog
|
|
134
|
+
? { readmeChangelog: options.readmeChangelog }
|
|
135
|
+
: {}),
|
|
136
|
+
...(options.changelogInsertAfter
|
|
137
|
+
? { changelogInsertAfter: options.changelogInsertAfter }
|
|
138
|
+
: {}),
|
|
139
|
+
root: '.',
|
|
140
|
+
changesets: options.changesets ?? '.changeset',
|
|
141
|
+
tagFormat: tagFormat ?? 'v{version}',
|
|
142
|
+
packages: [{ glob: '.', idFrom, version: { from, to: targets } }],
|
|
143
|
+
};
|
|
144
|
+
}
|
package/dist/summary.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ChecksumsResult } from './commands/checksums.ts';
|
|
2
2
|
import type { SignResult } from './commands/sign.ts';
|
|
3
|
+
import type { BuildPackageResult } from './package-build.ts';
|
|
3
4
|
import type { ZipPackageResult } from './package-zip.ts';
|
|
4
5
|
import type { ChangesetTagResult } from './changeset-release.ts';
|
|
5
6
|
import type { PackageRelease } from './changesets.ts';
|
|
@@ -69,6 +70,14 @@ export declare function formatTable(header: string[], rows: string[][]): string;
|
|
|
69
70
|
* @return Markdown code.
|
|
70
71
|
*/
|
|
71
72
|
export declare function formatFile(context: SummaryContext, file: string, line?: number | null): string;
|
|
73
|
+
/**
|
|
74
|
+
* Get the summary of a directory build.
|
|
75
|
+
*
|
|
76
|
+
* @param context Workspace directory.
|
|
77
|
+
* @param result Output directory and number of copied files.
|
|
78
|
+
* @return Markdown summary.
|
|
79
|
+
*/
|
|
80
|
+
export declare function getBuildSummary(context: SummaryContext, result: BuildPackageResult): string;
|
|
72
81
|
/**
|
|
73
82
|
* Get the summary of a ZIP.
|
|
74
83
|
*
|
package/dist/summary.js
CHANGED
|
@@ -99,6 +99,26 @@ function formatDetails(title, content) {
|
|
|
99
99
|
function joinBlocks(blocks) {
|
|
100
100
|
return `${blocks.filter(Boolean).join('\n\n')}\n`;
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Get the summary of a directory build.
|
|
104
|
+
*
|
|
105
|
+
* @param context Workspace directory.
|
|
106
|
+
* @param result Output directory and number of copied files.
|
|
107
|
+
* @return Markdown summary.
|
|
108
|
+
*/
|
|
109
|
+
export function getBuildSummary(context, result) {
|
|
110
|
+
return joinBlocks([
|
|
111
|
+
'### Build',
|
|
112
|
+
formatList([
|
|
113
|
+
`**Directory:** ${formatFile(context, result.outputDir)}, ${result.files} files`,
|
|
114
|
+
...(result.checksumsPath
|
|
115
|
+
? [
|
|
116
|
+
`**Checksums:** ${formatFile(context, result.checksumsPath)}`,
|
|
117
|
+
]
|
|
118
|
+
: []),
|
|
119
|
+
]),
|
|
120
|
+
]);
|
|
121
|
+
}
|
|
102
122
|
/**
|
|
103
123
|
* Get the summary of a ZIP.
|
|
104
124
|
*
|
|
@@ -111,6 +131,11 @@ export function getZipSummary(context, result) {
|
|
|
111
131
|
'### ZIP',
|
|
112
132
|
formatList([
|
|
113
133
|
`**ZIP:** ${formatFile(context, result.zipPath)}, ${result.files} files`,
|
|
134
|
+
...(result.checksumsEmbedded
|
|
135
|
+
? [
|
|
136
|
+
`**Embedded checksums:** ${formatCode(result.checksumsEmbedded)}`,
|
|
137
|
+
]
|
|
138
|
+
: []),
|
|
114
139
|
...(result.checksumsPath
|
|
115
140
|
? [
|
|
116
141
|
`**Checksums:** ${formatFile(context, result.checksumsPath)}`,
|
package/dist/zip.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface CreateZipInput {
|
|
|
14
14
|
sourceDir: string;
|
|
15
15
|
/** Relative file paths with forward slashes, from selectFiles(). */
|
|
16
16
|
files: string[];
|
|
17
|
+
/** Generated entries, keyed by relative archive path. */
|
|
18
|
+
entries?: Record<string, Buffer>;
|
|
17
19
|
/** Archive path. */
|
|
18
20
|
zipPath: string;
|
|
19
21
|
/** Folder to put the files in inside the archive, or null for the root. */
|
|
@@ -30,3 +32,4 @@ export interface CreateZipInput {
|
|
|
30
32
|
* @throws {ValidationError} If the archive exists and force isn't set.
|
|
31
33
|
*/
|
|
32
34
|
export declare function createZip(input: CreateZipInput): Promise<void>;
|
|
35
|
+
export declare function isValidRootFolder(name: string): boolean;
|
package/dist/zip.js
CHANGED
|
@@ -31,11 +31,21 @@ export async function createZip(input) {
|
|
|
31
31
|
}
|
|
32
32
|
const zip = new yazl.ZipFile();
|
|
33
33
|
const output = createWriteStream(zipPath, { flags: force ? 'w' : 'wx' });
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
const entries = input.entries ?? {};
|
|
35
|
+
[...files, ...Object.keys(entries)].sort().forEach((file) => {
|
|
36
|
+
const path = rootFolder ? posix.join(rootFolder, file) : file;
|
|
37
|
+
const options = {
|
|
38
|
+
mtime: ZIP_MTIME,
|
|
39
|
+
mode: ZIP_FILE_MODE,
|
|
40
|
+
forceDosTimestamp: true,
|
|
41
|
+
};
|
|
42
|
+
if (Object.hasOwn(entries, file)) {
|
|
43
|
+
zip.addBuffer(entries[file] ?? Buffer.alloc(0), path, options);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
zip.addFile(join(sourceDir, file), path, options);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
39
49
|
zip.end();
|
|
40
50
|
try {
|
|
41
51
|
await pipeline(zip.outputStream, output);
|
|
@@ -48,6 +58,6 @@ export async function createZip(input) {
|
|
|
48
58
|
throw error;
|
|
49
59
|
}
|
|
50
60
|
}
|
|
51
|
-
function isValidRootFolder(name) {
|
|
61
|
+
export function isValidRootFolder(name) {
|
|
52
62
|
return !/[\\/]/.test(name) && '.' !== name && '..' !== name;
|
|
53
63
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wpelevator/wp-release",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Package, checksum, sign, verify and version-check WordPress plugins and themes, and deploy plugins to WordPress.org SVN",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"author": "WP Elevator (https://wpelevator.com)",
|
|
7
|
+
"homepage": "https://github.com/wpelevator/basement/tree/main/packages/js/wp-release#readme",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/wpelevator/basement/issues"
|
|
10
|
+
},
|
|
6
11
|
"repository": {
|
|
7
12
|
"type": "git",
|
|
8
13
|
"url": "git+https://github.com/wpelevator/basement.git",
|