@wpelevator/wp-release 0.6.1 → 0.8.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.
@@ -6,6 +6,8 @@ export interface ChangesetVersionResult {
6
6
  bump: string;
7
7
  currentVersion: string;
8
8
  nextVersion: string;
9
+ /** Changelog entries of the release as a Markdown list. */
10
+ changelog: string;
9
11
  }>;
10
12
  }
11
13
  declare const _default: {
@@ -20,6 +22,10 @@ declare const _default: {
20
22
  readonly date: {
21
23
  readonly type: "string";
22
24
  };
25
+ readonly package: {
26
+ readonly type: "string";
27
+ readonly multiple: true;
28
+ };
23
29
  };
24
30
  run({ values, cwd, configFile, logger }: import("./command.ts").CommandContext): Promise<{
25
31
  exitCode: number;
@@ -31,6 +37,7 @@ declare const _default: {
31
37
  bump: "patch" | "minor" | "major";
32
38
  currentVersion: string;
33
39
  nextVersion: string;
40
+ changelog: string;
34
41
  }[];
35
42
  };
36
43
  }>;
@@ -1,15 +1,19 @@
1
1
  import { versionChangesets } from "../changeset-release.js";
2
+ import { getChangesetVersionSummary } from "../summary.js";
2
3
  import { parseChangesetVersionArgs, changesetVersionArgs, } from "./changeset-args.js";
