Skip to content

Commit 73a1f43

Browse files
committed
chore: mechanize pr readiness authoring
1 parent 34cf4a5 commit 73a1f43

6 files changed

Lines changed: 436 additions & 14 deletions

File tree

.github/pull_request_template.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,30 @@
1111
- [ ] No baseline exception requested.
1212
- [ ] Baseline exception requested and linked below.
1313

14-
Tracking issue:
15-
Scoped checks run:
16-
Why full baseline is not required:
14+
<!-- Write values on the same line as each label, or generate this section via `pnpm pr:readiness:prepare ...`. -->
15+
Tracking issue:
16+
Scoped checks run:
17+
Why full baseline is not required:
1718

1819
## CLI Surface Migration
1920

2021
- [ ] No migration packet required for this CLI change.
2122
- [ ] CLI/user-facing surface change and migration packet completed.
2223

23-
<!-- Fill the fields below as plain label lines. Do not add list markers like "-" before labels. -->
24-
No-migration rationale:
25-
Upgrade note:
26-
Deprecation/removal plan or issue:
27-
Docs/help/examples updated:
28-
Release/changeset wording:
24+
<!-- Fill the fields below on the same line as each label, or generate this section via `pnpm pr:readiness:prepare ...`. Do not add list markers like "-" before labels. -->
25+
No-migration rationale:
26+
Upgrade note:
27+
Deprecation/removal plan or issue:
28+
Docs/help/examples updated:
29+
Release/changeset wording:
2930

3031
## Scaffold Contract Proof
3132

3233
- [ ] No scaffold contract proof required for this PR.
3334
- [ ] Scaffold contract proof completed.
3435

35-
<!-- Fill the fields below as plain label lines. Do not add list markers like "-" before labels. -->
36-
No-proof rationale:
37-
Non-edit assertion:
38-
Fail-fast input-contract proof:
39-
Generated-output viability proof:
36+
<!-- Fill the fields below on the same line as each label, or generate this section via `pnpm pr:readiness:prepare ...`. Do not add list markers like "-" before labels. -->
37+
No-proof rationale:
38+
Non-edit assertion:
39+
Fail-fast input-contract proof:
40+
Generated-output viability proof:

docs/guide/ztd-cli-quality-gates.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ The contract has three goals:
7070

7171
The author-facing entry point is `.github/pull_request_template.md`.
7272
The enforcement point is `scripts/check-pr-readiness.js`, which reads the PR body from `GITHUB_EVENT_PATH`.
73+
For mechanical authoring, use `pnpm pr:readiness:prepare ...` to generate a validator-compatible body from the changed-file classification and structured field inputs before opening the PR.
7374

7475
When scaffold-related files change, the PR body must cover:
7576

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"playground:typecheck": "pnpm --filter ztd-playground typecheck",
3535
"playground:test": "pnpm --filter ztd-playground test",
3636
"prepare": "husky",
37+
"pr:readiness:prepare": "node scripts/prepare-pr-readiness.js",
3738
"guard:branch-session": "node scripts/branch-session-guard.js",
3839
"verify:publish-readiness": "node scripts/publish-plan.mjs",
3940
"verify:publish-contract": "node scripts/verify-publish-contract.mjs",

packages/ztd-cli/tests/prReadiness.unit.test.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,41 @@ const {
4141
errors: string[];
4242
};
4343
};
44+
const {
45+
buildPreparedPrReadiness,
46+
} = require('../../../scripts/prepare-pr-readiness.js') as {
47+
buildPreparedPrReadiness(input: {
48+
baseSha?: string | null;
49+
headSha?: string | null;
50+
changedFiles: string[];
51+
summaryLines?: string[];
52+
verificationLines?: string[];
53+
baselineMode?: 'no-exception' | 'exception';
54+
trackingIssue?: string;
55+
scopedChecks?: string[];
56+
baselineRationale?: string;
57+
cliMode?: 'no-packet' | 'packet' | null;
58+
cliNoMigrationRationale?: string;
59+
upgradeNote?: string;
60+
deprecationPlan?: string;
61+
docsUpdated?: string;
62+
releaseWording?: string;
63+
scaffoldMode?: 'no-proof' | 'proof' | null;
64+
noProofRationale?: string;
65+
nonEditAssertion?: string;
66+
failFastProof?: string;
67+
generatedOutputProof?: string;
68+
}): {
69+
classification: {
70+
changedFiles: string[];
71+
requiresCliMigrationPacket: boolean;
72+
requiresScaffoldContractProof: boolean;
73+
cliMatchedFiles: string[];
74+
scaffoldMatchedFiles: string[];
75+
};
76+
body: string;
77+
};
78+
};
4479

