diff --git a/.github/scripts/issue-review/common.mjs b/.github/scripts/issue-review/common.mjs index 4de3f27..f318993 100644 --- a/.github/scripts/issue-review/common.mjs +++ b/.github/scripts/issue-review/common.mjs @@ -1,7 +1,7 @@ import crypto from "node:crypto"; export const ISSUE_REVIEW_SCHEMA_VERSION = 4; -export const PREFIXED_TITLE = /^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)*: \S.*$/; +export const PREFIXED_TITLE = /^[a-z][a-z0-9_-]*(?:\/[a-z][a-z0-9_-]*)*: \S.*$/; export function sha256(value) { return crypto.createHash("sha256").update(value).digest("hex"); diff --git a/.github/scripts/pr-readiness/test.mjs b/.github/scripts/pr-readiness/test.mjs index 81679db..ba8109b 100644 --- a/.github/scripts/pr-readiness/test.mjs +++ b/.github/scripts/pr-readiness/test.mjs @@ -108,12 +108,25 @@ assert.deepEqual( analyzePullRequest(manyLinkedIssuesInput).deterministic_blockers, [], ); +assert.ok(!blockerCodes(analyzePullRequest({ + ...input, + title: "h106/zero_esp: add the Zero ESP Main App package", +})).includes("invalid-title")); assert.ok(blockerCodes(analyzePullRequest({ ...manyLinkedIssuesInput, linked_issue_count: manyLinkedIssues.length + 1, })).includes("too-many-closing-issues")); -assert.ok(analyzePullRequest({ ...input, title: "Bad title" }) - .deterministic_blockers.some((item) => item.code === "invalid-title")); +for (const title of [ + "Bad title", + "H106/zero_esp: add the Zero ESP Main App package", + "h106/_zero_esp: add the Zero ESP Main App package", + "h106//zero_esp: add the Zero ESP Main App package", + "h106/zero esp: add the Zero ESP Main App package", + "h106/zero_esp: ", +]) { + assert.ok(analyzePullRequest({ ...input, title }) + .deterministic_blockers.some((item) => item.code === "invalid-title")); +} assert.ok(analyzePullRequest({ ...input, body: "" }) .deterministic_blockers.some((item) => item.code === "missing-body")); assert.ok(analyzePullRequest({ ...input, body_truncated: true }) diff --git a/README.md b/README.md index dfb87a6..1c47f28 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,9 @@ default-branch `AGENTS.md` hierarchy and the Issue-review documents it designates. The workflow itself enforces only cross-project integrity and PR linkage requirements: -- PR titles use lowercase `prefix: Subject` form. +- PR titles use lowercase `prefix: Subject` form. Each slash-separated prefix + segment starts with a lowercase letter and may then contain lowercase letters, + digits, hyphens, or underscores. - The PR body describes the delivered result and validation. - The PR has at least one same-repository native closing Issue from GraphQL `closingIssuesReferences`; text-only references do not count.