@avi2dg/checks 0.61.0 → 0.61.1
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
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Every release of `@avi2dg/checks`, newest first, written by the release from its conventional commits.
|
|
4
4
|
|
|
5
|
+
## 0.61.1
|
|
6
|
+
|
|
7
|
+
Released 2026-11-02.
|
|
8
|
+
|
|
9
|
+
### Fixes
|
|
10
|
+
|
|
11
|
+
- **changelog:** keep a release's section when its commit gets its tag [#23](https://github.com/avi2d/checks/pull/23)
|
|
12
|
+
|
|
5
13
|
## 0.61.0
|
|
6
14
|
|
|
7
15
|
Released 2026-11-01.
|
|
@@ -27,6 +27,8 @@ It finds releases in the version bumps of `package.json` across all of `HEAD` an
|
|
|
27
27
|
It reads a commit whose `package.json` is missing or has no version as unversioned, so the commit that adds the version is the first release and a repository that adopts a version late still writes its changelog.
|
|
28
28
|
A bump to a version no newer than the release before it is a revert.
|
|
29
29
|
A revert cancels every release above the version it returns to, except a release a `v` tag marks as published.
|
|
30
|
+
A `v` tag publishes only the newest bump of its version that the tagged commit reaches.
|
|
31
|
+
So a version bumped again after a cancel keeps its cancelled bump cancelled, and the tag leaves the changelog unchanged.
|
|
30
32
|
A version older than the newest in the committed `CHANGELOG.md` and absent from it was never published, so its commits go into the next release.
|
|
31
33
|
It refuses a shallow checkout, since the releases reach back past its history.
|
|
32
34
|
It refuses a `package.json` with no repository address, since each entry links its pull request under it.
|
package/package.json
CHANGED
|
@@ -64,9 +64,26 @@ const readBumps = Effect.fn("readBumps")(function* (root: string) {
|
|
|
64
64
|
return bumps;
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
const
|
|
67
|
+
const reaches = (root: string, ancestor: string, descendant: string) =>
|
|
68
|
+
git(["merge-base", "--is-ancestor", ancestor, descendant], root).pipe(
|
|
69
|
+
Effect.as(true),
|
|
70
|
+
Effect.catchTag("GitFailure", () => Effect.succeed(false)),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// A tag publishes the newest bump of its version that it reaches, so a cancelled older bump of that version stays cancelled.
|
|
74
|
+
const readPublishedShas = Effect.fn("readPublishedShas")(function* (root: string, bumps: readonly Bump[]) {
|
|
68
75
|
const tags = yield* git(["for-each-ref", "--format=%(refname:strip=2)", `refs/tags/${TAG_PREFIX}*`], root);
|
|
69
|
-
|
|
76
|
+
const published = new Set<string>();
|
|
77
|
+
for (const tag of tags.split("\n").filter((line) => line.startsWith(TAG_PREFIX))) {
|
|
78
|
+
const version = tag.slice(TAG_PREFIX.length);
|
|
79
|
+
for (const bump of bumps.filter((one) => one.version === version).toReversed()) {
|
|
80
|
+
if (yield* reaches(root, bump.sha, `refs/tags/${tag}`)) {
|
|
81
|
+
published.add(bump.sha);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return published;
|
|
70
87
|
});
|
|
71
88
|
|
|
72
89
|
const mergedTips = Effect.fn("mergedTips")(function* (root: string, through: string) {
|
|
@@ -78,11 +95,7 @@ const mergedTips = Effect.fn("mergedTips")(function* (root: string, through: str
|
|
|
78
95
|
for (const [, ...parents] of merges.split("\n").filter((line) => line !== "").map((line) => line.split(" "))) {
|
|
79
96
|
for (const parent of parents) {
|
|
80
97
|
// A parent past the bump belongs to a later release, so only a parent beside it joins this one.
|
|
81
|
-
|
|
82
|
-
Effect.as(true),
|
|
83
|
-
Effect.catchTag("GitFailure", () => Effect.succeed(false)),
|
|
84
|
-
);
|
|
85
|
-
if (!past) tips.push(parent);
|
|
98
|
+
if (!(yield* reaches(root, through, parent))) tips.push(parent);
|
|
86
99
|
}
|
|
87
100
|
}
|
|
88
101
|
return tips;
|
|
@@ -113,7 +126,8 @@ const write = Effect.gen(function* () {
|
|
|
113
126
|
}
|
|
114
127
|
const recorded = (yield* fs.exists(target)) ? releaseDates(yield* fs.readFileString(target)) : new Map<string, string>();
|
|
115
128
|
const pending = version === (yield* versionAt(root, "HEAD")) ? undefined : { sha: "HEAD", version, date: yield* today };
|
|
116
|
-
const
|
|
129
|
+
const bumps = yield* readBumps(root);
|
|
130
|
+
const released = cuts(bumps, recorded, yield* readPublishedShas(root, bumps), pending);
|
|
117
131
|
const tip = released.at(-1);
|
|
118
132
|
const extra = tip === undefined || tip.through === "HEAD" ? [] : yield* mergedTips(root, tip.through);
|
|
119
133
|
const found = (yield* Effect.forEach(released, (cut, index) => subjectsOf(root, cut, index === released.length - 1 ? extra : [])))
|
|
@@ -57,12 +57,13 @@ function entryOf(subject: string, repositoryUrl: string): Entry | undefined {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// A bump not newer than the release before it is a revert: it cancels every release above the version it
|
|
60
|
-
// returns to, except a published one.
|
|
61
|
-
|
|
60
|
+
// returns to, except a published one. A version cancelled and bumped again holds two bumps, so a bump is
|
|
61
|
+
// published by its sha and never by its version.
|
|
62
|
+
function standing(bumps: readonly Bump[], publishedShas: ReadonlySet<string>): readonly Bump[] {
|
|
62
63
|
return bumps.reduce<readonly Bump[]>((kept, bump) => {
|
|
63
64
|
const before = kept.at(-1);
|
|
64
65
|
if (before === undefined || Bun.semver.order(bump.version, before.version) === 1) return [...kept, bump];
|
|
65
|
-
return kept.filter(({ version }) =>
|
|
66
|
+
return kept.filter(({ sha, version }) => publishedShas.has(sha) || Bun.semver.order(version, bump.version) !== 1);
|
|
66
67
|
}, []);
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -71,11 +72,11 @@ function standing(bumps: readonly Bump[], published: ReadonlySet<string>): reado
|
|
|
71
72
|
export function cuts(
|
|
72
73
|
bumps: readonly Bump[],
|
|
73
74
|
recorded: ReadonlyMap<string, string>,
|
|
74
|
-
|
|
75
|
+
publishedShas: ReadonlySet<string>,
|
|
75
76
|
pending: Bump | undefined,
|
|
76
77
|
): readonly Cut[] {
|
|
77
78
|
const newest = [...recorded.keys()].toSorted(Bun.semver.order).at(-1);
|
|
78
|
-
const candidates = standing(pending === undefined ? bumps : [...bumps, pending],
|
|
79
|
+
const candidates = standing(pending === undefined ? bumps : [...bumps, pending], publishedShas);
|
|
79
80
|
const released = candidates.filter(
|
|
80
81
|
({ version }, index) =>
|
|
81
82
|
index === candidates.length - 1 || newest === undefined || recorded.has(version) || Bun.semver.order(version, newest) !== -1,
|