done-done-axi 0.6.15 → 0.6.16
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/dist/cli.js +1 -1
- package/dist/lint.js +49 -16
- package/docs/reference.md +3 -3
- package/docs/releasing.md +3 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -281,7 +281,7 @@ each prints the files it changed and runs the journey once as a dirty-tree trial
|
|
|
281
281
|
when the repo (the current folder) has none; repro is not n/a on a fix PR. evidence names files in the evidence folder (or absolute):
|
|
282
282
|
each exists, is non-empty and is newer than the folder itself; no two are byte-identical; at least one has a hash no other PR used
|
|
283
283
|
(hash store lint.hashes in ~/.done-done, or $DONE_DONE_HOME). "evidence: not proven: <cause>" passes. A PR with 1,000 or more added
|
|
284
|
-
non-generated lines fails (lockfiles, vendor/, dist/, LICENSE-type files, deletions and moved lines do not count); a bot PR passes.
|
|
284
|
+
non-generated lines fails; the whole PR is counted (every page of its file list, its compare diff), and a failed page or diff fails instead of counting part of it (lockfiles, vendor/, dist/, LICENSE-type files, deletions and moved lines do not count); a bot PR passes.
|
|
285
285
|
A PR URL whose diff changes a src/ file and no journeys/ file prints WARN instead of PASS (still exit 0): run the journey and commit it before the PR opens.
|
|
286
286
|
In .done-done.yaml, checks.upstream_catch_up: true also drops a fork's upstream catch-up lines, and checks.moved_from: true drops lines
|
|
287
287
|
a "moved-from: <owner>/<repo>@<ref> <dst>=<src>" body line says came from a repo of the same owner; both are off by default.
|
package/dist/lint.js
CHANGED
|
@@ -61,6 +61,34 @@ function without(a, b) {
|
|
|
61
61
|
}
|
|
62
62
|
const total = (n) => [...n.values()].reduce((sum, c) => sum + c, 0);
|
|
63
63
|
const stdout = (r) => (r.status === 0 ? r.stdout.trim() : '');
|
|
64
|
+
const worst = (r) => r.stderr.trim().split('\n').pop()?.slice(0, 160) || '?';
|
|
65
|
+
// `gh pr view --json files` stops at 100 files, so the whole list comes from the paginated pull-files endpoint instead.
|
|
66
|
+
// GitHub stops that endpoint at 3000 files, so page 30 being full is already past what it will list.
|
|
67
|
+
const MAX_PAGES = 30;
|
|
68
|
+
function prFiles(run, nwo, num) {
|
|
69
|
+
const paths = [];
|
|
70
|
+
for (let page = 1; page <= MAX_PAGES; page++) {
|
|
71
|
+
const call = `repos/${nwo}/pulls/${num}/files?per_page=100&page=${page}`;
|
|
72
|
+
const r = run('api', call);
|
|
73
|
+
if (r.status)
|
|
74
|
+
return { why: `${call} failed: ${worst(r)}` };
|
|
75
|
+
let files;
|
|
76
|
+
try {
|
|
77
|
+
files = JSON.parse(r.stdout);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return { why: `${call} returned no file list` };
|
|
81
|
+
}
|
|
82
|
+
if (!Array.isArray(files))
|
|
83
|
+
return { why: `${call} returned no file list` };
|
|
84
|
+
for (const f of files)
|
|
85
|
+
if (f.path)
|
|
86
|
+
paths.push(f.path);
|
|
87
|
+
if (files.length < 100)
|
|
88
|
+
return { paths };
|
|
89
|
+
}
|
|
90
|
+
return { why: `${nwo}/pulls/${num}/files is still full on page ${MAX_PAGES}: more files than lint can count` };
|
|
91
|
+
}
|
|
64
92
|
// checks.upstream_catch_up: lines the fork's parent repo already shipped are not authored here, so subtract the upstream delta the PR
|
|
65
93
|
// merges in (PR base ... the merge base with the parent's default branch). A plain fork PR merges no new upstream commit, so its delta
|
|
66
94
|
// is empty. Any API failure keeps the full count.
|
|
@@ -107,9 +135,9 @@ export function lint(src, ev, dir, rules = {}, run = gh) {
|
|
|
107
135
|
task = basename(dirname(resolve(src)));
|
|
108
136
|
}
|
|
109
137
|
else {
|
|
110
|
-
const r = run('pr', 'view', src, '--json', 'author,body,title,
|
|
138
|
+
const r = run('pr', 'view', src, '--json', 'author,body,title,headRefOid,headRefName,baseRefOid');
|
|
111
139
|
if (r.status)
|
|
112
|
-
return log({ ok: false, why: `gh pr view failed: ${r
|
|
140
|
+
return log({ ok: false, why: `gh pr view failed: ${worst(r)}`, head });
|
|
113
141
|
const pr = JSON.parse(r.stdout);
|
|
114
142
|
({ body, title } = { body: pr.body ?? '', title: pr.title ?? '' });
|
|
115
143
|
head = pr.headRefOid ?? '-';
|
|
@@ -118,26 +146,31 @@ export function lint(src, ev, dir, rules = {}, run = gh) {
|
|
|
118
146
|
if (/^(app\/)?(dependabot|renovate)(\[bot\])?$/.test(author))
|
|
119
147
|
return log({ ok: true, why: 'bot', head });
|
|
120
148
|
const nwo = /^https:\/\/github\.com\/([^/]+\/[^/]+)\/pull\//.exec(src)?.[1];
|
|
121
|
-
const
|
|
149
|
+
const num = /^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/(\d+)/.exec(src)?.[1];
|
|
150
|
+
if (!nwo || !num)
|
|
151
|
+
return log({ ok: false, why: `not a GitHub pull URL: ${src.slice(0, 120)}`, head });
|
|
152
|
+
const listed = prFiles(run, nwo, num);
|
|
153
|
+
if (!listed.paths)
|
|
154
|
+
return log({ ok: false, why: listed.why ?? 'the pull file list failed', head });
|
|
155
|
+
const paths = listed.paths;
|
|
156
|
+
const attrs = [head, pr.baseRefOid].map((ref) => ref && run('api', '-H', 'Accept: application/vnd.github.raw', `repos/${nwo}/contents/.gitattributes?ref=${ref}`)).find((a) => a && a.status === 0);
|
|
122
157
|
if (attrs) {
|
|
123
158
|
const byAttr = attrGenerated(attrs.stdout);
|
|
124
159
|
isGenerated = (p) => byConfig(p) || byAttr(p);
|
|
125
160
|
}
|
|
126
|
-
const paths = (pr.files ?? []).map((f) => f.path ?? '');
|
|
127
161
|
if (paths.some((p) => p.startsWith('src/')) && !paths.some((p) => p.startsWith('journeys/')))
|
|
128
162
|
warn = 'the diff changes src/ and no journeys/ file: run the journey, commit it, then open the PR';
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
163
|
+
// The PR's whole net comes from the compare diff (three dots: from the merge base), never from the per-file additions.
|
|
164
|
+
const cmp = `repos/${nwo}/compare/${pr.baseRefOid ?? ''}...${head}`;
|
|
165
|
+
const d = run('api', '-H', 'Accept: application/vnd.github.diff', cmp);
|
|
166
|
+
if (d.status)
|
|
167
|
+
return log({ ok: false, why: `${cmp} failed: ${worst(d)}`, head });
|
|
168
|
+
let net = netLines(d.stdout, isGenerated);
|
|
169
|
+
if (rules.upstream_catch_up && total(net) >= SIZE_LIMIT)
|
|
170
|
+
net = without(net, upstreamDelta(run, nwo, head, pr.baseRefOid ?? '', isGenerated));
|
|
171
|
+
if (rules.moved_from && total(net) >= SIZE_LIMIT)
|
|
172
|
+
net = without(net, movedLines(run, nwo, body, paths, isGenerated));
|
|
173
|
+
const size = total(net);
|
|
141
174
|
if (size >= SIZE_LIMIT)
|
|
142
175
|
return log({ ok: false, why: `${size} added non-generated lines (moved lines excluded): split it (limit ${SIZE_LIMIT})`, head });
|
|
143
176
|
}
|
package/docs/reference.md
CHANGED
|
@@ -314,7 +314,7 @@ journeys:
|
|
|
314
314
|
|
|
315
315
|
### Lint check
|
|
316
316
|
|
|
317
|
-
`done-done lint <PR URL | report file> <evidence folder>` is a deterministic gate on a worker's claim: no judge, no model, and the project config only switches on two optional size rules. It prints `PASS`, `WARN: <reason>` or `FAIL: <reason>` and exits 0 (PASS or WARN), 1, or 2 on a usage error. A PR URL is read with `gh pr view`; a file is read as the report.
|
|
317
|
+
`done-done lint <PR URL | report file> <evidence folder>` is a deterministic gate on a worker's claim: no judge, no model, and the project config only switches on two optional size rules. It prints `PASS`, `WARN: <reason>` or `FAIL: <reason>` and exits 0 (PASS or WARN), 1, or 2 on a usage error. A PR URL is read with `gh pr view` and `gh api`; a file is read as the report.
|
|
318
318
|
|
|
319
319
|
- The newest `## Checks` block needs `outcome:`, `repro:`, `proof:` and `evidence:`.
|
|
320
320
|
- `proof:` names a command or path, and the repo's `done-done-verify-<app>` skill (a legacy `verify-<app>` skill is read too); it may say `no verify skill` only when `.agents/skills/` in the current folder holds none.
|
|
@@ -322,8 +322,8 @@ journeys:
|
|
|
322
322
|
- `evidence: not proven: <cause>` passes.
|
|
323
323
|
- A PR URL whose changed files include one under `src/` and none under `journeys/` prints `WARN` instead of `PASS` (exit 0; a `FAIL` still wins). It needs no config and never applies to a report file. The worker rule it backs: run the journey, commit it, then open the PR.
|
|
324
324
|
- Otherwise each named file (relative to the evidence folder, or absolute) exists, is non-empty and is newer than the evidence folder itself; no two are byte-identical; and at least one has a hash no other PR used. Hashes are kept in `lint.hashes` and each run is appended to `lint.log`, both in `~/.done-done` (`$DONE_DONE_HOME`). A later lint of the same PR is not reuse.
|
|
325
|
-
- A PR with 1,000 or more added non-generated lines fails. Lockfiles, `vendor/`, `dist/` and `LICENSE`-type files do not count, and neither do deletions or lines moved between files. A dependabot or renovate PR passes.
|
|
326
|
-
- Two optional size rules, both off by default and switched on per repo in `.done-done.yaml` (read from the current folder; they apply to a PR URL, never a report file). With both off a big PR is counted exactly as above. Each runs only when the PR is still at 1,000 lines
|
|
325
|
+
- A PR with 1,000 or more added non-generated lines fails. The whole PR is counted: its file list comes from every page of `pulls/<number>/files` (100 a page, up to GitHub's 3,000-file ceiling) and its net lines from the compare diff from the merge base, so a PR of any size is counted whole. Lockfiles, `vendor/`, `dist/` and `LICENSE`-type files do not count, and neither do deletions or lines moved between files. A dependabot or renovate PR passes. A page of the file list or the compare diff that fails makes lint `FAIL` with that call, never a partial count.
|
|
326
|
+
- Two optional size rules, both off by default and switched on per repo in `.done-done.yaml` (read from the current folder; they apply to a PR URL, never a report file). With both off a big PR is counted exactly as above. Each runs only when the PR is still at 1,000 lines.
|
|
327
327
|
- `checks.upstream_catch_up: true`: in a fork, lines the parent repo already shipped are not authored here, so lint subtracts the changes between the PR's base and the merge base with the parent's default branch. A PR that merges in no new upstream commit loses nothing.
|
|
328
328
|
- `checks.moved_from: true`: a line in the PR body `moved-from: <owner>/<repo>@<ref> <dst-prefix>=<src-prefix>` (more `dst=src` pairs may follow) cancels added lines that match, byte for byte after trimming, the file at the same path under `<src-prefix>` in that repo at `<ref>`. The source repo must have the PR's owner; authored lines still count.
|
|
329
329
|
- `checks.generated_paths: ["gen/**", "*.snap"]`: globs for the repo's own generated files, counted as generated beside the built-in ones above, so they stay out of the size count. Default none, so results do not change. Like the two rules above it applies to a PR URL, never a report file.
|
package/docs/releasing.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# 0.6.
|
|
1
|
+
# 0.6.16 patch release
|
|
2
2
|
|
|
3
|
-
This release
|
|
3
|
+
This release counts a PR whole, however many files it touches. `lint` reads every page of the PR's file list (GitHub gives `gh pr view` only the first 100 files) and takes its net lines from the compare diff, so a PR over 100 files no longer gets a line count from its first 100 — one 408-file PR was counted as 6,198 added lines when its real net was about 688. The moved-from exclusion, the generated-file rules and the `journeys/` warning now see the whole list, and a failed page or compare diff fails the lint with that call instead of keeping a partial count.
|
|
4
4
|
|
|
5
|
-
Do not publish an unmerged candidate. The existing `release` workflow on main tests and publishes an unpublished package version using npm trusted publishing. After merge, confirm `npm view done-done-axi@0.6.
|
|
5
|
+
Do not publish an unmerged candidate. The existing `release` workflow on main tests and publishes an unpublished package version using npm trusted publishing. After merge, confirm `npm view done-done-axi@0.6.16 version dist.integrity` and smoke-test a clean `npx` install with `done-done --version`. Do not run `npm publish` manually unless the workflow fails and the release is blocked; if so, stop and report.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "done-done-axi",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.16",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Prove your app really works: done-done drives your app the way a user does, a fresh judge checks every capture, and the proof is tied to a commit.",
|
|
6
6
|
"type": "module",
|