@wpelevator/wp-release 0.4.0 → 0.5.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 +71 -8
- package/dist/cli.js +51 -12
- package/dist/commands/checksums.js +2 -0
- package/dist/commands/sign.js +2 -0
- package/dist/commands/verify.js +153 -58
- 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 +9 -4
- package/dist/index.js +5 -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
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Problem } from './errors.ts';
|
|
2
|
+
import type { Logger } from './logger.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Log each problem as an error on its file and line, and list them in the
|
|
5
|
+
* summary of the run.
|
|
6
|
+
*
|
|
7
|
+
* @param logger Logger.
|
|
8
|
+
* @param title What failed, like the command name, for the summary.
|
|
9
|
+
* @param problems Problems.
|
|
10
|
+
* @param description Text above the problems in the summary, if any.
|
|
11
|
+
*/
|
|
12
|
+
export declare function logProblems(logger: Logger, title: string, problems: Problem[], description?: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Log an error thrown while running a command, and add it to the summary of
|
|
15
|
+
* the run. A ValidationError with problems is logged problem by problem, so
|
|
16
|
+
* that each one is reported on its own file and line.
|
|
17
|
+
*
|
|
18
|
+
* @param logger Logger.
|
|
19
|
+
* @param error Thrown error.
|
|
20
|
+
* @param title What failed, like the command name, for the summary.
|
|
21
|
+
*/
|
|
22
|
+
export declare function logError(logger: Logger, error: unknown, title?: string): void;
|
package/dist/report.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ValidationError } from "./errors.js";
|
|
2
|
+
import { getErrorSummary, getProblemsSummary } from "./summary.js";
|
|
3
|
+
/**
|
|
4
|
+
* Log each problem as an error on its file and line, and list them in the
|
|
5
|
+
* summary of the run.
|
|
6
|
+
*
|
|
7
|
+
* @param logger Logger.
|
|
8
|
+
* @param title What failed, like the command name, for the summary.
|
|
9
|
+
* @param problems Problems.
|
|
10
|
+
* @param description Text above the problems in the summary, if any.
|
|
11
|
+
*/
|
|
12
|
+
export function logProblems(logger, title, problems, description = '') {
|
|
13
|
+
problems.forEach(({ message, ...annotation }) => logger.error(message, annotation));
|
|
14
|
+
logger.summary((context) => getProblemsSummary(context, title, problems, description));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Log an error thrown while running a command, and add it to the summary of
|
|
18
|
+
* the run. A ValidationError with problems is logged problem by problem, so
|
|
19
|
+
* that each one is reported on its own file and line.
|
|
20
|
+
*
|
|
21
|
+
* @param logger Logger.
|
|
22
|
+
* @param error Thrown error.
|
|
23
|
+
* @param title What failed, like the command name, for the summary.
|
|
24
|
+
*/
|
|
25
|
+
export function logError(logger, error, title = 'wp-release') {
|
|
26
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
27
|
+
const problems = error instanceof ValidationError ? error.problems : [];
|
|
28
|
+
if (problems.length) {
|
|
29
|
+
logProblems(logger, title, problems);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
logger.error(message);
|
|
33
|
+
logger.summary(() => getErrorSummary(title, message));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { ChecksumsResult } from './commands/checksums.ts';
|
|
2
|
+
import type { SignResult } from './commands/sign.ts';
|
|
3
|
+
import type { ZipResult } from './commands/zip.ts';
|
|
4
|
+
import type { DeployOptions } from './deploy-options.ts';
|
|
5
|
+
import type { SvnStatusEntry } from './svn.ts';
|
|
6
|
+
import type { Problem } from './errors.ts';
|
|
7
|
+
/**
|
|
8
|
+
* SVN host of the WordPress.org plugin repositories.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WPORG_SVN_HOST = "https://plugins.svn.wordpress.org/";
|
|
11
|
+
/**
|
|
12
|
+
* Number of files or SVN changes listed in a summary before the rest are
|
|
13
|
+
* counted.
|
|
14
|
+
*/
|
|
15
|
+
export declare const SUMMARY_LIST_LIMIT = 100;
|
|
16
|
+
/**
|
|
17
|
+
* Where summary file paths are relative to.
|
|
18
|
+
*/
|
|
19
|
+
export interface SummaryContext {
|
|
20
|
+
/** Directory that file paths are shown relative to. */
|
|
21
|
+
workspace: string;
|
|
22
|
+
}
|
|
23
|
+
export interface DeploySummaryInput {
|
|
24
|
+
/** Resolved deploy options. */
|
|
25
|
+
options: DeployOptions;
|
|
26
|
+
/** Whether a commit was made. */
|
|
27
|
+
committed: boolean;
|
|
28
|
+
/** Revision of the commit. */
|
|
29
|
+
revision: number | null;
|
|
30
|
+
/** Deployed version. */
|
|
31
|
+
version: string | null;
|
|
32
|
+
/** Changed paths in the working copy. */
|
|
33
|
+
changes: SvnStatusEntry[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get the path of a file relative to the workspace.
|
|
37
|
+
*
|
|
38
|
+
* @param workspace Workspace directory.
|
|
39
|
+
* @param file File path, absolute or relative to the working directory.
|
|
40
|
+
* @return Path with forward slashes, or null when it's outside the workspace.
|
|
41
|
+
*/
|
|
42
|
+
export declare function getWorkspacePath(workspace: string, file: string): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Format text as inline code, with a fence that is longer than any backticks
|
|
45
|
+
* in the text.
|
|
46
|
+
*
|
|
47
|
+
* @param text Text.
|
|
48
|
+
* @return Markdown code span.
|
|
49
|
+
*/
|
|
50
|
+
export declare function formatCode(text: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* Format a Markdown table.
|
|
53
|
+
*
|
|
54
|
+
* @param header Column titles.
|
|
55
|
+
* @param rows Cells of each row, already formatted as Markdown.
|
|
56
|
+
* @return Markdown table.
|
|
57
|
+
*/
|
|
58
|
+
export declare function formatTable(header: string[], rows: string[][]): string;
|
|
59
|
+
/**
|
|
60
|
+
* Format a file path as code, relative to the workspace when it's inside it.
|
|
61
|
+
* Files aren't linked, since build directories and release files usually
|
|
62
|
+
* aren't in the repository.
|
|
63
|
+
*
|
|
64
|
+
* @param context Workspace directory.
|
|
65
|
+
* @param file File path.
|
|
66
|
+
* @param line Line in the file, if known.
|
|
67
|
+
* @return Markdown code.
|
|
68
|
+
*/
|
|
69
|
+
export declare function formatFile(context: SummaryContext, file: string, line?: number | null): string;
|
|
70
|
+
/**
|
|
71
|
+
* Get the summary of a ZIP.
|
|
72
|
+
*
|
|
73
|
+
* @param context Workspace directory.
|
|
74
|
+
* @param result ZIP and manifest paths and the number of files.
|
|
75
|
+
* @return Markdown summary.
|
|
76
|
+
*/
|
|
77
|
+
export declare function getZipSummary(context: SummaryContext, result: ZipResult): string;
|
|
78
|
+
/**
|
|
79
|
+
* Get the summary of a checksums manifest.
|
|
80
|
+
*
|
|
81
|
+
* @param context Workspace directory.
|
|
82
|
+
* @param result Manifest path and the number of hashed files.
|
|
83
|
+
* @return Markdown summary.
|
|
84
|
+
*/
|
|
85
|
+
export declare function getChecksumsSummary(context: SummaryContext, result: ChecksumsResult): string;
|
|
86
|
+
/**
|
|
87
|
+
* Get the summary of signed files.
|
|
88
|
+
*
|
|
89
|
+
* @param context Workspace directory.
|
|
90
|
+
* @param result Signature paths and the public key.
|
|
91
|
+
* @return Markdown summary.
|
|
92
|
+
*/
|
|
93
|
+
export declare function getSignSummary(context: SummaryContext, result: SignResult): string;
|
|
94
|
+
/**
|
|
95
|
+
* Get the summary of a verify run where every file matches. Failed runs are
|
|
96
|
+
* summarized with their problems instead.
|
|
97
|
+
*
|
|
98
|
+
* @param context Workspace directory.
|
|
99
|
+
* @param result Verify result.
|
|
100
|
+
* @param result.checksumsPath Checksums manifest path.
|
|
101
|
+
* @param result.matched Number of matching files.
|
|
102
|
+
* @return Markdown summary.
|
|
103
|
+
*/
|
|
104
|
+
export declare function getVerifySummary(context: SummaryContext, result: {
|
|
105
|
+
checksumsPath: string;
|
|
106
|
+
matched: number;
|
|
107
|
+
}): string;
|
|
108
|
+
/**
|
|
109
|
+
* Get the summary of a version check without mismatches.
|
|
110
|
+
*
|
|
111
|
+
* @param version Version that all sources match.
|
|
112
|
+
* @return Markdown summary.
|
|
113
|
+
*/
|
|
114
|
+
export declare function getVersionCheckSummary(version: string | null): string;
|
|
115
|
+
/**
|
|
116
|
+
* Get the summary of failed checks, with the file and line of each problem.
|
|
117
|
+
* Problems after the list limit are counted instead of listed.
|
|
118
|
+
*
|
|
119
|
+
* @param context Workspace directory.
|
|
120
|
+
* @param title What failed, like the command name.
|
|
121
|
+
* @param problems Problems.
|
|
122
|
+
* @param description Text above the problems, if any.
|
|
123
|
+
* @return Markdown summary.
|
|
124
|
+
*/
|
|
125
|
+
export declare function getProblemsSummary(context: SummaryContext, title: string, problems: Problem[], description?: string): string;
|
|
126
|
+
/**
|
|
127
|
+
* Get the summary of a failed run.
|
|
128
|
+
*
|
|
129
|
+
* @param title What failed, like the command name.
|
|
130
|
+
* @param message Error message.
|
|
131
|
+
* @return Markdown summary.
|
|
132
|
+
*/
|
|
133
|
+
export declare function getErrorSummary(title: string, message: string): string;
|
|
134
|
+
/**
|
|
135
|
+
* Get the summary of a deploy, with the written paths, the commit and the
|
|
136
|
+
* SVN changes.
|
|
137
|
+
*
|
|
138
|
+
* @param input Deploy options and result.
|
|
139
|
+
* @return Markdown summary.
|
|
140
|
+
*/
|
|
141
|
+
export declare function getDeploySummary(input: DeploySummaryInput): string;
|
package/dist/summary.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { isAbsolute, relative, resolve, sep } from 'node:path';
|
|
2
|
+
import { normalizeTag } from "./deploy-options.js";
|
|
3
|
+
/**
|
|
4
|
+
* SVN host of the WordPress.org plugin repositories.
|
|
5
|
+
*/
|
|
6
|
+
export const WPORG_SVN_HOST = 'https://plugins.svn.wordpress.org/';
|
|
7
|
+
/**
|
|
8
|
+
* Number of files or SVN changes listed in a summary before the rest are
|
|
9
|
+
* counted.
|
|
10
|
+
*/
|
|
11
|
+
export const SUMMARY_LIST_LIMIT = 100;
|
|
12
|
+
/**
|
|
13
|
+
* Get the path of a file relative to the workspace.
|
|
14
|
+
*
|
|
15
|
+
* @param workspace Workspace directory.
|
|
16
|
+
* @param file File path, absolute or relative to the working directory.
|
|
17
|
+
* @return Path with forward slashes, or null when it's outside the workspace.
|
|
18
|
+
*/
|
|
19
|
+
export function getWorkspacePath(workspace, file) {
|
|
20
|
+
const path = relative(workspace, resolve(file));
|
|
21
|
+
const inWorkspace = '' !== path && !path.startsWith('..') && !isAbsolute(path);
|
|
22
|
+
return inWorkspace ? path.split(sep).join('/') : null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Format text as inline code, with a fence that is longer than any backticks
|
|
26
|
+
* in the text.
|
|
27
|
+
*
|
|
28
|
+
* @param text Text.
|
|
29
|
+
* @return Markdown code span.
|
|
30
|
+
*/
|
|
31
|
+
export function formatCode(text) {
|
|
32
|
+
const longest = Math.max(0, ...[...text.matchAll(/`+/g)].map(([ticks]) => ticks.length));
|
|
33
|
+
const fence = '`'.repeat(longest + 1);
|
|
34
|
+
const padding = longest ? ' ' : '';
|
|
35
|
+
return `${fence}${padding}${text}${padding}${fence}`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Format a Markdown table.
|
|
39
|
+
*
|
|
40
|
+
* @param header Column titles.
|
|
41
|
+
* @param rows Cells of each row, already formatted as Markdown.
|
|
42
|
+
* @return Markdown table.
|
|
43
|
+
*/
|
|
44
|
+
export function formatTable(header, rows) {
|
|
45
|
+
const formatRow = (cells) => `| ${cells
|
|
46
|
+
.map((cell) => cell.replaceAll('|', '\\|').replace(/\r?\n/g, ' '))
|
|
47
|
+
.join(' | ')} |`;
|
|
48
|
+
return [
|
|
49
|
+
formatRow(header),
|
|
50
|
+
formatRow(header.map(() => '---')),
|
|
51
|
+
...rows.map(formatRow),
|
|
52
|
+
].join('\n');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Format a file path as code, relative to the workspace when it's inside it.
|
|
56
|
+
* Files aren't linked, since build directories and release files usually
|
|
57
|
+
* aren't in the repository.
|
|
58
|
+
*
|
|
59
|
+
* @param context Workspace directory.
|
|
60
|
+
* @param file File path.
|
|
61
|
+
* @param line Line in the file, if known.
|
|
62
|
+
* @return Markdown code.
|
|
63
|
+
*/
|
|
64
|
+
export function formatFile(context, file, line) {
|
|
65
|
+
const path = getWorkspacePath(context.workspace, file) ?? file;
|
|
66
|
+
return formatCode(`${path}${line ? `:${line}` : ''}`);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Format a list, counting the items after the limit instead of listing them.
|
|
70
|
+
*
|
|
71
|
+
* @param items Items, already formatted as Markdown.
|
|
72
|
+
* @return Markdown list.
|
|
73
|
+
*/
|
|
74
|
+
function formatList(items) {
|
|
75
|
+
const listed = items.slice(0, SUMMARY_LIST_LIMIT);
|
|
76
|
+
const more = items.length - listed.length;
|
|
77
|
+
return [
|
|
78
|
+
...listed.map((item) => `- ${item}`),
|
|
79
|
+
...(more ? [`- … and ${more} more`] : []),
|
|
80
|
+
].join('\n');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Wrap content in a collapsed section.
|
|
84
|
+
*
|
|
85
|
+
* @param title Section title.
|
|
86
|
+
* @param content Markdown content.
|
|
87
|
+
* @return Markdown with a details element.
|
|
88
|
+
*/
|
|
89
|
+
function formatDetails(title, content) {
|
|
90
|
+
return `<details><summary>${title}</summary>\n\n${content}\n\n</details>`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Join summary blocks into one summary.
|
|
94
|
+
*
|
|
95
|
+
* @param blocks Markdown blocks, empty ones are left out.
|
|
96
|
+
* @return Markdown with a line break at the end.
|
|
97
|
+
*/
|
|
98
|
+
function joinBlocks(blocks) {
|
|
99
|
+
return `${blocks.filter(Boolean).join('\n\n')}\n`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get the summary of a ZIP.
|
|
103
|
+
*
|
|
104
|
+
* @param context Workspace directory.
|
|
105
|
+
* @param result ZIP and manifest paths and the number of files.
|
|
106
|
+
* @return Markdown summary.
|
|
107
|
+
*/
|
|
108
|
+
export function getZipSummary(context, result) {
|
|
109
|
+
return joinBlocks([
|
|
110
|
+
'### ZIP',
|
|
111
|
+
formatList([
|
|
112
|
+
`**ZIP:** ${formatFile(context, result.zipPath)}, ${result.files} files`,
|
|
113
|
+
...(result.checksumsPath
|
|
114
|
+
? [
|
|
115
|
+
`**Checksums:** ${formatFile(context, result.checksumsPath)}`,
|
|
116
|
+
]
|
|
117
|
+
: []),
|
|
118
|
+
]),
|
|
119
|
+
]);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the summary of a checksums manifest.
|
|
123
|
+
*
|
|
124
|
+
* @param context Workspace directory.
|
|
125
|
+
* @param result Manifest path and the number of hashed files.
|
|
126
|
+
* @return Markdown summary.
|
|
127
|
+
*/
|
|
128
|
+
export function getChecksumsSummary(context, result) {
|
|
129
|
+
return joinBlocks([
|
|
130
|
+
'### Checksums',
|
|
131
|
+
formatList([
|
|
132
|
+
`**Manifest:** ${formatFile(context, result.checksumsPath)}, ${result.files} files`,
|
|
133
|
+
]),
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get the summary of signed files.
|
|
138
|
+
*
|
|
139
|
+
* @param context Workspace directory.
|
|
140
|
+
* @param result Signature paths and the public key.
|
|
141
|
+
* @return Markdown summary.
|
|
142
|
+
*/
|
|
143
|
+
export function getSignSummary(context, result) {
|
|
144
|
+
return joinBlocks([
|
|
145
|
+
'### Signatures',
|
|
146
|
+
formatList(result.signatures.map((path) => formatFile(context, path))),
|
|
147
|
+
`Public key: ${formatCode(result.publicKey)}`,
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get the summary of a verify run where every file matches. Failed runs are
|
|
152
|
+
* summarized with their problems instead.
|
|
153
|
+
*
|
|
154
|
+
* @param context Workspace directory.
|
|
155
|
+
* @param result Verify result.
|
|
156
|
+
* @param result.checksumsPath Checksums manifest path.
|
|
157
|
+
* @param result.matched Number of matching files.
|
|
158
|
+
* @return Markdown summary.
|
|
159
|
+
*/
|
|
160
|
+
export function getVerifySummary(context, result) {
|
|
161
|
+
return joinBlocks([
|
|
162
|
+
'### Verify',
|
|
163
|
+
`All ${result.matched} files match ${formatFile(context, result.checksumsPath)}.`,
|
|
164
|
+
]);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the summary of a version check without mismatches.
|
|
168
|
+
*
|
|
169
|
+
* @param version Version that all sources match.
|
|
170
|
+
* @return Markdown summary.
|
|
171
|
+
*/
|
|
172
|
+
export function getVersionCheckSummary(version) {
|
|
173
|
+
return joinBlocks([
|
|
174
|
+
'### Version check',
|
|
175
|
+
`All versions match ${formatCode(version ?? '')}.`,
|
|
176
|
+
]);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get the summary of failed checks, with the file and line of each problem.
|
|
180
|
+
* Problems after the list limit are counted instead of listed.
|
|
181
|
+
*
|
|
182
|
+
* @param context Workspace directory.
|
|
183
|
+
* @param title What failed, like the command name.
|
|
184
|
+
* @param problems Problems.
|
|
185
|
+
* @param description Text above the problems, if any.
|
|
186
|
+
* @return Markdown summary.
|
|
187
|
+
*/
|
|
188
|
+
export function getProblemsSummary(context, title, problems, description = '') {
|
|
189
|
+
const more = problems.length - SUMMARY_LIST_LIMIT;
|
|
190
|
+
return joinBlocks([
|
|
191
|
+
`### ${title} failed`,
|
|
192
|
+
description,
|
|
193
|
+
formatTable(['Problem', 'Location'], problems
|
|
194
|
+
.slice(0, SUMMARY_LIST_LIMIT)
|
|
195
|
+
.map(({ message, file, line }) => [
|
|
196
|
+
message,
|
|
197
|
+
file ? formatFile(context, file, line) : '',
|
|
198
|
+
])),
|
|
199
|
+
more > 0 && `… and ${more} more`,
|
|
200
|
+
]);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get the summary of a failed run.
|
|
204
|
+
*
|
|
205
|
+
* @param title What failed, like the command name.
|
|
206
|
+
* @param message Error message.
|
|
207
|
+
* @return Markdown summary.
|
|
208
|
+
*/
|
|
209
|
+
export function getErrorSummary(title, message) {
|
|
210
|
+
return joinBlocks([
|
|
211
|
+
`### ${title} failed`,
|
|
212
|
+
message
|
|
213
|
+
.split(/\r?\n/)
|
|
214
|
+
.map((line) => `> ${line}`)
|
|
215
|
+
.join('\n'),
|
|
216
|
+
]);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Get the paths that a deploy writes to.
|
|
220
|
+
*
|
|
221
|
+
* @param options Resolved deploy options.
|
|
222
|
+
* @return SVN paths.
|
|
223
|
+
*/
|
|
224
|
+
function getDeployWrites(options) {
|
|
225
|
+
const { trunk, readmeOnly, svnTag, assets, assetsDir, readme } = options;
|
|
226
|
+
return [
|
|
227
|
+
trunk && 'trunk/',
|
|
228
|
+
readmeOnly && `trunk/${readme}`,
|
|
229
|
+
svnTag && `tags/${normalizeTag(svnTag)}/`,
|
|
230
|
+
assets && assetsDir && 'assets/',
|
|
231
|
+
].filter((path) => Boolean(path));
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Describe the result of a deploy commit.
|
|
235
|
+
*
|
|
236
|
+
* @param input Deploy options and result.
|
|
237
|
+
* @return Markdown text.
|
|
238
|
+
*/
|
|
239
|
+
function describeDeployResult(input) {
|
|
240
|
+
const { options, committed, revision, changes } = input;
|
|
241
|
+
const isWporg = options.svnUrl.startsWith(WPORG_SVN_HOST);
|
|
242
|
+
const revisionLabel = `r${revision}`;
|
|
243
|
+
const revisionLink = isWporg
|
|
244
|
+
? `[${revisionLabel}](https://plugins.trac.wordpress.org/changeset/${revision})`
|
|
245
|
+
: revisionLabel;
|
|
246
|
+
const uncommitted = changes.length
|
|
247
|
+
? `Dry run, ${changes.length} changes were not committed.`
|
|
248
|
+
: 'No changes to commit.';
|
|
249
|
+
return committed
|
|
250
|
+
? `Committed ${revisionLink} with ${changes.length} changes.`
|
|
251
|
+
: uncommitted;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get the summary of a deploy, with the written paths, the commit and the
|
|
255
|
+
* SVN changes.
|
|
256
|
+
*
|
|
257
|
+
* @param input Deploy options and result.
|
|
258
|
+
* @return Markdown summary.
|
|
259
|
+
*/
|
|
260
|
+
export function getDeploySummary(input) {
|
|
261
|
+
const { options, version, changes } = input;
|
|
262
|
+
const isWporg = options.svnUrl.startsWith(WPORG_SVN_HOST);
|
|
263
|
+
const plugin = isWporg
|
|
264
|
+
? `[${options.slug}](https://wordpress.org/plugins/${options.slug}/)`
|
|
265
|
+
: formatCode(options.slug);
|
|
266
|
+
return joinBlocks([
|
|
267
|
+
isWporg ? '### Deploy to WordPress.org' : '### Deploy to SVN',
|
|
268
|
+
formatList([
|
|
269
|
+
`**Plugin:** ${plugin}`,
|
|
270
|
+
...(version ? [`**Version:** ${formatCode(version)}`] : []),
|
|
271
|
+
`**Writes:** ${getDeployWrites(options)
|
|
272
|
+
.map(formatCode)
|
|
273
|
+
.join(', ')}`,
|
|
274
|
+
`**Result:** ${describeDeployResult(input)}`,
|
|
275
|
+
]),
|
|
276
|
+
changes.length > 0 &&
|
|
277
|
+
formatDetails(`SVN changes (${changes.length})`, formatTable(['Status', 'Path'], changes
|
|
278
|
+
.slice(0, SUMMARY_LIST_LIMIT)
|
|
279
|
+
.map(({ status, path }) => [
|
|
280
|
+
status,
|
|
281
|
+
formatCode(path),
|
|
282
|
+
])) +
|
|
283
|
+
(changes.length > SUMMARY_LIST_LIMIT
|
|
284
|
+
? `\n\n… and ${changes.length - SUMMARY_LIST_LIMIT} more`
|
|
285
|
+
: '')),
|
|
286
|
+
]);
|
|
287
|
+
}
|
package/dist/svn-deploy.d.ts
CHANGED
|
@@ -78,7 +78,8 @@ export declare class SvnDeploy {
|
|
|
78
78
|
* pre-release tag doesn't change the stable tag. Readme-only updates need
|
|
79
79
|
* the readme.
|
|
80
80
|
*
|
|
81
|
-
* @throws {ValidationError} When the files
|
|
81
|
+
* @throws {ValidationError} When the files don't match.
|
|
82
|
+
* @throws {VersionMismatchError} When the versions don't match.
|
|
82
83
|
*/
|
|
83
84
|
checkVersions(): Promise<void>;
|
|
84
85
|
/**
|
package/dist/svn-deploy.js
CHANGED
|
@@ -10,8 +10,9 @@ import { loadFileRules, selectFiles } from "./file-selection.js";
|
|
|
10
10
|
import { readPackageMeta } from "./package-meta.js";
|
|
11
11
|
import { Svn } from "./svn.js";
|
|
12
12
|
import { copyFileIfChanged, syncDirectory } from "./sync.js";
|
|
13
|
+
import { getDeploySummary } from "./summary.js";
|
|
13
14
|
import { extractZip } from "./unzip.js";
|
|
14
|
-
import { findVersionMismatches } from "./version-check.js";
|
|
15
|
+
import { VersionMismatchError, findVersionMismatches, } from "./version-check.js";
|
|
15
16
|
/**
|
|
16
17
|
* MIME types of the plugin directory asset formats. svn guesses binary
|
|
17
18
|
* types, but WordPress.org serves assets with the svn:mime-type property,
|
|
@@ -102,7 +103,8 @@ export class SvnDeploy {
|
|
|
102
103
|
* pre-release tag doesn't change the stable tag. Readme-only updates need
|
|
103
104
|
* the readme.
|
|
104
105
|
*
|
|
105
|
-
* @throws {ValidationError} When the files
|
|
106
|
+
* @throws {ValidationError} When the files don't match.
|
|
107
|
+
* @throws {VersionMismatchError} When the versions don't match.
|
|
106
108
|
*/
|
|
107
109
|
async checkVersions() {
|
|
108
110
|
const { trunk, readmeOnly, svnTag, slug, readme } = this.options;
|
|
@@ -122,9 +124,7 @@ export class SvnDeploy {
|
|
|
122
124
|
});
|
|
123
125
|
this.version = version;
|
|
124
126
|
if (mismatches.length) {
|
|
125
|
-
throw new
|
|
126
|
-
.map(({ message }) => message)
|
|
127
|
-
.join('\n'));
|
|
127
|
+
throw new VersionMismatchError(sourceDir, mismatches);
|
|
128
128
|
}
|
|
129
129
|
this.logger.info(`Deploying version ${version}.`);
|
|
130
130
|
}
|
|
@@ -379,7 +379,9 @@ export class SvnDeploy {
|
|
|
379
379
|
await this.checkVersions();
|
|
380
380
|
await this.checkout();
|
|
381
381
|
await this.sync();
|
|
382
|
-
|
|
382
|
+
const result = await this.commit();
|
|
383
|
+
this.logger.summary(() => getDeploySummary({ options: this.options, ...result }));
|
|
384
|
+
return result;
|
|
383
385
|
}
|
|
384
386
|
finally {
|
|
385
387
|
await this.cleanup();
|
package/dist/version-check.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ValidationError } from './errors.ts';
|
|
2
|
+
import type { Problem } from './errors.ts';
|
|
1
3
|
import type { PackageMeta } from './package-meta.ts';
|
|
2
4
|
export declare const GIT_TAG_FORMAT = "{version}";
|
|
3
5
|
/**
|
|
@@ -6,8 +8,10 @@ export declare const GIT_TAG_FORMAT = "{version}";
|
|
|
6
8
|
export interface VersionMismatch {
|
|
7
9
|
/** Where the version comes from, like "Stable tag" or "Git tag". */
|
|
8
10
|
source: string;
|
|
9
|
-
/** File that holds the version, if any. */
|
|
11
|
+
/** File that holds the version, relative to the source directory, if any. */
|
|
10
12
|
file: string | null;
|
|
13
|
+
/** Line of the version in the file, starting at 1, if known. */
|
|
14
|
+
line: number | null;
|
|
11
15
|
/** Version found, or null when it's missing. */
|
|
12
16
|
actual: string | null;
|
|
13
17
|
/** Human-readable description. */
|
|
@@ -45,6 +49,28 @@ export interface VersionCheckResult {
|
|
|
45
49
|
/** Every mismatch, empty when all versions agree. */
|
|
46
50
|
mismatches: VersionMismatch[];
|
|
47
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the problems of version mismatches, with their files relative to the
|
|
54
|
+
* working directory instead of the plugin directory.
|
|
55
|
+
*
|
|
56
|
+
* @param sourceDir Directory that the mismatch files are relative to.
|
|
57
|
+
* @param mismatches Mismatches from findVersionMismatches().
|
|
58
|
+
* @return Problems.
|
|
59
|
+
*/
|
|
60
|
+
export declare function getVersionMismatchProblems(sourceDir: string, mismatches: VersionMismatch[]): Problem[];
|
|
61
|
+
/**
|
|
62
|
+
* Versions that don't agree, thrown by a deploy before anything is written.
|
|
63
|
+
* The message lists every mismatch, and the problems have their files and
|
|
64
|
+
* lines.
|
|
65
|
+
*/
|
|
66
|
+
export declare class VersionMismatchError extends ValidationError {
|
|
67
|
+
name: string;
|
|
68
|
+
/** Directory that the mismatch files are relative to. */
|
|
69
|
+
readonly sourceDir: string;
|
|
70
|
+
/** Every mismatch. */
|
|
71
|
+
readonly mismatches: VersionMismatch[];
|
|
72
|
+
constructor(sourceDir: string, mismatches: VersionMismatch[]);
|
|
73
|
+
}
|
|
48
74
|
/**
|
|
49
75
|
* Get the version from a git tag with a format like v{version} or
|
|
50
76
|
* {slug}-{version}. A leading "v" is stripped from the version, like for
|
|
@@ -64,6 +90,18 @@ export declare function getGitTagVersion(input: GitTagInput): string | null;
|
|
|
64
90
|
* @return Values in the order they appear.
|
|
65
91
|
*/
|
|
66
92
|
export declare function findConstantValues(contents: string, name: string): string[];
|
|
93
|
+
/**
|
|
94
|
+
* Find the definitions of a PHP constant set with define( 'NAME', '1.2.0' )
|
|
95
|
+
* or const NAME = '1.2.0'.
|
|
96
|
+
*
|
|
97
|
+
* @param contents PHP code.
|
|
98
|
+
* @param name Constant name.
|
|
99
|
+
* @return Values and their line numbers, in the order they appear.
|
|
100
|
+
*/
|
|
101
|
+
export declare function findConstantDefinitions(contents: string, name: string): Array<{
|
|
102
|
+
value: string;
|
|
103
|
+
line: number;
|
|
104
|
+
}>;
|
|
67
105
|
/**
|
|
68
106
|
* Check that the Version header, readme Stable tag, PHP constants and git tag
|
|
69
107
|
* of a plugin or theme agree, and report every one that doesn't. Themes have
|