ghagga 3.0.0 → 3.2.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/commands/login.test.js +0 -2
- package/dist/commands/login.test.js.map +1 -1
- package/dist/commands/memory/backfill.d.ts +13 -0
- package/dist/commands/memory/backfill.d.ts.map +1 -0
- package/dist/commands/memory/backfill.js +47 -0
- package/dist/commands/memory/backfill.js.map +1 -0
- package/dist/commands/memory/backfill.test.d.ts +11 -0
- package/dist/commands/memory/backfill.test.d.ts.map +1 -0
- package/dist/commands/memory/backfill.test.js +127 -0
- package/dist/commands/memory/backfill.test.js.map +1 -0
- package/dist/commands/memory/clear.test.js +9 -0
- package/dist/commands/memory/clear.test.js.map +1 -1
- package/dist/commands/memory/delete.test.js +9 -0
- package/dist/commands/memory/delete.test.js.map +1 -1
- package/dist/commands/memory/index.d.ts +3 -3
- package/dist/commands/memory/index.d.ts.map +1 -1
- package/dist/commands/memory/index.js +5 -3
- package/dist/commands/memory/index.js.map +1 -1
- package/dist/commands/memory/list.test.js +9 -0
- package/dist/commands/memory/list.test.js.map +1 -1
- package/dist/commands/memory/search.test.js +9 -0
- package/dist/commands/memory/search.test.js.map +1 -1
- package/dist/commands/memory/show.test.js +9 -0
- package/dist/commands/memory/show.test.js.map +1 -1
- package/dist/commands/memory/stats.test.js +9 -0
- package/dist/commands/memory/stats.test.js.map +1 -1
- package/dist/commands/memory/utils.d.ts.map +1 -1
- package/dist/commands/memory/utils.js +14 -1
- package/dist/commands/memory/utils.js.map +1 -1
- package/dist/commands/review-output.test.js +37 -0
- package/dist/commands/review-output.test.js.map +1 -1
- package/dist/commands/review.d.ts +12 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +239 -5
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/review.mr-exit.test.d.ts +13 -0
- package/dist/commands/review.mr-exit.test.d.ts.map +1 -0
- package/dist/commands/review.mr-exit.test.js +190 -0
- package/dist/commands/review.mr-exit.test.js.map +1 -0
- package/dist/commands/review.postback-disclosure.test.d.ts +22 -0
- package/dist/commands/review.postback-disclosure.test.d.ts.map +1 -0
- package/dist/commands/review.postback-disclosure.test.js +192 -0
- package/dist/commands/review.postback-disclosure.test.js.map +1 -0
- package/dist/commands/review.pr-exit.test.d.ts +13 -0
- package/dist/commands/review.pr-exit.test.d.ts.map +1 -0
- package/dist/commands/review.pr-exit.test.js +162 -0
- package/dist/commands/review.pr-exit.test.js.map +1 -0
- package/dist/commands/review.pr-jenkins.test.d.ts +16 -0
- package/dist/commands/review.pr-jenkins.test.d.ts.map +1 -0
- package/dist/commands/review.pr-jenkins.test.js +106 -0
- package/dist/commands/review.pr-jenkins.test.js.map +1 -0
- package/dist/commands/review.pr-nativeid-fallback.test.d.ts +15 -0
- package/dist/commands/review.pr-nativeid-fallback.test.d.ts.map +1 -0
- package/dist/commands/review.pr-nativeid-fallback.test.js +151 -0
- package/dist/commands/review.pr-nativeid-fallback.test.js.map +1 -0
- package/dist/commands/review.test.js +13 -0
- package/dist/commands/review.test.js.map +1 -1
- package/dist/index.js +39 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/cli-github-client-port.d.ts +52 -0
- package/dist/lib/cli-github-client-port.d.ts.map +1 -0
- package/dist/lib/cli-github-client-port.js +199 -0
- package/dist/lib/cli-github-client-port.js.map +1 -0
- package/dist/lib/cli-github-client-port.test.d.ts +10 -0
- package/dist/lib/cli-github-client-port.test.d.ts.map +1 -0
- package/dist/lib/cli-github-client-port.test.js +47 -0
- package/dist/lib/cli-github-client-port.test.js.map +1 -0
- package/dist/lib/cli-gitlab-client-port.d.ts +62 -0
- package/dist/lib/cli-gitlab-client-port.d.ts.map +1 -0
- package/dist/lib/cli-gitlab-client-port.js +209 -0
- package/dist/lib/cli-gitlab-client-port.js.map +1 -0
- package/dist/lib/cli-gitlab-client-port.test.d.ts +9 -0
- package/dist/lib/cli-gitlab-client-port.test.d.ts.map +1 -0
- package/dist/lib/cli-gitlab-client-port.test.js +292 -0
- package/dist/lib/cli-gitlab-client-port.test.js.map +1 -0
- package/dist/lib/config.d.ts +23 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +9 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/embedding.d.ts +23 -0
- package/dist/lib/embedding.d.ts.map +1 -0
- package/dist/lib/embedding.js +39 -0
- package/dist/lib/embedding.js.map +1 -0
- package/dist/lib/embedding.test.d.ts +8 -0
- package/dist/lib/embedding.test.d.ts.map +1 -0
- package/dist/lib/embedding.test.js +101 -0
- package/dist/lib/embedding.test.js.map +1 -0
- package/dist/lib/forge-postback.d.ts +72 -0
- package/dist/lib/forge-postback.d.ts.map +1 -0
- package/dist/lib/forge-postback.js +39 -0
- package/dist/lib/forge-postback.js.map +1 -0
- package/dist/lib/gitlab-api.d.ts +50 -0
- package/dist/lib/gitlab-api.d.ts.map +1 -0
- package/dist/lib/gitlab-api.js +75 -0
- package/dist/lib/gitlab-api.js.map +1 -0
- package/dist/lib/gitlab-api.test.d.ts +2 -0
- package/dist/lib/gitlab-api.test.d.ts.map +1 -0
- package/dist/lib/gitlab-api.test.js +79 -0
- package/dist/lib/gitlab-api.test.js.map +1 -0
- package/dist/lib/gitlab-e2e.manual.test.d.ts +57 -0
- package/dist/lib/gitlab-e2e.manual.test.d.ts.map +1 -0
- package/dist/lib/gitlab-e2e.manual.test.js +135 -0
- package/dist/lib/gitlab-e2e.manual.test.js.map +1 -0
- package/dist/lib/gitlab-token.d.ts +17 -0
- package/dist/lib/gitlab-token.d.ts.map +1 -0
- package/dist/lib/gitlab-token.js +24 -0
- package/dist/lib/gitlab-token.js.map +1 -0
- package/dist/lib/gitlab-token.test.d.ts +2 -0
- package/dist/lib/gitlab-token.test.d.ts.map +1 -0
- package/dist/lib/gitlab-token.test.js +38 -0
- package/dist/lib/gitlab-token.test.js.map +1 -0
- package/dist/lib/oauth.test.js +0 -1
- package/dist/lib/oauth.test.js.map +1 -1
- package/dist/lib/pr-postback.d.ts +42 -0
- package/dist/lib/pr-postback.d.ts.map +1 -0
- package/dist/lib/pr-postback.js +44 -0
- package/dist/lib/pr-postback.js.map +1 -0
- package/dist/lib/pr-postback.test.d.ts +9 -0
- package/dist/lib/pr-postback.test.d.ts.map +1 -0
- package/dist/lib/pr-postback.test.js +212 -0
- package/dist/lib/pr-postback.test.js.map +1 -0
- package/dist/lib/pr-token.d.ts +15 -0
- package/dist/lib/pr-token.d.ts.map +1 -0
- package/dist/lib/pr-token.js +22 -0
- package/dist/lib/pr-token.js.map +1 -0
- package/dist/lib/pr-token.test.d.ts +2 -0
- package/dist/lib/pr-token.test.d.ts.map +1 -0
- package/dist/lib/pr-token.test.js +25 -0
- package/dist/lib/pr-token.test.js.map +1 -0
- package/package.json +9 -8
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI-side implementation of the forge `GitHubClientPort`.
|
|
3
|
+
*
|
|
4
|
+
* The `GitHubForgeAdapter` (packages/forge) depends on an injected
|
|
5
|
+
* {@link GitHubClientPort} (dependency inversion — forge MUST NOT import any
|
|
6
|
+
* concrete HTTP client). The SERVER injects `apps/server/src/github/client.ts`.
|
|
7
|
+
* The CLI has its OWN minimal client built on the same native-fetch +
|
|
8
|
+
* {@link apiHeaders} / {@link GitHubApiError} pattern as `github-api.ts`.
|
|
9
|
+
*
|
|
10
|
+
* SCOPE (P3 — PR summary post-back only):
|
|
11
|
+
* REAL members — the write/idempotency fns `upsertSummaryComment` folds over:
|
|
12
|
+
* - postComment (POST /repos/{o}/{r}/issues/{n}/comments)
|
|
13
|
+
* - findExistingComment(GET /repos/{o}/{r}/issues/{n}/comments — marker match)
|
|
14
|
+
* - deleteComment (DELETE /repos/{o}/{r}/issues/comments/{id})
|
|
15
|
+
* - updateComment (PATCH /repos/{o}/{r}/issues/comments/{id})
|
|
16
|
+
* STUBBED members — read fns the CLI never needs (it has the diff locally and
|
|
17
|
+
* does not consume reactions / graph in the `--pr` flow):
|
|
18
|
+
* - fetchPRDiff, fetchPRDetails, getPRFileList, getPRCommitMessages
|
|
19
|
+
* - addCommentReaction
|
|
20
|
+
* - fetchGraphFromBranch, fetchGraphMetadata
|
|
21
|
+
* Each stub THROWS so any accidental call surfaces loudly instead of silently
|
|
22
|
+
* returning bad data. The `--pr` post-back path (find → delete → post) only
|
|
23
|
+
* ever touches the REAL members; see pr-postback.ts + tests.
|
|
24
|
+
*
|
|
25
|
+
* The stale-comment match here mirrors the server EXACTLY: bot-authored-or-not is
|
|
26
|
+
* NOT inspected (the CLI token's own comments carry the marker), the match is the
|
|
27
|
+
* fixed `<!-- ghagga-review -->` marker substring (REVIEW_COMMENT_MARKER), latest
|
|
28
|
+
* = last in chronological order, the rest are stale. This keeps idempotency
|
|
29
|
+
* byte-compatible with the server post-back.
|
|
30
|
+
*/
|
|
31
|
+
import type { GitHubClientPort } from 'ghagga-forge';
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the GitHub NUMERIC repo id from an owner/name pair (forge identity).
|
|
34
|
+
*
|
|
35
|
+
* `GET /repos/{owner}/{repo}` → `.id`. owner/repo is the MUTABLE display path
|
|
36
|
+
* (a rename/transfer changes it but NOT the numeric id), so the numeric id is the
|
|
37
|
+
* canonical {@link RepoRef.nativeId}. This MIRRORS the GitLab `--mr` flow's
|
|
38
|
+
* {@link resolveGitLabProjectId} (one pre-construction call that turns the mutable
|
|
39
|
+
* path into the immutable id). It is NOT part of the {@link GitHubClientPort} — the
|
|
40
|
+
* adapter's actual API calls still key on owner/repo from its ctor; nativeId is
|
|
41
|
+
* identity metadata only.
|
|
42
|
+
*
|
|
43
|
+
* @returns the numeric repo id as a STRING (RepoRef.nativeId is a string,
|
|
44
|
+
* consistent with GitLab's `String(id)`).
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveGitHubRepoId(owner: string, repo: string, token: string): Promise<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Build a {@link GitHubClientPort} backed by native fetch for the CLI `--pr`
|
|
49
|
+
* post-back. Only the comment-write members are real; read members throw.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createCliGitHubClientPort(): GitHubClientPort;
|
|
52
|
+
//# sourceMappingURL=cli-github-client-port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-github-client-port.d.ts","sourceRoot":"","sources":["../../src/lib/cli-github-client-port.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAyB,MAAM,cAAc,CAAC;AAoC5E;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAWD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,gBAAgB,CAoH5D"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI-side implementation of the forge `GitHubClientPort`.
|
|
3
|
+
*
|
|
4
|
+
* The `GitHubForgeAdapter` (packages/forge) depends on an injected
|
|
5
|
+
* {@link GitHubClientPort} (dependency inversion — forge MUST NOT import any
|
|
6
|
+
* concrete HTTP client). The SERVER injects `apps/server/src/github/client.ts`.
|
|
7
|
+
* The CLI has its OWN minimal client built on the same native-fetch +
|
|
8
|
+
* {@link apiHeaders} / {@link GitHubApiError} pattern as `github-api.ts`.
|
|
9
|
+
*
|
|
10
|
+
* SCOPE (P3 — PR summary post-back only):
|
|
11
|
+
* REAL members — the write/idempotency fns `upsertSummaryComment` folds over:
|
|
12
|
+
* - postComment (POST /repos/{o}/{r}/issues/{n}/comments)
|
|
13
|
+
* - findExistingComment(GET /repos/{o}/{r}/issues/{n}/comments — marker match)
|
|
14
|
+
* - deleteComment (DELETE /repos/{o}/{r}/issues/comments/{id})
|
|
15
|
+
* - updateComment (PATCH /repos/{o}/{r}/issues/comments/{id})
|
|
16
|
+
* STUBBED members — read fns the CLI never needs (it has the diff locally and
|
|
17
|
+
* does not consume reactions / graph in the `--pr` flow):
|
|
18
|
+
* - fetchPRDiff, fetchPRDetails, getPRFileList, getPRCommitMessages
|
|
19
|
+
* - addCommentReaction
|
|
20
|
+
* - fetchGraphFromBranch, fetchGraphMetadata
|
|
21
|
+
* Each stub THROWS so any accidental call surfaces loudly instead of silently
|
|
22
|
+
* returning bad data. The `--pr` post-back path (find → delete → post) only
|
|
23
|
+
* ever touches the REAL members; see pr-postback.ts + tests.
|
|
24
|
+
*
|
|
25
|
+
* The stale-comment match here mirrors the server EXACTLY: bot-authored-or-not is
|
|
26
|
+
* NOT inspected (the CLI token's own comments carry the marker), the match is the
|
|
27
|
+
* fixed `<!-- ghagga-review -->` marker substring (REVIEW_COMMENT_MARKER), latest
|
|
28
|
+
* = last in chronological order, the rest are stale. This keeps idempotency
|
|
29
|
+
* byte-compatible with the server post-back.
|
|
30
|
+
*/
|
|
31
|
+
import { REVIEW_COMMENT_MARKER } from 'ghagga-core';
|
|
32
|
+
import { GitHubApiError } from './github-api.js';
|
|
33
|
+
// The fixed marker the summary body carries. SINGLE SOURCE OF TRUTH: imported
|
|
34
|
+
// from ghagga-core (REVIEW_COMMENT_MARKER) so the stale-comment match here can
|
|
35
|
+
// never drift from the marker the body actually carries.
|
|
36
|
+
const REVIEW_MARKER = REVIEW_COMMENT_MARKER;
|
|
37
|
+
const API_BASE = 'https://api.github.com';
|
|
38
|
+
/**
|
|
39
|
+
* Per-request timeout for the CLI's GitHub fetch calls. Mirrors the server
|
|
40
|
+
* client's `AbortSignal.timeout(10_000)` so a slow/hung GitHub can never hang a
|
|
41
|
+
* CI job indefinitely — the fetch aborts and surfaces as a thrown error.
|
|
42
|
+
*/
|
|
43
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
44
|
+
/** Shared auth/version headers — same shape as github-api.ts apiHeaders. */
|
|
45
|
+
function apiHeaders(token) {
|
|
46
|
+
return {
|
|
47
|
+
Authorization: `Bearer ${token}`,
|
|
48
|
+
Accept: 'application/vnd.github+json',
|
|
49
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function failOn(res, action) {
|
|
54
|
+
const body = await res.text();
|
|
55
|
+
throw new GitHubApiError(`GitHub API error ${action}: ${res.status} ${res.statusText}`, res.status, body);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the GitHub NUMERIC repo id from an owner/name pair (forge identity).
|
|
59
|
+
*
|
|
60
|
+
* `GET /repos/{owner}/{repo}` → `.id`. owner/repo is the MUTABLE display path
|
|
61
|
+
* (a rename/transfer changes it but NOT the numeric id), so the numeric id is the
|
|
62
|
+
* canonical {@link RepoRef.nativeId}. This MIRRORS the GitLab `--mr` flow's
|
|
63
|
+
* {@link resolveGitLabProjectId} (one pre-construction call that turns the mutable
|
|
64
|
+
* path into the immutable id). It is NOT part of the {@link GitHubClientPort} — the
|
|
65
|
+
* adapter's actual API calls still key on owner/repo from its ctor; nativeId is
|
|
66
|
+
* identity metadata only.
|
|
67
|
+
*
|
|
68
|
+
* @returns the numeric repo id as a STRING (RepoRef.nativeId is a string,
|
|
69
|
+
* consistent with GitLab's `String(id)`).
|
|
70
|
+
*/
|
|
71
|
+
export async function resolveGitHubRepoId(owner, repo, token) {
|
|
72
|
+
const url = `${API_BASE}/repos/${owner}/${repo}`;
|
|
73
|
+
const res = await fetch(url, {
|
|
74
|
+
headers: apiHeaders(token),
|
|
75
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
76
|
+
});
|
|
77
|
+
if (!res.ok)
|
|
78
|
+
await failOn(res, 'resolving repo id');
|
|
79
|
+
const data = (await res.json());
|
|
80
|
+
if (typeof data.id !== 'number') {
|
|
81
|
+
throw new GitHubApiError(`GitHub API error resolving repo id: response had no numeric "id" for "${owner}/${repo}"`, res.status, JSON.stringify(data));
|
|
82
|
+
}
|
|
83
|
+
return String(data.id);
|
|
84
|
+
}
|
|
85
|
+
/** Thrown by every stubbed port member so an accidental call is loud, not silent. */
|
|
86
|
+
function unsupported(member) {
|
|
87
|
+
throw new Error(`CliGitHubClientPort.${member} is not supported in CLI context — the CLI only ` +
|
|
88
|
+
'posts the PR summary comment (postComment/findExistingComment/deleteComment/' +
|
|
89
|
+
'updateComment). The diff/commits/file-list/graph are sourced locally.');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build a {@link GitHubClientPort} backed by native fetch for the CLI `--pr`
|
|
93
|
+
* post-back. Only the comment-write members are real; read members throw.
|
|
94
|
+
*/
|
|
95
|
+
export function createCliGitHubClientPort() {
|
|
96
|
+
return {
|
|
97
|
+
// ── REAL: PR/issue comment writes (the upsert fold) ──────────
|
|
98
|
+
async postComment(owner, repo, prNumber, body, token) {
|
|
99
|
+
const url = `${API_BASE}/repos/${owner}/${repo}/issues/${prNumber}/comments`;
|
|
100
|
+
const res = await fetch(url, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: apiHeaders(token),
|
|
103
|
+
body: JSON.stringify({ body }),
|
|
104
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
105
|
+
});
|
|
106
|
+
if (!res.ok)
|
|
107
|
+
await failOn(res, 'posting PR comment');
|
|
108
|
+
const data = (await res.json());
|
|
109
|
+
return { id: data.id };
|
|
110
|
+
},
|
|
111
|
+
async findExistingComment(owner, repo, prNumber, token) {
|
|
112
|
+
const baseUrl = `${API_BASE}/repos/${owner}/${repo}/issues/${prNumber}/comments`;
|
|
113
|
+
// Paginate until exhausted (a page with < 100 items is the last page).
|
|
114
|
+
// MAX_PAGES is a safety upper bound (50 × 100 = 5000 comments) so a
|
|
115
|
+
// pathological PR can't loop forever; if hit we log rather than silently
|
|
116
|
+
// truncate, since a stale marker beyond the bound would yield a DUPLICATE
|
|
117
|
+
// comment. (Was 5 pages / 500 items — backlog #6.)
|
|
118
|
+
const MAX_PAGES = 50;
|
|
119
|
+
const allMatchIds = [];
|
|
120
|
+
for (let page = 1; page <= MAX_PAGES; page++) {
|
|
121
|
+
const url = `${baseUrl}?per_page=100&page=${page}`;
|
|
122
|
+
const res = await fetch(url, {
|
|
123
|
+
headers: apiHeaders(token),
|
|
124
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
125
|
+
});
|
|
126
|
+
if (!res.ok)
|
|
127
|
+
await failOn(res, 'listing PR comments');
|
|
128
|
+
const comments = (await res.json());
|
|
129
|
+
for (const comment of comments) {
|
|
130
|
+
if (comment.body.includes(REVIEW_MARKER)) {
|
|
131
|
+
allMatchIds.push(comment.id);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (comments.length < 100)
|
|
135
|
+
break;
|
|
136
|
+
if (page === MAX_PAGES) {
|
|
137
|
+
console.warn(`[ghagga] findExistingComment hit MAX_PAGES (${MAX_PAGES}) for ${owner}/${repo}#${prNumber}; comment listing may be truncated`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (allMatchIds.length === 0)
|
|
141
|
+
return null;
|
|
142
|
+
// Latest = last (GitHub returns oldest first); the rest are stale.
|
|
143
|
+
const latestId = allMatchIds[allMatchIds.length - 1];
|
|
144
|
+
if (latestId == null)
|
|
145
|
+
return null;
|
|
146
|
+
const staleIds = allMatchIds.slice(0, -1);
|
|
147
|
+
return { latestId, staleIds };
|
|
148
|
+
},
|
|
149
|
+
async deleteComment(owner, repo, commentId, token) {
|
|
150
|
+
const url = `${API_BASE}/repos/${owner}/${repo}/issues/comments/${commentId}`;
|
|
151
|
+
const res = await fetch(url, {
|
|
152
|
+
method: 'DELETE',
|
|
153
|
+
headers: apiHeaders(token),
|
|
154
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
155
|
+
});
|
|
156
|
+
// The adapter's upsert tolerates delete failures (best-effort), but we still
|
|
157
|
+
// surface a non-2xx so `deleted[]` only reflects genuinely-removed ids.
|
|
158
|
+
if (!res.ok && res.status !== 404)
|
|
159
|
+
await failOn(res, 'deleting PR comment');
|
|
160
|
+
},
|
|
161
|
+
async updateComment(owner, repo, commentId, body, token) {
|
|
162
|
+
const url = `${API_BASE}/repos/${owner}/${repo}/issues/comments/${commentId}`;
|
|
163
|
+
const res = await fetch(url, {
|
|
164
|
+
method: 'PATCH',
|
|
165
|
+
headers: apiHeaders(token),
|
|
166
|
+
body: JSON.stringify({ body }),
|
|
167
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
168
|
+
});
|
|
169
|
+
if (!res.ok)
|
|
170
|
+
await failOn(res, 'updating PR comment');
|
|
171
|
+
},
|
|
172
|
+
// ── STUBBED: read/reaction/graph members (never hit in --pr flow) ──
|
|
173
|
+
// Declared `async` so the throw surfaces as a REJECTED promise (not a sync
|
|
174
|
+
// throw): callers `await` these, and a rejected promise is the contract-true
|
|
175
|
+
// failure shape — also keeps test spies/`.rejects` well-behaved.
|
|
176
|
+
async fetchPRDiff() {
|
|
177
|
+
return unsupported('fetchPRDiff');
|
|
178
|
+
},
|
|
179
|
+
async fetchPRDetails() {
|
|
180
|
+
return unsupported('fetchPRDetails');
|
|
181
|
+
},
|
|
182
|
+
async getPRFileList() {
|
|
183
|
+
return unsupported('getPRFileList');
|
|
184
|
+
},
|
|
185
|
+
async getPRCommitMessages() {
|
|
186
|
+
return unsupported('getPRCommitMessages');
|
|
187
|
+
},
|
|
188
|
+
async addCommentReaction(_owner, _repo, _commentId, _reaction, _token) {
|
|
189
|
+
return unsupported('addCommentReaction');
|
|
190
|
+
},
|
|
191
|
+
async fetchGraphFromBranch() {
|
|
192
|
+
return unsupported('fetchGraphFromBranch');
|
|
193
|
+
},
|
|
194
|
+
async fetchGraphMetadata() {
|
|
195
|
+
return unsupported('fetchGraphMetadata');
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=cli-github-client-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-github-client-port.js","sourceRoot":"","sources":["../../src/lib/cli-github-client-port.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveGitHubRepoId — numeric repo id resolution for RepoRef.nativeId.
|
|
3
|
+
*
|
|
4
|
+
* The CLI `--pr` flow resolves the IMMUTABLE numeric GitHub repo id once before
|
|
5
|
+
* the post-back (mirroring the GitLab `--mr` flow's resolveGitLabProjectId). We
|
|
6
|
+
* mock ONLY `fetch` (the network seam) so this exercises the genuine GET
|
|
7
|
+
* /repos/{owner}/{repo} → .id call + its error handling.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=cli-github-client-port.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-github-client-port.test.d.ts","sourceRoot":"","sources":["../../src/lib/cli-github-client-port.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveGitHubRepoId — numeric repo id resolution for RepoRef.nativeId.
|
|
3
|
+
*
|
|
4
|
+
* The CLI `--pr` flow resolves the IMMUTABLE numeric GitHub repo id once before
|
|
5
|
+
* the post-back (mirroring the GitLab `--mr` flow's resolveGitLabProjectId). We
|
|
6
|
+
* mock ONLY `fetch` (the network seam) so this exercises the genuine GET
|
|
7
|
+
* /repos/{owner}/{repo} → .id call + its error handling.
|
|
8
|
+
*/
|
|
9
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
10
|
+
import { resolveGitHubRepoId } from './cli-github-client-port.js';
|
|
11
|
+
const mockFetch = vi.fn();
|
|
12
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
13
|
+
function jsonResponse(status, body) {
|
|
14
|
+
return {
|
|
15
|
+
ok: status >= 200 && status < 300,
|
|
16
|
+
status,
|
|
17
|
+
statusText: status === 200 ? 'OK' : 'ERR',
|
|
18
|
+
text: () => Promise.resolve(JSON.stringify(body)),
|
|
19
|
+
json: () => Promise.resolve(body),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
describe('resolveGitHubRepoId (numeric repo id resolution → RepoRef.nativeId)', () => {
|
|
23
|
+
beforeEach(() => mockFetch.mockReset());
|
|
24
|
+
it('GET /repos/{owner}/{repo} → numeric id as string', async () => {
|
|
25
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, { id: 555000111, full_name: 'acme/widgets' }));
|
|
26
|
+
const id = await resolveGitHubRepoId('acme', 'widgets', 'ghp');
|
|
27
|
+
// Stringified to match RepoRef.nativeId's string type (consistent with GitLab).
|
|
28
|
+
expect(id).toBe('555000111');
|
|
29
|
+
const [url] = mockFetch.mock.calls[0];
|
|
30
|
+
expect(url).toBe('https://api.github.com/repos/acme/widgets');
|
|
31
|
+
});
|
|
32
|
+
it('passes an AbortSignal (timeout) so CI cannot hang', async () => {
|
|
33
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, { id: 1 }));
|
|
34
|
+
await resolveGitHubRepoId('acme', 'widgets', 'ghp');
|
|
35
|
+
const [, init] = mockFetch.mock.calls[0];
|
|
36
|
+
expect(init.signal).toBeInstanceOf(AbortSignal);
|
|
37
|
+
});
|
|
38
|
+
it('throws on a non-ok response (e.g. 404)', async () => {
|
|
39
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(404, { message: 'Not Found' }));
|
|
40
|
+
await expect(resolveGitHubRepoId('nope', 'nope', 'ghp')).rejects.toThrow(/resolving repo id/);
|
|
41
|
+
});
|
|
42
|
+
it('throws when the response has no numeric "id"', async () => {
|
|
43
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, { full_name: 'acme/widgets' }));
|
|
44
|
+
await expect(resolveGitHubRepoId('acme', 'widgets', 'ghp')).rejects.toThrow(/no numeric "id"/);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=cli-github-client-port.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-github-client-port.test.js","sourceRoot":"","sources":["../../src/lib/cli-github-client-port.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI-side implementation of the forge `GitLabClientPort` + numeric-project-id
|
|
3
|
+
* resolution for the `ghagga review --mr N` MR summary post-back.
|
|
4
|
+
*
|
|
5
|
+
* The `GitLabForgeAdapter` (packages/forge) depends on an injected
|
|
6
|
+
* {@link GitLabClientPort} (dependency inversion — forge MUST NOT import any
|
|
7
|
+
* concrete HTTP client). The CLI provides the real native-fetch implementation
|
|
8
|
+
* here, on the same `AbortSignal.timeout` + error-class pattern as
|
|
9
|
+
* `cli-github-client-port.ts`.
|
|
10
|
+
*
|
|
11
|
+
* AUTH: we send ONLY the `PRIVATE-TOKEN: <pat>` header — GitLab's recommended
|
|
12
|
+
* header for Personal/Project/Group Access Tokens (the kind `ghagga` uses). We do
|
|
13
|
+
* NOT also send `Authorization: Bearer`, which is for OAuth2 access tokens; mixing
|
|
14
|
+
* both is unnecessary and the PAT header is the canonical PAT auth path.
|
|
15
|
+
*
|
|
16
|
+
* HOST: the API base is derived from the resolved GitLab host
|
|
17
|
+
* (`https://<host>/api/v4`) so self-managed instances work, with a `GITLAB_HOST`
|
|
18
|
+
* env override for the rare case the API host differs from the git remote host.
|
|
19
|
+
*
|
|
20
|
+
* SCOPE (P4 — MR summary post-back): the four note members the adapter's
|
|
21
|
+
* `upsertSummaryComment` folds over (list/create/delete/update) plus
|
|
22
|
+
* `publishInline` (create). All four route through the NUMERIC project id (the
|
|
23
|
+
* canonical R-GITLAB identity). `resolveGitLabProjectId` is the pre-construction
|
|
24
|
+
* step that turns the mutable group/project path into that numeric id.
|
|
25
|
+
*/
|
|
26
|
+
import type { GitLabClientPort } from 'ghagga-forge';
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the GitLab API base (`https://<host>/api/v4`) for a remote host.
|
|
29
|
+
*
|
|
30
|
+
* Precedence:
|
|
31
|
+
* 1. `GITLAB_API_BASE` — a FULL API base override. Required for a self-managed
|
|
32
|
+
* GitLab served under a SUBPATH (e.g. `https://example.com/gitlab`), where a
|
|
33
|
+
* host-only value cannot express the `/gitlab` prefix. Used verbatim (only a
|
|
34
|
+
* trailing slash is trimmed); supply the complete `.../api/v4` URL.
|
|
35
|
+
* 2. `GITLAB_HOST` — a host-only override (for when the API host differs from
|
|
36
|
+
* the git remote host, e.g. a reverse proxy on a different hostname).
|
|
37
|
+
* 3. the host parsed from the git remote.
|
|
38
|
+
* For (2)/(3) a bare host is expected; a stray scheme/trailing slash is tolerated.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveGitLabApiBase(host: string, env?: NodeJS.ProcessEnv): string;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the GitLab NUMERIC project id from a group/project path (R-GITLAB).
|
|
43
|
+
*
|
|
44
|
+
* `GET /projects/:url-encoded-path` → `.id`. The path is mutable, so the numeric
|
|
45
|
+
* id is the canonical `RepoRef.nativeId`. This runs ONCE before constructing the
|
|
46
|
+
* adapter; it is NOT part of the {@link GitLabClientPort} (the adapter only ever
|
|
47
|
+
* speaks numeric ids).
|
|
48
|
+
*
|
|
49
|
+
* @param apiBase the resolved API base (`https://<host>/api/v4`) — see
|
|
50
|
+
* {@link resolveGitLabApiBase}. Defaults to gitlab.com for back-compat callers.
|
|
51
|
+
* @returns the numeric project id as a STRING (RepoRef.nativeId is a string).
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveGitLabProjectId(path: string, token: string, apiBase?: string): Promise<string>;
|
|
54
|
+
/**
|
|
55
|
+
* Build a {@link GitLabClientPort} backed by native fetch for the CLI `--mr`
|
|
56
|
+
* post-back. All members route through the numeric project id.
|
|
57
|
+
*
|
|
58
|
+
* @param apiBase the resolved API base (`https://<host>/api/v4`) — see
|
|
59
|
+
* {@link resolveGitLabApiBase}. Defaults to gitlab.com for back-compat callers.
|
|
60
|
+
*/
|
|
61
|
+
export declare function createCliGitLabClientPort(apiBase?: string): GitLabClientPort;
|
|
62
|
+
//# sourceMappingURL=cli-gitlab-client-port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-gitlab-client-port.d.ts","sourceRoot":"","sources":["../../src/lib/cli-gitlab-client-port.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,cAAc,CAAC;AAUjE;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAU/F;AAwBD;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,SAA8B,GACpC,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,SAA8B,GAAG,gBAAgB,CA2GjG"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI-side implementation of the forge `GitLabClientPort` + numeric-project-id
|
|
3
|
+
* resolution for the `ghagga review --mr N` MR summary post-back.
|
|
4
|
+
*
|
|
5
|
+
* The `GitLabForgeAdapter` (packages/forge) depends on an injected
|
|
6
|
+
* {@link GitLabClientPort} (dependency inversion — forge MUST NOT import any
|
|
7
|
+
* concrete HTTP client). The CLI provides the real native-fetch implementation
|
|
8
|
+
* here, on the same `AbortSignal.timeout` + error-class pattern as
|
|
9
|
+
* `cli-github-client-port.ts`.
|
|
10
|
+
*
|
|
11
|
+
* AUTH: we send ONLY the `PRIVATE-TOKEN: <pat>` header — GitLab's recommended
|
|
12
|
+
* header for Personal/Project/Group Access Tokens (the kind `ghagga` uses). We do
|
|
13
|
+
* NOT also send `Authorization: Bearer`, which is for OAuth2 access tokens; mixing
|
|
14
|
+
* both is unnecessary and the PAT header is the canonical PAT auth path.
|
|
15
|
+
*
|
|
16
|
+
* HOST: the API base is derived from the resolved GitLab host
|
|
17
|
+
* (`https://<host>/api/v4`) so self-managed instances work, with a `GITLAB_HOST`
|
|
18
|
+
* env override for the rare case the API host differs from the git remote host.
|
|
19
|
+
*
|
|
20
|
+
* SCOPE (P4 — MR summary post-back): the four note members the adapter's
|
|
21
|
+
* `upsertSummaryComment` folds over (list/create/delete/update) plus
|
|
22
|
+
* `publishInline` (create). All four route through the NUMERIC project id (the
|
|
23
|
+
* canonical R-GITLAB identity). `resolveGitLabProjectId` is the pre-construction
|
|
24
|
+
* step that turns the mutable group/project path into that numeric id.
|
|
25
|
+
*/
|
|
26
|
+
import { GitLabApiError } from './gitlab-api.js';
|
|
27
|
+
/**
|
|
28
|
+
* Per-request timeout for the CLI's GitLab fetch calls. Mirrors the GitHub CLI
|
|
29
|
+
* port's `AbortSignal.timeout(10_000)` so a slow/hung GitLab can never hang a CI
|
|
30
|
+
* job indefinitely.
|
|
31
|
+
*/
|
|
32
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the GitLab API base (`https://<host>/api/v4`) for a remote host.
|
|
35
|
+
*
|
|
36
|
+
* Precedence:
|
|
37
|
+
* 1. `GITLAB_API_BASE` — a FULL API base override. Required for a self-managed
|
|
38
|
+
* GitLab served under a SUBPATH (e.g. `https://example.com/gitlab`), where a
|
|
39
|
+
* host-only value cannot express the `/gitlab` prefix. Used verbatim (only a
|
|
40
|
+
* trailing slash is trimmed); supply the complete `.../api/v4` URL.
|
|
41
|
+
* 2. `GITLAB_HOST` — a host-only override (for when the API host differs from
|
|
42
|
+
* the git remote host, e.g. a reverse proxy on a different hostname).
|
|
43
|
+
* 3. the host parsed from the git remote.
|
|
44
|
+
* For (2)/(3) a bare host is expected; a stray scheme/trailing slash is tolerated.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveGitLabApiBase(host, env = process.env) {
|
|
47
|
+
const apiBaseOverride = env.GITLAB_API_BASE?.trim();
|
|
48
|
+
if (apiBaseOverride) {
|
|
49
|
+
return apiBaseOverride.replace(/\/+$/, '');
|
|
50
|
+
}
|
|
51
|
+
const hostOverride = env.GITLAB_HOST?.trim();
|
|
52
|
+
const chosen = hostOverride || host;
|
|
53
|
+
// Tolerate an override that includes a scheme and/or trailing slash.
|
|
54
|
+
const bare = chosen.replace(/^https?:\/\//i, '').replace(/\/+$/, '');
|
|
55
|
+
return `https://${bare}/api/v4`;
|
|
56
|
+
}
|
|
57
|
+
/** Auth headers — PRIVATE-TOKEN only (GitLab's recommended header for PATs). */
|
|
58
|
+
function apiHeaders(token) {
|
|
59
|
+
return {
|
|
60
|
+
'PRIVATE-TOKEN': token,
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async function failOn(res, action) {
|
|
65
|
+
const body = await res.text();
|
|
66
|
+
throw new GitLabApiError(`GitLab API error ${action}: ${res.status} ${res.statusText}`, res.status, body);
|
|
67
|
+
}
|
|
68
|
+
/** Encode a path segment that itself contains slashes (group/subgroup/project). */
|
|
69
|
+
function encodeProjectPath(path) {
|
|
70
|
+
return encodeURIComponent(path);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the GitLab NUMERIC project id from a group/project path (R-GITLAB).
|
|
74
|
+
*
|
|
75
|
+
* `GET /projects/:url-encoded-path` → `.id`. The path is mutable, so the numeric
|
|
76
|
+
* id is the canonical `RepoRef.nativeId`. This runs ONCE before constructing the
|
|
77
|
+
* adapter; it is NOT part of the {@link GitLabClientPort} (the adapter only ever
|
|
78
|
+
* speaks numeric ids).
|
|
79
|
+
*
|
|
80
|
+
* @param apiBase the resolved API base (`https://<host>/api/v4`) — see
|
|
81
|
+
* {@link resolveGitLabApiBase}. Defaults to gitlab.com for back-compat callers.
|
|
82
|
+
* @returns the numeric project id as a STRING (RepoRef.nativeId is a string).
|
|
83
|
+
*/
|
|
84
|
+
export async function resolveGitLabProjectId(path, token, apiBase = 'https://gitlab.com/api/v4') {
|
|
85
|
+
const url = `${apiBase}/projects/${encodeProjectPath(path)}`;
|
|
86
|
+
const res = await fetch(url, {
|
|
87
|
+
headers: apiHeaders(token),
|
|
88
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
89
|
+
});
|
|
90
|
+
if (!res.ok)
|
|
91
|
+
await failOn(res, 'resolving project id');
|
|
92
|
+
const data = (await res.json());
|
|
93
|
+
if (typeof data.id !== 'number') {
|
|
94
|
+
throw new GitLabApiError(`GitLab API error resolving project id: response had no numeric "id" for path "${path}"`, res.status, JSON.stringify(data));
|
|
95
|
+
}
|
|
96
|
+
return String(data.id);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Build a {@link GitLabClientPort} backed by native fetch for the CLI `--mr`
|
|
100
|
+
* post-back. All members route through the numeric project id.
|
|
101
|
+
*
|
|
102
|
+
* @param apiBase the resolved API base (`https://<host>/api/v4`) — see
|
|
103
|
+
* {@link resolveGitLabApiBase}. Defaults to gitlab.com for back-compat callers.
|
|
104
|
+
*/
|
|
105
|
+
export function createCliGitLabClientPort(apiBase = 'https://gitlab.com/api/v4') {
|
|
106
|
+
return {
|
|
107
|
+
async listMrNotes(projectId, mrIid, token) {
|
|
108
|
+
// Paginate until exhausted (a page with < 100 items is the last page),
|
|
109
|
+
// like the GitHub port. MAX_PAGES is a safety upper bound (50 × 100 = 5000
|
|
110
|
+
// notes) so a pathological MR can't loop forever; if hit we log rather
|
|
111
|
+
// than silently truncate, since a stale marker beyond the bound would
|
|
112
|
+
// yield a DUPLICATE note. (Was 5 pages / 500 items — backlog #6.)
|
|
113
|
+
const baseUrl = `${apiBase}/projects/${projectId}/merge_requests/${mrIid}/notes`;
|
|
114
|
+
const MAX_PAGES = 50;
|
|
115
|
+
const out = [];
|
|
116
|
+
for (let page = 1; page <= MAX_PAGES; page++) {
|
|
117
|
+
const url = `${baseUrl}?per_page=100&page=${page}&sort=asc&order_by=created_at`;
|
|
118
|
+
const res = await fetch(url, {
|
|
119
|
+
headers: apiHeaders(token),
|
|
120
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
121
|
+
});
|
|
122
|
+
if (!res.ok)
|
|
123
|
+
await failOn(res, 'listing MR notes');
|
|
124
|
+
const notes = (await res.json());
|
|
125
|
+
for (const note of notes) {
|
|
126
|
+
out.push({ id: note.id, body: note.body });
|
|
127
|
+
}
|
|
128
|
+
if (notes.length < 100)
|
|
129
|
+
break;
|
|
130
|
+
if (page === MAX_PAGES) {
|
|
131
|
+
console.warn(`[ghagga] listMrNotes hit MAX_PAGES (${MAX_PAGES}) for project ${projectId} MR !${mrIid}; note listing may be truncated`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
},
|
|
136
|
+
async createMrNote(projectId, mrIid, body, token) {
|
|
137
|
+
const url = `${apiBase}/projects/${projectId}/merge_requests/${mrIid}/notes`;
|
|
138
|
+
const res = await fetch(url, {
|
|
139
|
+
method: 'POST',
|
|
140
|
+
headers: apiHeaders(token),
|
|
141
|
+
body: JSON.stringify({ body }),
|
|
142
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
143
|
+
});
|
|
144
|
+
if (!res.ok)
|
|
145
|
+
await failOn(res, 'creating MR note');
|
|
146
|
+
const data = (await res.json());
|
|
147
|
+
return { id: data.id };
|
|
148
|
+
},
|
|
149
|
+
async deleteMrNote(projectId, mrIid, noteId, token) {
|
|
150
|
+
const url = `${apiBase}/projects/${projectId}/merge_requests/${mrIid}/notes/${noteId}`;
|
|
151
|
+
const res = await fetch(url, {
|
|
152
|
+
method: 'DELETE',
|
|
153
|
+
headers: apiHeaders(token),
|
|
154
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
155
|
+
});
|
|
156
|
+
// The adapter's upsert tolerates delete failures (best-effort), but we
|
|
157
|
+
// still surface a non-2xx (except 404) so `deleted[]` only reflects
|
|
158
|
+
// genuinely-removed ids.
|
|
159
|
+
if (!res.ok && res.status !== 404)
|
|
160
|
+
await failOn(res, 'deleting MR note');
|
|
161
|
+
},
|
|
162
|
+
async createMrDiscussion(projectId, mrIid, body, position, token) {
|
|
163
|
+
// True diff-anchored discussion: POST /merge_requests/:iid/discussions with
|
|
164
|
+
// position[position_type]=text + the three SHAs + old/new path + line(s).
|
|
165
|
+
const url = `${apiBase}/projects/${projectId}/merge_requests/${mrIid}/discussions`;
|
|
166
|
+
const payload = {
|
|
167
|
+
body,
|
|
168
|
+
position: {
|
|
169
|
+
position_type: 'text',
|
|
170
|
+
base_sha: position.baseSha,
|
|
171
|
+
head_sha: position.headSha,
|
|
172
|
+
start_sha: position.startSha,
|
|
173
|
+
old_path: position.oldPath,
|
|
174
|
+
new_path: position.newPath,
|
|
175
|
+
...(position.oldLine != null ? { old_line: position.oldLine } : {}),
|
|
176
|
+
...(position.newLine != null ? { new_line: position.newLine } : {}),
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
const res = await fetch(url, {
|
|
180
|
+
method: 'POST',
|
|
181
|
+
headers: apiHeaders(token),
|
|
182
|
+
body: JSON.stringify(payload),
|
|
183
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
184
|
+
});
|
|
185
|
+
if (!res.ok)
|
|
186
|
+
await failOn(res, 'creating MR discussion');
|
|
187
|
+
// The discussion response nests its notes; box the FIRST note's id so the
|
|
188
|
+
// result matches the createMrNote contract ({ id: number }).
|
|
189
|
+
const data = (await res.json());
|
|
190
|
+
const firstNoteId = data.notes?.[0]?.id;
|
|
191
|
+
if (typeof firstNoteId !== 'number') {
|
|
192
|
+
throw new GitLabApiError('GitLab API error creating MR discussion: response had no numeric notes[0].id', res.status, JSON.stringify(data));
|
|
193
|
+
}
|
|
194
|
+
return { id: firstNoteId };
|
|
195
|
+
},
|
|
196
|
+
async updateMrNote(projectId, mrIid, noteId, body, token) {
|
|
197
|
+
const url = `${apiBase}/projects/${projectId}/merge_requests/${mrIid}/notes/${noteId}`;
|
|
198
|
+
const res = await fetch(url, {
|
|
199
|
+
method: 'PUT',
|
|
200
|
+
headers: apiHeaders(token),
|
|
201
|
+
body: JSON.stringify({ body }),
|
|
202
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
203
|
+
});
|
|
204
|
+
if (!res.ok)
|
|
205
|
+
await failOn(res, 'updating MR note');
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=cli-gitlab-client-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-gitlab-client-port.js","sourceRoot":"","sources":["../../src/lib/cli-gitlab-client-port.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R-GITLAB / R-LEAK-PUBLISH: the `--mr` post-back routes through the REAL
|
|
3
|
+
* GitLabForgeAdapter folding over the CLI's own GitLabClientPort. We mock ONLY
|
|
4
|
+
* `fetch` (the network seam), so this exercises the genuine adapter
|
|
5
|
+
* find→delete→repost idempotency AND the genuine CLI port REST calls — a
|
|
6
|
+
* faithful simulation against a mocked GitLab.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=cli-gitlab-client-port.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-gitlab-client-port.test.d.ts","sourceRoot":"","sources":["../../src/lib/cli-gitlab-client-port.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|