@osdlc/repo-cleaner 0.17.2 → 0.19.0
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 +31 -0
- package/README.md +691 -305
- package/dist/branches.d.ts +37 -36
- package/dist/branches.js +199 -196
- package/dist/clean.d.ts +179 -0
- package/dist/clean.js +824 -0
- package/dist/cli.d.ts +12 -16
- package/dist/cli.js +367 -478
- package/dist/hooks.d.ts +8 -12
- package/dist/hooks.js +2 -2
- package/dist/index.d.ts +18 -25
- package/dist/index.js +16 -23
- package/dist/landing.d.ts +3 -3
- package/dist/landing.js +7 -7
- package/dist/plan.d.ts +76 -70
- package/dist/plan.js +82 -77
- package/dist/providers/github.d.ts +2 -1
- package/dist/providers/github.js +2 -1
- package/dist/providers/gitlab.d.ts +3 -2
- package/dist/providers/gitlab.js +14 -8
- package/dist/providers/index.d.ts +5 -4
- package/dist/providers/index.js +8 -5
- package/dist/providers/types.d.ts +8 -2
- package/dist/prs.d.ts +35 -7
- package/dist/prs.js +45 -12
- package/dist/receipt.d.ts +46 -57
- package/dist/receipt.js +52 -28
- package/dist/reference.d.ts +12 -0
- package/dist/reference.js +152 -0
- package/dist/remote-mirror.d.ts +9 -1
- package/dist/remote-mirror.js +19 -1
- package/dist/render.d.ts +66 -61
- package/dist/render.js +206 -255
- package/dist/resolve.d.ts +3 -3
- package/dist/resolve.js +4 -12
- package/dist/status-line.d.ts +1 -1
- package/dist/status-line.js +5 -5
- package/dist/step-board.d.ts +1 -1
- package/dist/step-board.js +2 -5
- package/dist/submodules.d.ts +120 -0
- package/dist/submodules.js +292 -0
- package/dist/sweep.d.ts +107 -64
- package/dist/sweep.js +333 -119
- package/dist/types.d.ts +294 -105
- package/dist/types.js +106 -54
- package/dist/util.d.ts +13 -0
- package/dist/util.js +36 -0
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/worktrees.d.ts +21 -37
- package/dist/worktrees.js +198 -165
- package/package.json +5 -5
- package/dist/apply.d.ts +0 -131
- package/dist/apply.js +0 -541
|
@@ -25,8 +25,9 @@ interface MergeRequest {
|
|
|
25
25
|
/** One merge request as a {@link PRInfo}, or null for a fork's or an unknown state's. */
|
|
26
26
|
export declare function mergeRequestToPr(mr: MergeRequest): PRInfo | null;
|
|
27
27
|
/**
|
|
28
|
-
* A provider over `glab`. It needs `target.project
|
|
29
|
-
*
|
|
28
|
+
* A provider over `glab`. It needs `target.project`. A listing it cannot
|
|
29
|
+
* make or read throws with the reason: no project in the remote URL, `glab`'s
|
|
30
|
+
* own error, or a page that cannot be read.
|
|
30
31
|
*/
|
|
31
32
|
export declare function gitlabProvider(glab: CommandRunner): PrProvider;
|
|
32
33
|
export {};
|
package/dist/providers/gitlab.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* an explicit host and project, so a checkout with several remotes is read
|
|
7
7
|
* against the one the sweep measures.
|
|
8
8
|
*/
|
|
9
|
-
import { parseJsonResult, runFailed, } from '@osdlc/command-seam';
|
|
9
|
+
import { parseJsonResult, runFailed, stderrOrError, } from '@osdlc/command-seam';
|
|
10
10
|
import { PR_LIMIT } from "./github.js";
|
|
11
11
|
const PER_PAGE = 100;
|
|
12
12
|
/** GitLab's states, as the GitHub names classification reads. A locked MR is an open one mid-update. */
|
|
@@ -59,8 +59,9 @@ function succeeded(result) {
|
|
|
59
59
|
return !runFailed(result);
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
* A provider over `glab`. It needs `target.project
|
|
63
|
-
*
|
|
62
|
+
* A provider over `glab`. It needs `target.project`. A listing it cannot
|
|
63
|
+
* make or read throws with the reason: no project in the remote URL, `glab`'s
|
|
64
|
+
* own error, or a page that cannot be read.
|
|
64
65
|
*/
|
|
65
66
|
export function gitlabProvider(glab) {
|
|
66
67
|
const run = (root, argv) => glab.run(argv, { cwd: root });
|
|
@@ -75,7 +76,7 @@ export function gitlabProvider(glab) {
|
|
|
75
76
|
},
|
|
76
77
|
listPrs(root, target, branch) {
|
|
77
78
|
if (target.project === null)
|
|
78
|
-
|
|
79
|
+
throw new Error('the remote URL names no GitLab project');
|
|
79
80
|
const project = encodeURIComponent(target.project);
|
|
80
81
|
const prs = [];
|
|
81
82
|
for (let page = 1; (page - 1) * PER_PAGE < PR_LIMIT; page++) {
|
|
@@ -95,11 +96,16 @@ export function gitlabProvider(glab) {
|
|
|
95
96
|
]);
|
|
96
97
|
// A failed, cut-short or unreadable page fails the listing: a missing
|
|
97
98
|
// open MR would read as no MR.
|
|
98
|
-
if (!succeeded(result))
|
|
99
|
-
|
|
99
|
+
if (!succeeded(result)) {
|
|
100
|
+
// Not stdout: a page cut short is half a JSON listing, not a reason.
|
|
101
|
+
throw new Error(result.outputIncomplete === true
|
|
102
|
+
? `page ${page} was cut short`
|
|
103
|
+
: stderrOrError(result) || `glab exited ${String(result.exitCode)}`);
|
|
104
|
+
}
|
|
100
105
|
const listed = parseJsonResult(result);
|
|
101
|
-
if (!listed.ok || !Array.isArray(listed.value))
|
|
102
|
-
|
|
106
|
+
if (!listed.ok || !Array.isArray(listed.value)) {
|
|
107
|
+
throw new Error(`page ${page} is not a merge request list`);
|
|
108
|
+
}
|
|
103
109
|
const rows = listed.value;
|
|
104
110
|
for (const row of rows) {
|
|
105
111
|
if (!isMergeRequest(row))
|
|
@@ -20,10 +20,11 @@ export declare function providers(clients: {
|
|
|
20
20
|
*/
|
|
21
21
|
export declare function forgeTarget(url: string | null): ForgeTarget;
|
|
22
22
|
/**
|
|
23
|
-
* The provider `choice` names for `target`. `auto` reads the host:
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* The provider `choice` names for `target`. `auto` reads the host: none, for
|
|
24
|
+
* a remote that names no host (a local path or `file://`), which cannot have
|
|
25
|
+
* pull requests; one with `gitlab` in its name is GitLab; any other is
|
|
26
|
+
* GitHub, which is what the sweep did before providers existed (`gh` answers
|
|
27
|
+
* nothing for a host it does not know). `none` is no provider.
|
|
27
28
|
*/
|
|
28
29
|
export declare function chooseProvider(choice: ProviderChoice, target: ForgeTarget): ProviderName | null;
|
|
29
30
|
/** The chosen provider for a repository, probed; null for none. */
|
package/dist/providers/index.js
CHANGED
|
@@ -41,17 +41,20 @@ export function forgeTarget(url) {
|
|
|
41
41
|
return { host: match[1].toLowerCase(), project: parts.join('/') };
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
* The provider `choice` names for `target`. `auto` reads the host:
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
44
|
+
* The provider `choice` names for `target`. `auto` reads the host: none, for
|
|
45
|
+
* a remote that names no host (a local path or `file://`), which cannot have
|
|
46
|
+
* pull requests; one with `gitlab` in its name is GitLab; any other is
|
|
47
|
+
* GitHub, which is what the sweep did before providers existed (`gh` answers
|
|
48
|
+
* nothing for a host it does not know). `none` is no provider.
|
|
48
49
|
*/
|
|
49
50
|
export function chooseProvider(choice, target) {
|
|
50
51
|
if (choice === 'none')
|
|
51
52
|
return null;
|
|
52
53
|
if (choice !== 'auto')
|
|
53
54
|
return choice;
|
|
54
|
-
|
|
55
|
+
if (target.host === null)
|
|
56
|
+
return null;
|
|
57
|
+
return target.host.includes('gitlab') ? 'gitlab' : 'github';
|
|
55
58
|
}
|
|
56
59
|
/** The chosen provider for a repository, probed; null for none. */
|
|
57
60
|
export function probeProvider(choice, root, target, all) {
|
|
@@ -34,6 +34,11 @@ export interface ProviderStatus extends ForgeTarget, ProviderWords {
|
|
|
34
34
|
available: boolean;
|
|
35
35
|
/** The CLI has credentials for `host`. */
|
|
36
36
|
authenticated: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Set by the sweep when the provider was asked and its listing failed: why,
|
|
39
|
+
* in the provider's words. Absent when it answered or was not asked.
|
|
40
|
+
*/
|
|
41
|
+
listError?: string | undefined;
|
|
37
42
|
}
|
|
38
43
|
/** One source of pull request evidence. */
|
|
39
44
|
export interface PrProvider {
|
|
@@ -46,8 +51,9 @@ export interface PrProvider {
|
|
|
46
51
|
};
|
|
47
52
|
/**
|
|
48
53
|
* The repository's pull requests, fork PRs already dropped, in any order;
|
|
49
|
-
* null
|
|
50
|
-
* classifies on git evidence alone
|
|
54
|
+
* null, or a throw whose message says why, when the listing failed. A
|
|
55
|
+
* failure is not "no PRs": the caller classifies on git evidence alone and
|
|
56
|
+
* notes the failure on the repository.
|
|
51
57
|
*
|
|
52
58
|
* @param branch Narrow the listing to this exact head branch. The caller
|
|
53
59
|
* checks the head again, so a provider that cannot narrow may list all.
|
package/dist/prs.d.ts
CHANGED
|
@@ -7,24 +7,52 @@
|
|
|
7
7
|
* `providers/`.
|
|
8
8
|
*/
|
|
9
9
|
import type { PrProvider } from './providers/index.ts';
|
|
10
|
+
import type { ProviderStatus } from './providers/types.ts';
|
|
10
11
|
import type { PRInfo, RepoInfo } from './types.ts';
|
|
12
|
+
/** Why the provider did not answer, and the words for it. */
|
|
13
|
+
export interface PrsUnchecked {
|
|
14
|
+
kind: 'not-installed' | 'not-signed-in' | 'list-failed';
|
|
15
|
+
/** For a sentence: "`gh` is not installed", "`gh pr list` failed". */
|
|
16
|
+
why: string;
|
|
17
|
+
}
|
|
11
18
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
19
|
+
* Why open pull requests cannot be ruled out for this repository, or null
|
|
20
|
+
* when the provider answered. A missing or signed-out CLI was never asked, and
|
|
21
|
+
* a failed listing answered nothing; either way a remote branch with no known
|
|
22
|
+
* PR may still have an open one. Every sentence about a lookup that did not
|
|
23
|
+
* answer is built from this one answer.
|
|
24
|
+
*/
|
|
25
|
+
export declare function prsUnchecked(status: ProviderStatus): PrsUnchecked | null;
|
|
26
|
+
/** A provider's answer for one repository: its pull requests, or why there are none to read. */
|
|
27
|
+
export interface PrLookup {
|
|
28
|
+
/** Pull requests keyed by head branch; empty when the lookup failed or was not made. */
|
|
29
|
+
prs: Map<string, PRInfo>;
|
|
30
|
+
/**
|
|
31
|
+
* Why the listing failed, in the provider's own words where it gave any;
|
|
32
|
+
* null when it answered, or when it was not asked at all.
|
|
33
|
+
*/
|
|
34
|
+
error: string | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Every same-repository pull request, keyed by head branch, and why there are
|
|
38
|
+
* none when the listing failed. Fork PRs are dropped by the provider: a fork
|
|
39
|
+
* branch that shares a name proves nothing about ours.
|
|
15
40
|
*
|
|
16
41
|
* A branch can carry several PRs over its life. The one that decides a
|
|
17
42
|
* verdict is the most live: an open PR means keep whatever else happened, and
|
|
18
43
|
* a merged one means the work landed. Ties go to the higher number, so two
|
|
19
44
|
* runs over unchanged state agree.
|
|
20
45
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
46
|
+
* The map is empty when the provider's CLI is missing or unauthenticated, when
|
|
47
|
+
* there is no provider, and when the listing fails. A provider that answers
|
|
48
|
+
* null or throws has failed (a repository the signed-in account cannot see, a
|
|
49
|
+
* forge that is down, output that cannot be read), and `error` says why.
|
|
50
|
+
* Classification then degrades to git evidence, and the sweep notes it rather
|
|
51
|
+
* than losing every row to one listing.
|
|
24
52
|
*
|
|
25
53
|
* @param provider The provider to ask. It is asked only when it is the one
|
|
26
54
|
* `repo.provider` names and that probe found it signed in.
|
|
27
55
|
* @param branch Ask only for PRs whose head is exactly this branch; rows
|
|
28
56
|
* for any other head are dropped here too.
|
|
29
57
|
*/
|
|
30
|
-
export declare function
|
|
58
|
+
export declare function lookupPrs(repo: RepoInfo, provider: PrProvider, branch?: string): PrLookup;
|
package/dist/prs.js
CHANGED
|
@@ -6,37 +6,70 @@
|
|
|
6
6
|
* one listing covers. Which forge answers is the provider's business; see
|
|
7
7
|
* `providers/`.
|
|
8
8
|
*/
|
|
9
|
+
import { errorText } from "./util.js";
|
|
10
|
+
/**
|
|
11
|
+
* Why open pull requests cannot be ruled out for this repository, or null
|
|
12
|
+
* when the provider answered. A missing or signed-out CLI was never asked, and
|
|
13
|
+
* a failed listing answered nothing; either way a remote branch with no known
|
|
14
|
+
* PR may still have an open one. Every sentence about a lookup that did not
|
|
15
|
+
* answer is built from this one answer.
|
|
16
|
+
*/
|
|
17
|
+
export function prsUnchecked(status) {
|
|
18
|
+
if (!status.available)
|
|
19
|
+
return { kind: 'not-installed', why: `\`${status.tool}\` is not installed` };
|
|
20
|
+
if (!status.authenticated) {
|
|
21
|
+
return { kind: 'not-signed-in', why: `\`${status.tool}\` is not signed in` };
|
|
22
|
+
}
|
|
23
|
+
if (status.listError !== undefined) {
|
|
24
|
+
return { kind: 'list-failed', why: `\`${status.listing}\` failed` };
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
9
28
|
/** Open outranks merged outranks closed, and a newer PR outranks an older. */
|
|
10
29
|
function priority(state) {
|
|
11
30
|
return { OPEN: 3, MERGED: 2, CLOSED: 1 }[state] ?? 0;
|
|
12
31
|
}
|
|
13
32
|
/**
|
|
14
|
-
* Every same-repository pull request, keyed by head branch
|
|
15
|
-
*
|
|
16
|
-
* about ours.
|
|
33
|
+
* Every same-repository pull request, keyed by head branch, and why there are
|
|
34
|
+
* none when the listing failed. Fork PRs are dropped by the provider: a fork
|
|
35
|
+
* branch that shares a name proves nothing about ours.
|
|
17
36
|
*
|
|
18
37
|
* A branch can carry several PRs over its life. The one that decides a
|
|
19
38
|
* verdict is the most live: an open PR means keep whatever else happened, and
|
|
20
39
|
* a merged one means the work landed. Ties go to the higher number, so two
|
|
21
40
|
* runs over unchanged state agree.
|
|
22
41
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
42
|
+
* The map is empty when the provider's CLI is missing or unauthenticated, when
|
|
43
|
+
* there is no provider, and when the listing fails. A provider that answers
|
|
44
|
+
* null or throws has failed (a repository the signed-in account cannot see, a
|
|
45
|
+
* forge that is down, output that cannot be read), and `error` says why.
|
|
46
|
+
* Classification then degrades to git evidence, and the sweep notes it rather
|
|
47
|
+
* than losing every row to one listing.
|
|
26
48
|
*
|
|
27
49
|
* @param provider The provider to ask. It is asked only when it is the one
|
|
28
50
|
* `repo.provider` names and that probe found it signed in.
|
|
29
51
|
* @param branch Ask only for PRs whose head is exactly this branch; rows
|
|
30
52
|
* for any other head are dropped here too.
|
|
31
53
|
*/
|
|
32
|
-
export function
|
|
54
|
+
export function lookupPrs(repo, provider, branch) {
|
|
33
55
|
const byHead = new Map();
|
|
34
56
|
const status = repo.provider;
|
|
35
|
-
if (status === null || status.name !== provider.name || !status.authenticated)
|
|
36
|
-
return byHead;
|
|
37
|
-
|
|
57
|
+
if (status === null || status.name !== provider.name || !status.authenticated) {
|
|
58
|
+
return { prs: byHead, error: null };
|
|
59
|
+
}
|
|
60
|
+
let rows;
|
|
61
|
+
try {
|
|
62
|
+
rows = provider.listPrs(repo.root, status, branch);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
// A bug in the provider is not a listing that failed: let it fail loudly,
|
|
66
|
+
// as an error on the repository, rather than gate every remote branch.
|
|
67
|
+
if (err instanceof TypeError || err instanceof ReferenceError)
|
|
68
|
+
throw err;
|
|
69
|
+
return { prs: byHead, error: errorText(err) };
|
|
70
|
+
}
|
|
38
71
|
if (rows === null)
|
|
39
|
-
return byHead;
|
|
72
|
+
return { prs: byHead, error: 'the provider gave no reason' };
|
|
40
73
|
for (const info of rows) {
|
|
41
74
|
const head = info.headRef;
|
|
42
75
|
if (!head)
|
|
@@ -54,5 +87,5 @@ export function fetchPrs(repo, provider, branch) {
|
|
|
54
87
|
byHead.set(head, info);
|
|
55
88
|
}
|
|
56
89
|
}
|
|
57
|
-
return byHead;
|
|
90
|
+
return { prs: byHead, error: null };
|
|
58
91
|
}
|
package/dist/receipt.d.ts
CHANGED
|
@@ -1,56 +1,53 @@
|
|
|
1
|
-
/** What
|
|
1
|
+
/** What a run did, step by step, rewritten after every step. */
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
/** The receipt format's version, written into every receipt. */
|
|
4
|
-
export declare const RECEIPT_VERSION =
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
export declare const RECEIPT_VERSION = 2;
|
|
5
|
+
/**
|
|
6
|
+
* Why a row did not run:
|
|
7
|
+
*
|
|
8
|
+
* `gone` no longer in the sweep
|
|
9
|
+
* `blocked` the sweep now finds a blocker
|
|
10
|
+
* `keep` the sweep keeps it for structure; it has no action
|
|
11
|
+
* `held` a branch whose worktree this run does not remove
|
|
12
|
+
* `needs-pick` not judged `delete`; it runs only when picked
|
|
13
|
+
* `changed` its evidence moved since the plan
|
|
14
|
+
* `not-allowed` it carries a risk that was not allowed
|
|
15
|
+
* `duplicate` another checkout of the same remote deletes the same branch
|
|
16
|
+
* `spared` the same remote branch is spared through another checkout
|
|
17
|
+
*/
|
|
18
|
+
export declare const DROP_REASONS: readonly ["gone", "blocked", "keep", "held", "needs-pick", "changed", "not-allowed", "duplicate", "spared"];
|
|
19
|
+
export type DropReason = (typeof DROP_REASONS)[number];
|
|
14
20
|
export declare const DroppedSchema: z.ZodObject<{
|
|
15
|
-
category: z.ZodEnum<{
|
|
16
|
-
local_branch: "local_branch";
|
|
17
|
-
worktree: "worktree";
|
|
18
|
-
remote_branch: "remote_branch";
|
|
19
|
-
}>;
|
|
20
|
-
id: z.ZodString;
|
|
21
21
|
repo: z.ZodString;
|
|
22
|
+
row: z.ZodCustom<`worktree:${string}` | `branch:${string}` | `remote:${string}`, `worktree:${string}` | `branch:${string}` | `remote:${string}`>;
|
|
22
23
|
reason: z.ZodEnum<{
|
|
24
|
+
keep: "keep";
|
|
25
|
+
blocked: "blocked";
|
|
23
26
|
gone: "gone";
|
|
24
|
-
|
|
25
|
-
"needs-
|
|
26
|
-
|
|
27
|
-
"not-
|
|
27
|
+
held: "held";
|
|
28
|
+
"needs-pick": "needs-pick";
|
|
29
|
+
changed: "changed";
|
|
30
|
+
"not-allowed": "not-allowed";
|
|
28
31
|
duplicate: "duplicate";
|
|
29
|
-
|
|
32
|
+
spared: "spared";
|
|
30
33
|
}>;
|
|
31
34
|
detail: z.ZodString;
|
|
32
35
|
}, z.core.$strip>;
|
|
33
36
|
export type Dropped = z.infer<typeof DroppedSchema>;
|
|
37
|
+
export declare const STEP_ACTIONS: readonly ["verify-remote", "unlock-worktree", "remove-worktree", "delete-branch", "delete-remote", "prune-worktrees"];
|
|
34
38
|
export declare const StepSchema: z.ZodObject<{
|
|
35
39
|
repo: z.ZodString;
|
|
36
|
-
row: z.
|
|
37
|
-
category: z.ZodEnum<{
|
|
38
|
-
local_branch: "local_branch";
|
|
39
|
-
worktree: "worktree";
|
|
40
|
-
remote_branch: "remote_branch";
|
|
41
|
-
}>;
|
|
42
|
-
id: z.ZodString;
|
|
43
|
-
}, z.core.$strip>>;
|
|
40
|
+
row: z.ZodCustom<`worktree:${string}` | `branch:${string}` | `remote:${string}`, `worktree:${string}` | `branch:${string}` | `remote:${string}`>;
|
|
44
41
|
action: z.ZodEnum<{
|
|
45
42
|
"verify-remote": "verify-remote";
|
|
46
43
|
"unlock-worktree": "unlock-worktree";
|
|
47
44
|
"remove-worktree": "remove-worktree";
|
|
48
|
-
"delete-
|
|
45
|
+
"delete-branch": "delete-branch";
|
|
49
46
|
"delete-remote": "delete-remote";
|
|
50
47
|
"prune-worktrees": "prune-worktrees";
|
|
51
48
|
}>;
|
|
52
49
|
command: z.ZodString;
|
|
53
|
-
|
|
50
|
+
expectedSha: z.ZodNullable<z.ZodString>;
|
|
54
51
|
result: z.ZodEnum<{
|
|
55
52
|
pending: "pending";
|
|
56
53
|
"would-run": "would-run";
|
|
@@ -59,58 +56,49 @@ export declare const StepSchema: z.ZodObject<{
|
|
|
59
56
|
}>;
|
|
60
57
|
error: z.ZodNullable<z.ZodString>;
|
|
61
58
|
verification: z.ZodNullable<z.ZodString>;
|
|
59
|
+
gone: z.ZodOptional<z.ZodLiteral<true>>;
|
|
62
60
|
}, z.core.$strip>;
|
|
63
61
|
export type Step = z.infer<typeof StepSchema>;
|
|
64
62
|
export declare const ReceiptSchema: z.ZodObject<{
|
|
65
|
-
version: z.ZodLiteral<
|
|
63
|
+
version: z.ZodLiteral<2>;
|
|
66
64
|
plan: z.ZodString;
|
|
67
65
|
status: z.ZodEnum<{
|
|
68
66
|
failed: "failed";
|
|
69
67
|
"dry-run": "dry-run";
|
|
70
|
-
|
|
68
|
+
running: "running";
|
|
71
69
|
complete: "complete";
|
|
72
70
|
}>;
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
startedAt: z.ZodString;
|
|
72
|
+
finishedAt: z.ZodNullable<z.ZodString>;
|
|
75
73
|
dropped: z.ZodArray<z.ZodObject<{
|
|
76
|
-
category: z.ZodEnum<{
|
|
77
|
-
local_branch: "local_branch";
|
|
78
|
-
worktree: "worktree";
|
|
79
|
-
remote_branch: "remote_branch";
|
|
80
|
-
}>;
|
|
81
|
-
id: z.ZodString;
|
|
82
74
|
repo: z.ZodString;
|
|
75
|
+
row: z.ZodCustom<`worktree:${string}` | `branch:${string}` | `remote:${string}`, `worktree:${string}` | `branch:${string}` | `remote:${string}`>;
|
|
83
76
|
reason: z.ZodEnum<{
|
|
77
|
+
keep: "keep";
|
|
78
|
+
blocked: "blocked";
|
|
84
79
|
gone: "gone";
|
|
85
|
-
|
|
86
|
-
"needs-
|
|
87
|
-
|
|
88
|
-
"not-
|
|
80
|
+
held: "held";
|
|
81
|
+
"needs-pick": "needs-pick";
|
|
82
|
+
changed: "changed";
|
|
83
|
+
"not-allowed": "not-allowed";
|
|
89
84
|
duplicate: "duplicate";
|
|
90
|
-
|
|
85
|
+
spared: "spared";
|
|
91
86
|
}>;
|
|
92
87
|
detail: z.ZodString;
|
|
93
88
|
}, z.core.$strip>>;
|
|
94
89
|
steps: z.ZodArray<z.ZodObject<{
|
|
95
90
|
repo: z.ZodString;
|
|
96
|
-
row: z.
|
|
97
|
-
category: z.ZodEnum<{
|
|
98
|
-
local_branch: "local_branch";
|
|
99
|
-
worktree: "worktree";
|
|
100
|
-
remote_branch: "remote_branch";
|
|
101
|
-
}>;
|
|
102
|
-
id: z.ZodString;
|
|
103
|
-
}, z.core.$strip>>;
|
|
91
|
+
row: z.ZodCustom<`worktree:${string}` | `branch:${string}` | `remote:${string}`, `worktree:${string}` | `branch:${string}` | `remote:${string}`>;
|
|
104
92
|
action: z.ZodEnum<{
|
|
105
93
|
"verify-remote": "verify-remote";
|
|
106
94
|
"unlock-worktree": "unlock-worktree";
|
|
107
95
|
"remove-worktree": "remove-worktree";
|
|
108
|
-
"delete-
|
|
96
|
+
"delete-branch": "delete-branch";
|
|
109
97
|
"delete-remote": "delete-remote";
|
|
110
98
|
"prune-worktrees": "prune-worktrees";
|
|
111
99
|
}>;
|
|
112
100
|
command: z.ZodString;
|
|
113
|
-
|
|
101
|
+
expectedSha: z.ZodNullable<z.ZodString>;
|
|
114
102
|
result: z.ZodEnum<{
|
|
115
103
|
pending: "pending";
|
|
116
104
|
"would-run": "would-run";
|
|
@@ -119,6 +107,7 @@ export declare const ReceiptSchema: z.ZodObject<{
|
|
|
119
107
|
}>;
|
|
120
108
|
error: z.ZodNullable<z.ZodString>;
|
|
121
109
|
verification: z.ZodNullable<z.ZodString>;
|
|
110
|
+
gone: z.ZodOptional<z.ZodLiteral<true>>;
|
|
122
111
|
}, z.core.$strip>>;
|
|
123
112
|
}, z.core.$strip>;
|
|
124
113
|
export type Receipt = z.infer<typeof ReceiptSchema>;
|
package/dist/receipt.js
CHANGED
|
@@ -1,46 +1,70 @@
|
|
|
1
|
-
/** What
|
|
1
|
+
/** What a run did, step by step, rewritten after every step. */
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import { RowIdSchema } from "./plan.js";
|
|
4
4
|
/** The receipt format's version, written into every receipt. */
|
|
5
|
-
export const RECEIPT_VERSION =
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export const RECEIPT_VERSION = 2;
|
|
6
|
+
/**
|
|
7
|
+
* Why a row did not run:
|
|
8
|
+
*
|
|
9
|
+
* `gone` no longer in the sweep
|
|
10
|
+
* `blocked` the sweep now finds a blocker
|
|
11
|
+
* `keep` the sweep keeps it for structure; it has no action
|
|
12
|
+
* `held` a branch whose worktree this run does not remove
|
|
13
|
+
* `needs-pick` not judged `delete`; it runs only when picked
|
|
14
|
+
* `changed` its evidence moved since the plan
|
|
15
|
+
* `not-allowed` it carries a risk that was not allowed
|
|
16
|
+
* `duplicate` another checkout of the same remote deletes the same branch
|
|
17
|
+
* `spared` the same remote branch is spared through another checkout
|
|
18
|
+
*/
|
|
19
|
+
export const DROP_REASONS = [
|
|
20
|
+
'gone',
|
|
21
|
+
'blocked',
|
|
22
|
+
'keep',
|
|
23
|
+
'held',
|
|
24
|
+
'needs-pick',
|
|
25
|
+
'changed',
|
|
26
|
+
'not-allowed',
|
|
27
|
+
'duplicate',
|
|
28
|
+
'spared',
|
|
29
|
+
];
|
|
30
|
+
export const DroppedSchema = z.object({
|
|
8
31
|
repo: z.string(),
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'not-deletable',
|
|
12
|
-
'needs-review',
|
|
13
|
-
'facts-changed',
|
|
14
|
-
'not-authorized',
|
|
15
|
-
'duplicate',
|
|
16
|
-
'kept',
|
|
17
|
-
]),
|
|
32
|
+
row: RowIdSchema,
|
|
33
|
+
reason: z.enum(DROP_REASONS),
|
|
18
34
|
detail: z.string(),
|
|
19
35
|
});
|
|
36
|
+
export const STEP_ACTIONS = [
|
|
37
|
+
'verify-remote',
|
|
38
|
+
'unlock-worktree',
|
|
39
|
+
'remove-worktree',
|
|
40
|
+
'delete-branch',
|
|
41
|
+
'delete-remote',
|
|
42
|
+
'prune-worktrees',
|
|
43
|
+
];
|
|
20
44
|
export const StepSchema = z.object({
|
|
21
45
|
repo: z.string(),
|
|
22
|
-
/**
|
|
23
|
-
row:
|
|
24
|
-
action: z.enum(
|
|
25
|
-
'verify-remote',
|
|
26
|
-
'unlock-worktree',
|
|
27
|
-
'remove-worktree',
|
|
28
|
-
'delete-local',
|
|
29
|
-
'delete-remote',
|
|
30
|
-
'prune-worktrees',
|
|
31
|
-
]),
|
|
46
|
+
/** The row the step acts on. */
|
|
47
|
+
row: RowIdSchema,
|
|
48
|
+
action: z.enum(STEP_ACTIONS),
|
|
32
49
|
command: z.string(),
|
|
33
|
-
|
|
50
|
+
expectedSha: z.string().nullable(),
|
|
34
51
|
result: z.enum(['pending', 'would-run', 'ok', 'failed']),
|
|
35
52
|
error: z.string().nullable(),
|
|
36
53
|
verification: z.string().nullable(),
|
|
54
|
+
/**
|
|
55
|
+
* The remote no longer listed the branch when the step ran: someone deleted
|
|
56
|
+
* it after the run's re-check. A `delete-remote` step so marked deleted
|
|
57
|
+
* nothing, and the run summary counts it apart. Absent otherwise.
|
|
58
|
+
*/
|
|
59
|
+
gone: z.literal(true).optional(),
|
|
37
60
|
});
|
|
38
61
|
export const ReceiptSchema = z.object({
|
|
39
62
|
version: z.literal(RECEIPT_VERSION),
|
|
63
|
+
/** Where the plan came from: a path, `(stdin)`, or `(swept)`. */
|
|
40
64
|
plan: z.string(),
|
|
41
|
-
status: z.enum(['dry-run', '
|
|
42
|
-
|
|
43
|
-
|
|
65
|
+
status: z.enum(['dry-run', 'running', 'complete', 'failed']),
|
|
66
|
+
startedAt: z.string(),
|
|
67
|
+
finishedAt: z.string().nullable(),
|
|
44
68
|
dropped: z.array(DroppedSchema),
|
|
45
69
|
steps: z.array(StepSchema),
|
|
46
70
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The full reference `--help --extended` prints: what every option means,
|
|
3
|
+
* the words the report uses, and which combinations are refused. The README
|
|
4
|
+
* says the same in its own layout; keep the two in step.
|
|
5
|
+
*/
|
|
6
|
+
/** The extended help for each command: its own options, then the shared vocabulary. */
|
|
7
|
+
export declare const REFERENCE: {
|
|
8
|
+
readonly report: string;
|
|
9
|
+
readonly plan: string;
|
|
10
|
+
readonly clean: string;
|
|
11
|
+
readonly cache: "repo-cleaner cache [list | remove <url>... | remove --all]\n Lists or removes the clones kept for remote URL targets. A removed clone is\n cloned again by the next sweep of its URL; a plan that names it cannot run.";
|
|
12
|
+
};
|