@wpelevator/wp-release 0.10.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 +61 -4
- package/dist/changelog.d.ts +45 -0
- package/dist/changelog.js +246 -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 +153 -19
- package/dist/changeset-release.js +359 -1685
- package/dist/commands/changeset-args.d.ts +0 -4
- package/dist/commands/changeset-args.js +0 -5
- package/dist/commands/changeset-tag.d.ts +0 -3
- package/dist/commands/changeset-tag.js +8 -10
- package/dist/file-journal.d.ts +22 -0
- package/dist/file-journal.js +56 -0
- package/dist/index.d.ts +2 -2
- 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 +1 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { readChangelogSection, getLatestChangelogVersion, } from "./changelog.js";
|
|
2
|
+
import { assertKnownPackages, toChangesetPackage, } from "./changeset-packages.js";
|
|
3
|
+
import { ValidationError } from "./errors.js";
|
|
4
|
+
import { compareVersions, isVersion } from "./versions.js";
|
|
5
|
+
/**
|
|
6
|
+
* Pick the packages to tag.
|
|
7
|
+
*
|
|
8
|
+
* @param packages Configured packages.
|
|
9
|
+
* @param names Packages passed with --package, empty for all.
|
|
10
|
+
* @param version Expected version passed with --version, if any.
|
|
11
|
+
* @return Selected packages in the configured order.
|
|
12
|
+
* @throws {ValidationError} For unknown packages, or an expected version without a single package.
|
|
13
|
+
*/
|
|
14
|
+
export function selectTagPackages(packages, names, version) {
|
|
15
|
+
if (undefined !== version && 1 !== names.length) {
|
|
16
|
+
throw new ValidationError('An expected version requires exactly one package.');
|
|
17
|
+
}
|
|
18
|
+
assertKnownPackages(packages, names);
|
|
19
|
+
return names.length
|
|
20
|
+
? packages.filter((pkg) => names.includes(pkg.name))
|
|
21
|
+
: packages;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the version to tag. Packages versioned by their git tags have no
|
|
25
|
+
* version file, so the expected version is the version to tag, or else the
|
|
26
|
+
* latest CHANGELOG.md version.
|
|
27
|
+
*
|
|
28
|
+
* @param pkg Configured package.
|
|
29
|
+
* @param expected Expected version from --version, if any.
|
|
30
|
+
* @return Version to tag.
|
|
31
|
+
*/
|
|
32
|
+
export async function getTagVersion(pkg, expected) {
|
|
33
|
+
if ('git-tag' !== pkg.versionConfig.from.kind) {
|
|
34
|
+
return pkg.currentVersion;
|
|
35
|
+
}
|
|
36
|
+
return (expected ??
|
|
37
|
+
(await getLatestChangelogVersion(pkg.directory, pkg.currentVersion)));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Find the tag of the newest release before a version.
|
|
41
|
+
*
|
|
42
|
+
* @param repository Repository with the tags.
|
|
43
|
+
* @param prefix Tag prefix of the package, like `plugins/alpha/`.
|
|
44
|
+
* @param version Version being released.
|
|
45
|
+
* @return Previous tag, or undefined for the first release.
|
|
46
|
+
*/
|
|
47
|
+
export async function getPreviousTag(repository, prefix, version) {
|
|
48
|
+
const tags = await repository.listTags(prefix);
|
|
49
|
+
return tags
|
|
50
|
+
.filter((tag) => tag.startsWith(prefix))
|
|
51
|
+
.map((tag) => ({ tag, version: tag.slice(prefix.length) }))
|
|
52
|
+
.filter((item) => isVersion(item.version) &&
|
|
53
|
+
compareVersions(item.version, version) < 0)
|
|
54
|
+
.sort((a, b) => compareVersions(b.version, a.version))[0]?.tag;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build the release notes of a tag from its CHANGELOG.md section, or from the
|
|
58
|
+
* commits since the previous release without one, with the configured
|
|
59
|
+
* formatter.
|
|
60
|
+
*
|
|
61
|
+
* @param repository Repository with the release commits.
|
|
62
|
+
* @param config Repository release configuration.
|
|
63
|
+
* @param pkg Released package.
|
|
64
|
+
* @param release Version, tag and previous tag of the release.
|
|
65
|
+
* @param end Commit of the release: the tag, or HEAD before tagging.
|
|
66
|
+
* @return Release notes.
|
|
67
|
+
*/
|
|
68
|
+
export async function getReleaseNotes(repository, config, pkg, release, end) {
|
|
69
|
+
const changelog = await readChangelogSection(pkg.directory, release.version);
|
|
70
|
+
const commits = await repository.getDirectoryCommits(release.previousTag ? `${release.previousTag}..${end}` : end, pkg.directory);
|
|
71
|
+
const notes = changelog ||
|
|
72
|
+
commits
|
|
73
|
+
.map((commit) => `- ${commit.subject} (${commit.shortHash})`)
|
|
74
|
+
.join('\n');
|
|
75
|
+
if (!config.releaseNotes) {
|
|
76
|
+
return notes;
|
|
77
|
+
}
|
|
78
|
+
const formatted = await config.releaseNotes({
|
|
79
|
+
package: toChangesetPackage(pkg),
|
|
80
|
+
...release,
|
|
81
|
+
changelog,
|
|
82
|
+
commits,
|
|
83
|
+
notes,
|
|
84
|
+
});
|
|
85
|
+
if ('string' !== typeof formatted) {
|
|
86
|
+
throw new ValidationError(`The releaseNotes formatter didn't return a string for package "${pkg.name}".`);
|
|
87
|
+
}
|
|
88
|
+
return formatted.trim();
|
|
89
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ConfiguredPackage } from './changeset-packages.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Format the tag of a package release.
|
|
4
|
+
*
|
|
5
|
+
* @param format Tag format with {name}, {slug}, {path}, {type} and {version}.
|
|
6
|
+
* @param pkg Configured package.
|
|
7
|
+
* @param version Released version, empty for the tag prefix of the package.
|
|
8
|
+
* @return Tag name.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatTag(format: string, pkg: ConfiguredPackage, version: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Format the tag prefix of a package before its name is known, for packages
|
|
13
|
+
* versioned by their git tags.
|
|
14
|
+
*
|
|
15
|
+
* @param pattern Tag pattern of the version source.
|
|
16
|
+
* @param packagePath Package path relative to the package root.
|
|
17
|
+
* @param tagType Configured {type} of the package tags.
|
|
18
|
+
* @return Tag prefix.
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatTemplatePrefix(pattern: string, packagePath: string, tagType?: string): string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Format the tag of a package release.
|
|
4
|
+
*
|
|
5
|
+
* @param format Tag format with {name}, {slug}, {path}, {type} and {version}.
|
|
6
|
+
* @param pkg Configured package.
|
|
7
|
+
* @param version Released version, empty for the tag prefix of the package.
|
|
8
|
+
* @return Tag name.
|
|
9
|
+
*/
|
|
10
|
+
export function formatTag(format, pkg, version) {
|
|
11
|
+
const type = pkg.group.tagType ?? defaultTagType(pkg.path, pkg.type);
|
|
12
|
+
return format
|
|
13
|
+
.replaceAll('{name}', pkg.name)
|
|
14
|
+
.replaceAll('{slug}', '.' === pkg.path
|
|
15
|
+
? path.basename(pkg.directory)
|
|
16
|
+
: path.basename(pkg.path))
|
|
17
|
+
.replaceAll('{path}', pkg.path)
|
|
18
|
+
.replaceAll('{type}', type)
|
|
19
|
+
.replaceAll('{version}', version);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Format the tag prefix of a package before its name is known, for packages
|
|
23
|
+
* versioned by their git tags.
|
|
24
|
+
*
|
|
25
|
+
* @param pattern Tag pattern of the version source.
|
|
26
|
+
* @param packagePath Package path relative to the package root.
|
|
27
|
+
* @param tagType Configured {type} of the package tags.
|
|
28
|
+
* @return Tag prefix.
|
|
29
|
+
*/
|
|
30
|
+
export function formatTemplatePrefix(pattern, packagePath, tagType) {
|
|
31
|
+
return pattern
|
|
32
|
+
.replaceAll('{path}', packagePath)
|
|
33
|
+
.replaceAll('{type}', tagType ?? defaultTagType(packagePath))
|
|
34
|
+
.replaceAll('{name}', packagePath.split('/').at(-1) ?? packagePath)
|
|
35
|
+
.replaceAll('{slug}', packagePath.split('/').at(-1) ?? packagePath)
|
|
36
|
+
.replaceAll('{version}', '');
|
|
37
|
+
}
|
|
38
|
+
function defaultTagType(packagePath, type) {
|
|
39
|
+
if ('.' === packagePath && type) {
|
|
40
|
+
return type;
|
|
41
|
+
}
|
|
42
|
+
const first = packagePath.split('/')[0] ?? 'package';
|
|
43
|
+
const irregular = {
|
|
44
|
+
actions: 'action',
|
|
45
|
+
plugins: 'plugin',
|
|
46
|
+
themes: 'theme',
|
|
47
|
+
php: 'php',
|
|
48
|
+
js: 'js',
|
|
49
|
+
};
|
|
50
|
+
return irregular[first] ?? first.replace(/s$/, '');
|
|
51
|
+
}
|
package/dist/version-check.js
CHANGED
|
@@ -5,6 +5,7 @@ import { normalizeTag } from "./deploy-options.js";
|
|
|
5
5
|
import { ValidationError } from "./errors.js";
|
|
6
6
|
import { selectFiles } from "./file-selection.js";
|
|
7
7
|
import { findFileHeaderLine, findReadmeHeaderLine, getLineNumber, readFileStart, } from "./package-meta.js";
|
|
8
|
+
import { escapeRegExp } from "./regexp.js";
|
|
8
9
|
export const GIT_TAG_FORMAT = '{version}';
|
|
9
10
|
const TAG_REF_PREFIX = 'refs/tags/';
|
|
10
11
|
/**
|
|
@@ -66,9 +67,6 @@ export function getGitTagVersion(input) {
|
|
|
66
67
|
const version = new RegExp(`^${pattern}$`).exec(tag)?.[1];
|
|
67
68
|
return version ? normalizeTag(version) : null;
|
|
68
69
|
}
|
|
69
|
-
function escapeRegExp(text) {
|
|
70
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
71
|
-
}
|
|
72
70
|
/**
|
|
73
71
|
* Find the values of a PHP constant set with define( 'NAME', '1.2.0' ) or
|
|
74
72
|
* const NAME = '1.2.0'.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PackageVersionSource, PackageVersionTarget } from './changeset-config.ts';
|
|
2
|
+
import type { ConfiguredPackage } from './changeset-packages.ts';
|
|
3
|
+
import type { FileJournal } from './file-journal.ts';
|
|
4
|
+
import type { ReleaseRepository } from './release-repository.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Read the current version of a package from its configured source.
|
|
7
|
+
*
|
|
8
|
+
* @param repository Repository, for versions stored as git tags.
|
|
9
|
+
* @param directory Package directory.
|
|
10
|
+
* @param descriptor Version source.
|
|
11
|
+
* @param relativePath Package path relative to the package root.
|
|
12
|
+
* @param tagType Configured {type} of the package tags.
|
|
13
|
+
* @return Current version.
|
|
14
|
+
* @throws {ValidationError} If the version is missing.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readVersion(repository: ReleaseRepository, directory: string, descriptor: PackageVersionSource, relativePath: string, tagType?: string): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Write a version to a configured version target.
|
|
19
|
+
*
|
|
20
|
+
* @param directory Package directory.
|
|
21
|
+
* @param descriptor Version target.
|
|
22
|
+
* @param version Version to write.
|
|
23
|
+
* @param journal File journal for rolling back.
|
|
24
|
+
* @throws {ValidationError} If the target file has no version to replace.
|
|
25
|
+
*/
|
|
26
|
+
export declare function writeVersion(directory: string, descriptor: PackageVersionTarget, version: string, journal: FileJournal): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Check that every version target of a package has the expected version.
|
|
29
|
+
* Optional targets that are absent are skipped.
|
|
30
|
+
*
|
|
31
|
+
* @param repository Repository, for versions stored as git tags.
|
|
32
|
+
* @param pkg Configured package.
|
|
33
|
+
* @param expected Expected version.
|
|
34
|
+
* @throws {ValidationError} For the first target with another version.
|
|
35
|
+
*/
|
|
36
|
+
export declare function verifyVersionTargets(repository: ReleaseRepository, pkg: ConfiguredPackage, expected: string): Promise<void>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { access, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ValidationError } from "./errors.js";
|
|
4
|
+
import { readJson } from "./json-files.js";
|
|
5
|
+
import { findMainPluginFile } from "./package-meta.js";
|
|
6
|
+
import { escapeRegExp } from "./regexp.js";
|
|
7
|
+
import { formatTemplatePrefix } from "./tag-format.js";
|
|
8
|
+
import { findConstantValues } from "./version-check.js";
|
|
9
|
+
import { compareVersions } from "./versions.js";
|
|
10
|
+
/**
|
|
11
|
+
* Read the current version of a package from its configured source.
|
|
12
|
+
*
|
|
13
|
+
* @param repository Repository, for versions stored as git tags.
|
|
14
|
+
* @param directory Package directory.
|
|
15
|
+
* @param descriptor Version source.
|
|
16
|
+
* @param relativePath Package path relative to the package root.
|
|
17
|
+
* @param tagType Configured {type} of the package tags.
|
|
18
|
+
* @return Current version.
|
|
19
|
+
* @throws {ValidationError} If the version is missing.
|
|
20
|
+
*/
|
|
21
|
+
export async function readVersion(repository, directory, descriptor, relativePath, tagType) {
|
|
22
|
+
if ('package-json' === descriptor.kind ||
|
|
23
|
+
'composer-json' === descriptor.kind) {
|
|
24
|
+
const manifest = await readJson(path.join(directory, descriptor.file));
|
|
25
|
+
const version = manifest[descriptor.field];
|
|
26
|
+
if ('string' === typeof version && version.trim()) {
|
|
27
|
+
return version;
|
|
28
|
+
}
|
|
29
|
+
throw new ValidationError(`Missing ${descriptor.file}#${descriptor.field} in ${directory}.`);
|
|
30
|
+
}
|
|
31
|
+
if ('git-tag' === descriptor.kind) {
|
|
32
|
+
const pattern = descriptor.pattern ?? '{path}/{version}';
|
|
33
|
+
const tags = await repository.listTags(formatTemplatePrefix(pattern, relativePath, tagType));
|
|
34
|
+
const versions = tags
|
|
35
|
+
.map((tag) => tag.match(/(?:^|\/|v)(\d+\.\d+\.\d+)$/)?.[1])
|
|
36
|
+
.filter((item) => Boolean(item));
|
|
37
|
+
versions.sort((a, b) => compareVersions(b, a));
|
|
38
|
+
if (versions[0]) {
|
|
39
|
+
return versions[0];
|
|
40
|
+
}
|
|
41
|
+
throw new ValidationError(`No git tag matches ${pattern} for ${relativePath}.`);
|
|
42
|
+
}
|
|
43
|
+
if ('php-constant' === descriptor.kind) {
|
|
44
|
+
const file = path.join(directory, descriptor.file);
|
|
45
|
+
const contents = await readFile(file, 'utf8');
|
|
46
|
+
const versions = findConstantValues(contents, descriptor.constant);
|
|
47
|
+
if (versions[0]) {
|
|
48
|
+
return versions[0];
|
|
49
|
+
}
|
|
50
|
+
throw new ValidationError(`Missing PHP constant ${descriptor.constant} in ${file}.`);
|
|
51
|
+
}
|
|
52
|
+
const file = path.join(directory, await getVersionFile(directory, descriptor.kind, descriptor.file));
|
|
53
|
+
const contents = await readFile(file, 'utf8');
|
|
54
|
+
const label = 'wordpress-stable-tag' === descriptor.kind ? 'Stable tag' : 'Version';
|
|
55
|
+
const match = new RegExp(`^\\s*\\*?\\s*${label}:\\s*([^\\r\\n]+)`, 'im').exec(contents);
|
|
56
|
+
if (!match) {
|
|
57
|
+
throw new ValidationError(`Missing ${label} header in ${file}.`);
|
|
58
|
+
}
|
|
59
|
+
return match[1]?.trim() ?? '';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Write a version to a configured version target.
|
|
63
|
+
*
|
|
64
|
+
* @param directory Package directory.
|
|
65
|
+
* @param descriptor Version target.
|
|
66
|
+
* @param version Version to write.
|
|
67
|
+
* @param journal File journal for rolling back.
|
|
68
|
+
* @throws {ValidationError} If the target file has no version to replace.
|
|
69
|
+
*/
|
|
70
|
+
export async function writeVersion(directory, descriptor, version, journal) {
|
|
71
|
+
if ('package-json' === descriptor.kind ||
|
|
72
|
+
'composer-json' === descriptor.kind) {
|
|
73
|
+
const file = path.join(directory, descriptor.file);
|
|
74
|
+
const contents = await readFile(file, 'utf8');
|
|
75
|
+
const manifest = JSON.parse(contents);
|
|
76
|
+
if ('composer-json' === descriptor.kind &&
|
|
77
|
+
descriptor.ifPresent &&
|
|
78
|
+
!Object.hasOwn(manifest, descriptor.field)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
manifest[descriptor.field] = version;
|
|
82
|
+
await journal.remember(file);
|
|
83
|
+
await writeFile(file, `${JSON.stringify(manifest, null, '\t')}\n`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if ('php-constant' === descriptor.kind) {
|
|
87
|
+
const file = path.join(directory, descriptor.file);
|
|
88
|
+
const contents = await readFile(file, 'utf8');
|
|
89
|
+
const constant = escapeRegExp(descriptor.constant);
|
|
90
|
+
const definePattern = new RegExp(`(\\bdefine\\s*\\(\\s*(['"])${constant}\\2\\s*,\\s*)(['"])(.*?)\\3`, 'g');
|
|
91
|
+
const declarationPattern = new RegExp(`(\\bconst\\s+${constant}\\s*=\\s*)(['"])(.*?)\\2`, 'g');
|
|
92
|
+
const updated = contents
|
|
93
|
+
.replace(definePattern, (_match, prefix, _nameQuote, quote) => `${prefix}${quote}${version}${quote}`)
|
|
94
|
+
.replace(declarationPattern, (_match, prefix, quote) => `${prefix}${quote}${version}${quote}`);
|
|
95
|
+
if (updated === contents) {
|
|
96
|
+
throw new ValidationError(`Missing PHP constant ${descriptor.constant} in ${file}.`);
|
|
97
|
+
}
|
|
98
|
+
await journal.remember(file);
|
|
99
|
+
await writeFile(file, updated);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if ('wordpress-stable-tag' === descriptor.kind &&
|
|
103
|
+
descriptor.ifPresent &&
|
|
104
|
+
!(await versionFileExists(directory, descriptor.kind, descriptor.file))) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const file = path.join(directory, await getVersionFile(directory, descriptor.kind, descriptor.file));
|
|
108
|
+
const contents = await readFile(file, 'utf8');
|
|
109
|
+
const label = 'wordpress-stable-tag' === descriptor.kind ? 'Stable tag' : 'Version';
|
|
110
|
+
const expression = new RegExp(`(^\\s*\\*?\\s*${label}:\\s*)[^\\r\\n]+`, 'im');
|
|
111
|
+
if (!expression.test(contents)) {
|
|
112
|
+
throw new ValidationError(`Missing ${label} header in ${file}.`);
|
|
113
|
+
}
|
|
114
|
+
await journal.remember(file);
|
|
115
|
+
await writeFile(file, contents.replace(expression, `$1${version}`));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Check that every version target of a package has the expected version.
|
|
119
|
+
* Optional targets that are absent are skipped.
|
|
120
|
+
*
|
|
121
|
+
* @param repository Repository, for versions stored as git tags.
|
|
122
|
+
* @param pkg Configured package.
|
|
123
|
+
* @param expected Expected version.
|
|
124
|
+
* @throws {ValidationError} For the first target with another version.
|
|
125
|
+
*/
|
|
126
|
+
export async function verifyVersionTargets(repository, pkg, expected) {
|
|
127
|
+
for (const target of pkg.versionConfig.to) {
|
|
128
|
+
let actual;
|
|
129
|
+
if ('composer-json' === target.kind &&
|
|
130
|
+
target.ifPresent &&
|
|
131
|
+
!Object.hasOwn(await readJson(path.join(pkg.directory, target.file)), target.field)) {
|
|
132
|
+
actual = undefined;
|
|
133
|
+
}
|
|
134
|
+
else if ('wordpress-stable-tag' === target.kind &&
|
|
135
|
+
target.ifPresent &&
|
|
136
|
+
!(await versionFileExists(pkg.directory, target.kind, target.file))) {
|
|
137
|
+
actual = undefined;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
actual = await readVersion(repository, pkg.directory, target, pkg.path, pkg.group.tagType);
|
|
141
|
+
}
|
|
142
|
+
if (undefined !== actual && actual !== expected) {
|
|
143
|
+
throw new ValidationError(`Version mismatch for ${pkg.name}: expected ${expected}, found ${actual}.`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async function getVersionFile(directory, kind, configuredFile) {
|
|
148
|
+
if (configuredFile) {
|
|
149
|
+
return configuredFile;
|
|
150
|
+
}
|
|
151
|
+
if ('wordpress-plugin-header' === kind) {
|
|
152
|
+
const file = await findMainPluginFile({ dir: directory });
|
|
153
|
+
if (file) {
|
|
154
|
+
return file;
|
|
155
|
+
}
|
|
156
|
+
throw new ValidationError(`Could not find a plugin header file in ${directory}.`);
|
|
157
|
+
}
|
|
158
|
+
if ('wordpress-stable-tag' === kind) {
|
|
159
|
+
for (const file of ['readme.txt', 'readme.md']) {
|
|
160
|
+
try {
|
|
161
|
+
await access(path.join(directory, file));
|
|
162
|
+
return file;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Try the next WordPress readme filename.
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
throw new ValidationError(`Could not find readme.txt or readme.md in ${directory}.`);
|
|
169
|
+
}
|
|
170
|
+
return 'style.css';
|
|
171
|
+
}
|
|
172
|
+
async function versionFileExists(directory, kind, configuredFile) {
|
|
173
|
+
if (configuredFile) {
|
|
174
|
+
try {
|
|
175
|
+
await access(path.join(directory, configuredFile));
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if ('wordpress-stable-tag' === kind) {
|
|
183
|
+
const files = await Promise.all(['readme.txt', 'readme.md'].map(async (file) => {
|
|
184
|
+
try {
|
|
185
|
+
await access(path.join(directory, file));
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}));
|
|
192
|
+
return files.some(Boolean);
|
|
193
|
+
}
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check whether a string is a SemVer version, like 1.2.0 or 1.2.0-rc.1.
|
|
3
|
+
*
|
|
4
|
+
* @param version Version.
|
|
5
|
+
* @return Whether the version is valid.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isVersion(version: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Check whether a version has a pre-release part, like 1.0.0-rc.1.
|
|
10
|
+
*
|
|
11
|
+
* @param version Version.
|
|
12
|
+
* @return Whether the version is a valid pre-release.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isPrerelease(version: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Compare two versions with SemVer precedence, where a pre-release like
|
|
17
|
+
* 1.0.0-rc.1 comes before 1.0.0. Unlike the semver package, it doesn't throw
|
|
18
|
+
* for versions outside SemVer, like the 1.2 of a custom nextVersion
|
|
19
|
+
* strategy: missing parts count as 0.
|
|
20
|
+
*
|
|
21
|
+
* @param left Version.
|
|
22
|
+
* @param right Version to compare with.
|
|
23
|
+
* @return Negative when left is lower, positive when higher, otherwise 0.
|
|
24
|
+
*/
|
|
25
|
+
export declare function compareVersions(left: string, right: string): number;
|
package/dist/versions.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable or pre-release SemVer version without build metadata.
|
|
3
|
+
*/
|
|
4
|
+
const VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?$/;
|
|
5
|
+
/**
|
|
6
|
+
* Check whether a string is a SemVer version, like 1.2.0 or 1.2.0-rc.1.
|
|
7
|
+
*
|
|
8
|
+
* @param version Version.
|
|
9
|
+
* @return Whether the version is valid.
|
|
10
|
+
*/
|
|
11
|
+
export function isVersion(version) {
|
|
12
|
+
return VERSION_PATTERN.test(version);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Check whether a version has a pre-release part, like 1.0.0-rc.1.
|
|
16
|
+
*
|
|
17
|
+
* @param version Version.
|
|
18
|
+
* @return Whether the version is a valid pre-release.
|
|
19
|
+
*/
|
|
20
|
+
export function isPrerelease(version) {
|
|
21
|
+
return Boolean(VERSION_PATTERN.exec(version)?.[4]);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compare two versions with SemVer precedence, where a pre-release like
|
|
25
|
+
* 1.0.0-rc.1 comes before 1.0.0. Unlike the semver package, it doesn't throw
|
|
26
|
+
* for versions outside SemVer, like the 1.2 of a custom nextVersion
|
|
27
|
+
* strategy: missing parts count as 0.
|
|
28
|
+
*
|
|
29
|
+
* @param left Version.
|
|
30
|
+
* @param right Version to compare with.
|
|
31
|
+
* @return Negative when left is lower, positive when higher, otherwise 0.
|
|
32
|
+
*/
|
|
33
|
+
export function compareVersions(left, right) {
|
|
34
|
+
const [leftCore = '', leftPre] = splitPrerelease(left);
|
|
35
|
+
const [rightCore = '', rightPre] = splitPrerelease(right);
|
|
36
|
+
const a = leftCore.split('.').map(Number);
|
|
37
|
+
const b = rightCore.split('.').map(Number);
|
|
38
|
+
const core = (a[0] ?? 0) - (b[0] ?? 0) ||
|
|
39
|
+
(a[1] ?? 0) - (b[1] ?? 0) ||
|
|
40
|
+
(a[2] ?? 0) - (b[2] ?? 0);
|
|
41
|
+
if (core || leftPre === rightPre) {
|
|
42
|
+
return core;
|
|
43
|
+
}
|
|
44
|
+
if (undefined === leftPre || undefined === rightPre) {
|
|
45
|
+
return undefined === leftPre ? 1 : -1;
|
|
46
|
+
}
|
|
47
|
+
return comparePrerelease(leftPre.split('.'), rightPre.split('.'));
|
|
48
|
+
}
|
|
49
|
+
function splitPrerelease(version) {
|
|
50
|
+
const index = version.indexOf('-');
|
|
51
|
+
return -1 === index
|
|
52
|
+
? [version]
|
|
53
|
+
: [version.slice(0, index), version.slice(index + 1)];
|
|
54
|
+
}
|
|
55
|
+
function comparePrerelease(left, right) {
|
|
56
|
+
const [a, ...leftRest] = left;
|
|
57
|
+
const [b, ...rightRest] = right;
|
|
58
|
+
if (undefined === a || undefined === b) {
|
|
59
|
+
return (undefined === a ? 0 : 1) - (undefined === b ? 0 : 1);
|
|
60
|
+
}
|
|
61
|
+
const order = compareIdentifier(a, b);
|
|
62
|
+
return order || comparePrerelease(leftRest, rightRest);
|
|
63
|
+
}
|
|
64
|
+
function compareIdentifier(a, b) {
|
|
65
|
+
const aNumeric = /^\d+$/.test(a);
|
|
66
|
+
const bNumeric = /^\d+$/.test(b);
|
|
67
|
+
if (aNumeric && bNumeric) {
|
|
68
|
+
return Number(a) - Number(b);
|
|
69
|
+
}
|
|
70
|
+
if (aNumeric || bNumeric) {
|
|
71
|
+
return aNumeric ? -1 : 1;
|
|
72
|
+
}
|
|
73
|
+
return Number(a > b) - Number(a < b);
|
|
74
|
+
}
|
package/package.json
CHANGED