4580
function createBaseBody(): string {
4681
return [
@@ -249,3 +284,62 @@ test('pr-readiness classifies a changeset release branch as a release PR', () =>
249284
authorLogin: 'github-actions[bot]',
250285
});
251286
});
287+
288+
test('pr-readiness preparation renders a validator-compatible CLI packet body', () => {
289+
const prepared = buildPreparedPrReadiness({
290+
changedFiles: ['packages/ztd-cli/src/commands/query.ts'],
291+
summaryLines: ['align query flag migration guidance'],
292+
verificationLines: ['pnpm --filter @rawsql-ts/ztd-cli test -- prReadiness.unit.test.ts'],
293+
baselineMode: 'no-exception',
294+
cliMode: 'packet',
295+
upgradeNote: 'Replace `--specs-dir` with `--scope-dir` in command examples.',
296+
deprecationPlan: 'Issue #746 tracks the deprecated alias removal.',
297+
docsUpdated: 'CLI help output and guide examples were updated together.',
298+
releaseWording: 'Call out the required flag rename in the release note.',
299+
});
300+
301+
expect(prepared.body).toContain('Tracking issue: not needed; no baseline exception requested.');
302+
expect(prepared.body).toContain('Upgrade note: Replace `--specs-dir` with `--scope-dir` in command examples.');
303+
304+
const validation = validatePrReadiness({
305+
body: prepared.body,
306+
classification: prepared.classification,
307+
});
308+
309+
expect(validation.ok).toBe(true);
310+
expect(validation.errors).toEqual([]);
311+
});
312+
313+
test('pr-readiness preparation renders scaffold proof fields on the same line as labels', () => {
314+
const prepared = buildPreparedPrReadiness({
315+
changedFiles: ['packages/ztd-cli/templates/src/features/smoke/boundary.ts'],
316+
summaryLines: ['mechanize scaffold proof authoring'],
317+
verificationLines: ['pnpm --filter @rawsql-ts/ztd-cli test -- prReadiness.unit.test.ts'],
318+
baselineMode: 'no-exception',
319+
scaffoldMode: 'proof',
320+
nonEditAssertion: 'The parent feature boundary remains untouched while the generated child import shape is asserted separately.',
321+
failFastProof: 'The prepared body requires the explicit proof field before validation succeeds.',
322+
generatedOutputProof: 'Generated project verification confirms the scaffolded output stays viable.',
323+
});
324+
325+
expect(prepared.body).toContain('Non-edit assertion: The parent feature boundary remains untouched while the generated child import shape is asserted separately.');
326+
expect(prepared.body).toContain('Fail-fast input-contract proof: The prepared body requires the explicit proof field before validation succeeds.');
327+
expect(prepared.body).not.toContain('Non-edit assertion:\n');
328+
329+
const validation = validatePrReadiness({
330+
body: prepared.body,
331+
classification: prepared.classification,
332+
});
333+
334+
expect(validation.ok).toBe(true);
335+
expect(validation.errors).toEqual([]);
336+
});
337+
338+
test('pr-readiness preparation fails fast when classified CLI changes omit a mode selection', () => {
339+
expect(() => buildPreparedPrReadiness({
340+
changedFiles: ['packages/ztd-cli/src/commands/query.ts'],
341+
summaryLines: ['omit CLI mode to prove fail-fast guidance'],
342+
verificationLines: ['pnpm --filter @rawsql-ts/ztd-cli test -- prReadiness.unit.test.ts'],
343+
baselineMode: 'no-exception',
344+
})).toThrow('CLI-facing changes require --cli-mode set to "no-packet" or "packet".');
345+
});

scripts/check-pr-readiness.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,13 @@ if (require.main === module) {
353353
module.exports = {
354354
CLI_SURFACE_PATTERNS,
355355
SCAFFOLD_CONTRACT_PATTERNS,
356+
MERGE_NO_EXCEPTION_LABEL,
357+
MERGE_EXCEPTION_LABEL,
358+
CLI_NO_PACKET_LABEL,
359+
CLI_PACKET_LABEL,
360+
SCAFFOLD_NO_PROOF_LABEL,
361+
SCAFFOLD_PROOF_LABEL,
362+
getChangedFiles,
356363
classifyPullRequestContext,
357364
classifyPrReadiness,
358365
validatePrReadiness,

0 commit comments

Comments
 (0)