Files
DeepSeek-Reasonix/scripts/studio-release-notes.test.mjs
T
esengine 11920eb387 ci(release-studio): credit pull request authors and issue fixers in published notes
The publish job now renders release-notes/studio/<semver>.md before it
signs anything. A #N that is a pull request gains "by @author"; a #N that
is an issue gains "fixed in #M by @author" for each merged pull request
GitHub links as closing it (the ClosedEvent closer and
closedByPullRequestsReferences, read over GraphQL; mentions are not
fixes). An issue fixed by a direct push stays plain. A 贡献者 list of the
credited humans, in first-appearance order, closes the notes. Bot authors
are never credited; the source file is not rewritten.

scripts/markdown-refs.mjs decides what is a reference: #N at a line start
or after whitespace, "(", "(" or a list separator, outside code spans,
backtick and tilde fences (each closed only by its own kind), indented
code, HTML comments and link targets. A number that names a discussion or
nothing stays plain with a warning instead of failing the release.

Lookups retry with backoff on 5xx, rate limits and dropped connections. A
failure that persists, or an authorisation failure, fails the job with a
release_credits.* code before signing. The publish job gains
issues: read and pull-requests: read.

CI gains a release-notes-scripts job, gated on scripts/ and
release-notes/studio/, that runs the three test files with contents: read.

scripts/release-credits.mjs is the same module the 1.x renderer uses.
2026-09-26 23:28:25 -07:00

83 lines
3.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { readdir, readFile } from "node:fs/promises";
import { test } from "node:test";
import { markdownRefs } from "./markdown-refs.mjs";
import { CreditError, CreditErrorCode, resolveCredits } from "./release-credits.mjs";
import { renderStudioNotes } from "./studio-release-notes.mjs";
const notes = `本版修复两件事。
## 修复
- 读图模型不再声称看不到图片(#20)(44150b0aa)
- Windows 窗口可以打开 #21
- 依赖升级 #22,并补上 #20 的回归测试
- 会话不再丢失(#23)
`;
const authors = {
20: { kind: "pull", login: "alice", bot: false },
21: { kind: "issue", fixes: [] },
22: { kind: "pull", login: "dependabot[bot]", bot: true },
23: { kind: "issue", fixes: [{ number: 30, login: "bob", bot: false }] },
};
test("pull requests credit their authors, fixed issues their fixers, the rest stay plain", async () => {
const calls = [];
const { credits, failures } = await resolveCredits(markdownRefs(notes), async (ref) => {
calls.push(ref);
return authors[ref];
});
assert.deepEqual(failures, []);
assert.deepEqual(calls.sort(), [20, 21, 22, 23]);
assert.equal(
renderStudioNotes(notes, credits),
`本版修复两件事。
## 修复
- 读图模型不再声称看不到图片(#20 by @alice)(44150b0aa)
- Windows 窗口可以打开 #21
- 依赖升级 #22,并补上 #20 by @alice 的回归测试
- 会话不再丢失(#23 fixed in #30 by @bob)
## 贡献者
感谢本版本的贡献者:@alice、@bob
`,
);
});
test("an unresolved ref stays plain and is reported by code", async () => {
const { credits, failures } = await resolveCredits(markdownRefs(notes), async (ref) => {
if (ref === 20) throw new CreditError(CreditErrorCode.unreachable, "#20: down", { ref });
return authors[ref];
});
assert.deepEqual(failures.map((failure) => [failure.ref, failure.code]), [[20, CreditErrorCode.unreachable]]);
const rendered = renderStudioNotes(notes, credits);
assert.doesNotMatch(rendered, /#20 by/);
assert.match(rendered, /#23 fixed in #30 by @bob/);
assert.match(rendered, /感谢本版本的贡献者:@bob\n$/);
});
test("committed notes render unchanged when nothing is credited", async () => {
const dir = new URL("../release-notes/studio/", import.meta.url);
for (const name of await readdir(dir)) {
const source = await readFile(new URL(name, dir), "utf8");
assert.equal(renderStudioNotes(source, new Map()), `${source.trimEnd()}\n`, name);
}
});
test("a number naming a discussion or nothing stays plain and only warns", async () => {
const source = "- 讨论见 #40,颜色改为 #123456\n";
const { credits, failures, warnings } = await resolveCredits(markdownRefs(source), async (ref) =>
ref === 40 ? { kind: "discussion" } : { kind: "missing" },
);
assert.deepEqual(failures, []);
assert.deepEqual(
warnings.map((warning) => warning.code),
[CreditErrorCode.discussion, CreditErrorCode.notFound],
);
assert.equal(renderStudioNotes(source, credits), source);
});