@wpelevator/wp-release 0.4.1 → 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/dist/index.d.ts CHANGED
@@ -1,17 +1,19 @@
1
1
  export { run, execute, commands, getHelp, getCommandHelp } from './cli.ts';
2
+ export { logError, logProblems } from './report.ts';
2
3
  export { getDeployInputFromArgs } from './commands/deploy-svn.ts';
3
4
  export { ValidationError, CredentialsError } from './errors.ts';
4
- export { Logger } from './logger.ts';
5
+ export { Logger, TextWriter } from './logger.ts';
6
+ export { GitHubActionsWriter } from './github-actions-writer.ts';
5
7
  export { SVN_URL, isPrerelease, normalizeTag, isTagRef, isValidSlug, isValidVersion, getDeployOptionErrors, getDeployOptionWarnings, resolveDeployOptions, } from './deploy-options.ts';
6
8
  export { DISTIGNORE_FILENAME, parseExclude, resolveFileSelection, loadFileRules, selectFiles, } from './file-selection.ts';
7
9
  export { FILENAME_FORMAT, formatFilename } from './filename.ts';
8
10
  export { CHECKSUMS_EXTENSION, CHECKSUM_ALGORITHMS, hashFile, hashFiles, createChecksums, writeChecksums, readChecksums, parseChecksums, compareChecksums, verifyChecksums, } from './checksums.ts';
9
- export { HEADER_BYTES, PLUGIN_HEADERS, THEME_HEADERS, README_HEADERS, README_FILENAMES, parseFileHeaders, parseReadmeHeaders, readFileStart, findMainPluginFile, readPackageMeta, } from './package-meta.ts';
11
+ export { HEADER_BYTES, PLUGIN_HEADERS, THEME_HEADERS, README_HEADERS, README_FILENAMES, parseFileHeaders, parseReadmeHeaders, readFileStart, findFileHeaderLine, findReadmeHeaderLine, findMainPluginFile, readPackageMeta, } from './package-meta.ts';
10
12
  export { SIGNATURE_EXTENSION, SIGNING_KEY_ENV, parseSigningKey, parsePublicKey, getPublicKey, getFileDigest, signFile, writeSignature, verifyFileSignature, } from './signing.ts';
11
13
  export { ZIP_MTIME, ZIP_FILE_MODE, createZip } from './zip.ts';
12
14
  export { isUrl, downloadFile } from './download.ts';
13
15
  export { readZipEntries, getZipEntryErrors, extractZip } from './unzip.ts';
14
- export { GIT_TAG_FORMAT, getGitTagVersion, findConstantValues, findVersionMismatches, } from './version-check.ts';
16
+ export { GIT_TAG_FORMAT, VersionMismatchError, getGitTagVersion, findConstantValues, findConstantDefinitions, findVersionMismatches, getVersionMismatchProblems, } from './version-check.ts';
15
17
  export { Svn, SvnError, createSvnRunner, parseStatus, toSvnPath, } from './svn.ts';
16
18
  export { syncDirectory, copyFileIfChanged } from './sync.ts';
17
19
  export { ASSET_MIME_TYPES, SvnDeploy } from './svn-deploy.ts';
@@ -21,7 +23,9 @@ export type { SignResult } from './commands/sign.ts';
21
23
  export type { ZipResult } from './commands/zip.ts';
22
24
  export type { Command, CommandContext, CommandOutcome, ParsedValues, } from './commands/command.ts';
23
25
  export type { DeployArgsInput } from './commands/deploy-svn.ts';
24
- export type { LoggerOptions, OutputStream } from './logger.ts';
26
+ export type { Annotation, LogEntry, LogLevel, LogWriter, LoggerOptions, OutputStream, SummaryBuilder, TextWriterOptions, } from './logger.ts';
27
+ export type { GitHubActionsWriterOptions } from './github-actions-writer.ts';
28
+ export type { Problem } from './errors.ts';
25
29
  export type { DeployInput, DeployOptions } from './deploy-options.ts';
26
30
  export type { FileRules, FileSelection, FileSelectionInput, } from './file-selection.ts';
27
31
  export type { FilenameValues } from './filename.ts';
