Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(version): support custom command for git tag #2760

Merged
merged 3 commits into from Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 21 additions & 0 deletions commands/version/README.md
Expand Up @@ -59,6 +59,7 @@ Running `lerna version --conventional-commits` without the above flags will rele
- [`--create-release <type>`](#--create-release-type)
- [`--exact`](#--exact)
- [`--force-publish`](#--force-publish)
- [`--git-tag-command <cmd>`](#--git-tag-command-cmd)
- [`--git-remote <name>`](#--git-remote-name)
- [`--ignore-changes`](#--ignore-changes)
- [`--ignore-scripts`](#--ignore-scripts)
Expand Down Expand Up @@ -264,6 +265,26 @@ When run with this flag, `lerna version` will force publish the specified packag

> This will skip the `lerna changed` check for changed packages and forces a package that didn't have a `git diff` change to be updated.

### `--git-tag-command <cmd>`

Allows users to specify a custom command to be used when applying git tags. For example, this may be useful for providing a wrapper command in CI/CD pipelines that have no direct write access.

```sh
lerna version --git-tag-command "git gh-tag %s -m %s"
```

This can also be configured in `lerna.json`.

```json
{
"command": {
"version": {
"gitTagCommand": "git gh-tag %s -m %s"
}
}
}
```

### `--git-remote <name>`

```sh
Expand Down
9 changes: 9 additions & 0 deletions commands/version/__tests__/git-tag.test.js
Expand Up @@ -34,4 +34,13 @@ describe("gitTag", () => {

expect(childProcess.exec).toHaveBeenLastCalledWith("git", ["tag", tag, "-m", tag, "--force"], opts);
});

it("creates an annotated git tag using the wrapper arguments", async () => {
const tag = "v1.2.4";
const opts = { cwd: "default" };

await gitTag(tag, {}, opts, "git-wrapper gh-tag %s -m %s");

expect(childProcess.exec).toHaveBeenLastCalledWith("git-wrapper", ["gh-tag", tag, "-m", tag], opts);
});
});
5 changes: 5 additions & 0 deletions commands/version/command.js
Expand Up @@ -168,6 +168,11 @@ exports.builder = (yargs, composed) => {
requiresArg: true,
defaultDescription: "v",
},
"git-tag-command": {
describe:
"Allows users to specify a custom command to be used when applying git tags. For example, this may be useful for providing a wrapper command in CI/CD pipelines that have no direct write access.",
type: "string",
},
"npm-client-args": {
describe: "Additional arguments to pass to the npm client when performing 'npm install'.",
type: "array",
Expand Down
6 changes: 4 additions & 2 deletions commands/version/index.js
Expand Up @@ -694,7 +694,9 @@ class VersionCommand extends Command {

return Promise.resolve()
.then(() => gitCommit(message, this.gitOpts, this.execOpts))
.then(() => Promise.all(tags.map((tag) => gitTag(tag, this.gitOpts, this.execOpts))))
.then(() =>
Promise.all(tags.map((tag) => gitTag(tag, this.gitOpts, this.execOpts, this.options.gitTagCommand)))
)
.then(() => tags);
}

Expand All @@ -707,7 +709,7 @@ class VersionCommand extends Command {

return Promise.resolve()
.then(() => gitCommit(message, this.gitOpts, this.execOpts))
.then(() => gitTag(tag, this.gitOpts, this.execOpts))
.then(() => gitTag(tag, this.gitOpts, this.execOpts, this.options.gitTagCommand))
.then(() => [tag]);
}

Expand Down
16 changes: 9 additions & 7 deletions commands/version/lib/git-tag.js
Expand Up @@ -10,19 +10,21 @@ module.exports.gitTag = gitTag;
* @param {{ forceGitTag: boolean; signGitTag: boolean; }} gitOpts
* @param {import("@lerna/child-process").ExecOpts} opts
*/
function gitTag(tag, { forceGitTag, signGitTag }, opts) {
log.silly("gitTag", tag);
function gitTag(tag, { forceGitTag, signGitTag }, opts, command = "git tag %s -m %s") {
log.silly("gitTag", tag, command);

const args = ["tag", tag, "-m", tag];
const [cmd, ...args] = command.split(" ");

const interpolatedArgs = args.map((arg) => arg.replace(/%s/, tag));

if (forceGitTag) {
args.push("--force");
interpolatedArgs.push("--force");
}

if (signGitTag) {
args.push("--sign");
interpolatedArgs.push("--sign");
}

log.verbose("git", args);
return childProcess.exec("git", args, opts);
log.verbose(cmd, interpolatedArgs);
return childProcess.exec(cmd, interpolatedArgs, opts);
}