Skip to content

Commit

Permalink
feat(version): Add --include-merged-tags option (#1712)
Browse files Browse the repository at this point in the history
  • Loading branch information
HazAT authored and evocateur committed Nov 27, 2018
1 parent e2c0342 commit 7ee05d7
Show file tree
Hide file tree
Showing 21 changed files with 256 additions and 8 deletions.
7 changes: 6 additions & 1 deletion commands/changed/README.md
Expand Up @@ -26,4 +26,9 @@ package-2

Unlike `lerna ls`, however, `lerna changed` **does not** support [filter options](https://www.npmjs.com/package/@lerna/filter-options), as filtering is not supported by `lerna version` or `lerna publish`.

`lerna changed` also supports all the flags supported by [`lerna version`](https://github.com/lerna/lerna/tree/master/commands/version#options), but the only relevant one is [`--ignore-changes`](https://github.com/lerna/lerna/tree/master/commands/version#--ignore-changes).
`lerna changed` also supports all the flags supported by [`lerna version`](https://github.com/lerna/lerna/tree/master/commands/version#options).

Relevant ones are maybe:

- [`--ignore-changes`](https://github.com/lerna/lerna/tree/master/commands/version#--ignore-changes).
- [`--include-merged-tags`](https://github.com/lerna/lerna/tree/master/commands/version#--include-merged-tags).
10 changes: 10 additions & 0 deletions commands/version/README.md
Expand Up @@ -52,6 +52,7 @@ If you have any packages with a prerelease version number (e.g. `2.0.0-beta.3`)
* [`--sign-git-commit`](#--sign-git-commit)
* [`--sign-git-tag`](#--sign-git-tag)
* [`--yes`](#--yes)
* [`--include-merged-tags`](#--include-merged-tags)

### `--allow-branch <glob>`

Expand Down Expand Up @@ -273,6 +274,15 @@ lerna version --yes
When run with this flag, `lerna version` will skip all confirmation prompts.
Useful in [Continuous integration (CI)](https://en.wikipedia.org/wiki/Continuous_integration) to automatically answer the publish confirmation prompt.

### `--include-merged-tags`

```sh
lerna version --include-merged-tags
```

When run with this flag, `lerna version` will also consider tags of merged branches
while fetching changes for packages to update.

## Deprecated Options

### `--cd-version`
Expand Down
3 changes: 3 additions & 0 deletions commands/version/__tests__/__fixtures__/basic/lerna.json
@@ -0,0 +1,3 @@
{
"version": "1.0.0"
}
3 changes: 3 additions & 0 deletions commands/version/__tests__/__fixtures__/basic/package.json
@@ -0,0 +1,3 @@
{
"name": "independent"
}
@@ -0,0 +1,4 @@
{
"name": "package-1",
"version": "1.0.0"
}
@@ -0,0 +1,7 @@
{
"name": "package-2",
"version": "1.0.0",
"dependencies": {
"package-1": "^1.0.0"
}
}
@@ -0,0 +1,7 @@
{
"name": "package-3",
"version": "1.0.0",
"devDependencies": {
"package-2": "^1.0.0"
}
}
@@ -0,0 +1,7 @@
{
"name": "package-4",
"version": "1.0.0",
"dependencies": {
"package-1": "^0.0.0"
}
}
@@ -0,0 +1,8 @@
{
"name": "package-5",
"version": "1.0.0",
"private": true,
"dependencies": {
"package-1": "^1.0.0"
}
}
13 changes: 13 additions & 0 deletions commands/version/__tests__/version-command.test.js
Expand Up @@ -599,4 +599,17 @@ describe("VersionCommand", () => {
});
});
});

describe("--include-merged-tags", () => {
it("accepts --include-merged-tags", async () => {
const testDir = await initFixture("normal");
await lernaVersion(testDir)("--include-merged-tags", "--yes", "patch");

expect(PromptUtilities.select).not.toBeCalled();
expect(PromptUtilities.confirm).not.toBeCalled();

const message = await getCommitMessage(testDir);
expect(message).toBe("v1.0.1");
});
});
});
106 changes: 106 additions & 0 deletions commands/version/__tests__/version-include-merged-tags.test.js
@@ -0,0 +1,106 @@
"use strict";

// we're actually testing integration with git
jest.unmock("@lerna/collect-updates");

const path = require("path");
const fs = require("fs");

// mocked modules
const output = require("@lerna/output");

// helpers
const initFixture = require("@lerna-test/init-fixture")(__dirname);
const gitAdd = require("@lerna-test/git-add");
const gitCommit = require("@lerna-test/git-commit");
const gitTag = require("@lerna-test/git-tag");
const gitCheckout = require("@lerna-test/git-checkout");
const gitMerge = require("@lerna-test/git-merge");

// file under test
const lernaVersion = require("@lerna-test/command-runner")(require("../command"));

// remove quotes around top-level strings
expect.addSnapshotSerializer({
test(val) {
return typeof val === "string";
},
serialize(val, config, indentation, depth) {
// top-level strings don't need quotes, but nested ones do (object properties, etc)
return depth ? `"${val}"` : val;
},
});

// normalize temp directory paths in snapshots
expect.addSnapshotSerializer(require("@lerna-test/serialize-windows-paths"));
expect.addSnapshotSerializer(require("@lerna-test/serialize-tempdir"));

describe("version --include-merged-tags", () => {
const setupGitChangesWithBranch = async (cwd, masterPaths, branchPaths) => {
await gitTag(cwd, "v1.0.0");
await Promise.all(masterPaths.map(fp => fs.appendFileSync(path.join(cwd, fp), "1")));
await gitAdd(cwd, "-A");
await gitCommit(cwd, "Commit");
// Create release branch
await gitCheckout(cwd, ["-b", "release/v1.0.1"]);
// Switch into release branch
await Promise.all(branchPaths.map(fp => fs.appendFileSync(path.join(cwd, fp), "1")));
await gitAdd(cwd, "-A");
await gitCommit(cwd, "Bump");
await gitTag(cwd, "v1.0.1");
await gitCheckout(cwd, ["master"]);
await gitMerge(cwd, ["--no-ff", "release/v1.0.1"]);
// Commit after merge
await Promise.all(masterPaths.map(fp => fs.appendFileSync(path.join(cwd, fp), "1")));
await gitAdd(cwd, "-A");
await gitCommit(cwd, "Commit2");
};

describe("disabled", () => {
it("should list changes to package-4", async () => {
const testDir = await initFixture("basic");

await setupGitChangesWithBranch(
testDir,
["packages/package-2/random-file"],
["packages/package-4/random-file"]
);
// Without --include-merged-tags we receive all changes since the last tag on master
// in this case it's v1.0.0, this includes changes to package-4 which was released
// in the release branch with v1.0.1
await lernaVersion(testDir)("--no-git-tag-version");

expect(output.logged()).toMatchInlineSnapshot(`
Changes:
- package-2: 1.0.0 => 1.0.1
- package-3: 1.0.0 => 1.0.1
- package-4: 1.0.0 => 1.0.1
`);
});
});

describe("enabled", () => {
it("should not list changes to package-4", async () => {
const testDir = await initFixture("basic");

await setupGitChangesWithBranch(
testDir,
["packages/package-2/random-file"],
["packages/package-4/random-file"]
);
// With --include-merged-tags we correctly detect that v1.0.1 was already tagged
// and merged. We no longer want to receive package-4.
await lernaVersion(testDir)("--no-git-tag-version", "--include-merged-tags");

expect(output.logged()).toMatchInlineSnapshot(`
Changes:
- package-2: 1.0.0 => 1.0.1
- package-3: 1.0.0 => 1.0.1
`);
});
});
});
5 changes: 5 additions & 0 deletions commands/version/command.js
Expand Up @@ -84,6 +84,11 @@ exports.builder = (yargs, composed) => {
requiresArg: true,
defaultDescription: "v",
},
"include-merged-tags": {
describe: "Also include tags from merged branches",
type: "boolean",
defaultDescription: "false",
},
y: {
describe: "Skip all confirmation prompts.",
alias: "yes",
Expand Down
9 changes: 9 additions & 0 deletions helpers/git-checkout/index.js
@@ -0,0 +1,9 @@
"use strict";

const execa = require("execa");

module.exports = gitCheckout;

function gitCheckout(cwd, args) {
return execa("git", ["checkout", ...args], { cwd });
}
11 changes: 11 additions & 0 deletions helpers/git-checkout/package.json
@@ -0,0 +1,11 @@
{
"name": "@lerna-test/git-checkout",
"version": "0.0.0-test-only",
"description": "A local test helper",
"main": "index.js",
"private": true,
"license": "MIT",
"dependencies": {
"execa": "^1.0.0"
}
}
9 changes: 9 additions & 0 deletions helpers/git-merge/index.js
@@ -0,0 +1,9 @@
"use strict";

const execa = require("execa");

module.exports = gitMerge;

function gitMerge(cwd, args) {
return execa("git", ["merge", ...args], { cwd });
}
11 changes: 11 additions & 0 deletions helpers/git-merge/package.json
@@ -0,0 +1,11 @@
{
"name": "@lerna-test/git-merge",
"version": "0.0.0-test-only",
"description": "A local test helper",
"main": "index.js",
"private": true,
"license": "MIT",
"dependencies": {
"execa": "^1.0.0"
}
}
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -33,8 +33,10 @@
"@lerna-test/find-fixture": "file:helpers/find-fixture",
"@lerna-test/get-commit-message": "file:helpers/get-commit-message",
"@lerna-test/git-add": "file:helpers/git-add",
"@lerna-test/git-checkout": "file:helpers/git-checkout",
"@lerna-test/git-commit": "file:helpers/git-commit",
"@lerna-test/git-init": "file:helpers/git-init",
"@lerna-test/git-merge": "file:helpers/git-merge",
"@lerna-test/git-status": "file:helpers/git-status",
"@lerna-test/git-tag": "file:helpers/git-tag",
"@lerna-test/init-fixture": "file:helpers/init-fixture",
Expand Down
2 changes: 1 addition & 1 deletion utils/collect-updates/collect-updates.js
Expand Up @@ -21,7 +21,7 @@ function collectUpdates(filteredPackages, packageGraph, execOpts, commandOptions

if (hasTags(execOpts)) {
// describe the last annotated tag in the current branch
const { sha, refCount, lastTagName } = describeRef.sync(execOpts);
const { sha, refCount, lastTagName } = describeRef.sync(execOpts, commandOptions);
// TODO: warn about dirty tree?

if (refCount === "0" && forced.size === 0) {
Expand Down
9 changes: 9 additions & 0 deletions utils/describe-ref/__tests__/describe-ref.test.js
Expand Up @@ -41,6 +41,15 @@ describe("describeRef()", () => {
options
);
});

it("accepts commandOptions.include-merged-tags", async () => {
const commandOptions = { "include-merged-tags": true, includeMergedTags: true };
await describeRef({}, commandOptions);

const newArgs = [...DEFAULT_ARGS];
newArgs.pop();
expect(childProcess.exec).toHaveBeenLastCalledWith("git", newArgs, {});
});
});

describe("describeRef.sync()", () => {
Expand Down
17 changes: 11 additions & 6 deletions utils/describe-ref/lib/describe-ref.js
Expand Up @@ -7,8 +7,8 @@ module.exports = describeRef;
module.exports.parse = parse;
module.exports.sync = sync;

function getArgs(options) {
const args = [
function getArgs(options, commandOptions = {}) {
let args = [
"describe",
// fallback to short sha if no tags located
"--always",
Expand All @@ -24,11 +24,16 @@ function getArgs(options) {
args.push("--match", options.match);
}

if (commandOptions.includeMergedTags) {
// we want to consider all tags, also from merged branches
args = args.filter(arg => arg !== "--first-parent");
}

return args;
}

function describeRef(options = {}) {
const promise = childProcess.exec("git", getArgs(options), options);
function describeRef(options = {}, commandOptions = {}) {
const promise = childProcess.exec("git", getArgs(options, commandOptions), options);

return promise.then(({ stdout }) => {
const result = parse(stdout, options);
Expand All @@ -40,8 +45,8 @@ function describeRef(options = {}) {
});
}

function sync(options = {}) {
const stdout = childProcess.execSync("git", getArgs(options), options);
function sync(options = {}, commandOptions = {}) {
const stdout = childProcess.execSync("git", getArgs(options, commandOptions), options);
const result = parse(stdout, options);

// only called by collect-updates with no matcher
Expand Down

0 comments on commit 7ee05d7

Please sign in to comment.