@tallyrelease/core 0.3.2-beta.4 → 0.4.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/affected.js +8 -2
- package/dist/branches.d.ts +16 -0
- package/dist/branches.js +43 -0
- package/dist/config.d.ts +6 -2
- package/dist/discover.d.ts +4 -3
- package/dist/discover.js +66 -21
- package/dist/explain.js +11 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/plan.d.ts +16 -1
- package/dist/released.d.ts +2 -5
- package/dist/released.js +24 -16
- package/dist/workspace.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.2](https://github.com/abinnovision/tallyrelease/compare/core-v0.3.1...core-v0.3.2) (2026-10-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* **core:** Synchronize tallyrelease versions
|
|
9
|
+
|
|
3
10
|
## [0.3.1](https://github.com/abinnovision/tallyrelease/compare/core-v0.3.0...core-v0.3.1) (2026-10-16)
|
|
4
11
|
|
|
5
12
|
|
package/dist/affected.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { attribution, matcher } from "./attribution.js";
|
|
2
|
+
import { changelogPath } from "./changelog.js";
|
|
2
3
|
import { uniqueSorted } from "./util.js";
|
|
3
4
|
/** Computes the build set for `base..head` from a tree-to-tree diff. */
|
|
4
5
|
export const computeAffected = async (workspace, git, opts) => {
|
|
@@ -30,7 +31,11 @@ export const computeAffected = async (workspace, git, opts) => {
|
|
|
30
31
|
const ignored = matcher(workspace.ignore);
|
|
31
32
|
const isGlobal = matcher(workspace.globalInputs);
|
|
32
33
|
const owners = attribution(units);
|
|
33
|
-
|
|
34
|
+
// A released unit owns its changelog regardless of ignore, include and exclude.
|
|
35
|
+
const changelogs = new Map(units
|
|
36
|
+
.filter((u) => u.version !== "none")
|
|
37
|
+
.map((u) => [changelogPath(u), u.id]));
|
|
38
|
+
const files = (await git.diffFiles(opts.base, opts.head)).filter((f) => changelogs.has(f) || !ignored(f));
|
|
34
39
|
const hits = uniqueSorted(files.filter(isGlobal));
|
|
35
40
|
const direct = new Set();
|
|
36
41
|
const unattributed = [];
|
|
@@ -38,7 +43,8 @@ export const computeAffected = async (workspace, git, opts) => {
|
|
|
38
43
|
if (isGlobal(file)) {
|
|
39
44
|
continue;
|
|
40
45
|
}
|
|
41
|
-
const
|
|
46
|
+
const own = changelogs.get(file);
|
|
47
|
+
const ids = own === undefined ? owners(file) : [own];
|
|
42
48
|
if (ids.length === 0) {
|
|
43
49
|
unattributed.push(file);
|
|
44
50
|
}
|
package/dist/branches.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { Plan } from "./plan.js";
|
|
1
2
|
import type { BumpLevel } from "./plugin.js";
|
|
3
|
+
import type { ReleaseItem as PrItem } from "./release-items.js";
|
|
2
4
|
import type { BranchRule } from "./release.js";
|
|
5
|
+
import type { Workspace } from "./workspace.js";
|
|
3
6
|
/** The branch rule matching the planned branch. */
|
|
4
7
|
export interface Line {
|
|
5
8
|
rule: string;
|
|
@@ -68,3 +71,16 @@ export declare const checkLimits: (line: Line | null, items: readonly LimitItem[
|
|
|
68
71
|
branch: string;
|
|
69
72
|
implicit: boolean;
|
|
70
73
|
}) => void;
|
|
74
|
+
/** A maintenance branch to cut at the last release of the previous major. */
|
|
75
|
+
export interface MaintenanceCut {
|
|
76
|
+
branch: string;
|
|
77
|
+
tag: string;
|
|
78
|
+
/** `2.x`, or `2.3.x` for a `{minor}` rule. */
|
|
79
|
+
line: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The cut for `item` when a default-line plan releases a new major: the first
|
|
83
|
+
* maintenance rule with `{major}` and no `*` that targets the item or nothing,
|
|
84
|
+
* rendered from `from`, at the item's base tag; else undefined.
|
|
85
|
+
*/
|
|
86
|
+
export declare const maintenanceCut: (workspace: Workspace, plan: Plan, item: PrItem) => MaintenanceCut | undefined;
|
package/dist/branches.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TallyError } from "./errors.js";
|
|
2
|
+
import { schemeRegistry } from "./schemes.js";
|
|
2
3
|
import { maxLevel } from "./util.js";
|
|
3
4
|
const SPECIAL = /[\\^$.*+?()[\]{}|/]/gu;
|
|
4
5
|
const PART = /\{(major|minor)\}|\*/gu;
|
|
@@ -166,3 +167,45 @@ export const checkLimits = (line, items, { branch, implicit }) => {
|
|
|
166
167
|
});
|
|
167
168
|
}
|
|
168
169
|
};
|
|
170
|
+
/**
|
|
171
|
+
* The cut for `item` when a default-line plan releases a new major: the first
|
|
172
|
+
* maintenance rule with `{major}` and no `*` that targets the item or nothing,
|
|
173
|
+
* rendered from `from`, at the item's base tag; else undefined.
|
|
174
|
+
*/
|
|
175
|
+
export const maintenanceCut = (workspace, plan, item) => {
|
|
176
|
+
const base = item.kind === "group"
|
|
177
|
+
? plan.groups.find((g) => g.name === item.name)
|
|
178
|
+
: plan.units.find((u) => u.id === item.name);
|
|
179
|
+
const unit = workspace.units.find((u) => u.id === item.units[0]);
|
|
180
|
+
const scheme = unit && schemeRegistry(workspace.schemes).get(unit.scheme);
|
|
181
|
+
if (plan.line?.kind !== "default" ||
|
|
182
|
+
!scheme ||
|
|
183
|
+
!base?.from ||
|
|
184
|
+
!base.baseTag) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
const from = scheme.parse(base.from);
|
|
188
|
+
const next = scheme.parse(item.version);
|
|
189
|
+
if (from === undefined || next === undefined) {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
const { major, minor } = scheme.core(from);
|
|
193
|
+
const rule = workspace.release.branches.find((r) => r.line === "maintenance" &&
|
|
194
|
+
r.name.includes("{major}") &&
|
|
195
|
+
!r.name.includes("*") &&
|
|
196
|
+
((r.unit === null && r.group === null) ||
|
|
197
|
+
(item.kind === "group" ? r.group : r.unit) === item.name));
|
|
198
|
+
if (!rule || scheme.core(next).major <= major) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
const withMinor = rule.name.includes("{minor}");
|
|
202
|
+
return {
|
|
203
|
+
branch: rule.name
|
|
204
|
+
.replace("{major}", String(major))
|
|
205
|
+
.replace("{minor}", String(minor)),
|
|
206
|
+
tag: base.baseTag,
|
|
207
|
+
line: withMinor
|
|
208
|
+
? `${String(major)}.${String(minor)}.x`
|
|
209
|
+
: `${String(major)}.x`,
|
|
210
|
+
};
|
|
211
|
+
};
|
package/dist/config.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { BumpLevel, Propagate, VersionSource } from "./plugin.js";
|
|
2
2
|
/** Release PR of a release item: the shared PR or its own. */
|
|
3
3
|
export type ReleasePrMode = "shared" | "separate";
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Config overlay for the unit at a root; creates a config-only unit if none is
|
|
6
|
+
* discovered. A glob key (`*` matches one segment, not dot directories) never
|
|
7
|
+
* creates units and cannot set `id`, `include`, `exclude` or `versionFiles`.
|
|
8
|
+
*/
|
|
5
9
|
export interface UnitOverlay {
|
|
6
10
|
id?: string;
|
|
7
11
|
include?: string[];
|
|
@@ -83,7 +87,7 @@ export interface TallyConfig {
|
|
|
83
87
|
/** Default `shared`. */
|
|
84
88
|
releasePr?: ReleasePrMode;
|
|
85
89
|
};
|
|
86
|
-
/** Overlays keyed by unit root. */
|
|
90
|
+
/** Overlays keyed by unit root or glob; exact keys win over globs per field. */
|
|
87
91
|
units?: Record<string, UnitOverlay>;
|
|
88
92
|
deps?: DepConfig[];
|
|
89
93
|
ignore?: string[];
|
package/dist/discover.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { Warning } from "./errors.js";
|
|
1
2
|
import type { Unit } from "./plugin.js";
|
|
2
3
|
import type { ActivePlugin, PluginEnv } from "./plugins.js";
|
|
3
4
|
/** Drops `.` and empty segments; rejects absolute roots and `..` segments. */
|
|
4
5
|
export declare const normalizeRoot: (root: string) => string;
|
|
5
6
|
/**
|
|
6
|
-
* Runs `discover` hooks in config order, applies config overlays
|
|
7
|
-
* defaults. Returns units sorted by id.
|
|
7
|
+
* Runs `discover` hooks in config order, applies config overlays (glob keys
|
|
8
|
+
* first, then exact keys) and fills defaults. Returns units sorted by id.
|
|
8
9
|
*/
|
|
9
|
-
export declare const discoverUnits: (active: readonly ActivePlugin[], env: Pick<PluginEnv, "config" | "fs" | "repo"
|
|
10
|
+
export declare const discoverUnits: (active: readonly ActivePlugin[], env: Pick<PluginEnv, "config" | "fs" | "repo">, warnings?: Warning[]) => Promise<Unit[]>;
|
package/dist/discover.js
CHANGED
|
@@ -7,6 +7,41 @@ const UNIT_TAG = /^[A-Za-z0-9._-]+$/;
|
|
|
7
7
|
/** Escapes glob metacharacters so a root matches literally. */
|
|
8
8
|
const escapeGlob = (path) => path.replace(/[[\]{}()!*?+@\\]/g, "\\$&");
|
|
9
9
|
const isInside = (path, root) => path !== root && (root === "." || path.startsWith(`${root}/`));
|
|
10
|
+
/** Fields a glob overlay cannot set. */
|
|
11
|
+
const GLOB_REJECTED = ["id", "include", "exclude", "versionFiles"];
|
|
12
|
+
/**
|
|
13
|
+
* Validates a glob key and returns its segments: each is `*` (any segment not
|
|
14
|
+
* starting with `.`) or a literal.
|
|
15
|
+
*/
|
|
16
|
+
const globSegments = (key, root, overlay) => {
|
|
17
|
+
const segments = root.split("/");
|
|
18
|
+
if (segments.some((s) => s !== "*" && s.includes("*"))) {
|
|
19
|
+
throw new TallyError("E_UNIT_GLOB", `unit overlay "${key}" may use "*" only as a whole path segment`, { key });
|
|
20
|
+
}
|
|
21
|
+
const field = GLOB_REJECTED.find((f) => overlay[f] !== undefined);
|
|
22
|
+
if (field !== undefined) {
|
|
23
|
+
throw new TallyError("E_UNIT_GLOB", `unit overlay "${key}" cannot set "${field}" on a glob key`, { key, field });
|
|
24
|
+
}
|
|
25
|
+
return segments;
|
|
26
|
+
};
|
|
27
|
+
const globMatches = (segments, root) => {
|
|
28
|
+
const parts = root.split("/");
|
|
29
|
+
return (parts.length === segments.length &&
|
|
30
|
+
parts.every((p, i) => segments[i] === "*" ? !p.startsWith(".") : segments[i] === p));
|
|
31
|
+
};
|
|
32
|
+
/** Merges draft fields; sets `release`, `tags` and `initialVersion` when defined. */
|
|
33
|
+
const applyOverlay = (entry, { release, tags, initialVersion, ...overlay }) => {
|
|
34
|
+
entry.draft = { ...entry.draft, ...overlay };
|
|
35
|
+
if (release !== undefined) {
|
|
36
|
+
entry.release = release;
|
|
37
|
+
}
|
|
38
|
+
if (tags !== undefined) {
|
|
39
|
+
entry.tags = tags;
|
|
40
|
+
}
|
|
41
|
+
if (initialVersion !== undefined) {
|
|
42
|
+
entry.initialVersion = initialVersion;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
10
45
|
/** Drops `.` and empty segments; rejects absolute roots and `..` segments. */
|
|
11
46
|
export const normalizeRoot = (root) => {
|
|
12
47
|
const segments = root.split("/");
|
|
@@ -16,10 +51,10 @@ export const normalizeRoot = (root) => {
|
|
|
16
51
|
return segments.filter((s) => s !== "" && s !== ".").join("/") || ".";
|
|
17
52
|
};
|
|
18
53
|
/**
|
|
19
|
-
* Runs `discover` hooks in config order, applies config overlays
|
|
20
|
-
* defaults. Returns units sorted by id.
|
|
54
|
+
* Runs `discover` hooks in config order, applies config overlays (glob keys
|
|
55
|
+
* first, then exact keys) and fills defaults. Returns units sorted by id.
|
|
21
56
|
*/
|
|
22
|
-
export const discoverUnits = async (active, env) => {
|
|
57
|
+
export const discoverUnits = async (active, env, warnings = []) => {
|
|
23
58
|
const byRoot = new Map();
|
|
24
59
|
for (const { plugin, ctx } of active) {
|
|
25
60
|
const discover = plugin.discover?.bind(plugin);
|
|
@@ -41,33 +76,43 @@ export const discoverUnits = async (active, env) => {
|
|
|
41
76
|
});
|
|
42
77
|
}
|
|
43
78
|
}
|
|
44
|
-
|
|
79
|
+
const exact = [];
|
|
80
|
+
const globs = [];
|
|
81
|
+
for (const [key, overlay] of Object.entries(env.config.units ?? {})) {
|
|
45
82
|
const root = normalizeRoot(key);
|
|
46
|
-
const invalid = tags?.find((t) => !UNIT_TAG.test(t));
|
|
83
|
+
const invalid = overlay.tags?.find((t) => !UNIT_TAG.test(t));
|
|
47
84
|
if (invalid !== undefined) {
|
|
48
85
|
throw new TallyError("E_UNIT_TAG", `tag "${invalid}" of unit at "${root}" must match ${UNIT_TAG.source}`, { tag: invalid, root });
|
|
49
86
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
entry.release = release;
|
|
54
|
-
entry.tags = tags;
|
|
55
|
-
entry.initialVersion = initialVersion;
|
|
87
|
+
if (root.includes("*")) {
|
|
88
|
+
globs.push([key, globSegments(key, root, overlay), overlay]);
|
|
89
|
+
continue;
|
|
56
90
|
}
|
|
57
|
-
|
|
58
|
-
|
|
91
|
+
let entry = byRoot.get(root);
|
|
92
|
+
if (!entry) {
|
|
93
|
+
entry = {
|
|
59
94
|
plugin: "config",
|
|
60
|
-
draft: {
|
|
61
|
-
...overlay,
|
|
62
|
-
id: overlay.id ?? defaultUnitId(root, env.repo.name),
|
|
63
|
-
root,
|
|
64
|
-
},
|
|
95
|
+
draft: { id: overlay.id ?? defaultUnitId(root, env.repo.name), root },
|
|
65
96
|
meta: {},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
97
|
+
};
|
|
98
|
+
byRoot.set(root, entry);
|
|
99
|
+
}
|
|
100
|
+
exact.push([entry, overlay]);
|
|
101
|
+
}
|
|
102
|
+
for (const [key, segments, overlay] of globs) {
|
|
103
|
+
const matched = [...byRoot.entries()].filter(([root]) => globMatches(segments, root));
|
|
104
|
+
if (matched.length === 0) {
|
|
105
|
+
warnings.push({
|
|
106
|
+
code: "W_UNIT_GLOB_UNMATCHED",
|
|
107
|
+
message: `unit overlay "${key}" matches no unit`,
|
|
69
108
|
});
|
|
70
109
|
}
|
|
110
|
+
for (const [, entry] of matched) {
|
|
111
|
+
applyOverlay(entry, overlay);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const [entry, overlay] of exact) {
|
|
115
|
+
applyOverlay(entry, overlay);
|
|
71
116
|
}
|
|
72
117
|
const byId = new Map();
|
|
73
118
|
for (const entry of byRoot.values()) {
|
package/dist/explain.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { attribution, matcher } from "./attribution.js";
|
|
2
|
+
import { changelogPath } from "./changelog.js";
|
|
2
3
|
import { TallyError } from "./errors.js";
|
|
3
4
|
import { planWithFacts } from "./plan.js";
|
|
4
5
|
/** Explains one unit of the plan of `opts.head`; throws `E_UNIT_UNKNOWN`. */
|
|
@@ -16,7 +17,16 @@ export const explainUnit = async (workspace, git, { unit: id, ...opts }) => {
|
|
|
16
17
|
const ignored = matcher(workspace.ignore);
|
|
17
18
|
const isGlobal = matcher(workspace.globalInputs);
|
|
18
19
|
const owners = attribution(workspace.units);
|
|
19
|
-
|
|
20
|
+
// As in `computeAffected`: a released unit owns its changelog.
|
|
21
|
+
const changelogs = new Map(workspace.units
|
|
22
|
+
.filter((u) => u.version !== "none")
|
|
23
|
+
.map((u) => [changelogPath(u), u.id]));
|
|
24
|
+
const owned = (files, owner) => files.filter((f) => {
|
|
25
|
+
const own = changelogs.get(f);
|
|
26
|
+
return own === undefined
|
|
27
|
+
? !ignored(f) && !isGlobal(f) && owners(f).includes(owner)
|
|
28
|
+
: own === owner && !isGlobal(f);
|
|
29
|
+
});
|
|
20
30
|
const { base } = plan.build;
|
|
21
31
|
const reason = unit?.affected?.reason;
|
|
22
32
|
const files = reason === "global"
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type { SchemeEntry } from "./schemes.js";
|
|
|
17
17
|
export type { SemVer } from "./semver.js";
|
|
18
18
|
export type { IntentEntry, Workspace, WorkspaceInput } from "./workspace.js";
|
|
19
19
|
export { computeAffected } from "./affected.js";
|
|
20
|
+
export { maintenanceCut } from "./branches.js";
|
|
20
21
|
export { changelogSection, releaseNotes, renderChangelogSection, updateChangelog, } from "./changelog.js";
|
|
21
22
|
export { CONFIG_FILE } from "./config.js";
|
|
22
23
|
export { conventionalCommits, parseCommit } from "./conventional.js";
|
|
@@ -30,7 +31,7 @@ export { computePlan } from "./plan.js";
|
|
|
30
31
|
export { decodeMarker, encodeMarker } from "./marker.js";
|
|
31
32
|
export { activatePlugins } from "./plugins.js";
|
|
32
33
|
export { planEquals, releaseEntries, releaseItems } from "./release-items.js";
|
|
33
|
-
export {
|
|
34
|
+
export { releasedFromTags, withReleased } from "./released.js";
|
|
34
35
|
export { semver } from "./semver.js";
|
|
35
36
|
export { validateRelease, validateTags } from "./validate.js";
|
|
36
37
|
export { releaseFiles, versionFileClaims } from "./version-files.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const version = "0.0.0";
|
|
2
2
|
export { computeAffected } from "./affected.js";
|
|
3
|
+
export { maintenanceCut } from "./branches.js";
|
|
3
4
|
export { changelogSection, releaseNotes, renderChangelogSection, updateChangelog, } from "./changelog.js";
|
|
4
5
|
export { CONFIG_FILE } from "./config.js";
|
|
5
6
|
export { conventionalCommits, parseCommit } from "./conventional.js";
|
|
@@ -13,7 +14,7 @@ export { computePlan } from "./plan.js";
|
|
|
13
14
|
export { decodeMarker, encodeMarker } from "./marker.js";
|
|
14
15
|
export { activatePlugins } from "./plugins.js";
|
|
15
16
|
export { planEquals, releaseEntries, releaseItems } from "./release-items.js";
|
|
16
|
-
export {
|
|
17
|
+
export { releasedFromTags, withReleased } from "./released.js";
|
|
17
18
|
export { semver } from "./semver.js";
|
|
18
19
|
export { validateRelease, validateTags } from "./validate.js";
|
|
19
20
|
export { releaseFiles, versionFileClaims } from "./version-files.js";
|
package/dist/plan.d.ts
CHANGED
|
@@ -63,9 +63,24 @@ export interface ReleasedUnit {
|
|
|
63
63
|
tag: string;
|
|
64
64
|
floatingTags: string[];
|
|
65
65
|
releaseSha: string;
|
|
66
|
+
/** Not built from HEAD by this run (release sha differs from HEAD, or the unit is outside the build set). */
|
|
66
67
|
catchUp: boolean;
|
|
67
|
-
|
|
68
|
+
/** Null when not looked up (no forge, or a forge error in `plan`). */
|
|
69
|
+
forge: ReleasedForge | null;
|
|
68
70
|
line: "default" | "maintenance";
|
|
71
|
+
/** Highest stable version tagged for the unit, never on a maintenance line. */
|
|
72
|
+
latest: boolean;
|
|
73
|
+
}
|
|
74
|
+
export interface ReleasedForge {
|
|
75
|
+
/** PR that merged the release sha. */
|
|
76
|
+
pr: {
|
|
77
|
+
number: number;
|
|
78
|
+
url: string;
|
|
79
|
+
} | null;
|
|
80
|
+
/** Forge release of the tag. */
|
|
81
|
+
release: {
|
|
82
|
+
url: string;
|
|
83
|
+
} | null;
|
|
69
84
|
}
|
|
70
85
|
/** `tallyrelease plan --json`, schema 1. */
|
|
71
86
|
export interface Plan extends Omit<AffectedDoc, "units"> {
|
package/dist/released.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ import type { Workspace } from "./workspace.js";
|
|
|
5
5
|
* `plan` with `released`: stable unit tags whose commit is on HEAD's
|
|
6
6
|
* first-parent chain and not an ancestor of `build.base`. With a null base
|
|
7
7
|
* only tags at HEAD, warning `W_RELEASED_NO_BASE` when earlier releases on the
|
|
8
|
-
* chain are left out.
|
|
8
|
+
* chain are left out. A release at HEAD of a unit outside the build set warns
|
|
9
|
+
* `W_RELEASE_NOT_BUILT`.
|
|
9
10
|
*/
|
|
10
11
|
export declare const withReleased: (workspace: Workspace, plan: Plan, { git }: {
|
|
11
12
|
git: GitReader;
|
|
@@ -19,7 +20,3 @@ export declare const releasedFromTags: (workspace: Workspace, plan: Plan, { git,
|
|
|
19
20
|
git: GitReader;
|
|
20
21
|
tags: readonly string[];
|
|
21
22
|
}) => Promise<ReleasedUnit[]>;
|
|
22
|
-
/** Tag of the highest stable version of each released unit with one. */
|
|
23
|
-
export declare const highestReleases: (workspace: Workspace, { git }: {
|
|
24
|
-
git: GitReader;
|
|
25
|
-
}) => Promise<Set<string>>;
|
package/dist/released.js
CHANGED
|
@@ -14,12 +14,14 @@ const stable = (scheme, version) => {
|
|
|
14
14
|
const releasedEntries = async (workspace, plan, { git, keep, }) => {
|
|
15
15
|
const matched = matchUnitTags(workspace.units, await git.tags(), schemeRegistry(workspace.schemes));
|
|
16
16
|
const line = plan.line?.kind ?? "default";
|
|
17
|
+
const built = new Set(plan.units.filter((u) => u.affected !== null).map((u) => u.id));
|
|
17
18
|
const candidates = workspace.units.flatMap((unit) => {
|
|
18
19
|
const m = matched.get(unit.id);
|
|
19
20
|
if (!m) {
|
|
20
21
|
return [];
|
|
21
22
|
}
|
|
22
23
|
const names = m.tags.map((t) => t.name);
|
|
24
|
+
const highest = m.tags.findLast((t) => stable(m.scheme, t.version))?.name;
|
|
23
25
|
return m.tags
|
|
24
26
|
.filter((tag) => stable(m.scheme, tag.version))
|
|
25
27
|
.map((tag) => ({
|
|
@@ -33,9 +35,10 @@ const releasedEntries = async (workspace, plan, { git, keep, }) => {
|
|
|
33
35
|
formats: workspace.release.floating,
|
|
34
36
|
}),
|
|
35
37
|
releaseSha: tag.sha,
|
|
36
|
-
catchUp: tag.sha !== plan.head,
|
|
37
|
-
|
|
38
|
+
catchUp: tag.sha !== plan.head || !built.has(unit.id),
|
|
39
|
+
forge: null,
|
|
38
40
|
line,
|
|
41
|
+
latest: line !== "maintenance" && tag.name === highest,
|
|
39
42
|
}));
|
|
40
43
|
});
|
|
41
44
|
const kept = await Promise.all(candidates.map(async (r) => await keep({ name: r.tag, sha: r.releaseSha, version: r.version })));
|
|
@@ -52,7 +55,8 @@ const releasedEntries = async (workspace, plan, { git, keep, }) => {
|
|
|
52
55
|
* `plan` with `released`: stable unit tags whose commit is on HEAD's
|
|
53
56
|
* first-parent chain and not an ancestor of `build.base`. With a null base
|
|
54
57
|
* only tags at HEAD, warning `W_RELEASED_NO_BASE` when earlier releases on the
|
|
55
|
-
* chain are left out.
|
|
58
|
+
* chain are left out. A release at HEAD of a unit outside the build set warns
|
|
59
|
+
* `W_RELEASE_NOT_BUILT`.
|
|
56
60
|
*/
|
|
57
61
|
export const withReleased = async (workspace, plan, { git }) => {
|
|
58
62
|
const { head } = plan;
|
|
@@ -75,14 +79,23 @@ export const withReleased = async (workspace, plan, { git }) => {
|
|
|
75
79
|
return true;
|
|
76
80
|
},
|
|
77
81
|
});
|
|
78
|
-
const warnings =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
const warnings = [
|
|
83
|
+
...(omitted === 0
|
|
84
|
+
? []
|
|
85
|
+
: [
|
|
86
|
+
{
|
|
87
|
+
code: "W_RELEASED_NO_BASE",
|
|
88
|
+
message: "the build base is unknown; released leaves out earlier releases on the first-parent chain",
|
|
89
|
+
},
|
|
90
|
+
]),
|
|
91
|
+
...released
|
|
92
|
+
.filter((r) => r.releaseSha === head && r.catchUp)
|
|
93
|
+
.map((r) => ({
|
|
94
|
+
code: "W_RELEASE_NOT_BUILT",
|
|
95
|
+
message: `release ${r.tag} is at HEAD but unit ${r.id} is not in the build set; it is listed as a catch-up`,
|
|
96
|
+
unit: r.id,
|
|
97
|
+
})),
|
|
98
|
+
];
|
|
86
99
|
return { ...plan, released, warnings: [...plan.warnings, ...warnings] };
|
|
87
100
|
};
|
|
88
101
|
/**
|
|
@@ -97,8 +110,3 @@ export const releasedFromTags = async (workspace, plan, { git, tags }) => {
|
|
|
97
110
|
keep: (tag) => names.has(tag.name),
|
|
98
111
|
});
|
|
99
112
|
};
|
|
100
|
-
/** Tag of the highest stable version of each released unit with one. */
|
|
101
|
-
export const highestReleases = async (workspace, { git }) => {
|
|
102
|
-
const matched = matchUnitTags(workspace.units, await git.tags(), schemeRegistry(workspace.schemes));
|
|
103
|
-
return new Set([...matched.values()].flatMap(({ scheme, tags }) => tags.findLast((t) => stable(scheme, t.version))?.name ?? []));
|
|
104
|
-
};
|
package/dist/workspace.js
CHANGED
|
@@ -70,7 +70,7 @@ const versionFilesOf = (active, units) => {
|
|
|
70
70
|
export const loadWorkspace = async (input) => {
|
|
71
71
|
const warnings = [];
|
|
72
72
|
const active = await activatePlugins(input, warnings);
|
|
73
|
-
const units = await discoverUnits(active, input);
|
|
73
|
+
const units = await discoverUnits(active, input, warnings);
|
|
74
74
|
const graph = buildGraph(units, await collectEdges(active, input.config, units));
|
|
75
75
|
const globalInputs = await collectGlobalInputs(active, input.config, input.configFile ?? CONFIG_FILE);
|
|
76
76
|
const groups = resolveGroups(units, input.config.groups, warnings);
|