-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
collect-updates.js
117 lines (99 loc) · 4.89 KB
/
collect-updates.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
"use strict";
const log = require("npmlog");
const { describeRefSync } = require("@lerna/describe-ref");
const { hasTags } = require("./lib/has-tags");
const { collectPackages } = require("./lib/collect-packages");
const { getPackagesForOption } = require("./lib/get-packages-for-option");
const { makeDiffPredicate } = require("./lib/make-diff-predicate");
module.exports.collectUpdates = collectUpdates;
module.exports.collectPackages = collectPackages;
module.exports.getPackagesForOption = getPackagesForOption;
/**
* @typedef {object} UpdateCollectorOptions
* @property {string} [bump] The semver bump keyword (patch/minor/major) or explicit version used
* @property {boolean} [canary] Whether or not to use a "nightly" range (`ref^..ref`) for commits
* @property {string[]} [ignoreChanges]
* A list of globs that match files/directories whose changes
* should not be considered when identifying changed packages
* @property {boolean} [includeMergedTags]
* Whether or not to include the --first-parent flag when calling `git describe`
* (awkwardly, pass `true` to _omit_ the flag, the default is to include it)
* @property {boolean | string[]} [forcePublish] Which packages, if any, to always include
* Force all packages to be versioned with `true`, or pass a list of globs that match package names
* @property {string} [since] Ref to use when querying git, defaults to most recent annotated tag
* @property {boolean} [conventionalCommits]
* @property {boolean} [conventionalGraduate]
* @property {boolean} [excludeDependents]
*/
/**
* Create a list of graph nodes representing packages changed since the previous release, tagged or otherwise.
* @param {import("@lerna/package").Package[]} filteredPackages
* @param {import("@lerna/package-graph").PackageGraph} packageGraph
* @param {import("@lerna/child-process").ExecOpts} execOpts
* @param {UpdateCollectorOptions} commandOptions
*/
function collectUpdates(filteredPackages, packageGraph, execOpts, commandOptions) {
const { forcePublish, conventionalCommits, conventionalGraduate, excludeDependents } = commandOptions;
// If --conventional-commits and --conventional-graduate are both set, ignore --force-publish
const useConventionalGraduate = conventionalCommits && conventionalGraduate;
const forced = getPackagesForOption(useConventionalGraduate ? conventionalGraduate : forcePublish);
const packages =
filteredPackages.length === packageGraph.size
? packageGraph
: new Map(filteredPackages.map(({ name }) => [name, packageGraph.get(name)]));
let committish = commandOptions.since;
if (hasTags(execOpts)) {
// describe the last annotated tag in the current branch
const { sha, refCount, lastTagName } = describeRefSync(execOpts, commandOptions.includeMergedTags);
// TODO: warn about dirty tree?
if (refCount === "0" && forced.size === 0 && !committish) {
// no commits since previous release
log.notice("", "Current HEAD is already released, skipping change detection.");
return [];
}
if (commandOptions.canary) {
// if it's a merge commit, it will return all the commits that were part of the merge
// ex: If `ab7533e` had 2 commits, ab7533e^..ab7533e would contain 2 commits + the merge commit
committish = `${sha}^..${sha}`;
} else if (!committish) {
// if no tags found, this will be undefined and we'll use the initial commit
committish = lastTagName;
}
}
if (forced.size) {
// "warn" might seem a bit loud, but it is appropriate for logging anything _forced_
log.warn(
useConventionalGraduate ? "conventional-graduate" : "force-publish",
forced.has("*") ? "all packages" : Array.from(forced.values()).join("\n")
);
}
if (useConventionalGraduate) {
// --conventional-commits --conventional-graduate
if (forced.has("*")) {
log.info("", "Graduating all prereleased packages");
} else {
log.info("", "Graduating prereleased packages");
}
} else if (!committish || forced.has("*")) {
// --force-publish or no tag
log.info("", "Assuming all packages changed");
return collectPackages(packages, {
onInclude: (name) => log.verbose("updated", name),
excludeDependents,
});
}
log.info("", `Looking for changed packages since ${committish}`);
const hasDiff = makeDiffPredicate(committish, execOpts, commandOptions.ignoreChanges);
const needsBump =
!commandOptions.bump || commandOptions.bump.startsWith("pre")
? () => false
: /* skip packages that have not been previously prereleased */
(node) => node.prereleaseId;
const isForced = (node, name) =>
(forced.has("*") || forced.has(name)) && (useConventionalGraduate ? node.prereleaseId : true);
return collectPackages(packages, {
isCandidate: (node, name) => isForced(node, name) || needsBump(node) || hasDiff(node),
onInclude: (name) => log.verbose("updated", name),
excludeDependents,
});
}