@wpelevator/wp-release 0.9.0 → 0.11.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 +101 -4
- package/dist/changelog.d.ts +45 -0
- package/dist/changelog.js +246 -0
- package/dist/changeset-config.d.ts +75 -0
- package/dist/changeset-config.js +48 -0
- package/dist/changeset-dependents.d.ts +132 -0
- package/dist/changeset-dependents.js +540 -0
- package/dist/changeset-files.d.ts +41 -0
- package/dist/changeset-files.js +100 -0
- package/dist/changeset-packages.d.ts +59 -0
- package/dist/changeset-packages.js +186 -0
- package/dist/changeset-release.d.ts +155 -18
- package/dist/changeset-release.js +366 -1090
- package/dist/changesets.d.ts +2 -0
- package/dist/commands/changeset-args.d.ts +5 -4
- package/dist/commands/changeset-args.js +2 -5
- package/dist/commands/changeset-status.d.ts +2 -0
- package/dist/commands/changeset-status.js +6 -2
- package/dist/commands/changeset-tag.d.ts +0 -3
- package/dist/commands/changeset-tag.js +8 -10
- package/dist/commands/changeset-version.d.ts +3 -0
- package/dist/commands/changeset-version.js +2 -1
- package/dist/file-journal.d.ts +22 -0
- package/dist/file-journal.js +56 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/json-files.d.ts +15 -0
- package/dist/json-files.js +35 -0
- package/dist/package-meta.js +1 -3
- package/dist/regexp.d.ts +7 -0
- package/dist/regexp.js +9 -0
- package/dist/release-repository.d.ts +102 -0
- package/dist/release-repository.js +159 -0
- package/dist/release-tags.d.ts +56 -0
- package/dist/release-tags.js +89 -0
- package/dist/tag-format.d.ts +20 -0
- package/dist/tag-format.js +51 -0
- package/dist/version-check.js +1 -3
- package/dist/version-files.d.ts +36 -0
- package/dist/version-files.js +195 -0
- package/dist/versions.d.ts +25 -0
- package/dist/versions.js +74 -0
- package/package.json +3 -1
package/dist/changesets.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export interface PackageRelease {
|
|
|
31
31
|
currentVersion: string;
|
|
32
32
|
nextVersion: string;
|
|
33
33
|
changesets: Changeset[];
|
|
34
|
+
/** Names of released source packages that this dependent release bundles; absent for changeset-driven releases. */
|
|
35
|
+
sources?: string[];
|
|
34
36
|
}
|
|
35
37
|
/** A package release with its formatted changelog entries, once versioned. */
|
|
36
38
|
export interface VersionedRelease extends PackageRelease {
|
|
@@ -65,12 +65,17 @@ export declare const changesetVersionArgs: {
|
|
|
65
65
|
readonly type: "string";
|
|
66
66
|
readonly multiple: true;
|
|
67
67
|
};
|
|
68
|
+
readonly 'no-dependents': {
|
|
69
|
+
readonly type: "boolean";
|
|
70
|
+
};
|
|
68
71
|
};
|
|
69
72
|
/** Parsed input for `changeset-version`. */
|
|
70
73
|
export interface ChangesetVersionArgs {
|
|
71
74
|
dryRun: boolean;
|
|
72
75
|
date?: string;
|
|
73
76
|
packages?: string[];
|
|
77
|
+
/** Whether the selected sources release their configured dependents; defaults to true. */
|
|
78
|
+
dependents: boolean;
|
|
74
79
|
}
|
|
75
80
|
/**
|
|
76
81
|
* Validate and normalize a release date option.
|
|
@@ -99,9 +104,6 @@ export declare const changesetTagArgs: {
|
|
|
99
104
|
readonly untagged: {
|
|
100
105
|
readonly type: "boolean";
|
|
101
106
|
};
|
|
102
|
-
readonly 'github-release': {
|
|
103
|
-
readonly type: "boolean";
|
|
104
|
-
};
|
|
105
107
|
readonly since: {
|
|
106
108
|
readonly type: "string";
|
|
107
109
|
};
|
|
@@ -118,7 +120,6 @@ export interface ChangesetTagArgs {
|
|
|
118
120
|
push: boolean;
|
|
119
121
|
dryRun: boolean;
|
|
120
122
|
untagged: boolean;
|
|
121
|
-
githubRelease: boolean;
|
|
122
123
|
since?: string;
|
|
123
124
|
packages: string[];
|
|
124
125
|
version?: string;
|
|
@@ -75,6 +75,7 @@ export const changesetVersionArgs = {
|
|
|
75
75
|
'dry-run': { type: 'boolean' },
|
|
76
76
|
date: { type: 'string' },
|
|
77
77
|
package: { type: 'string', multiple: true },
|
|
78
|
+
'no-dependents': { type: 'boolean' },
|
|
78
79
|
};
|
|
79
80
|
/**
|
|
80
81
|
* Validate and normalize a release date option.
|
|
@@ -111,6 +112,7 @@ export function parseChangesetVersionArgs(values) {
|
|
|
111
112
|
}
|
|
112
113
|
return {
|
|
113
114
|
dryRun: getBoolean(values, 'dry-run'),
|
|
115
|
+
dependents: !getBoolean(values, 'no-dependents'),
|
|
114
116
|
...(date ? { date } : {}),
|
|
115
117
|
...(packages.length ? { packages } : {}),
|
|
116
118
|
};
|
|
@@ -120,7 +122,6 @@ export const changesetTagArgs = {
|
|
|
120
122
|
push: { type: 'boolean' },
|
|
121
123
|
'dry-run': { type: 'boolean' },
|
|
122
124
|
untagged: { type: 'boolean' },
|
|
123
|
-
'github-release': { type: 'boolean' },
|
|
124
125
|
since: { type: 'string' },
|
|
125
126
|
package: { type: 'string', multiple: true },
|
|
126
127
|
version: { type: 'string' },
|
|
@@ -136,7 +137,6 @@ export function parseChangesetTagArgs(values) {
|
|
|
136
137
|
push: getBoolean(values, 'push'),
|
|
137
138
|
dryRun: getBoolean(values, 'dry-run'),
|
|
138
139
|
untagged: getBoolean(values, 'untagged'),
|
|
139
|
-
githubRelease: getBoolean(values, 'github-release'),
|
|
140
140
|
since: getString(values, 'since'),
|
|
141
141
|
packages: getStrings(values, 'package'),
|
|
142
142
|
version: getString(values, 'version')?.trim(),
|
|
@@ -153,9 +153,6 @@ export function parseChangesetTagArgs(values) {
|
|
|
153
153
|
if (undefined !== args.version && 1 !== args.packages.length) {
|
|
154
154
|
throw new ValidationError('--version <version> requires exactly one --package <name>.');
|
|
155
155
|
}
|
|
156
|
-
if (args.githubRelease && !args.push) {
|
|
157
|
-
throw new ValidationError('--github-release requires --push.');
|
|
158
|
-
}
|
|
159
156
|
if (args.untagged && args.push) {
|
|
160
157
|
throw new ValidationError('--untagged cannot be combined with --push.');
|
|
161
158
|
}
|
|
@@ -13,6 +13,7 @@ export interface ChangesetStatusResult {
|
|
|
13
13
|
changedPackages: string[];
|
|
14
14
|
changedPackageFiles: Record<string, string[]>;
|
|
15
15
|
missingChangesets: string[];
|
|
16
|
+
warnings: string[];
|
|
16
17
|
}
|
|
17
18
|
declare const _default: {
|
|
18
19
|
name: string;
|
|
@@ -37,6 +38,7 @@ declare const _default: {
|
|
|
37
38
|
changedPackages: string[];
|
|
38
39
|
changedPackageFiles: Record<string, string[]>;
|
|
39
40
|
missingChangesets: string[];
|
|
41
|
+
warnings: string[];
|
|
40
42
|
};
|
|
41
43
|
}>;
|
|
42
44
|
};
|
|
@@ -20,8 +20,11 @@ An empty changeset added since the comparison base counts as an explicit no-rele
|
|
|
20
20
|
logger.summary(() => {
|
|
21
21
|
const rows = result.changedPackages.map((name) => {
|
|
22
22
|
let status = 'no release requested';
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const release = result.releases.find((item) => item.package.name === name);
|
|
24
|
+
if (release) {
|
|
25
|
+
status = release.changesets.length
|
|
26
|
+
? 'changeset found'
|
|
27
|
+
: 'releases with its sources';
|
|
25
28
|
}
|
|
26
29
|
if (result.missingChangesets.includes(name)) {
|
|
27
30
|
status = 'missing changeset';
|
|
@@ -49,6 +52,7 @@ An empty changeset added since the comparison base counts as an explicit no-rele
|
|
|
49
52
|
else if (!result.releases.length) {
|
|
50
53
|
logger.info('No pending package releases.');
|
|
51
54
|
}
|
|
55
|
+
result.warnings.forEach((warning) => logger.warning(warning));
|
|
52
56
|
return {
|
|
53
57
|
exitCode: result.missingChangesets.length ? 2 : 0,
|
|
54
58
|
result: {
|
|
@@ -3,7 +3,7 @@ import { parseChangesetTagArgs, changesetTagArgs } from "./changeset-args.js";
|
|
|
3
3
|
import { getChangesetTagSummary, getTagStatus } from "../summary.js";
|
|
4
4
|
export default {
|
|
5
5
|
name: 'changeset-tag',
|
|
6
|
-
usage: 'changeset-tag [--dry-run] [--untagged] [--since <ref>] [--package <name>] [--version <version>] [--push]
|
|
6
|
+
usage: 'changeset-tag [--dry-run] [--untagged] [--since <ref>] [--package <name>] [--version <version>] [--push]',
|
|
7
7
|
summary: 'Create missing release tags for configured package versions.',
|
|
8
8
|
help: `Options:
|
|
9
9
|
--dry-run List missing tags and their release notes without
|
|
@@ -13,16 +13,14 @@ export default {
|
|
|
13
13
|
--package <name> Tag only this package (repeatable)
|
|
14
14
|
--version <version> Fail unless the single --package is at this version;
|
|
15
15
|
the version to tag for packages versioned by git tags
|
|
16
|
-
--push Push newly created tags to origin
|
|
17
|
-
--github-release Create a GitHub Release for each tag, marked as a
|
|
18
|
-
pre-release for versions like 1.0.0-rc.1
|
|
16
|
+
--push Push newly created tags to origin, one at a time
|
|
19
17
|
|
|
20
|
-
Tags are created only when absent,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
that still need a tag, for
|
|
25
|
-
workflow.`,
|
|
18
|
+
Tags are created only when absent, so rerunning after a partial failure is
|
|
19
|
+
safe. Before a tag is created, every configured version target must match the
|
|
20
|
+
version. With --json or --github-output, each tag comes with the title, notes
|
|
21
|
+
and pre-release flag of its release, for a workflow step that creates the
|
|
22
|
+
GitHub Release. --untagged lists only the releases that still need a tag, for
|
|
23
|
+
example to release each of them with a separate workflow.`,
|
|
26
24
|
options: changesetTagArgs,
|
|
27
25
|
async run({ values, cwd, configFile, logger }) {
|
|
28
26
|
const args = parseChangesetTagArgs(values);
|
|
@@ -26,6 +26,9 @@ declare const _default: {
|
|
|
26
26
|
readonly type: "string";
|
|
27
27
|
readonly multiple: true;
|
|
28
28
|
};
|
|
29
|
+
readonly 'no-dependents': {
|
|
30
|
+
readonly type: "boolean";
|
|
31
|
+
};
|
|
29
32
|
};
|
|
30
33
|
run({ values, cwd, configFile, logger }: import("./command.ts").CommandContext): Promise<{
|
|
31
34
|
exitCode: number;
|
|
@@ -3,12 +3,13 @@ import { getChangesetVersionSummary } from "../summary.js";
|
|
|
3
3
|
import { parseChangesetVersionArgs, changesetVersionArgs, } from "./changeset-args.js";
|
|
4
4
|
export default {
|
|
5
5
|
name: 'changeset-version',
|
|
6
|
-
usage: 'changeset-version [--dry-run] [--date <YYYY-MM-DD>] [--package <name>]',
|
|
6
|
+
usage: 'changeset-version [--dry-run] [--date <YYYY-MM-DD>] [--package <name>] [--no-dependents]',
|
|
7
7
|
summary: 'Apply pending version bumps and changelog entries.',
|
|
8
8
|
help: `Options:
|
|
9
9
|
--dry-run Print the release plan without writing files
|
|
10
10
|
--date <YYYY-MM-DD> Changelog date (default: today)
|
|
11
11
|
--package <name> Version only this package (repeatable)
|
|
12
|
+
--no-dependents Leave the configured dependents of the selected sources out
|
|
12
13
|
|
|
13
14
|
Updates configured version files, prepends changelog entries and removes the
|
|
14
15
|
applied changeset files. With --package, a changeset that also names other
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Original contents of the files that a versioning run changes, so that a
|
|
3
|
+
* failed run can put every file back the way it was.
|
|
4
|
+
*/
|
|
5
|
+
export declare class FileJournal {
|
|
6
|
+
/** Original contents by file, undefined for files that didn't exist. */
|
|
7
|
+
private readonly files;
|
|
8
|
+
/**
|
|
9
|
+
* Remember the contents of a file before its first change. Later calls
|
|
10
|
+
* for the same file keep the original contents.
|
|
11
|
+
*
|
|
12
|
+
* @param file File about to change.
|
|
13
|
+
*/
|
|
14
|
+
remember(file: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Put the remembered files back in reverse order, removing the files that
|
|
17
|
+
* didn't exist. Every file is attempted, even after a failure.
|
|
18
|
+
*
|
|
19
|
+
* @return Errors of the files that couldn't be restored.
|
|
20
|
+
*/
|
|
21
|
+
restore(): Promise<Error[]>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
/**
|
|
3
|
+
* Original contents of the files that a versioning run changes, so that a
|
|
4
|
+
* failed run can put every file back the way it was.
|
|
5
|
+
*/
|
|
6
|
+
export class FileJournal {
|
|
7
|
+
/** Original contents by file, undefined for files that didn't exist. */
|
|
8
|
+
files = new Map();
|
|
9
|
+
/**
|
|
10
|
+
* Remember the contents of a file before its first change. Later calls
|
|
11
|
+
* for the same file keep the original contents.
|
|
12
|
+
*
|
|
13
|
+
* @param file File about to change.
|
|
14
|
+
*/
|
|
15
|
+
async remember(file) {
|
|
16
|
+
if (this.files.has(file)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
this.files.set(file, await readFile(file, 'utf8'));
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if ('ENOENT' !== error.code) {
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
this.files.set(file, undefined);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Put the remembered files back in reverse order, removing the files that
|
|
31
|
+
* didn't exist. Every file is attempted, even after a failure.
|
|
32
|
+
*
|
|
33
|
+
* @return Errors of the files that couldn't be restored.
|
|
34
|
+
*/
|
|
35
|
+
async restore() {
|
|
36
|
+
const errors = [];
|
|
37
|
+
for (const [file, contents] of [
|
|
38
|
+
...this.files.entries(),
|
|
39
|
+
].reverse()) {
|
|
40
|
+
try {
|
|
41
|
+
if (undefined === contents) {
|
|
42
|
+
await rm(file, { force: true });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
await writeFile(file, contents);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
errors.push(error instanceof Error
|
|
50
|
+
? error
|
|
51
|
+
: new Error(String(error)));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return errors;
|
|
55
|
+
}
|
|
56
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { isUrl, downloadFile } from './download.ts';
|
|
|
15
15
|
export { readZipEntries, getZipEntryErrors, extractZip } from './unzip.ts';
|
|
16
16
|
export { GIT_TAG_FORMAT, VersionMismatchError, getGitTagVersion, findConstantValues, findConstantDefinitions, findVersionMismatches, getVersionMismatchProblems, } from './version-check.ts';
|
|
17
17
|
export { CHANGESET_BUMPS, parseChangeset, formatChangeset, formatChangelogEntries, formatChangelogList, getChangesetBump, getNextVersion, } from './changesets.ts';
|
|
18
|
-
export { addChangeset, getChangesetPackages, getChangesetReleasePlan, getChangesetStatus, versionChangesets, tagChangesets, } from './changeset-release.ts';
|
|
18
|
+
export { ChangesetRelease, addChangeset, getChangesetPackages, getChangesetReleasePlan, getChangesetStatus, versionChangesets, tagChangesets, } from './changeset-release.ts';
|
|
19
19
|
export { defineConfig, packageJsonVersion, composerJsonVersion, wordpressPluginVersion, wordpressThemeVersion, wordpressStableTag, gitTagVersion, phpConstantVersion, loadChangesetConfig, } from './changeset-config.ts';
|
|
20
20
|
export { Svn, SvnError, createSvnRunner, parseStatus, toSvnPath, } from './svn.ts';
|
|
21
21
|
export { syncDirectory, copyFileIfChanged } from './sync.ts';
|
|
@@ -42,8 +42,8 @@ export type { CreateZipInput } from './zip.ts';
|
|
|
42
42
|
export type { ExtractZipInput, ZipEntryInfo, ZipEntryType } from './unzip.ts';
|
|
43
43
|
export type { FindVersionMismatchesInput, GitTagInput, VersionCheckResult, VersionMismatch, } from './version-check.ts';
|
|
44
44
|
export type { Changeset, ChangesetBump, ChangesetPackages, ChangesetConfig, ChangesetPackageType, ChangesetPackage, PackageRelease, VersionedRelease, ChangesetReleasePlan, } from './changesets.ts';
|
|
45
|
-
export type { ChangesetRepository, ChangesetVersionInput, VersionChangesetsResult, ChangesetTagInput, ChangesetTagResult, } from './changeset-release.ts';
|
|
46
|
-
export type { WpReleaseConfig, ChangesetPackageGroup, PackageVersionConfig, PackageVersionSource, PackageVersionTarget, PackageIdSource, NextVersionInput, ReleaseCommit, ReleaseNotesInput, ChangelogEntryInput, PackageJsonVersionOptions, ComposerJsonVersionOptions, WordPressVersionFileOptions, GitTagVersionOptions, PhpConstantVersionOptions, LoadChangesetConfigInput, } from './changeset-config.ts';
|
|
45
|
+
export type { ChangesetRepository, ChangesetReleaseOptions, ChangesetAddOptions, ChangesetVersionOptions, ChangesetTagOptions, ChangesetStatusOptions, ChangesetStatusResult, ChangesetVersionInput, VersionChangesetsResult, ChangesetTagInput, ChangesetTagResult, } from './changeset-release.ts';
|
|
46
|
+
export type { WpReleaseConfig, ChangesetPackageGroup, PackageVersionConfig, PackageVersionSource, PackageVersionTarget, PackageIdSource, NextVersionInput, ReleaseCommit, ReleaseNotesInput, ChangelogEntryInput, DependentsChangelogInput, DependentsConfig, PackageJsonVersionOptions, ComposerJsonVersionOptions, WordPressVersionFileOptions, GitTagVersionOptions, PhpConstantVersionOptions, LoadChangesetConfigInput, } from './changeset-config.ts';
|
|
47
47
|
export type { SvnCheckoutInput, SvnCommandInput, SvnCommandOutput, SvnCommitInput, SvnCopyInput, SvnDepth, SvnOptions, SvnPathsInput, SvnPropsetInput, SvnRunner, SvnStatusEntry, SvnStatusType, SvnUpdateInput, } from './svn.ts';
|
|
48
48
|
export type { SyncDirectoryInput, SyncResult } from './sync.ts';
|
|
49
49
|
export type { SummaryContext } from './summary.ts';
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ export { isUrl, downloadFile } from "./download.js";
|
|
|
15
15
|
export { readZipEntries, getZipEntryErrors, extractZip } from "./unzip.js";
|
|
16
16
|
export { GIT_TAG_FORMAT, VersionMismatchError, getGitTagVersion, findConstantValues, findConstantDefinitions, findVersionMismatches, getVersionMismatchProblems, } from "./version-check.js";
|
|
17
17
|
export { CHANGESET_BUMPS, parseChangeset, formatChangeset, formatChangelogEntries, formatChangelogList, getChangesetBump, getNextVersion, } from "./changesets.js";
|
|
18
|
-
export { addChangeset, getChangesetPackages, getChangesetReleasePlan, getChangesetStatus, versionChangesets, tagChangesets, } from "./changeset-release.js";
|
|
18
|
+
export { ChangesetRelease, addChangeset, getChangesetPackages, getChangesetReleasePlan, getChangesetStatus, versionChangesets, tagChangesets, } from "./changeset-release.js";
|
|
19
19
|
export { defineConfig, packageJsonVersion, composerJsonVersion, wordpressPluginVersion, wordpressThemeVersion, wordpressStableTag, gitTagVersion, phpConstantVersion, loadChangesetConfig, } from "./changeset-config.js";
|
|
20
20
|
export { Svn, SvnError, createSvnRunner, parseStatus, toSvnPath, } from "./svn.js";
|
|
21
21
|
export { syncDirectory, copyFileIfChanged } from "./sync.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a JSON manifest that has to exist.
|
|
3
|
+
*
|
|
4
|
+
* @param file JSON file.
|
|
5
|
+
* @return Parsed object.
|
|
6
|
+
* @throws {ValidationError} If the file is missing or isn't valid JSON.
|
|
7
|
+
*/
|
|
8
|
+
export declare function readJson(file: string): Promise<Record<string, unknown>>;
|
|
9
|
+
/**
|
|
10
|
+
* Read an optional JSON manifest.
|
|
11
|
+
*
|
|
12
|
+
* @param file JSON file.
|
|
13
|
+
* @return Parsed object, or undefined when the file doesn't exist.
|
|
14
|
+
*/
|
|
15
|
+
export declare function readJsonIfExists(file: string): Promise<Record<string, unknown> | undefined>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { ValidationError } from "./errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read a JSON manifest that has to exist.
|
|
5
|
+
*
|
|
6
|
+
* @param file JSON file.
|
|
7
|
+
* @return Parsed object.
|
|
8
|
+
* @throws {ValidationError} If the file is missing or isn't valid JSON.
|
|
9
|
+
*/
|
|
10
|
+
export async function readJson(file) {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(await readFile(file, 'utf8'));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16
|
+
throw new ValidationError(`Could not read JSON manifest ${file}: ${message}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read an optional JSON manifest.
|
|
21
|
+
*
|
|
22
|
+
* @param file JSON file.
|
|
23
|
+
* @return Parsed object, or undefined when the file doesn't exist.
|
|
24
|
+
*/
|
|
25
|
+
export async function readJsonIfExists(file) {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(await readFile(file, 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if ('ENOENT' !== error.code) {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
package/dist/package-meta.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { open, readdir, readFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { isErrorCode } from "./file-selection.js";
|
|
4
|
+
import { escapeRegExp } from "./regexp.js";
|
|
4
5
|
/**
|
|
5
6
|
* Number of bytes that WordPress reads from a file to parse its headers.
|
|
6
7
|
*/
|
|
@@ -112,9 +113,6 @@ export function findFileHeaderLine(contents, header) {
|
|
|
112
113
|
export function getLineNumber(contents, index) {
|
|
113
114
|
return contents.slice(0, index).split('\n').length;
|
|
114
115
|
}
|
|
115
|
-
function escapeRegExp(text) {
|
|
116
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
117
|
-
}
|
|
118
116
|
/**
|
|
119
117
|
* Parse the headers of a readme.txt or readme.md, the "Key: value" lines
|
|
120
118
|
* between the title and the first section. Markdown emphasis around the
|
package/dist/regexp.d.ts
ADDED
package/dist/regexp.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { ReleaseCommit } from './changeset-config.ts';
|
|
2
|
+
import type { GitRunner } from './git.ts';
|
|
3
|
+
export interface ReleaseRepositoryOptions {
|
|
4
|
+
/** Repository root that relative paths resolve against. */
|
|
5
|
+
cwd: string;
|
|
6
|
+
/** Git runner, spawning git by default. */
|
|
7
|
+
runner?: GitRunner;
|
|
8
|
+
}
|
|
9
|
+
export interface ChangedFilesOptions {
|
|
10
|
+
/** Directory to limit the diff to. */
|
|
11
|
+
directory?: string;
|
|
12
|
+
/** Value of --diff-filter, like ACMR for files that still exist. */
|
|
13
|
+
diffFilter?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The git queries and writes of a changeset release: tags, the commits of a
|
|
17
|
+
* package and the files changed since a ref.
|
|
18
|
+
*
|
|
19
|
+
* Every command runs through the runner, so that tests can replace git, and
|
|
20
|
+
* fails with a ValidationError that names the command.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ReleaseRepository {
|
|
23
|
+
readonly cwd: string;
|
|
24
|
+
readonly runner: GitRunner;
|
|
25
|
+
/**
|
|
26
|
+
* @param options Repository root and git runner.
|
|
27
|
+
*/
|
|
28
|
+
constructor(options: ReleaseRepositoryOptions);
|
|
29
|
+
/**
|
|
30
|
+
* Run a git command in the repository. The repository is marked as a safe
|
|
31
|
+
* directory, because CI containers often check it out as another user.
|
|
32
|
+
*
|
|
33
|
+
* @param args Arguments after "git".
|
|
34
|
+
* @return Standard output.
|
|
35
|
+
* @throws {ValidationError} If the command fails.
|
|
36
|
+
*/
|
|
37
|
+
run(args: string[]): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Get the path of a file relative to the repository root, with forward
|
|
40
|
+
* slashes as git expects.
|
|
41
|
+
*
|
|
42
|
+
* @param file Absolute or relative file path.
|
|
43
|
+
* @return Relative path, empty for the root itself.
|
|
44
|
+
*/
|
|
45
|
+
relativePath(file: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Check whether a tag exists.
|
|
48
|
+
*
|
|
49
|
+
* @param tag Tag name.
|
|
50
|
+
* @return Whether the tag exists.
|
|
51
|
+
*/
|
|
52
|
+
tagExists(tag: string): Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* List the tags that start with a prefix.
|
|
55
|
+
*
|
|
56
|
+
* @param prefix Tag prefix, like `plugins/alpha/`.
|
|
57
|
+
* @return Tag names.
|
|
58
|
+
*/
|
|
59
|
+
listTags(prefix: string): Promise<string[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Tag the current commit.
|
|
62
|
+
*
|
|
63
|
+
* @param tag Tag name.
|
|
64
|
+
*/
|
|
65
|
+
createTag(tag: string): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Push a tag to the origin remote.
|
|
68
|
+
*
|
|
69
|
+
* @param tag Tag name.
|
|
70
|
+
*/
|
|
71
|
+
pushTag(tag: string): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Find the commit that added a file.
|
|
74
|
+
*
|
|
75
|
+
* @param file File path.
|
|
76
|
+
* @return Commit, or undefined when the file isn't committed.
|
|
77
|
+
*/
|
|
78
|
+
getAddedCommit(file: string): Promise<ReleaseCommit | undefined>;
|
|
79
|
+
/**
|
|
80
|
+
* List the commits of a revision range that changed a directory.
|
|
81
|
+
*
|
|
82
|
+
* @param revision Revision range, like `plugins/alpha/1.0.0..HEAD`.
|
|
83
|
+
* @param directory Directory the commits changed.
|
|
84
|
+
* @return Commits, newest first.
|
|
85
|
+
*/
|
|
86
|
+
getDirectoryCommits(revision: string, directory: string): Promise<ReleaseCommit[]>;
|
|
87
|
+
/**
|
|
88
|
+
* List the files changed between the merge base of a ref and HEAD.
|
|
89
|
+
*
|
|
90
|
+
* @param since Base ref, like origin/main.
|
|
91
|
+
* @param options Directory and diff filter.
|
|
92
|
+
* @return Changed files relative to the repository root.
|
|
93
|
+
*/
|
|
94
|
+
getChangedFiles(since: string, options?: ChangedFilesOptions): Promise<string[]>;
|
|
95
|
+
/**
|
|
96
|
+
* Run git log and parse the commits.
|
|
97
|
+
*
|
|
98
|
+
* @param args Arguments after the format option.
|
|
99
|
+
* @return Commits, newest first.
|
|
100
|
+
*/
|
|
101
|
+
private getCommits;
|
|
102
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { ValidationError } from "./errors.js";
|
|
3
|
+
import { createGitRunner } from "./git.js";
|
|
4
|
+
/**
|
|
5
|
+
* The git queries and writes of a changeset release: tags, the commits of a
|
|
6
|
+
* package and the files changed since a ref.
|
|
7
|
+
*
|
|
8
|
+
* Every command runs through the runner, so that tests can replace git, and
|
|
9
|
+
* fails with a ValidationError that names the command.
|
|
10
|
+
*/
|
|
11
|
+
export class ReleaseRepository {
|
|
12
|
+
cwd;
|
|
13
|
+
runner;
|
|
14
|
+
/**
|
|
15
|
+
* @param options Repository root and git runner.
|
|
16
|
+
*/
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.cwd = path.resolve(options.cwd);
|
|
19
|
+
this.runner = options.runner ?? createGitRunner();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Run a git command in the repository. The repository is marked as a safe
|
|
23
|
+
* directory, because CI containers often check it out as another user.
|
|
24
|
+
*
|
|
25
|
+
* @param args Arguments after "git".
|
|
26
|
+
* @return Standard output.
|
|
27
|
+
* @throws {ValidationError} If the command fails.
|
|
28
|
+
*/
|
|
29
|
+
async run(args) {
|
|
30
|
+
try {
|
|
31
|
+
const { stdout } = await this.runner({
|
|
32
|
+
args: ['-c', `safe.directory=${this.cwd}`, ...args],
|
|
33
|
+
cwd: this.cwd,
|
|
34
|
+
});
|
|
35
|
+
return stdout;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
39
|
+
throw new ValidationError(`Git command failed (${args.join(' ')}): ${message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get the path of a file relative to the repository root, with forward
|
|
44
|
+
* slashes as git expects.
|
|
45
|
+
*
|
|
46
|
+
* @param file Absolute or relative file path.
|
|
47
|
+
* @return Relative path, empty for the root itself.
|
|
48
|
+
*/
|
|
49
|
+
relativePath(file) {
|
|
50
|
+
return path.relative(this.cwd, file).split(path.sep).join('/');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check whether a tag exists.
|
|
54
|
+
*
|
|
55
|
+
* @param tag Tag name.
|
|
56
|
+
* @return Whether the tag exists.
|
|
57
|
+
*/
|
|
58
|
+
async tagExists(tag) {
|
|
59
|
+
const output = await this.run(['tag', '--list', tag]);
|
|
60
|
+
return output.trim() === tag;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* List the tags that start with a prefix.
|
|
64
|
+
*
|
|
65
|
+
* @param prefix Tag prefix, like `plugins/alpha/`.
|
|
66
|
+
* @return Tag names.
|
|
67
|
+
*/
|
|
68
|
+
async listTags(prefix) {
|
|
69
|
+
const output = await this.run(['tag', '--list', `${prefix}*`]);
|
|
70
|
+
return output.trim().split(/\r?\n/).filter(Boolean);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Tag the current commit.
|
|
74
|
+
*
|
|
75
|
+
* @param tag Tag name.
|
|
76
|
+
*/
|
|
77
|
+
async createTag(tag) {
|
|
78
|
+
await this.run(['tag', tag]);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Push a tag to the origin remote.
|
|
82
|
+
*
|
|
83
|
+
* @param tag Tag name.
|
|
84
|
+
*/
|
|
85
|
+
async pushTag(tag) {
|
|
86
|
+
await this.run(['push', 'origin', tag]);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Find the commit that added a file.
|
|
90
|
+
*
|
|
91
|
+
* @param file File path.
|
|
92
|
+
* @return Commit, or undefined when the file isn't committed.
|
|
93
|
+
*/
|
|
94
|
+
async getAddedCommit(file) {
|
|
95
|
+
const [commit] = await this.getCommits([
|
|
96
|
+
'--diff-filter=A',
|
|
97
|
+
'-1',
|
|
98
|
+
'--',
|
|
99
|
+
this.relativePath(file),
|
|
100
|
+
]);
|
|
101
|
+
return commit;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* List the commits of a revision range that changed a directory.
|
|
105
|
+
*
|
|
106
|
+
* @param revision Revision range, like `plugins/alpha/1.0.0..HEAD`.
|
|
107
|
+
* @param directory Directory the commits changed.
|
|
108
|
+
* @return Commits, newest first.
|
|
109
|
+
*/
|
|
110
|
+
async getDirectoryCommits(revision, directory) {
|
|
111
|
+
return this.getCommits([
|
|
112
|
+
revision,
|
|
113
|
+
'--',
|
|
114
|
+
this.relativePath(directory) || '.',
|
|
115
|
+
]);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* List the files changed between the merge base of a ref and HEAD.
|
|
119
|
+
*
|
|
120
|
+
* @param since Base ref, like origin/main.
|
|
121
|
+
* @param options Directory and diff filter.
|
|
122
|
+
* @return Changed files relative to the repository root.
|
|
123
|
+
*/
|
|
124
|
+
async getChangedFiles(since, options = {}) {
|
|
125
|
+
const output = await this.run([
|
|
126
|
+
'diff',
|
|
127
|
+
'--name-only',
|
|
128
|
+
...(options.diffFilter
|
|
129
|
+
? [`--diff-filter=${options.diffFilter}`]
|
|
130
|
+
: []),
|
|
131
|
+
`${since}...HEAD`,
|
|
132
|
+
...(options.directory
|
|
133
|
+
? ['--', this.relativePath(options.directory)]
|
|
134
|
+
: []),
|
|
135
|
+
]);
|
|
136
|
+
return output.trim().split(/\r?\n/).filter(Boolean);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Run git log and parse the commits.
|
|
140
|
+
*
|
|
141
|
+
* @param args Arguments after the format option.
|
|
142
|
+
* @return Commits, newest first.
|
|
143
|
+
*/
|
|
144
|
+
async getCommits(args) {
|
|
145
|
+
const output = await this.run([
|
|
146
|
+
'log',
|
|
147
|
+
'--format=%H%x1f%h%x1f%s',
|
|
148
|
+
...args,
|
|
149
|
+
]);
|
|
150
|
+
return output
|
|
151
|
+
.trim()
|
|
152
|
+
.split(/\r?\n/)
|
|
153
|
+
.filter(Boolean)
|
|
154
|
+
.map((line) => {
|
|
155
|
+
const [hash = '', shortHash = '', subject = ''] = line.split('\x1f');
|
|
156
|
+
return { hash, shortHash, subject };
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|