@@ -32,4 +36,5 @@ export type { ExtractZipInput, ZipEntryInfo, ZipEntryType } from './unzip.ts';
32
36
  export type { FindVersionMismatchesInput, GitTagInput, VersionCheckResult, VersionMismatch, } from './version-check.ts';
33
37
  export type { SvnCheckoutInput, SvnCommandInput, SvnCommandOutput, SvnCommitInput, SvnCopyInput, SvnDepth, SvnOptions, SvnPathsInput, SvnPropsetInput, SvnRunner, SvnStatusEntry, SvnStatusType, SvnUpdateInput, } from './svn.ts';
34
38
  export type { SyncDirectoryInput, SyncResult } from './sync.ts';
39
+ export type { SummaryContext } from './summary.ts';
35
40
  export type { CheckoutPath, DeployResult } from './svn-deploy.ts';
package/dist/index.js CHANGED
@@ -1,17 +1,19 @@
1
1
  export { run, execute, commands, getHelp, getCommandHelp } from "./cli.js";
2
+ export { logError, logProblems } from "./report.js";
2
3
  export { getDeployInputFromArgs } from "./commands/deploy-svn.js";
3
4
  export { ValidationError, CredentialsError } from "./errors.js";
4
- export { Logger } from "./logger.js";
5
+ export { Logger, TextWriter } from "./logger.js";
6
+ export { GitHubActionsWriter } from "./github-actions-writer.js";
5
7
  export { SVN_URL, isPrerelease, normalizeTag, isTagRef, isValidSlug, isValidVersion, getDeployOptionErrors, getDeployOptionWarnings, resolveDeployOptions, } from "./deploy-options.js";
6
8
  export { DISTIGNORE_FILENAME, parseExclude, resolveFileSelection, loadFileRules, selectFiles, } from "./file-selection.js";
7
9
  export { FILENAME_FORMAT, formatFilename } from "./filename.js";
8
10
  export { CHECKSUMS_EXTENSION, CHECKSUM_ALGORITHMS, hashFile, hashFiles, createChecksums, writeChecksums, readChecksums, parseChecksums, compareChecksums, verifyChecksums, } from "./checksums.js";
9
- export { HEADER_BYTES, PLUGIN_HEADERS, THEME_HEADERS, README_HEADERS, README_FILENAMES, parseFileHeaders, parseReadmeHeaders, readFileStart, findMainPluginFile, readPackageMeta, } from "./package-meta.js";
11
+ export { HEADER_BYTES, PLUGIN_HEADERS, THEME_HEADERS, README_HEADERS, README_FILENAMES, parseFileHeaders, parseReadmeHeaders, readFileStart, findFileHeaderLine, findReadmeHeaderLine, findMainPluginFile, readPackageMeta, } from "./package-meta.js";
10
12
  export { SIGNATURE_EXTENSION, SIGNING_KEY_ENV, parseSigningKey, parsePublicKey, getPublicKey, getFileDigest, signFile, writeSignature, verifyFileSignature, } from "./signing.js";
11
13
  export { ZIP_MTIME, ZIP_FILE_MODE, createZip } from "./zip.js";
12
14
  export { isUrl, downloadFile } from "./download.js";
13
15
  export { readZipEntries, getZipEntryErrors, extractZip } from "./unzip.js";
14
- export { GIT_TAG_FORMAT, getGitTagVersion, findConstantValues, findVersionMismatches, } from "./version-check.js";
16
+ export { GIT_TAG_FORMAT, VersionMismatchError, getGitTagVersion, findConstantValues, findConstantDefinitions, findVersionMismatches, getVersionMismatchProblems, } from "./version-check.js";
15
17
  export { Svn, SvnError, createSvnRunner, parseStatus, toSvnPath, } from "./svn.js";
16
18
  export { syncDirectory, copyFileIfChanged } from "./sync.js";
17
19
  export { ASSET_MIME_TYPES, SvnDeploy } from "./svn-deploy.js";
package/dist/logger.d.ts CHANGED
@@ -1,36 +1,108 @@
1
+ import type { SummaryContext } from './summary.ts';
1
2
  /**
2
3
  * Stream that output is written to, like process.stdout.
3
4
  */