3
4
  export default {
4
5
  name: 'changeset-version',
5
- usage: 'changeset-version [--dry-run] [--date <YYYY-MM-DD>]',
6
+ usage: 'changeset-version [--dry-run] [--date <YYYY-MM-DD>] [--package <name>]',
6
7
  summary: 'Apply pending version bumps and changelog entries.',
7
8
  help: `Options:
8
9
  --dry-run Print the release plan without writing files
9
10
  --date <YYYY-MM-DD> Changelog date (default: today)
11
+ --package <name> Version only this package (repeatable)
10
12
 
11
13
  Updates configured version files, prepends changelog entries and removes the
12
- applied changeset files.`,
14
+ applied changeset files. With --package, a changeset that also names other
15
+ packages keeps only their entries, so it still applies to their releases, and
16
+ changesets without packages are left for a run without --package.`,
13
17
  options: changesetVersionArgs,
14
18
  async run({ values, cwd, configFile, logger }) {
15
19
  const args = parseChangesetVersionArgs(values);
@@ -22,6 +26,7 @@ applied changeset files.`,
22
26
  if (!result.releases.length) {
23
27
  logger.info('No pending package releases.');
24
28
  }
29
+ logger.summary(() => getChangesetVersionSummary(result.releases, args.dryRun));
25
30
  return {
26
31
  exitCode: 0,
27
32
  result: {
@@ -32,6 +37,7 @@ applied changeset files.`,
32
37
  bump: item.bump,
33
38
  currentVersion: item.currentVersion,
34
39
  nextVersion: item.nextVersion,
40
+ changelog: item.changelog,
35
41
  })),
36
42
  },
37
43
  };
@@ -0,0 +1,45 @@
1
+ import type { GitDeployInput } from '../git-deploy.ts';
2
+ import type { ParsedValues } from './command.ts';
3
+ /**
4
+ * Map the parsed "deploy-git" arguments to resolveGitDeployOptions() input.
5
+ *
6
+ * @param values Parsed CLI values.
7
+ * @param positionals Positional arguments.
8
+ * @param cwd Working directory.
9
+ * @return Git deploy input.
10
+ */
11
+ export declare function getGitDeployInputFromArgs(values: ParsedValues, positionals: string[], cwd: string): GitDeployInput;
12
+ declare const _default: {
13
+ name: string;
14
+ usage: string;
15
+ summary: string;
16
+ help: string;
17
+ options: {
18
+ message: {
19
+ type: "string";
20
+ };
21
+ 'dry-run': {
22
+ type: "boolean";
23
+ };
24
+ 'git-url': {
25
+ type: "string";
26
+ };
27
+ branch: {
28
+ type: "string";
29
+ };
30
+ tag: {
31
+ type: "string";
32
+ };
33
+ 'split-prefix': {
34
+ type: "string";
35
+ };
36
+ 'source-ref': {
37
+ type: "string";
38
+ };
39
+ };
40
+ run({ values, positionals, cwd, logger }: import("./command.ts").CommandContext): Promise<{
41
+ exitCode: number;
42
+ result: import("../git-deploy.ts").GitDeployResult;
43
+ }>;
44
+ };
45
+ export default _default;
@@ -0,0 +1,81 @@
1
+ import { GitDeploy, resolveGitDeployOptions } from "../git-deploy.js";
2
+ import { fileSelectionArgs, getFileSelectionInput, getSourceDirArg, sourceDirArgs, } from "./args.js";
3
+ import { getBoolean, getString } from "./command.js";
4
+ /**
5
+ * Map the parsed "deploy-git" arguments to resolveGitDeployOptions() input.
6
+ *
7
+ * @param values Parsed CLI values.
8
+ * @param positionals Positional arguments.
9
+ * @param cwd Working directory.
10
+ * @return Git deploy input.
11
+ */
12
+ export function getGitDeployInputFromArgs(values, positionals, cwd) {
13
+ return {
14
+ cwd,
15
+ sourceDir: getSourceDirArg(values, positionals),
16
+ gitUrl: getString(values, 'git-url'),
17
+ branch: getString(values, 'branch'),
18
+ tag: getString(values, 'tag'),
19
+ splitPrefix: getString(values, 'split-prefix'),
20
+ sourceRef: getString(values, 'source-ref'),
21
+ ...getFileSelectionInput(values),
22
+ message: getString(values, 'message'),
23
+ dryRun: getBoolean(values, 'dry-run'),
24
+ };
25
+ }
26
+ export default {
27
+ name: 'deploy-git',
28
+ usage: 'deploy-git [<source-dir>] --git-url <url> [options]',
29
+ summary: 'Deploy the files of a plugin, theme or package to a Git repository as a release commit.',
30
+ help: `Arguments:
31
+ <source-dir> Directory with the files to release (default: .),
32
+ also accepted as --source-dir <dir>
33
+
34
+ Writes (none by default):
35
+ --branch <name> Push the release to this branch, on top of its
36
+ previous release
37
+ --tag <name> Create this tag for the release, on top of --branch
38
+ or the default branch of the repository
39
+
40
+ Options:
41
+ --git-url <url> Repository to deploy to
42
+ --split-prefix <dir> Use the history of this directory of the source
43
+ repository, from git subtree split, as the source
44
+ history (default: the source commit)
45
+ --source-ref <ref> Source commit (default: HEAD)
46
+ --distignore <file> Ignore file (default: <source-dir>/.distignore when present)
47
+ --no-distignore Don't read any ignore file
48
+ --exclude <patterns> Extra gitignore-style patterns, comma-separated or repeated
49
+ --message <text> Release commit message
50
+ --dry-run Run everything except the push
51
+
52
+ Each release is a commit with exactly the selected files, whose parents are
53
+ the previous release and the source history. Pushes are never forced: the
54
+ branch only moves forward, a release without changes isn't pushed again, an
55
+ older build doesn't move a branch that has newer source history, a tag that
56
+ already has the same files is reused, and a tag with other files
57
+ fails with exit code 2 (delete it in the repository to release it again). The source directory must be inside a Git repository.
58
+ Credentials come from git, like a token in the URL or an SSH key.
59
+
60
+ Examples:
61
+ wp-release deploy-git build --git-url git@github.com:me/my-plugin-dist.git --branch main --tag 1.2.0
62
+ Release a build to a distribution repository and tag it
63
+ wp-release deploy-git packages/my-plugin --split-prefix packages/my-plugin --git-url … --branch main
64
+ Release a monorepo package with its own history`,
65
+ options: {
66
+ ...sourceDirArgs,
67
+ 'git-url': { type: 'string' },
68
+ branch: { type: 'string' },
69
+ tag: { type: 'string' },
70
+ 'split-prefix': { type: 'string' },
71
+ 'source-ref': { type: 'string' },
72
+ ...fileSelectionArgs,
73
+ message: { type: 'string' },
74
+ 'dry-run': { type: 'boolean' },
75
+ },
76
+ async run({ values, positionals, cwd, logger }) {
77
+ const options = resolveGitDeployOptions(getGitDeployInputFromArgs(values, positionals, cwd));
78
+ const result = await new GitDeploy(options, logger).run();
79
+ return { exitCode: 0, result };
80
+ },
81
+ };
@@ -0,0 +1,218 @@
1
+ import type { FileSelection } from './file-selection.ts';
2
+ import type { GitRunner } from './git.ts';
3
+ import { Logger } from './logger.ts';
4
+ /**
5
+ * Git deploy options from the CLI or a library caller. Unset options fall
6
+ * back to the defaults in resolveGitDeployOptions().
7
+ */
8
+ export interface GitDeployInput {
9
+ /** Directory that relative paths resolve against. */
10
+ cwd?: string;
11
+ /** Directory with the files to release, defaults to cwd. */
12
+ sourceDir?: string;
13
+ /** URL of the repository to release to. */
14
+ gitUrl?: string;
15
+ /** Branch to push the release to. */
16
+ branch?: string;
17
+ /** Tag to create for the release. */
18
+ tag?: string;
19
+ /** Use the history of this directory, relative to the source repository root, from git subtree split as the source history. */
20
+ splitPrefix?: string;
21
+ /** Source commit, defaults to HEAD. */
22
+ sourceRef?: string;
23
+ /** Ignore file path, or false to not read one. */
24
+ distignore?: string | false;
25
+ /** Extra gitignore-style patterns. */
26
+ exclude?: string | string[];
27
+ /** Commit message of the release. */
28
+ message?: string;
29
+ /** Run everything except the push. */
30
+ dryRun?: boolean;
31
+ }
32
+ /**
33
+ * Git deploy options with the defaults applied, from resolveGitDeployOptions().
34
+ */
35
+ export interface GitDeployOptions extends FileSelection {
36
+ cwd: string;
37
+ sourceDir: string;
38
+ gitUrl: string;
39
+ branch: string | null;
40
+ tag: string | null;
41
+ splitPrefix: string | null;
42
+ sourceRef: string;
43
+ message: string | null;
44
+ dryRun: boolean;
45
+ }
46
+ export interface GitDeployResult {
47
+ /** Release commit, null when nothing was deployed. */
48
+ revision: string | null;
49
+ /** Previous release that the release builds on, null for the first one. */
50
+ previous: string | null;
51
+ /** Whether a new release commit was created, false when the files didn't change. */
52
+ created: boolean;
53
+ /** Whether the branch already has a release of newer source history, so it isn't moved. */
54
+ outdated: boolean;
55
+ /** Refs to write: the branch when the release changed it, and the tag when it doesn't point to the release yet. */
56
+ planned: string[];
57
+ /** Refs that were pushed, empty in a dry run. */
58
+ pushed: string[];
59
+ /** Number of released files. */
60
+ files: number;
61
+ }
62
+ /**
63
+ * Check a branch or tag name for the common mistakes before it's used in a
64
+ * refspec. It intentionally covers only the main rules of git
65
+ * check-ref-format, since git rejects any other invalid name when it pushes.
66
+ *
67
+ * @param name Branch or tag name.
68
+ * @return Whether the name can be used.
69
+ */
70
+ export declare function isValidRefName(name: string): boolean;
71
+ /**
72
+ * Apply the defaults to the Git deploy options and validate them.
73
+ *
74
+ * @param input Git deploy input.
75
+ * @return Git deploy options.
76
+ * @throws {ValidationError} For a missing URL or an invalid branch or tag.
77
+ */
78
+ export declare function resolveGitDeployOptions(input?: GitDeployInput): GitDeployOptions;
79
+ /**
80
+ * Deploy the files of a plugin, theme or package to a Git repository, as a
81
+ * release commit with exactly the selected files. Its parents are the
82
+ * previous release in the repository and the source commit, or with
83
+ * splitPrefix the history of that directory from git subtree split, so the
84
+ * repository keeps the source history and `git log --first-parent` lists the
85
+ * releases. Pushes are never forced: a branch only moves forward, a release
86
+ * without changes isn't pushed again, and an existing tag is never replaced.
87
+ *
88
+ * Each step is a separate method so that wrappers can run and report them
89
+ * one by one; run() does all of them.
90
+ */
91
+ export declare class GitDeploy {
92
+ readonly options: GitDeployOptions;
93
+ readonly logger: Logger;
94
+ readonly runner: GitRunner;
95
+ private repoRoot;
96
+ /**
97
+ * @param options Options from resolveGitDeployOptions().
98
+ * @param logger Logger for the progress.
99
+ * @param runner Git command runner, replaceable in tests.
100
+ */
101
+ constructor(options: GitDeployOptions, logger?: Logger, runner?: GitRunner);
102
+ /**
103
+ * Whether the options ask for any push.
104
+ *
105
+ * @return True with a branch or a tag.
106
+ */
107
+ hasWrites(): boolean;
108
+ /**
109
+ * Create the release commit and push it.
110
+ *
111
+ * @return Release, previous release and the pushed refs.
112
+ */
113
+ run(): Promise<GitDeployResult>;
114
+ /**
115
+ * Write the selected files to the object database of the source
116
+ * repository and create a tree of them, with a temporary index so that
117
+ * the working tree and the index of the repository are left alone.
118
+ *
119
+ * @return Tree hash and the number of files.
120
+ * @throws {ValidationError} When no files are selected, or a file name has a line break.
121
+ */
122
+ createTree(): Promise<{
123
+ tree: string;
124
+ files: number;
125
+ }>;
126
+ /**
127
+ * Fetch the previous release: the branch, or for a tag-only deploy the
128
+ * default branch of the repository.
129
+ *
130
+ * @return Commit hash, or null when the repository has no such branch yet.
131
+ */
132
+ fetchPrevious(): Promise<string | null>;
133
+ /**
134
+ * Fetch a ref of the repository.
135
+ *
136
+ * @param ref Branch or tag ref, or HEAD.
137
+ * @return Commit hash, with a tag peeled to its commit.
138
+ */
139
+ fetchCommit(ref: string): Promise<string>;
140
+ /**
141
+ * Get the release commit. When the files are the same as in the previous
142
+ * release, that release is reused. When the previous release on the
143
+ * branch already has newer source history, like when an older build runs
144
+ * again, the branch isn't moved: only a tag gets a new release commit.
145
+ *
146
+ * @param tree Tree of the released files.
147
+ * @param previous Previous release, or null for the first one.
148
+ * @return Release commit, whether it was created and whether the source is outdated.
149
+ */
150
+ createRelease(tree: string, previous: string | null): Promise<{
151
+ revision: string;
152
+ created: boolean;
153
+ outdated: boolean;
154
+ }>;
155
+ /**
156
+ * Check whether a release was made from newer source history: the source
157
+ * history of the release, its last parent, already has the source as an
158
+ * older commit. The same source, a newer one, including a revert, and
159
+ * unrelated history aren't outdated. With splitPrefix, git subtree split
160
+ * creates the same commits for the same history, so the split of an older
161
+ * build is part of the split of a newer one.
162
+ *
163
+ * @param source Source history from getSourceHistory().
164
+ * @param previous Previous release.
165
+ * @return Whether the source is older than the source of the release.
166
+ */
167
+ isOutdated(source: string, previous: string): Promise<boolean>;
168
+ /**
169
+ * Get the source history parent of a release: the source commit, or the
170
+ * history of splitPrefix from git subtree split.
171
+ *
172
+ * @return Commit hash.
173
+ */
174
+ getSourceHistory(): Promise<string>;
175
+ /**
176
+ * Check the tag in the repository before anything is pushed. Tags are
177
+ * never replaced, so a tag with other files is an error. A tag with the
178
+ * same files is the release, which makes running a tag release again a
179
+ * no-op, also when the release commit was created on top of an older
180
+ * branch tip. To release a tag again, delete it in the repository first.
181
+ *
182
+ * @param tree Tree of the released files.
183
+ * @return Tagged commit when the tag has the same files, null without the tag.
184
+ * @throws {ValidationError} When the tag has other files.
185
+ */
186
+ checkTag(tree: string): Promise<string | null>;
187
+ /**
188
+ * Get the refs to push: the branch, when the release moves it and the
189
+ * source isn't outdated, and the tag, unless it already exists with these
190
+ * files.
191
+ *
192
+ * @param revision Release commit.
193
+ * @param previous Previous release.
194
+ * @param tagged Commit of an existing tag with the same files, from checkTag().
195
+ * @param outdated Whether the branch has newer source history, from createRelease().
196
+ * @return Refs like refs/heads/main and refs/tags/1.2.0.
197
+ */
198
+ getRefsToPush(revision: string, previous: string | null, tagged?: string | null, outdated?: boolean): string[];
199
+ /**
200
+ * Push the release to the refs in one atomic push, never forced, so the
201
+ * branch only moves forward and a tag that was created in the meantime
202
+ * is never replaced. A dry run checks the push without writing.
203
+ *
204
+ * @param revision Release commit.
205
+ * @param refs Refs from getRefsToPush().
206
+ * @return Pushed refs, empty in a dry run or without refs.
207
+ */
208
+ push(revision: string, refs: string[]): Promise<string[]>;
209
+ private getDefaultMessage;
210
+ private getRepoRoot;
211
+ /**
212
+ * Run git in the source repository.
213
+ *
214
+ * @param input Command input without the working directory.
215
+ * @return Trimmed standard output.
216
+ */
217
+ private git;
218
+ }