Skip to content

Commit

Permalink
feat(filter-options): Add --exclude-dependents option
Browse files Browse the repository at this point in the history
Footguns abound.

Fixes #2198
  • Loading branch information
evocateur committed Oct 15, 2019
1 parent 54dca56 commit ff50e29
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 4 deletions.
1 change: 1 addition & 0 deletions commands/add/__tests__/add-command.test.js
Expand Up @@ -290,6 +290,7 @@ describe("AddCommand", () => {
ignore: undefined,
private: undefined,
since: undefined,
excludeDependents: undefined,
includeFilteredDependents: undefined,
includeFilteredDependencies: undefined,
})
Expand Down
1 change: 1 addition & 0 deletions commands/add/index.js
Expand Up @@ -105,6 +105,7 @@ class AddCommand extends Command {
ignore: undefined,
private: undefined,
since: undefined,
excludeDependents: undefined,
includeFilteredDependents: undefined,
includeFilteredDependencies: undefined,
});
Expand Down
6 changes: 6 additions & 0 deletions core/filter-options/README.md
Expand Up @@ -51,6 +51,12 @@ $ lerna ls --since some-branch

_This can be particularly useful when used in CI, if you can obtain the target branch a PR will be going into, because you can use that as the `ref` to the `--since` option. This works well for PRs going into master as well as feature branches._

### `--exclude-dependents`

Exclude all transitive dependents when running a command with `--since`, overriding the default "changed" algorithm.

This flag has no effect without `--since`, and will throw an error in that case.

### `--include-filtered-dependents`

Include all transitive dependents when running a command regardless of `--scope`, `--ignore`, or `--since`.
Expand Down
26 changes: 26 additions & 0 deletions core/filter-options/__tests__/get-filtered-packages.test.js
Expand Up @@ -169,6 +169,32 @@ test("--scope package-{2,3,4} --since master", async () => {
);
});

test("--exclude-dependents", async () => {
const packageGraph = await buildGraph(cwd);
const execOpts = { cwd };
const options = parseOptions("--since", "foo", "--exclude-dependents");

await getFilteredPackages(packageGraph, execOpts, options);

expect(collectUpdates).toHaveBeenLastCalledWith(
expect.any(Array),
packageGraph,
execOpts,
expect.objectContaining({ excludeDependents: true })
);
});

test("--exclude-dependents conflicts with --include-filtered-dependents", async () => {
try {
parseOptions("--exclude-dependents", "--include-filtered-dependents");
} catch (err) {
expect(err.message).toMatch("exclude-dependents");
expect(err.message).toMatch("include-filtered-dependents");
}

expect.hasAssertions();
});

test("--include-filtered-dependents", async () => {
const packageGraph = await buildGraph(cwd);
const execOpts = { cwd };
Expand Down
9 changes: 9 additions & 0 deletions core/filter-options/index.js
Expand Up @@ -35,11 +35,20 @@ function filterOptions(yargs) {
`,
type: "string",
},
"exclude-dependents": {
describe: dedent`
Exclude all transitive dependents when running a command
with --since, overriding the default "changed" algorithm.
`,
conflicts: "include-filtered-dependents",
type: "boolean",
},
"include-filtered-dependents": {
describe: dedent`
Include all transitive dependents when running a command
regardless of --scope, --ignore, or --since.
`,
conflicts: "exclude-dependents",
type: "boolean",
},
"include-filtered-dependencies": {
Expand Down
4 changes: 4 additions & 0 deletions core/filter-options/lib/get-filtered-packages.js
Expand Up @@ -30,6 +30,10 @@ function getFilteredPackages(packageGraph, execOpts, options) {
if (options.since !== undefined) {
log.notice("filter", "changed since %j", options.since);

if (options.excludeDependents) {
log.notice("filter", "excluding dependents");
}

chain = chain.then(filteredPackages =>
Promise.resolve(collectUpdates(filteredPackages, packageGraph, execOpts, options)).then(updates => {
const updated = new Set(updates.map(({ pkg }) => pkg.name));
Expand Down
17 changes: 17 additions & 0 deletions utils/collect-updates/__tests__/collect-updates.test.js
Expand Up @@ -95,6 +95,23 @@ describe("collectUpdates()", () => {
]);
});

it("constrains results by excluded dependents", () => {
changedPackages.add("package-dag-1");

const graph = buildGraph();
const pkgs = graph.rawPackageList;
const execOpts = { cwd: "/test" };

const updates = collectUpdates(pkgs, graph, execOpts, {
excludeDependents: true,
});

expect(updates).toEqual([
expect.objectContaining({ name: "package-dag-1" }),
// collectDependents() is skipped
]);
});

it("constrains results by filtered packages", () => {
changedPackages.add("package-dag-2a");
changedPackages.add("package-dag-3");
Expand Down
4 changes: 3 additions & 1 deletion utils/collect-updates/collect-updates.js
Expand Up @@ -13,7 +13,7 @@ module.exports.collectPackages = collectPackages;
module.exports.getPackagesForOption = getPackagesForOption;

function collectUpdates(filteredPackages, packageGraph, execOpts, commandOptions) {
const { forcePublish, conventionalCommits, conventionalGraduate } = commandOptions;
const { forcePublish, conventionalCommits, conventionalGraduate, excludeDependents } = commandOptions;

// If --conventional-commits and --conventional-graduate are both set, ignore --force-publish
const useConventionalGraduate = conventionalCommits && conventionalGraduate;
Expand Down Expand Up @@ -69,6 +69,7 @@ function collectUpdates(filteredPackages, packageGraph, execOpts, commandOptions

return collectPackages(packages, {
onInclude: name => log.verbose("updated", name),
excludeDependents,
});
}

Expand All @@ -86,5 +87,6 @@ function collectUpdates(filteredPackages, packageGraph, execOpts, commandOptions
return collectPackages(packages, {
isCandidate: (node, name) => isForced(node, name) || needsBump(node) || hasDiff(node),
onInclude: name => log.verbose("updated", name),
excludeDependents,
});
}
7 changes: 4 additions & 3 deletions utils/collect-updates/lib/collect-packages.js
Expand Up @@ -4,7 +4,7 @@ const collectDependents = require("./collect-dependents");

module.exports = collectPackages;

function collectPackages(packages, { isCandidate = () => true, onInclude } = {}) {
function collectPackages(packages, { isCandidate = () => true, onInclude, excludeDependents } = {}) {
const candidates = new Set();

packages.forEach((node, name) => {
Expand All @@ -13,8 +13,9 @@ function collectPackages(packages, { isCandidate = () => true, onInclude } = {})
}
});

const dependents = collectDependents(candidates);
dependents.forEach(node => candidates.add(node));
if (!excludeDependents) {
collectDependents(candidates).forEach(node => candidates.add(node));
}

// The result should always be in the same order as the input
const updates = [];
Expand Down

0 comments on commit ff50e29

Please sign in to comment.