4
5
  export interface OutputStream {
5
6
  write: (text: string) => unknown;
6
7
  }
7
- export interface LoggerOptions {
8
- /** Use GitHub Actions workflow commands. */
9
- ci?: boolean;
10
- /** Print errors only. */
11
- quiet?: boolean;
12
- /** Print debug messages. */
13
- verbose?: boolean;
8
+ /**
9
+ * Log levels, from the most to the least verbose.
10
+ */
11
+ export type LogLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error';
12
+ /**
13
+ * File and title that a message is about, which writers like the GitHub
14
+ * Actions writer show as an annotation on the file.
15
+ */
16
+ export interface Annotation {
17
+ /** File the message is about, absolute or relative to the working directory. */
18
+ file?: string | null;
19
+ /** Line in the file, starting at 1. */
20
+ line?: number | null;
21
+ /** Annotation title. */
22
+ title?: string;
23
+ }
24
+ /**
25
+ * A message passed from the logger to its writer.
26
+ */
27
+ export interface LogEntry {
28
+ level: LogLevel;
29
+ message: string;
30
+ annotation: Annotation;
31
+ }
32
+ /**
33
+ * Builds the Markdown of a summary for the context of a writer.
34
+ */
35
+ export type SummaryBuilder = (context: SummaryContext) => string;
36
+ /**
37
+ * Destination of the log, like a terminal or a CI system. The logger decides
38
+ * which messages to write, and the writer decides how they look.
39
+ */
40
+ export interface LogWriter {
41
+ /** Write a message. */
42
+ write: (entry: LogEntry) => void;
43
+ /** Start a collapsible group of messages. */
44
+ startGroup: (title: string) => void;
45
+ /** End the group started last. */
46
+ endGroup: () => void;
47
+ /** Add to the summary of the run, for writers that have one. */
48
+ summary: (build: SummaryBuilder) => void;
49
+ }
50
+ export interface TextWriterOptions {
14
51
  /** Stream for regular output. */
15
52
  stdout?: OutputStream;
16
53
  /** Stream for warnings and errors. */
17
54
  stderr?: OutputStream;
18
55
  }
19
56
  /**
20
- * Logger that prints plain text locally and GitHub Actions workflow commands in CI.
57
+ * Writer that prints plain text, for terminals and CI systems without
58
+ * special log formats.
59
+ */
60
+ export declare class TextWriter implements LogWriter {
61
+ readonly stdout: OutputStream;
62
+ readonly stderr: OutputStream;
63
+ constructor({ stdout, stderr, }?: TextWriterOptions);
64
+ write({ level, message }: LogEntry): void;
65
+ startGroup(title: string): void;
66
+ endGroup(): void;
67
+ summary(): void;
68
+ }
69
+ export interface LoggerOptions {
70
+ /** Writer for the messages, a TextWriter by default. */
71
+ writer?: LogWriter;
72
+ /** Print errors and warnings only. */
73
+ quiet?: boolean;
74
+ /** Print debug messages. */
75
+ verbose?: boolean;
76
+ }
77
+ /**
78
+ * Logger that filters messages by level and passes them to a writer, which
79
+ * formats them for a terminal or a CI system.
21
80
  */
22
81
  export declare class Logger {
23
- readonly ci: boolean;
82
+ readonly writer: LogWriter;
24
83
  readonly quiet: boolean;
25
84
  readonly verbose: boolean;
26
- readonly stdout: OutputStream;
27
- readonly stderr: OutputStream;
28
- constructor({ ci, quiet, verbose, stdout, stderr, }?: LoggerOptions);
29
- info(message: string): void;
85
+ constructor({ writer, quiet, verbose, }?: LoggerOptions);
86
+ /**
87
+ * Write a message unless its level is filtered out.
88
+ *
89
+ * @param level Log level.
90
+ * @param message Message.
91
+ * @param annotation File, line and title the message is about.
92
+ */
93
+ log(level: LogLevel, message: string, annotation?: Annotation): void;
30
94
  debug(message: string): void;
31
- notice(message: string): void;
32
- warning(message: string): void;
33
- error(message: string): void;
95
+ info(message: string): void;
96
+ notice(message: string, annotation?: Annotation): void;
97
+ warning(message: string, annotation?: Annotation): void;
98
+ error(message: string, annotation?: Annotation): void;
99
+ /**
100
+ * Add to the summary of the run. Only writers with a summary, like the
101
+ * GitHub Actions job summary, call the builder.
102
+ *
103
+ * @param build Builds the summary Markdown.
104
+ */
105
+ summary(build: SummaryBuilder): void;
34
106
  /**
35
107
  * Run a callback inside a collapsible log group.
36
108
  *
package/dist/logger.js CHANGED
@@ -1,39 +1,85 @@
1
1
  /**
2
- * Logger that prints plain text locally and GitHub Actions workflow commands in CI.
2
+ * Writer that prints plain text, for terminals and CI systems without
3
+ * special log formats.
4
+ */
5
+ export class TextWriter {
6
+ stdout;
7
+ stderr;
8
+ constructor({ stdout = process.stdout, stderr = process.stderr, } = {}) {
9
+ this.stdout = stdout;
10
+ this.stderr = stderr;
11
+ }
12
+ write({ level, message }) {
13
+ const prefixes = {
14
+ warning: 'Warning: ',
15
+ error: 'Error: ',
16
+ };
17
+ const stream = 'warning' === level || 'error' === level
18
+ ? this.stderr
19
+ : this.stdout;
20
+ stream.write(`${prefixes[level] ?? ''}${message}\n`);
21
+ }
22
+ startGroup(title) {
23
+ this.stdout.write(`== ${title}\n`);
24
+ }
25
+ endGroup() { }
26
+ summary() { }
27
+ }
28
+ /**
29
+ * Logger that filters messages by level and passes them to a writer, which
30
+ * formats them for a terminal or a CI system.
3
31
  */
4
32
  export class Logger {
5
- ci;
33
+ writer;
6
34
  quiet;
7
35
  verbose;
8
- stdout;
9
- stderr;
10
- constructor({ ci = 'true' === process.env.GITHUB_ACTIONS, quiet = false, verbose = false, stdout = process.stdout, stderr = process.stderr, } = {}) {
11
- this.ci = ci;
36
+ constructor({ writer = new TextWriter(), quiet = false, verbose = false, } = {}) {
37
+ this.writer = writer;
12
38
  this.quiet = quiet;
13
39
  this.verbose = verbose;
14
- this.stdout = stdout;
15
- this.stderr = stderr;
16
40
  }
17
- info(message) {
18
- if (!this.quiet) {
19
- this.stdout.write(`${message}\n`);
41
+ /**
42
+ * Write a message unless its level is filtered out.
43
+ *
44
+ * @param level Log level.
45
+ * @param message Message.
46
+ * @param annotation File, line and title the message is about.
47
+ */
48
+ log(level, message, annotation = {}) {
49
+ const shown = {
50
+ debug: this.verbose && !this.quiet,
51
+ info: !this.quiet,
52
+ notice: !this.quiet,
53
+ warning: true,
54
+ error: true,
55
+ }[level];
56
+ if (shown) {
57
+ this.writer.write({ level, message, annotation });
20
58
  }
21
59
  }
22
60
  debug(message) {
23
- if (this.verbose && !this.quiet) {
24
- this.stdout.write(this.ci ? `::debug::${message}\n` : `${message}\n`);
25
- }
61
+ this.log('debug', message);
26
62
  }
27
- notice(message) {
28
- if (!this.quiet) {
29
- this.stdout.write(this.ci ? `::notice::${message}\n` : `${message}\n`);
30
- }
63
+ info(message) {
64
+ this.log('info', message);
31
65
  }
32
- warning(message) {
33
- this.stderr.write(this.ci ? `::warning::${message}\n` : `Warning: ${message}\n`);
66
+ notice(message, annotation = {}) {
67
+ this.log('notice', message, annotation);
34
68
  }
35
- error(message) {
36
- this.stderr.write(this.ci ? `::error::${message}\n` : `Error: ${message}\n`);
69
+ warning(message, annotation = {}) {
70
+ this.log('warning', message, annotation);
71
+ }
72
+ error(message, annotation = {}) {
73
+ this.log('error', message, annotation);
74
+ }
75
+ /**
76
+ * Add to the summary of the run. Only writers with a summary, like the
77
+ * GitHub Actions job summary, call the builder.
78
+ *
79
+ * @param build Builds the summary Markdown.
80
+ */
81
+ summary(build) {
82
+ this.writer.summary(build);
37
83
  }
38
84
  /**
39
85
  * Run a callback inside a collapsible log group.
@@ -43,13 +89,15 @@ export class Logger {
43
89
  * @return Callback result.
44
90
  */
45
91
  async group(title, callback) {
46
- this.info(this.ci ? `::group::${title}` : `== ${title}`);
92
+ if (!this.quiet) {
93
+ this.writer.startGroup(title);
94
+ }
47
95
  try {
48
96
  return await callback();
49
97
  }
50
98
  finally {
51
- if (this.ci) {
52
- this.info('::endgroup::');
99
+ if (!this.quiet) {
100
+ this.writer.endGroup();
53
101
  }
54
102
  }
55
103
  }
@@ -76,6 +76,23 @@ export interface ReadPackageMetaInput {
76
76
  * @return Non-empty header values.
77
77
  */
78
78
  export declare function parseFileHeaders(input: ParseFileHeadersInput): HeaderValues;
79
+ /**
80
+ * Find the line of a file header like "Version: 1.2.0", matched the same way
81
+ * as parseFileHeaders().
82
+ *
83
+ * @param contents File contents.
84
+ * @param header Header name.
85
+ * @return Line number starting at 1, or null when the header isn't there.
86
+ */
87
+ export declare function findFileHeaderLine(contents: string, header: string): number | null;
88
+ /**
89
+ * Get the line number of a position in a text.
90
+ *
91
+ * @param contents Text.
92
+ * @param index Character position.
93
+ * @return Line number starting at 1.
94
+ */
95
+ export declare function getLineNumber(contents: string, index: number): number;
79
96
  /**
80
97
  * Parse the headers of a readme.txt or readme.md, the "Key: value" lines
81
98
  * between the title and the first section. Markdown emphasis around the
@@ -85,6 +102,15 @@ export declare function parseFileHeaders(input: ParseFileHeadersInput): HeaderVa
85
102
  * @return Non-empty header values keyed by the names in README_HEADERS.
86
103
  */
87
104
  export declare function parseReadmeHeaders(contents: string): HeaderValues;
105
+ /**
106
+ * Find the line of a readme header like "Stable tag: 1.2.0", the line that
107
+ * parseReadmeHeaders() reads the value from.
108
+ *
109
+ * @param contents Readme contents.
110
+ * @param header Header name from README_HEADERS.
111
+ * @return Line number starting at 1, or null when the header isn't there.
112
+ */
113
+ export declare function findReadmeHeaderLine(contents: string, header: string): number | null;
88
114
  /**
89
115
  * Read the start of a file, where WordPress looks for the headers.
90
116
  *
@@ -82,11 +82,36 @@ export function parseFileHeaders(input) {
82
82
  ]);
83
83
  return Object.fromEntries(entries.filter(([, value]) => value));
84
84
  }
85
+ function getFileHeaderPattern(header) {
86
+ return new RegExp(`^(?:[ \\t]*<\\?php)?[ \\t/*#@]*${escapeRegExp(header)}:(.*)$`, 'mi');
87
+ }
85
88
  function matchFileHeader(contents, header) {
86
- const pattern = new RegExp(`^(?:[ \\t]*<\\?php)?[ \\t/*#@]*${escapeRegExp(header)}:(.*)$`, 'mi');
87
- const value = pattern.exec(contents)?.[1] ?? '';
89
+ const value = getFileHeaderPattern(header).exec(contents)?.[1] ?? '';
88
90
  return value.replace(/\s*(?:\*\/|\?>).*/, '').trim();
89
91
  }
92
+ /**
93
+ * Find the line of a file header like "Version: 1.2.0", matched the same way
94
+ * as parseFileHeaders().
95
+ *
96
+ * @param contents File contents.
97
+ * @param header Header name.
98
+ * @return Line number starting at 1, or null when the header isn't there.
99
+ */
100
+ export function findFileHeaderLine(contents, header) {
101
+ const normalized = contents.replace(/\r\n?/g, '\n');
102
+ const match = getFileHeaderPattern(header).exec(normalized);
103
+ return match ? getLineNumber(normalized, match.index) : null;
104
+ }
105
+ /**
106
+ * Get the line number of a position in a text.
107
+ *
108
+ * @param contents Text.
109
+ * @param index Character position.
110
+ * @return Line number starting at 1.
111
+ */
112
+ export function getLineNumber(contents, index) {
113
+ return contents.slice(0, index).split('\n').length;
114
+ }
90
115
  function escapeRegExp(text) {
91
116
  return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
92
117
  }
@@ -99,19 +124,49 @@ function escapeRegExp(text) {
99
124
  * @return Non-empty header values keyed by the names in README_HEADERS.
100
125
  */
101
126
  export function parseReadmeHeaders(contents) {
102
- const lines = contents.replace(/\r\n?/g, '\n').split('\n');
103
- const firstSection = lines.findIndex((line, index) => index > 0 && /^\s*(==|##)/.test(line));
104
- const headerLines = lines.slice(0, -1 === firstSection ? lines.length : firstSection);
105
127
  const values = {};
106
- headerLines.forEach((line) => {
107
- const match = /^[\s*_-]*([^:*_]+?)[*_]*\s*:[*_]*\s*(.*?)\s*$/.exec(line);
108
- const header = README_HEADERS.find((name) => name.toLowerCase() === match?.[1]?.toLowerCase());
109
- if (header && match?.[2] && !Object.hasOwn(values, header)) {
110
- values[header] = match[2];
128
+ getReadmeHeaderLines(contents).forEach((line) => {
129
+ const match = matchReadmeHeader(line);
130
+ if (match && !Object.hasOwn(values, match.header)) {
131
+ values[match.header] = match.value;
111
132
  }
112
133
  });
113
134
  return values;
114
135
  }
136
+ /**
137
+ * Find the line of a readme header like "Stable tag: 1.2.0", the line that
138
+ * parseReadmeHeaders() reads the value from.
139
+ *
140
+ * @param contents Readme contents.
141
+ * @param header Header name from README_HEADERS.
142
+ * @return Line number starting at 1, or null when the header isn't there.
143
+ */
144
+ export function findReadmeHeaderLine(contents, header) {
145
+ const index = getReadmeHeaderLines(contents).findIndex((line) => header === matchReadmeHeader(line)?.header);
146
+ return -1 === index ? null : index + 1;
147
+ }
148
+ /**
149
+ * Get the readme lines before the first section, where the headers are.
150
+ *
151
+ * @param contents Readme contents.
152
+ * @return Lines from the first line.
153
+ */
154
+ function getReadmeHeaderLines(contents) {
155
+ const lines = contents.replace(/\r\n?/g, '\n').split('\n');
156
+ const firstSection = lines.findIndex((line, index) => index > 0 && /^\s*(==|##)/.test(line));
157
+ return lines.slice(0, -1 === firstSection ? lines.length : firstSection);
158
+ }
159
+ /**
160
+ * Match a readme header line. Markdown emphasis around the name is ignored.
161
+ *
162
+ * @param line Readme line.
163
+ * @return Header name from README_HEADERS and its value, or null when the line isn't a non-empty header.
164
+ */
165
+ function matchReadmeHeader(line) {
166
+ const match = /^[\s*_-]*([^:*_]+?)[*_]*\s*:[*_]*\s*(.*?)\s*$/.exec(line);
167
+ const header = README_HEADERS.find((name) => name.toLowerCase() === match?.[1]?.toLowerCase());
168
+ return header && match?.[2] ? { header, value: match[2] } : null;
169
+ }
115
170
  /**
116
171
  * Read the start of a file, where WordPress looks for the headers.
117
172
  *
@@ -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;