@renaiss-shipflow/cli 0.2.2 → 0.6.1
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/client.d.ts +41 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +57 -8
- package/dist/client.js.map +1 -1
- package/dist/commands/claims.js +2 -2
- package/dist/commands/claims.js.map +1 -1
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +86 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/features.d.ts +3 -0
- package/dist/commands/features.d.ts.map +1 -0
- package/dist/commands/features.js +50 -0
- package/dist/commands/features.js.map +1 -0
- package/dist/commands/inbox.d.ts +4 -0
- package/dist/commands/inbox.d.ts.map +1 -0
- package/dist/commands/inbox.js +72 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/init.js +2 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/issue.d.ts.map +1 -1
- package/dist/commands/issue.js +58 -7
- package/dist/commands/issue.js.map +1 -1
- package/dist/commands/issues.js +2 -2
- package/dist/commands/issues.js.map +1 -1
- package/dist/commands/pr.d.ts +4 -0
- package/dist/commands/pr.d.ts.map +1 -1
- package/dist/commands/pr.js +236 -12
- package/dist/commands/pr.js.map +1 -1
- package/dist/commands/regression.js +2 -2
- package/dist/commands/regression.js.map +1 -1
- package/dist/commands/release.js +2 -2
- package/dist/commands/release.js.map +1 -1
- package/dist/commands/status.js +2 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/config.d.ts +49 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +99 -0
- package/dist/config.js.map +1 -1
- package/dist/gh.d.ts +70 -1
- package/dist/gh.d.ts.map +1 -1
- package/dist/gh.js +88 -4
- package/dist/gh.js.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/issue-order.d.ts +8 -0
- package/dist/issue-order.d.ts.map +1 -0
- package/dist/issue-order.js +33 -0
- package/dist/issue-order.js.map +1 -0
- package/dist/pr-state.d.ts +57 -0
- package/dist/pr-state.d.ts.map +1 -0
- package/dist/pr-state.js +140 -0
- package/dist/pr-state.js.map +1 -0
- package/package.json +1 -1
- package/dist/__tests__/gh.test.d.ts +0 -2
- package/dist/__tests__/gh.test.d.ts.map +0 -1
- package/dist/__tests__/gh.test.js +0 -46
- package/dist/__tests__/gh.test.js.map +0 -1
- package/dist/__tests__/login.test.d.ts +0 -2
- package/dist/__tests__/login.test.d.ts.map +0 -1
- package/dist/__tests__/login.test.js +0 -25
- package/dist/__tests__/login.test.js.map +0 -1
- package/dist/__tests__/project.test.d.ts +0 -2
- package/dist/__tests__/project.test.d.ts.map +0 -1
- package/dist/__tests__/project.test.js +0 -17
- package/dist/__tests__/project.test.js.map +0 -1
package/dist/pr-state.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Check conclusions/states that mean "broken — go look".
|
|
2
|
+
const FAILING = new Set(["FAILURE", "TIMED_OUT", "CANCELLED", "ACTION_REQUIRED", "ERROR", "STARTUP_FAILURE"]);
|
|
3
|
+
// States that mean "still running — not a verdict yet".
|
|
4
|
+
const PENDING = new Set(["PENDING", "EXPECTED", "QUEUED", "IN_PROGRESS", "WAITING", "REQUESTED"]);
|
|
5
|
+
// A human (or the dashboard) can approve a PR with one of these labels, in
|
|
6
|
+
// addition to a native GitHub review approval.
|
|
7
|
+
const APPROVAL_LABELS = new Set(["shipflow-approved", "approved", "✅ approved"]);
|
|
8
|
+
/** Collapse the status-check rollup into one CI verdict. */
|
|
9
|
+
export function ciStateOf(checks) {
|
|
10
|
+
if (!checks || checks.length === 0)
|
|
11
|
+
return "none";
|
|
12
|
+
let failing = false;
|
|
13
|
+
let pending = false;
|
|
14
|
+
let passing = false;
|
|
15
|
+
for (const c of checks) {
|
|
16
|
+
const concl = (c.conclusion ?? "").toUpperCase();
|
|
17
|
+
const status = (c.status ?? "").toUpperCase();
|
|
18
|
+
const state = (c.state ?? "").toUpperCase();
|
|
19
|
+
if (FAILING.has(concl) || FAILING.has(state)) {
|
|
20
|
+
failing = true;
|
|
21
|
+
}
|
|
22
|
+
else if ((status && status !== "COMPLETED") || PENDING.has(state)) {
|
|
23
|
+
pending = true;
|
|
24
|
+
}
|
|
25
|
+
else if (concl === "SUCCESS" || concl === "NEUTRAL" || concl === "SKIPPED" || state === "SUCCESS") {
|
|
26
|
+
passing = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (failing)
|
|
30
|
+
return "failing";
|
|
31
|
+
if (pending)
|
|
32
|
+
return "pending";
|
|
33
|
+
if (passing)
|
|
34
|
+
return "passing";
|
|
35
|
+
return "none";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Why an open PR may need follow-up. Empty = nothing to do. "review_comments" is
|
|
39
|
+
* advisory (the comment may already be addressed); "changes_requested" and
|
|
40
|
+
* "ci_failing" are definite.
|
|
41
|
+
*/
|
|
42
|
+
export function prAttentionReasons(pr, me) {
|
|
43
|
+
const reasons = [];
|
|
44
|
+
if (pr.reviewDecision === "CHANGES_REQUESTED")
|
|
45
|
+
reasons.push("changes_requested");
|
|
46
|
+
const failing = (pr.statusCheckRollup ?? []).some((c) => FAILING.has((c.conclusion ?? "").toUpperCase()) || FAILING.has((c.state ?? "").toUpperCase()));
|
|
47
|
+
if (failing)
|
|
48
|
+
reasons.push("ci_failing");
|
|
49
|
+
const fromOthers = (a) => !!a.author && a.author.login !== me;
|
|
50
|
+
const reviewFeedback = (pr.reviews ?? []).filter((r) => fromOthers(r) && (r.state === "CHANGES_REQUESTED" || r.state === "COMMENTED"));
|
|
51
|
+
const otherComments = (pr.comments ?? []).filter(fromOthers);
|
|
52
|
+
if (reviewFeedback.length || otherComments.length)
|
|
53
|
+
reasons.push("review_comments");
|
|
54
|
+
return reasons;
|
|
55
|
+
}
|
|
56
|
+
/** The newest comment on an issue if it's from someone other than `me` (i.e. you
|
|
57
|
+
* may owe a reply); otherwise null. */
|
|
58
|
+
export function issueNeedsReply(comments, me) {
|
|
59
|
+
if (!comments?.length)
|
|
60
|
+
return null;
|
|
61
|
+
const last = comments[comments.length - 1];
|
|
62
|
+
return last.author && last.author.login !== me ? last : null;
|
|
63
|
+
}
|
|
64
|
+
/** Approved via a native GitHub review or a `shipflow-approved`-style label. */
|
|
65
|
+
export function isApproved(pr) {
|
|
66
|
+
if (pr.reviewDecision === "APPROVED")
|
|
67
|
+
return true;
|
|
68
|
+
return (pr.labels ?? []).some((l) => APPROVAL_LABELS.has(l.name.trim().toLowerCase()));
|
|
69
|
+
}
|
|
70
|
+
/** Whole hours since an ISO timestamp. */
|
|
71
|
+
export function hoursSince(iso, nowMs = Date.now()) {
|
|
72
|
+
if (!iso)
|
|
73
|
+
return 0;
|
|
74
|
+
const t = Date.parse(iso);
|
|
75
|
+
if (Number.isNaN(t))
|
|
76
|
+
return 0;
|
|
77
|
+
return Math.max(0, (nowMs - t) / 3_600_000);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Reduce a PR to the single next action the loop should take. Priority: a red
|
|
81
|
+
* build and explicit change requests come before advisory comments; pending CI
|
|
82
|
+
* means wait; an approved+green PR is a merge candidate; otherwise it's parked
|
|
83
|
+
* (or stale once it ages past the threshold).
|
|
84
|
+
*/
|
|
85
|
+
export function classifyPR(pr, me, opts = {}) {
|
|
86
|
+
const reasons = prAttentionReasons(pr, me);
|
|
87
|
+
const ciState = ciStateOf(pr.statusCheckRollup);
|
|
88
|
+
const approved = isApproved(pr);
|
|
89
|
+
const ageHours = hoursSince(pr.updatedAt, opts.nowMs);
|
|
90
|
+
const staleHours = opts.staleHours ?? 48;
|
|
91
|
+
let state;
|
|
92
|
+
if (ciState === "failing")
|
|
93
|
+
state = "ci_failing";
|
|
94
|
+
else if (pr.reviewDecision === "CHANGES_REQUESTED")
|
|
95
|
+
state = "changes_requested";
|
|
96
|
+
else if (reasons.includes("review_comments"))
|
|
97
|
+
state = "review_comments";
|
|
98
|
+
else if (ciState === "pending")
|
|
99
|
+
state = "ci_pending";
|
|
100
|
+
else if (approved)
|
|
101
|
+
state = "approved_ready"; // CI passing or none
|
|
102
|
+
else if (ageHours >= staleHours)
|
|
103
|
+
state = "stale";
|
|
104
|
+
else
|
|
105
|
+
state = "awaiting_review";
|
|
106
|
+
const needsAction = state !== "ci_pending" && state !== "awaiting_review";
|
|
107
|
+
return { number: pr.number, state, ciState, approved, ageHours, reasons, needsAction };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Decide whether the loop may merge this PR under the active policy. A red or
|
|
111
|
+
* pending build, a merge conflict, or requested changes always block. Approval
|
|
112
|
+
* is required for `auto-on-green`; `auto-timeout` also accepts a green PR that
|
|
113
|
+
* has aged past the stale threshold with no objection. `manual` never merges.
|
|
114
|
+
*/
|
|
115
|
+
export function mergeDecision(pr, me, opts) {
|
|
116
|
+
const cl = classifyPR(pr, me, { staleHours: opts.staleHours, nowMs: opts.nowMs });
|
|
117
|
+
const blockers = [];
|
|
118
|
+
if (opts.policy === "manual")
|
|
119
|
+
blockers.push("merge-policy is manual (human merge required)");
|
|
120
|
+
if (cl.ciState === "failing")
|
|
121
|
+
blockers.push("CI is failing");
|
|
122
|
+
if (cl.ciState === "pending")
|
|
123
|
+
blockers.push("CI still running");
|
|
124
|
+
if (opts.requireCi && cl.ciState === "none")
|
|
125
|
+
blockers.push("no CI checks to confirm (set require-ci=false to allow)");
|
|
126
|
+
if (pr.reviewDecision === "CHANGES_REQUESTED")
|
|
127
|
+
blockers.push("changes requested");
|
|
128
|
+
if ((opts.unresolvedThreads ?? 0) > 0)
|
|
129
|
+
blockers.push(`${opts.unresolvedThreads} unresolved review thread(s) — address + resolve them first`);
|
|
130
|
+
if ((pr.mergeable ?? "").toUpperCase() === "CONFLICTING")
|
|
131
|
+
blockers.push("merge conflict with base (run: pr sync)");
|
|
132
|
+
if (opts.policy === "auto-on-green" && !cl.approved) {
|
|
133
|
+
blockers.push("not approved (needs a GitHub review approval or a shipflow-approved label)");
|
|
134
|
+
}
|
|
135
|
+
if (opts.policy === "auto-timeout" && !cl.approved && cl.ageHours < opts.staleHours) {
|
|
136
|
+
blockers.push(`awaiting approval or the ${opts.staleHours}h timeout (age ${Math.round(cl.ageHours)}h)`);
|
|
137
|
+
}
|
|
138
|
+
return { policy: opts.policy, wouldMerge: blockers.length === 0, blockers };
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=pr-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-state.js","sourceRoot":"","sources":["../src/pr-state.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gh.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/gh.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, mock, beforeEach } from "bun:test";
|
|
2
|
-
// Mock child_process before importing gh.ts
|
|
3
|
-
let lastCmd = "";
|
|
4
|
-
let mockStdout = "";
|
|
5
|
-
let mockExit = 0;
|
|
6
|
-
mock.module("node:child_process", () => ({
|
|
7
|
-
execSync: (cmd) => {
|
|
8
|
-
lastCmd = cmd;
|
|
9
|
-
if (mockExit !== 0) {
|
|
10
|
-
const e = new Error("non-zero exit");
|
|
11
|
-
e.status = mockExit;
|
|
12
|
-
throw e;
|
|
13
|
-
}
|
|
14
|
-
return mockStdout;
|
|
15
|
-
},
|
|
16
|
-
spawnSync: (cmd, args) => {
|
|
17
|
-
lastCmd = `${cmd} ${args.join(" ")}`;
|
|
18
|
-
return { status: mockExit, stdout: Buffer.from(mockStdout), stderr: Buffer.from("") };
|
|
19
|
-
},
|
|
20
|
-
}));
|
|
21
|
-
const { ghAuthStatus, ghAuthToken, ghAuthLogin, ghIssueView } = await import("../gh.js");
|
|
22
|
-
beforeEach(() => { lastCmd = ""; mockStdout = ""; mockExit = 0; });
|
|
23
|
-
describe("ghAuthStatus", () => {
|
|
24
|
-
it("returns 'logged-in' when gh exits 0", () => {
|
|
25
|
-
mockExit = 0;
|
|
26
|
-
expect(ghAuthStatus()).toBe("logged-in");
|
|
27
|
-
});
|
|
28
|
-
it("returns 'logged-out' when gh exits non-zero", () => {
|
|
29
|
-
mockExit = 1;
|
|
30
|
-
expect(ghAuthStatus()).toBe("logged-out");
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
describe("ghAuthToken", () => {
|
|
34
|
-
it("returns the trimmed token", () => {
|
|
35
|
-
mockStdout = "gho_abc123\n";
|
|
36
|
-
expect(ghAuthToken()).toBe("gho_abc123");
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
describe("ghIssueView", () => {
|
|
40
|
-
it("parses JSON output", () => {
|
|
41
|
-
mockStdout = JSON.stringify({ number: 42, title: "x", body: "y", state: "open", labels: [], assignees: [], url: "https://x" });
|
|
42
|
-
const issue = ghIssueView("owner/repo", 42);
|
|
43
|
-
expect(issue.number).toBe(42);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
//# sourceMappingURL=gh.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gh.test.js","sourceRoot":"","sources":["../../src/__tests__/gh.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAElE,4CAA4C;AAC5C,IAAI,OAAO,GAAG,EAAE,CAAC;AACjB,IAAI,UAAU,GAAG,EAAE,CAAC;AACpB,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB,IAAI,CAAC,MAAM,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;IACvC,QAAQ,EAAE,CAAC,GAAW,EAAE,EAAE;QACxB,OAAO,GAAG,GAAG,CAAC;QACd,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnB,MAAM,CAAC,GAAQ,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;YAC1C,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC;YACpB,MAAM,CAAC,CAAC;QACV,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,SAAS,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE;QACzC,OAAO,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACxF,CAAC;CACF,CAAC,CAAC,CAAC;AAEJ,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;AAEzF,UAAU,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnE,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,QAAQ,GAAG,CAAC,CAAC;QACb,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,QAAQ,GAAG,CAAC,CAAC;QACb,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,UAAU,GAAG,cAAc,CAAC;QAC5B,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/H,MAAM,KAAK,GAAG,WAAW,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/login.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, mock } from "bun:test";
|
|
2
|
-
mock.module("../gh.js", () => ({
|
|
3
|
-
ghInstalled: () => true,
|
|
4
|
-
ghAuthStatus: () => "logged-in",
|
|
5
|
-
ghAuthLogin: () => true,
|
|
6
|
-
ghAuthToken: () => "gho_test",
|
|
7
|
-
}));
|
|
8
|
-
mock.module("../client.js", () => ({
|
|
9
|
-
ShipFlowClient: class {
|
|
10
|
-
async exchangeGhToken() {
|
|
11
|
-
return {
|
|
12
|
-
token: "jwt-1", refreshToken: "rt-1",
|
|
13
|
-
tenants: [{ token: "jwt-1", refreshToken: "rt-1", tenant: { id: "t1", githubOrg: "acme", displayName: "Acme" } }],
|
|
14
|
-
tenant: { id: "t1", githubOrg: "acme", displayName: "Acme" },
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
}));
|
|
19
|
-
describe("login command", () => {
|
|
20
|
-
it("imports without throwing", async () => {
|
|
21
|
-
const m = await import("../commands/login.js");
|
|
22
|
-
expect(typeof m.registerLoginCommand).toBe("function");
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
//# sourceMappingURL=login.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login.test.js","sourceRoot":"","sources":["../../src/__tests__/login.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEtD,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7B,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;IACvB,YAAY,EAAE,GAAG,EAAE,CAAC,WAAW;IAC/B,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;IACvB,WAAW,EAAE,GAAG,EAAE,CAAC,UAAU;CAC9B,CAAC,CAAC,CAAC;AACJ,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,cAAc,EAAE;QACd,KAAK,CAAC,eAAe;YACnB,OAAO;gBACL,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM;gBACpC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC;gBACjH,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;aAC7D,CAAC;QACJ,CAAC;KACF;CACF,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"project.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/project.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "bun:test";
|
|
2
|
-
import { parseGitRemote } from "../project.js";
|
|
3
|
-
describe("parseGitRemote", () => {
|
|
4
|
-
it("parses https URL", () => {
|
|
5
|
-
expect(parseGitRemote("https://github.com/owner/repo.git")).toEqual({ owner: "owner", repo: "repo" });
|
|
6
|
-
});
|
|
7
|
-
it("parses git@github.com SSH URL", () => {
|
|
8
|
-
expect(parseGitRemote("git@github.com:owner/repo.git")).toEqual({ owner: "owner", repo: "repo" });
|
|
9
|
-
});
|
|
10
|
-
it("parses URL without .git suffix", () => {
|
|
11
|
-
expect(parseGitRemote("https://github.com/owner/repo")).toEqual({ owner: "owner", repo: "repo" });
|
|
12
|
-
});
|
|
13
|
-
it("returns null for non-github URL", () => {
|
|
14
|
-
expect(parseGitRemote("https://gitlab.com/x/y")).toBeNull();
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
//# sourceMappingURL=project.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"project.test.js","sourceRoot":"","sources":["../../src/__tests__/project.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,CAAC,cAAc,CAAC,mCAAmC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACxG,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,cAAc,CAAC,+BAA+B,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,cAAc,CAAC,+BAA+B,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|