@navbook/cli 0.3.0 → 0.5.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/dist/args.d.ts +28 -0
- package/dist/args.js +48 -0
- package/dist/args.js.map +1 -0
- package/dist/commands/complete.d.ts +10 -0
- package/dist/commands/complete.js +59 -51
- package/dist/commands/complete.js.map +1 -1
- package/dist/commands/compose.d.ts +35 -0
- package/dist/commands/doctor.d.ts +15 -0
- package/dist/commands/entity.d.ts +73 -0
- package/dist/commands/entity.js +59 -44
- package/dist/commands/entity.js.map +1 -1
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/install.d.ts +17 -0
- package/dist/commands/install.js +6 -3
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/issue.d.ts +35 -0
- package/dist/commands/issue.js +4 -5
- package/dist/commands/issue.js.map +1 -1
- package/dist/commands/plugin.d.ts +36 -0
- package/dist/commands/plugin.js +386 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/policy.d.ts +58 -0
- package/dist/commands/policy.js +28 -2
- package/dist/commands/policy.js.map +1 -1
- package/dist/commands/pr-elsewhere.d.ts +40 -0
- package/dist/commands/pr-elsewhere.js +209 -0
- package/dist/commands/pr-elsewhere.js.map +1 -0
- package/dist/commands/pr.d.ts +69 -0
- package/dist/commands/pr.js +132 -68
- package/dist/commands/pr.js.map +1 -1
- package/dist/context.d.ts +42 -0
- package/dist/context.js +2 -0
- package/dist/context.js.map +1 -1
- package/dist/editor.d.ts +23 -0
- package/dist/editor.js +4 -0
- package/dist/editor.js.map +1 -1
- package/dist/errors.d.ts +17 -0
- package/dist/install/completions.d.ts +19 -0
- package/dist/install/hook.d.ts +32 -0
- package/dist/install/hook.js +48 -4
- package/dist/install/hook.js.map +1 -1
- package/dist/main.d.ts +21 -0
- package/dist/main.js +112 -8
- package/dist/main.js.map +1 -1
- package/dist/plugins/commands.d.ts +69 -0
- package/dist/plugins/commands.js +148 -0
- package/dist/plugins/commands.js.map +1 -0
- package/dist/plugins/hint.d.ts +23 -0
- package/dist/plugins/hint.js +65 -0
- package/dist/plugins/hint.js.map +1 -0
- package/dist/plugins/host.d.ts +125 -0
- package/dist/plugins/host.js +18 -0
- package/dist/plugins/host.js.map +1 -0
- package/dist/plugins/loader.d.ts +54 -0
- package/dist/plugins/loader.js +165 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/resolve.d.ts +50 -0
- package/dist/plugins/resolve.js +134 -0
- package/dist/plugins/resolve.js.map +1 -0
- package/dist/plugins/runtime.d.ts +69 -0
- package/dist/plugins/runtime.js +256 -0
- package/dist/plugins/runtime.js.map +1 -0
- package/dist/plugins/store.d.ts +96 -0
- package/dist/plugins/store.js +186 -0
- package/dist/plugins/store.js.map +1 -0
- package/dist/program.d.ts +49 -0
- package/dist/program.js +353 -114
- package/dist/program.js.map +1 -1
- package/dist/prompt.d.ts +31 -0
- package/dist/render/colors.d.ts +13 -0
- package/dist/render/detail.d.ts +22 -0
- package/dist/render/table.d.ts +32 -0
- package/dist/render/table.js +123 -13
- package/dist/render/table.js.map +1 -1
- package/dist/sort.d.ts +27 -0
- package/package.json +9 -2
- package/dist/commands/feature.js +0 -202
- package/dist/commands/feature.js.map +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saying what the review policy counts, and what it is short of.
|
|
3
|
+
*
|
|
4
|
+
* Shared by every verb that reads the policy, so a pull request short of two
|
|
5
|
+
* approvals is described in the same words wherever it is mentioned. Nothing
|
|
6
|
+
* here refuses anything: spec 02 §2.7 forbids acting on a review state, and
|
|
7
|
+
* §2.10 keeps a declared policy inside that. These are sentences, not gates.
|
|
8
|
+
*/
|
|
9
|
+
import { type MarkerVersionFault, type MergePolicyReading, type ReviewPolicyReading, type ReviewSummary } from "@navbook/core";
|
|
10
|
+
import type { Ctx } from "../context.ts";
|
|
11
|
+
/** Warn about a marker whose policy could not be read; D15 is the full report. */
|
|
12
|
+
export declare function warnPolicyProblems(ctx: Ctx, reading: ReviewPolicyReading): void;
|
|
13
|
+
/**
|
|
14
|
+
* The same, for the merge policy (spec 02 §2.10).
|
|
15
|
+
*
|
|
16
|
+
* Kept separate from the review policy's rather than folded into it, because a
|
|
17
|
+
* merge is the one command that reads both and a caller reading only one
|
|
18
|
+
* should not be made to hold the other.
|
|
19
|
+
*/
|
|
20
|
+
export declare function warnMergePolicyProblems(ctx: Ctx, reading: MergePolicyReading): void;
|
|
21
|
+
/**
|
|
22
|
+
* Say that the tree was written by a newer Navbook than this one (D16).
|
|
23
|
+
*
|
|
24
|
+
* Only the newer kind: a malformed `version` changes nothing a command does
|
|
25
|
+
* and is D15's to report, while a newer one means every answer that follows
|
|
26
|
+
* is this tool's guess at a format it has never seen — which is worth hearing
|
|
27
|
+
* before the answer rather than after a confusing one.
|
|
28
|
+
*/
|
|
29
|
+
export declare function warnNewerFormat(ctx: Ctx, fault: MarkerVersionFault | null): void;
|
|
30
|
+
/**
|
|
31
|
+
* What stands between a pull request and its policy, or null when nothing does.
|
|
32
|
+
*
|
|
33
|
+
* Only asked of a repository that declared a policy: a decision of `pending`
|
|
34
|
+
* where nobody asked for anything is not a shortfall, and saying so on every
|
|
35
|
+
* merge would be noise about a project that never opted in.
|
|
36
|
+
*/
|
|
37
|
+
export declare function describeShortfall(summary: ReviewSummary): string | null;
|
|
38
|
+
/** What a merge should do about a shortfall, before anything is written. */
|
|
39
|
+
export type MergeAction = "proceed" | "warn-and-proceed" | "ask";
|
|
40
|
+
export interface MergeSituation {
|
|
41
|
+
/** What the pull request is short of, or null when it is short of nothing. */
|
|
42
|
+
shortfall: string | null;
|
|
43
|
+
/** `--yes` was given. */
|
|
44
|
+
assumeYes: boolean;
|
|
45
|
+
/** There is somebody at a terminal to answer a question. */
|
|
46
|
+
interactive: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Decide how a merge should treat an unmet policy.
|
|
50
|
+
*
|
|
51
|
+
* Kept apart from the merge itself so every combination can be checked without
|
|
52
|
+
* a repository or a terminal, and so the one rule that matters is visible in
|
|
53
|
+
* one place: no combination returns a refusal. `--yes` proceeds, a terminal is
|
|
54
|
+
* asked, and everything else says its piece and proceeds — because a pipeline
|
|
55
|
+
* that stopped for a question nobody can answer would be the gate spec 02 §2.7
|
|
56
|
+
* forbids, arrived at by accident rather than on purpose.
|
|
57
|
+
*/
|
|
58
|
+
export declare function mergeAction(situation: MergeSituation): MergeAction;
|
package/dist/commands/policy.js
CHANGED
|
@@ -6,13 +6,39 @@
|
|
|
6
6
|
* here refuses anything: spec 02 §2.7 forbids acting on a review state, and
|
|
7
7
|
* §2.10 keeps a declared policy inside that. These are sentences, not gates.
|
|
8
8
|
*/
|
|
9
|
-
import { NAV_MARKER } from "@navbook/core";
|
|
9
|
+
import { NAV_MARKER, } from "@navbook/core";
|
|
10
10
|
/** Warn about a marker whose policy could not be read; D15 is the full report. */
|
|
11
11
|
export function warnPolicyProblems(ctx, reading) {
|
|
12
|
-
|
|
12
|
+
warnMarkerProblems(ctx, reading.problems);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The same, for the merge policy (spec 02 §2.10).
|
|
16
|
+
*
|
|
17
|
+
* Kept separate from the review policy's rather than folded into it, because a
|
|
18
|
+
* merge is the one command that reads both and a caller reading only one
|
|
19
|
+
* should not be made to hold the other.
|
|
20
|
+
*/
|
|
21
|
+
export function warnMergePolicyProblems(ctx, reading) {
|
|
22
|
+
warnMarkerProblems(ctx, reading.problems);
|
|
23
|
+
}
|
|
24
|
+
function warnMarkerProblems(ctx, problems) {
|
|
25
|
+
for (const problem of problems) {
|
|
13
26
|
ctx.stderr.write(`${ctx.colors.yellow("warning:")} ${ctx.navDir}/${NAV_MARKER}: ${problem}; using the default\n`);
|
|
14
27
|
}
|
|
15
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Say that the tree was written by a newer Navbook than this one (D16).
|
|
31
|
+
*
|
|
32
|
+
* Only the newer kind: a malformed `version` changes nothing a command does
|
|
33
|
+
* and is D15's to report, while a newer one means every answer that follows
|
|
34
|
+
* is this tool's guess at a format it has never seen — which is worth hearing
|
|
35
|
+
* before the answer rather than after a confusing one.
|
|
36
|
+
*/
|
|
37
|
+
export function warnNewerFormat(ctx, fault) {
|
|
38
|
+
if (fault?.kind !== "newer")
|
|
39
|
+
return;
|
|
40
|
+
ctx.stderr.write(`${ctx.colors.yellow("warning:")} ${ctx.navDir}/${NAV_MARKER}: ${fault.message}\n`);
|
|
41
|
+
}
|
|
16
42
|
/**
|
|
17
43
|
* What stands between a pull request and its policy, or null when nothing does.
|
|
18
44
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAGL,UAAU,GAGX,MAAM,eAAe,CAAC;AAGvB,kFAAkF;AAClF,MAAM,UAAU,kBAAkB,CAAC,GAAQ,EAAE,OAA4B;IACvE,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAQ,EAAE,OAA2B;IAC3E,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAQ,EAAE,QAA2B;IAC/D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,GAAG,CAAC,MAAM,CAAC,KAAK,CACd,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,UAAU,KAAK,OAAO,uBAAuB,CAChG,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,GAAQ,EAAE,KAAgC;IACxE,IAAI,KAAK,EAAE,IAAI,KAAK,OAAO;QAAE,OAAO;IACpC,GAAG,CAAC,MAAM,CAAC,KAAK,CACd,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,UAAU,KAAK,KAAK,CAAC,OAAO,IAAI,CACnF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAsB;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS;SAC/B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,iBAAiB,CAAC;SACpD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,wBAAwB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAE9E,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC;IAC9C,IAAI,KAAK,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,GAAG,KAAK,OAAO,QAAQ,qBAAqB,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AACjF,CAAC;AAcD;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,SAAyB;IACnD,IAAI,SAAS,CAAC,SAAS,KAAK,IAAI,IAAI,SAAS,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1E,OAAO,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writing to a pull request whose branch is not checked out here.
|
|
3
|
+
*
|
|
4
|
+
* A pull request's files live on its source branch (spec 03 §3.5), so the
|
|
5
|
+
* verbs that write into its directory refuse from any other checkout — core's
|
|
6
|
+
* `findPrToWrite` names the branch, and the worktree that has it. Everything
|
|
7
|
+
* needed to perform the write anyway is already known at that moment, so when
|
|
8
|
+
* somebody can be asked, this asks instead of only pointing:
|
|
9
|
+
*
|
|
10
|
+
* - When a clean worktree already has the branch, the write happens there.
|
|
11
|
+
* - When none has it, the branch is checked out into a temporary worktree,
|
|
12
|
+
* the write happens there, and the worktree goes away again once it holds
|
|
13
|
+
* nothing the user would lose.
|
|
14
|
+
*
|
|
15
|
+
* No directory changes either way. A child process cannot move its parent
|
|
16
|
+
* shell's working directory, and nothing is spawned in any case: a second
|
|
17
|
+
* `Ctx` rooted at the other worktree is enough, and the verb runs against it
|
|
18
|
+
* unchanged.
|
|
19
|
+
*/
|
|
20
|
+
import { type EntityRecord } from "@navbook/core";
|
|
21
|
+
import type { Ctx } from "../context.ts";
|
|
22
|
+
/**
|
|
23
|
+
* Help for `-y`, which answers the question in advance. The same letter
|
|
24
|
+
* answers `nav pr merge` and `nav install` in advance, and means the same
|
|
25
|
+
* thing here: this verb's one question, whichever of the two it would be.
|
|
26
|
+
*/
|
|
27
|
+
export declare const YES_HELP = "accept the offer to write in a worktree on the source branch \u2014 the clean one that has it, or a temporary one";
|
|
28
|
+
export interface PrWriteOptions {
|
|
29
|
+
/** `-y`: accept either offer in advance, and ask nobody. */
|
|
30
|
+
yes?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Run a pull-request write where it belongs, asking first when that is not here.
|
|
34
|
+
*
|
|
35
|
+
* `write` gets the context to write in and the pull request as that context
|
|
36
|
+
* sees it. When the write cannot or may not move, this is core's refusal
|
|
37
|
+
* naming where the pull request lives — declining the question included: the
|
|
38
|
+
* answer was "not there", not "do it here".
|
|
39
|
+
*/
|
|
40
|
+
export declare function withPrWriteSite<T>(ctx: Ctx, prefix: string, opts: PrWriteOptions, write: (at: Ctx, entity: EntityRecord) => T): T;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writing to a pull request whose branch is not checked out here.
|
|
3
|
+
*
|
|
4
|
+
* A pull request's files live on its source branch (spec 03 §3.5), so the
|
|
5
|
+
* verbs that write into its directory refuse from any other checkout — core's
|
|
6
|
+
* `findPrToWrite` names the branch, and the worktree that has it. Everything
|
|
7
|
+
* needed to perform the write anyway is already known at that moment, so when
|
|
8
|
+
* somebody can be asked, this asks instead of only pointing:
|
|
9
|
+
*
|
|
10
|
+
* - When a clean worktree already has the branch, the write happens there.
|
|
11
|
+
* - When none has it, the branch is checked out into a temporary worktree,
|
|
12
|
+
* the write happens there, and the worktree goes away again once it holds
|
|
13
|
+
* nothing the user would lose.
|
|
14
|
+
*
|
|
15
|
+
* No directory changes either way. A child process cannot move its parent
|
|
16
|
+
* shell's working directory, and nothing is spawned in any case: a second
|
|
17
|
+
* `Ctx` rooted at the other worktree is enough, and the verb runs against it
|
|
18
|
+
* unchanged.
|
|
19
|
+
*/
|
|
20
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
21
|
+
import { tmpdir } from "node:os";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { addWorktree, findPrToWrite, gitRun, isTreeClean, locatePrToWrite, refusePrWrite, removeWorktree, } from "@navbook/core";
|
|
24
|
+
import { makeContext } from "../context.js";
|
|
25
|
+
import { fail } from "../errors.js";
|
|
26
|
+
import { askYesNo, isInteractive } from "../prompt.js";
|
|
27
|
+
/**
|
|
28
|
+
* Help for `-y`, which answers the question in advance. The same letter
|
|
29
|
+
* answers `nav pr merge` and `nav install` in advance, and means the same
|
|
30
|
+
* thing here: this verb's one question, whichever of the two it would be.
|
|
31
|
+
*/
|
|
32
|
+
export const YES_HELP = "accept the offer to write in a worktree on the source branch — the clean one that has it, or a temporary one";
|
|
33
|
+
/**
|
|
34
|
+
* Where the write could go instead of here, or null when nowhere can take it.
|
|
35
|
+
*
|
|
36
|
+
* An existing worktree must be clean: without `--commit` a write leaves a
|
|
37
|
+
* staged change behind, and one mixed into somebody's work in progress where
|
|
38
|
+
* they are not looking is not a favour; with it, the commit would be refused
|
|
39
|
+
* over the unrelated staged paths anyway. A branch no worktree has can be
|
|
40
|
+
* checked out into a new one — but only a local branch: checking out a
|
|
41
|
+
* remote-tracking one would create a local branch as a side effect, which is
|
|
42
|
+
* more than a comment should do.
|
|
43
|
+
*/
|
|
44
|
+
function destination(where) {
|
|
45
|
+
if (where.sourceRemote)
|
|
46
|
+
return null;
|
|
47
|
+
if (where.worktree === null)
|
|
48
|
+
return { branch: where.branch, worktree: null };
|
|
49
|
+
return where.worktreeClean ? { branch: where.branch, worktree: where.worktree } : null;
|
|
50
|
+
}
|
|
51
|
+
/** Ask whether to write there, unless `-y` already said yes. */
|
|
52
|
+
function agreed(ctx, entity, to, opts) {
|
|
53
|
+
if (opts.yes)
|
|
54
|
+
return true;
|
|
55
|
+
// Only ever asked, never assumed. A run with nothing to answer the question
|
|
56
|
+
// keeps the refusal it has always had: a pipeline that started writing into
|
|
57
|
+
// a checkout nobody mentioned would be a worse surprise than exit 1.
|
|
58
|
+
if (!isInteractive(ctx))
|
|
59
|
+
return false;
|
|
60
|
+
if (to.worktree !== null) {
|
|
61
|
+
ctx.stdout.write(`#${entity.id} is on '${to.branch}', checked out in ${to.worktree} ${ctx.colors.dim("(clean)")}\n`);
|
|
62
|
+
return askYesNo(ctx, "Write it there? [y/N] ");
|
|
63
|
+
}
|
|
64
|
+
ctx.stdout.write(`#${entity.id} is on '${to.branch}', which no worktree has checked out\n`);
|
|
65
|
+
return askYesNo(ctx, "Check it out in a temporary worktree and write it there? [y/N] ");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A context rooted at `worktree`, reporting to the terminal we already have.
|
|
69
|
+
*
|
|
70
|
+
* The Navbook directory is the one already resolved here rather than found
|
|
71
|
+
* again: the pull request was located under it, and a second discovery from
|
|
72
|
+
* another root is one more chance to land somewhere it is not. The plugin
|
|
73
|
+
* extensions carry over for the same reason: the other checkout's tree is
|
|
74
|
+
* the same format, and read without them its registered keys would be raw.
|
|
75
|
+
*/
|
|
76
|
+
function contextIn(ctx, worktree) {
|
|
77
|
+
return makeContext({
|
|
78
|
+
cwd: worktree,
|
|
79
|
+
env: ctx.env,
|
|
80
|
+
stdout: ctx.stdout,
|
|
81
|
+
stderr: ctx.stderr,
|
|
82
|
+
navDir: ctx.navDir,
|
|
83
|
+
ext: ctx.ext,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Run `write` in `worktree`, refusing if that checkout does not hold the pull
|
|
88
|
+
* request after all — the branch moved since we looked, say. Without this the
|
|
89
|
+
* write would land beside no `pr.md`, the stranded comment the refusal exists
|
|
90
|
+
* to prevent.
|
|
91
|
+
*/
|
|
92
|
+
function writeIn(ctx, worktree, prefix, write) {
|
|
93
|
+
const there = contextIn(ctx, worktree);
|
|
94
|
+
return write(there, findPrToWrite(there, prefix));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* A new worktree on `branch` in a fresh temporary directory.
|
|
98
|
+
*
|
|
99
|
+
* `mkdtemp` rather than a fixed name, so two runs never collide and nothing a
|
|
100
|
+
* user made is ever in the way; under `os.tmpdir()`, so `TMPDIR` says where.
|
|
101
|
+
* The branch only flavours the name, so it is cut short: a directory name has
|
|
102
|
+
* a length limit and a branch name has none.
|
|
103
|
+
*/
|
|
104
|
+
function checkOutTemporarily(ctx, branch) {
|
|
105
|
+
const safe = branch.replace(/[^A-Za-z0-9._-]+/g, "-").slice(0, 40);
|
|
106
|
+
let dir = null;
|
|
107
|
+
try {
|
|
108
|
+
dir = mkdtempSync(join(tmpdir(), `nav-${safe}-`));
|
|
109
|
+
addWorktree(ctx.repoRoot, dir, branch);
|
|
110
|
+
return dir;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (dir !== null)
|
|
114
|
+
rmSync(dir, { recursive: true, force: true });
|
|
115
|
+
fail(`could not check '${branch}' out into a temporary worktree`, [
|
|
116
|
+
error instanceof Error ? error.message.trim() : String(error),
|
|
117
|
+
]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Take a temporary worktree away again, unless it holds what the user would lose.
|
|
122
|
+
*
|
|
123
|
+
* After `--commit` the write is on the branch and the worktree holds nothing.
|
|
124
|
+
* Without it — or when the commit itself failed, a hook refusing it, say — the
|
|
125
|
+
* write is staged there and nowhere else, so the worktree stays and says where
|
|
126
|
+
* it is: removing it would throw away a review somebody just wrote. A run that
|
|
127
|
+
* failed before writing anything leaves it clean, and it goes. Untracked files
|
|
128
|
+
* do not count: nothing but this run has been in there.
|
|
129
|
+
*/
|
|
130
|
+
function release(ctx, dir, branch, failed) {
|
|
131
|
+
if (isTreeClean(dir, { untracked: false })) {
|
|
132
|
+
try {
|
|
133
|
+
removeWorktree(ctx.repoRoot, dir, { force: true });
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Never mask the error that brought us here with one about tidying up.
|
|
137
|
+
// Deleting the directory alone would leave git recording the branch as
|
|
138
|
+
// checked out at a path that no longer exists, so prune that too.
|
|
139
|
+
rmSync(dir, { recursive: true, force: true });
|
|
140
|
+
gitRun(["worktree", "prune"], { cwd: ctx.repoRoot });
|
|
141
|
+
}
|
|
142
|
+
if (!failed) {
|
|
143
|
+
ctx.stderr.write(`${ctx.colors.dim(`written in a temporary worktree on '${branch}', since removed`)}\n`);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
ctx.stderr.write(`${ctx.colors.yellow("note:")} the change is staged in ${dir}, a temporary worktree on '${branch}'\n` +
|
|
148
|
+
`commit it there, then remove it: 'git worktree remove ${dir}'\n`);
|
|
149
|
+
}
|
|
150
|
+
/** Terminal signals, which reach the editor and git as well as us. */
|
|
151
|
+
const TERMINAL_SIGNALS = ["SIGINT", "SIGQUIT", "SIGHUP"];
|
|
152
|
+
/**
|
|
153
|
+
* Run `body` with terminal signals left to the children.
|
|
154
|
+
*
|
|
155
|
+
* Ctrl-C while `$EDITOR` is open goes to the whole foreground process group.
|
|
156
|
+
* By default it would kill us mid-`spawnSync`, before any `finally` runs, and
|
|
157
|
+
* leave the temporary worktree registered with the branch checked out. Git
|
|
158
|
+
* ignores these signals while its own editor runs, for the same reason; so
|
|
159
|
+
* does this. The editor still gets the signal, exits, and the command fails
|
|
160
|
+
* through its ordinary path — which is the one that tidies up.
|
|
161
|
+
*/
|
|
162
|
+
function sheltered(body) {
|
|
163
|
+
const ignore = () => { };
|
|
164
|
+
for (const signal of TERMINAL_SIGNALS)
|
|
165
|
+
process.on(signal, ignore);
|
|
166
|
+
try {
|
|
167
|
+
return body();
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
for (const signal of TERMINAL_SIGNALS)
|
|
171
|
+
process.off(signal, ignore);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Run a pull-request write where it belongs, asking first when that is not here.
|
|
176
|
+
*
|
|
177
|
+
* `write` gets the context to write in and the pull request as that context
|
|
178
|
+
* sees it. When the write cannot or may not move, this is core's refusal
|
|
179
|
+
* naming where the pull request lives — declining the question included: the
|
|
180
|
+
* answer was "not there", not "do it here".
|
|
181
|
+
*/
|
|
182
|
+
export function withPrWriteSite(ctx, prefix, opts, write) {
|
|
183
|
+
const { entity, elsewhere } = locatePrToWrite(ctx, prefix);
|
|
184
|
+
if (elsewhere === null)
|
|
185
|
+
return write(ctx, entity);
|
|
186
|
+
const to = destination(elsewhere);
|
|
187
|
+
// Built from what was just found, rather than scanning every ref again.
|
|
188
|
+
if (to === null || !agreed(ctx, entity, to, opts))
|
|
189
|
+
refusePrWrite(entity, elsewhere);
|
|
190
|
+
if (to.worktree !== null) {
|
|
191
|
+
const result = writeIn(ctx, to.worktree, prefix, write);
|
|
192
|
+
ctx.stderr.write(`${ctx.colors.dim(`written in ${to.worktree}`)}\n`);
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
const { branch } = to;
|
|
196
|
+
return sheltered(() => {
|
|
197
|
+
const dir = checkOutTemporarily(ctx, branch);
|
|
198
|
+
let failed = true;
|
|
199
|
+
try {
|
|
200
|
+
const result = writeIn(ctx, dir, prefix, write);
|
|
201
|
+
failed = false;
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
release(ctx, dir, branch, failed);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=pr-elsewhere.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-elsewhere.js","sourceRoot":"","sources":["../../src/commands/pr-elsewhere.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nav pr <verb>` — spec 04 §4.3.
|
|
3
|
+
*
|
|
4
|
+
* The eight shared verbs come from `entity.ts`; this module adds the four that
|
|
5
|
+
* only pull requests have (`update`, `request`, `review`, `merge`) and the
|
|
6
|
+
* parts of the shared verbs that must reach across branches, because a PR's
|
|
7
|
+
* files live on the branch it proposes to merge (spec 03 §3.5).
|
|
8
|
+
*/
|
|
9
|
+
import type { Ctx } from "../context.ts";
|
|
10
|
+
import { type CloseOptions, type GlobalFlags, type ListOptions } from "./entity.ts";
|
|
11
|
+
import { type PrWriteOptions } from "./pr-elsewhere.ts";
|
|
12
|
+
export interface PrOpenOptions extends GlobalFlags {
|
|
13
|
+
target?: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
message?: string;
|
|
16
|
+
draft?: boolean;
|
|
17
|
+
label?: string[];
|
|
18
|
+
assignee?: string[];
|
|
19
|
+
reviewer?: string[];
|
|
20
|
+
milestone?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Frontmatter a plugin contributed, from an option it declared (§2.12).
|
|
23
|
+
*
|
|
24
|
+
* Written by the same composer that writes the format's own keys, so a
|
|
25
|
+
* plugin's value lands in the file exactly as a built-in one would.
|
|
26
|
+
*/
|
|
27
|
+
ext?: Record<string, string | readonly string[]>;
|
|
28
|
+
}
|
|
29
|
+
export declare function cmdPrOpen(ctx: Ctx, opts: PrOpenOptions): void;
|
|
30
|
+
export interface PrUpdateOptions extends GlobalFlags, PrWriteOptions {
|
|
31
|
+
}
|
|
32
|
+
export declare function cmdPrUpdate(ctx: Ctx, prefix: string, opts: PrUpdateOptions): void;
|
|
33
|
+
export interface RequestOptions extends GlobalFlags, PrWriteOptions {
|
|
34
|
+
remove?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function cmdPrRequest(ctx: Ctx, prefix: string, people: string[], opts: RequestOptions): void;
|
|
37
|
+
export interface ReviewOptions extends GlobalFlags, PrWriteOptions {
|
|
38
|
+
approve?: boolean;
|
|
39
|
+
requestChanges?: boolean;
|
|
40
|
+
comment?: boolean;
|
|
41
|
+
message?: string;
|
|
42
|
+
revision?: string;
|
|
43
|
+
file?: string;
|
|
44
|
+
line?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare function cmdPrReview(ctx: Ctx, prefix: string, opts: ReviewOptions): void;
|
|
47
|
+
export interface PrListOptions extends ListOptions {
|
|
48
|
+
allRefs?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare function cmdPrList(ctx: Ctx, terms: string[], opts: PrListOptions): void;
|
|
51
|
+
export interface MergeOptions extends GlobalFlags {
|
|
52
|
+
/** `--method`: land by this method instead of the marker's (spec 02 §2.10). */
|
|
53
|
+
method?: string;
|
|
54
|
+
continue?: boolean;
|
|
55
|
+
/** Answer the review-policy question in advance. */
|
|
56
|
+
yes?: boolean;
|
|
57
|
+
/** `--no-sync-source`: leave the source branch where it is. */
|
|
58
|
+
syncSource?: boolean;
|
|
59
|
+
}
|
|
60
|
+
export declare function cmdPrMerge(ctx: Ctx, prefix: string | undefined, opts: MergeOptions): void;
|
|
61
|
+
/**
|
|
62
|
+
* Decline a pull request.
|
|
63
|
+
*
|
|
64
|
+
* Its files usually live on the source branch, so when the ID is not in the
|
|
65
|
+
* current tree the directory is first checked out from the ref that has it —
|
|
66
|
+
* which is exactly the manual recipe spec 02 §2.8 describes for keeping a
|
|
67
|
+
* durable record of a declined PR on the default branch.
|
|
68
|
+
*/
|
|
69
|
+
export declare function cmdPrClose(ctx: Ctx, prefix: string, opts: CloseOptions): void;
|