diff --git a/.gitignore b/.gitignore index ca0105c35e2..e279cf65f31 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ tmp coverage/ .nyc_output/ .eslintcache +yarn.lock diff --git a/commands/version/README.md b/commands/version/README.md index d7a7f5f3337..08e121cdc2c 100644 --- a/commands/version/README.md +++ b/commands/version/README.md @@ -53,6 +53,7 @@ Running `lerna version --conventional-commits` without the above flags will rele - [`--exact`](#--exact) - [`--force-publish`](#--force-publish) - [`--git-remote`](#--git-remote-name) +- [`--git-tag-command`](#--git-tag-command-cmd) - [`--ignore-changes`](#--ignore-changes) - [`--ignore-scripts`](#--ignore-scripts) - [`--include-merged-tags`](#--include-merged-tags) @@ -233,6 +234,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 ` + +Allows users to specify a wrapper command in CD/CI 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 ` ```sh diff --git a/commands/version/__tests__/git-tag.test.js b/commands/version/__tests__/git-tag.test.js index 4c06cab46d7..448a2cdbe8d 100644 --- a/commands/version/__tests__/git-tag.test.js +++ b/commands/version/__tests__/git-tag.test.js @@ -34,4 +34,13 @@ describe("gitTag", () => { expect(mockExec).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(mockExec).toHaveBeenLastCalledWith("git-wrapper", ["gh-tag", tag, "-m", tag], opts); + }); }); diff --git a/commands/version/command.js b/commands/version/command.js index 974ce66687a..ccd3b76f688 100644 --- a/commands/version/command.js +++ b/commands/version/command.js @@ -160,6 +160,11 @@ exports.builder = (yargs, composed) => { requiresArg: true, defaultDescription: "v", }, + "git-tag-command": { + describe: + "Allows users to specify a wrapper command in CD/CI pipelines that have no direct write access.", + type: "string", + }, y: { describe: "Skip all confirmation prompts.", alias: "yes", diff --git a/commands/version/index.js b/commands/version/index.js index 30836fec41f..df7a5d6dfc9 100644 --- a/commands/version/index.js +++ b/commands/version/index.js @@ -655,7 +655,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); } @@ -668,7 +670,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]); } diff --git a/commands/version/lib/git-tag.js b/commands/version/lib/git-tag.js index b08970a8fad..46a31ec323b 100644 --- a/commands/version/lib/git-tag.js +++ b/commands/version/lib/git-tag.js @@ -5,19 +5,21 @@ const childProcess = require("@lerna/child-process"); module.exports = gitTag; -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); }