@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,94 @@
|
|
|
1
|
+
import { appendFileSync } from 'node:fs';
|
|
2
|
+
import { getWorkspacePath } from "./summary.js";
|
|
3
|
+
/**
|
|
4
|
+
* Escape the message of a workflow command, so that a multi-line message
|
|
5
|
+
* stays one annotation.
|
|
6
|
+
*
|
|
7
|
+
* @param text Message.
|
|
8
|
+
* @return Escaped message.
|
|
9
|
+
*/
|
|
10
|
+
function escapeData(text) {
|
|
11
|
+
return text
|
|
12
|
+
.replaceAll('%', '%25')
|
|
13
|
+
.replaceAll('\r', '%0D')
|
|
14
|
+
.replaceAll('\n', '%0A');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Escape a workflow command property like a file path or title.
|
|
18
|
+
*
|
|
19
|
+
* @param text Property value.
|
|
20
|
+
* @return Escaped value.
|
|
21
|
+
*/
|
|
22
|
+
function escapeProperty(text) {
|
|
23
|
+
return escapeData(text).replaceAll(':', '%3A').replaceAll(',', '%2C');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Writer that prints GitHub Actions workflow commands, so that notices,
|
|
27
|
+
* warnings and errors are annotations on the run and on the files they're
|
|
28
|
+
* about, and appends summaries to the job summary.
|
|
29
|
+
*/
|
|
30
|
+
export class GitHubActionsWriter {
|
|
31
|
+
stdout;
|
|
32
|
+
stderr;
|
|
33
|
+
workspace;
|
|
34
|
+
summaryPath;
|
|
35
|
+
constructor({ stdout = process.stdout, stderr = process.stderr, workspace = process.env.GITHUB_WORKSPACE || process.cwd(), summaryPath = process.env.GITHUB_STEP_SUMMARY || null, } = {}) {
|
|
36
|
+
this.stdout = stdout;
|
|
37
|
+
this.stderr = stderr;
|
|
38
|
+
this.workspace = workspace;
|
|
39
|
+
this.summaryPath = summaryPath;
|
|
40
|
+
}
|
|
41
|
+
write({ level, message, annotation }) {
|
|
42
|
+
const stream = 'warning' === level || 'error' === level
|
|
43
|
+
? this.stderr
|
|
44
|
+
: this.stdout;
|
|
45
|
+
stream.write('info' === level
|
|
46
|
+
? `${message}\n`
|
|
47
|
+
: this.formatCommand(level, message, annotation));
|
|
48
|
+
}
|
|
49
|
+
startGroup(title) {
|
|
50
|
+
this.stdout.write(`::group::${escapeData(title)}\n`);
|
|
51
|
+
}
|
|
52
|
+
endGroup() {
|
|
53
|
+
this.stdout.write('::endgroup::\n');
|
|
54
|
+
}
|
|
55
|
+
summary(build) {
|
|
56
|
+
if (this.summaryPath) {
|
|
57
|
+
// A blank line keeps the Markdown of separate summaries apart.
|
|
58
|
+
appendFileSync(this.summaryPath, `${build({ workspace: this.workspace }).trimEnd()}\n\n`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Format a workflow command like
|
|
63
|
+
* "::error file=my-plugin.php,line=3,title=Version mismatch::message".
|
|
64
|
+
*
|
|
65
|
+
* @param name Command name.
|
|
66
|
+
* @param message Message.
|
|
67
|
+
* @param annotation File, line and title of the annotation.
|
|
68
|
+
* @return Workflow command with a line break.
|
|
69
|
+
*/
|
|
70
|
+
formatCommand(name, message, annotation = {}) {
|
|
71
|
+
const file = this.getAnnotationFile(annotation.file);
|
|
72
|
+
const properties = [
|
|
73
|
+
file ? `file=${escapeProperty(file)}` : '',
|
|
74
|
+
file && annotation.line ? `line=${annotation.line}` : '',
|
|
75
|
+
annotation.title
|
|
76
|
+
? `title=${escapeProperty(annotation.title)}`
|
|
77
|
+
: '',
|
|
78
|
+
]
|
|
79
|
+
.filter(Boolean)
|
|
80
|
+
.join(',');
|
|
81
|
+
return `::${name}${properties ? ` ${properties}` : ''}::${escapeData(message)}\n`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get the path of an annotation file relative to the workspace. GitHub
|
|
85
|
+
* only links files of the repository, so files outside the workspace,
|
|
86
|
+
* like an extracted ZIP in a temporary directory, get no file.
|
|
87
|
+
*
|
|
88
|
+
* @param file File path, absolute or relative to the working directory.
|
|
89
|
+
* @return Path with forward slashes, or null when it's outside the workspace.
|
|
90
|
+
*/
|
|
91
|
+
getAnnotationFile(file) {
|
|
92
|
+
return file ? getWorkspacePath(this.workspace, file) : null;
|
|
93
|
+
}
|
|
94
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
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';
|
|
17
|
+
export { CHANGESET_BUMPS, parseChangeset, formatChangeset, getChangesetBump, getNextVersion, } from './changesets.ts';
|
|
18
|
+
export { addChangeset, getChangesetReleasePlan, getChangesetStatus, versionChangesets, tagChangesets, } from './changeset-release.ts';
|
|
19
|
+
export { defineConfig, packageJsonVersion, composerJsonVersion, wordpressPluginVersion, wordpressThemeVersion, wordpressStableTag, gitTagVersion, phpConstantVersion, loadChangesetConfig, } from './changeset-config.ts';
|
|
15
20
|
export { Svn, SvnError, createSvnRunner, parseStatus, toSvnPath, } from './svn.ts';
|
|
16
21
|
export { syncDirectory, copyFileIfChanged } from './sync.ts';
|
|
17
22
|
export { ASSET_MIME_TYPES, SvnDeploy } from './svn-deploy.ts';
|
|
@@ -21,7 +26,9 @@ export type { SignResult } from './commands/sign.ts';
|
|
|
21
26
|
export type { ZipResult } from './commands/zip.ts';
|
|
22
27
|
export type { Command, CommandContext, CommandOutcome, ParsedValues, } from './commands/command.ts';
|
|
23
28
|
export type { DeployArgsInput } from './commands/deploy-svn.ts';
|
|
24
|
-
export type { LoggerOptions, OutputStream } from './logger.ts';
|
|
29
|
+
export type { Annotation, LogEntry, LogLevel, LogWriter, LoggerOptions, OutputStream, SummaryBuilder, TextWriterOptions, } from './logger.ts';
|
|
30
|
+
export type { GitHubActionsWriterOptions } from './github-actions-writer.ts';
|
|
31
|
+
export type { Problem } from './errors.ts';
|
|
25
32
|
export type { DeployInput, DeployOptions } from './deploy-options.ts';
|
|
26
33
|
export type { FileRules, FileSelection, FileSelectionInput, } from './file-selection.ts';
|
|
27
34
|
export type { FilenameValues } from './filename.ts';
|
|
@@ -30,6 +37,10 @@ export type { FindMainPluginFileInput, HeaderValues, PackageMeta, ParseFileHeade
|
|
|
30
37
|
export type { CreateZipInput } from './zip.ts';
|
|
31
38
|
export type { ExtractZipInput, ZipEntryInfo, ZipEntryType } from './unzip.ts';
|
|
32
39
|
export type { FindVersionMismatchesInput, GitTagInput, VersionCheckResult, VersionMismatch, } from './version-check.ts';
|
|
40
|
+
export type { Changeset, ChangesetBump, ChangesetPackages, ChangesetConfig, ChangesetPackageType, ChangesetPackage, PackageRelease, ChangesetReleasePlan, } from './changesets.ts';
|
|
41
|
+
export type { ChangesetRepository, ChangesetVersionInput, ChangesetTagInput, ChangesetTagResult, } from './changeset-release.ts';
|
|
42
|
+
export type { WpReleaseConfig, ChangesetPackageGroup, PackageVersionConfig, PackageVersionSource, PackageVersionTarget, PackageIdSource, NextVersionInput, PackageJsonVersionOptions, ComposerJsonVersionOptions, WordPressVersionFileOptions, GitTagVersionOptions, PhpConstantVersionOptions, LoadChangesetConfigInput, } from './changeset-config.ts';
|
|
33
43
|
export type { SvnCheckoutInput, SvnCommandInput, SvnCommandOutput, SvnCommitInput, SvnCopyInput, SvnDepth, SvnOptions, SvnPathsInput, SvnPropsetInput, SvnRunner, SvnStatusEntry, SvnStatusType, SvnUpdateInput, } from './svn.ts';
|
|
34
44
|
export type { SyncDirectoryInput, SyncResult } from './sync.ts';
|
|
45
|
+
export type { SummaryContext } from './summary.ts';
|
|
35
46
|
export type { CheckoutPath, DeployResult } from './svn-deploy.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
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";
|
|
17
|
+
export { CHANGESET_BUMPS, parseChangeset, formatChangeset, getChangesetBump, getNextVersion, } from "./changesets.js";
|
|
18
|
+
export { addChangeset, getChangesetReleasePlan, getChangesetStatus, versionChangesets, tagChangesets, } from "./changeset-release.js";
|
|
19
|
+
export { defineConfig, packageJsonVersion, composerJsonVersion, wordpressPluginVersion, wordpressThemeVersion, wordpressStableTag, gitTagVersion, phpConstantVersion, loadChangesetConfig, } from "./changeset-config.js";
|
|
15
20
|
export { Svn, SvnError, createSvnRunner, parseStatus, toSvnPath, } from "./svn.js";
|
|
16
21
|
export { syncDirectory, copyFileIfChanged } from "./sync.js";
|
|
17
22
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
*
|
|
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
|
|
82
|
+
readonly writer: LogWriter;
|
|
24
83
|
readonly quiet: boolean;
|
|
25
84
|
readonly verbose: boolean;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
33
|
+
writer;
|
|
6
34
|
quiet;
|
|
7
35
|
verbose;
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
24
|
-
this.stdout.write(this.ci ? `::debug::${message}\n` : `${message}\n`);
|
|
25
|
-
}
|
|
61
|
+
this.log('debug', message);
|
|
26
62
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.stdout.write(this.ci ? `::notice::${message}\n` : `${message}\n`);
|
|
30
|
-
}
|
|
63
|
+
info(message) {
|
|
64
|
+
this.log('info', message);
|
|
31
65
|
}
|
|
32
|
-
|
|
33
|
-
this.
|
|
66
|
+
notice(message, annotation = {}) {
|
|
67
|
+
this.log('notice', message, annotation);
|
|
34
68
|
}
|
|
35
|
-
|
|
36
|
-
this.
|
|
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
|
-
|
|
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.
|
|
52
|
-
this.
|
|
99
|
+
if (!this.quiet) {
|
|
100
|
+
this.writer.endGroup();
|
|
53
101
|
}
|
|
54
102
|
}
|
|
55
103
|
}
|
package/dist/package-meta.d.ts
CHANGED
|
@@ -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
|
*
|
package/dist/package-meta.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
107
|
-
const match =
|
|
108
|
-
|
|
109
|
-
|
|
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
|
*
|
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
|
+
}
|