@g-abhishek/gitx 0.1.2 → 0.1.5
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/README.md +386 -3
- package/dist/ai/claudeAi.d.ts +35 -0
- package/dist/ai/claudeAi.d.ts.map +1 -0
- package/dist/ai/claudeAi.js +396 -0
- package/dist/ai/claudeAi.js.map +1 -0
- package/dist/ai/claudeCliAi.d.ts +27 -0
- package/dist/ai/claudeCliAi.d.ts.map +1 -0
- package/dist/ai/claudeCliAi.js +312 -0
- package/dist/ai/claudeCliAi.js.map +1 -0
- package/dist/ai/localClaudeAi.d.ts +2 -0
- package/dist/ai/localClaudeAi.d.ts.map +1 -0
- package/dist/ai/localClaudeAi.js +4 -0
- package/dist/ai/localClaudeAi.js.map +1 -0
- package/dist/ai/mockAi.d.ts +8 -1
- package/dist/ai/mockAi.d.ts.map +1 -1
- package/dist/ai/mockAi.js +57 -0
- package/dist/ai/mockAi.js.map +1 -1
- package/dist/ai/openAiAi.d.ts +33 -0
- package/dist/ai/openAiAi.d.ts.map +1 -0
- package/dist/ai/openAiAi.js +388 -0
- package/dist/ai/openAiAi.js.map +1 -0
- package/dist/ai/reviewHelpers.d.ts +66 -0
- package/dist/ai/reviewHelpers.d.ts.map +1 -0
- package/dist/ai/reviewHelpers.js +574 -0
- package/dist/ai/reviewHelpers.js.map +1 -0
- package/dist/ai/types.d.ts +247 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/cli/commands/ask.d.ts +27 -0
- package/dist/cli/commands/ask.d.ts.map +1 -0
- package/dist/cli/commands/ask.js +230 -0
- package/dist/cli/commands/ask.js.map +1 -0
- package/dist/cli/commands/commit.d.ts +16 -0
- package/dist/cli/commands/commit.d.ts.map +1 -0
- package/dist/cli/commands/commit.js +163 -0
- package/dist/cli/commands/commit.js.map +1 -0
- package/dist/cli/commands/config.d.ts +4 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +666 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/implement.d.ts.map +1 -1
- package/dist/cli/commands/implement.js +149 -31
- package/dist/cli/commands/implement.js.map +1 -1
- package/dist/cli/commands/init.d.ts +4 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +7 -69
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/port.d.ts +32 -0
- package/dist/cli/commands/port.d.ts.map +1 -0
- package/dist/cli/commands/port.js +554 -0
- package/dist/cli/commands/port.js.map +1 -0
- package/dist/cli/commands/pr/close.d.ts +15 -0
- package/dist/cli/commands/pr/close.d.ts.map +1 -0
- package/dist/cli/commands/pr/close.js +71 -0
- package/dist/cli/commands/pr/close.js.map +1 -0
- package/dist/cli/commands/pr/create.d.ts +17 -0
- package/dist/cli/commands/pr/create.d.ts.map +1 -1
- package/dist/cli/commands/pr/create.js +208 -7
- package/dist/cli/commands/pr/create.js.map +1 -1
- package/dist/cli/commands/pr/fixComments.d.ts +5 -2
- package/dist/cli/commands/pr/fixComments.d.ts.map +1 -1
- package/dist/cli/commands/pr/fixComments.js +5 -13
- package/dist/cli/commands/pr/fixComments.js.map +1 -1
- package/dist/cli/commands/pr/index.d.ts.map +1 -1
- package/dist/cli/commands/pr/index.js +6 -2
- package/dist/cli/commands/pr/index.js.map +1 -1
- package/dist/cli/commands/pr/list.d.ts.map +1 -1
- package/dist/cli/commands/pr/list.js +24 -4
- package/dist/cli/commands/pr/list.js.map +1 -1
- package/dist/cli/commands/pr/merge.d.ts +23 -0
- package/dist/cli/commands/pr/merge.d.ts.map +1 -0
- package/dist/cli/commands/pr/merge.js +191 -0
- package/dist/cli/commands/pr/merge.js.map +1 -0
- package/dist/cli/commands/pr/resolve.d.ts +3 -0
- package/dist/cli/commands/pr/resolve.d.ts.map +1 -0
- package/dist/cli/commands/pr/resolve.js +92 -0
- package/dist/cli/commands/pr/resolve.js.map +1 -0
- package/dist/cli/commands/pr/review.d.ts.map +1 -1
- package/dist/cli/commands/pr/review.js +121 -6
- package/dist/cli/commands/pr/review.js.map +1 -1
- package/dist/cli/commands/push.d.ts +16 -0
- package/dist/cli/commands/push.d.ts.map +1 -0
- package/dist/cli/commands/push.js +166 -0
- package/dist/cli/commands/push.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +24 -0
- package/dist/cli/commands/sync.d.ts.map +1 -0
- package/dist/cli/commands/sync.js +414 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +34 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/config/config.d.ts +20 -3
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +98 -45
- package/dist/config/config.js.map +1 -1
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +61 -6
- package/dist/config/schema.js.map +1 -1
- package/dist/core/context.d.ts +6 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js.map +1 -1
- package/dist/core/gitx.d.ts +43 -0
- package/dist/core/gitx.d.ts.map +1 -1
- package/dist/core/gitx.js +187 -20
- package/dist/core/gitx.js.map +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/providers/azure.d.ts +26 -0
- package/dist/providers/azure.d.ts.map +1 -0
- package/dist/providers/azure.js +256 -0
- package/dist/providers/azure.js.map +1 -0
- package/dist/providers/base.d.ts +104 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +5 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/factory.d.ts +8 -0
- package/dist/providers/factory.d.ts.map +1 -0
- package/dist/providers/factory.js +25 -0
- package/dist/providers/factory.js.map +1 -0
- package/dist/providers/github.d.ts +19 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +291 -0
- package/dist/providers/github.js.map +1 -0
- package/dist/providers/gitlab.d.ts +19 -0
- package/dist/providers/gitlab.d.ts.map +1 -0
- package/dist/providers/gitlab.js +186 -0
- package/dist/providers/gitlab.js.map +1 -0
- package/dist/types/config.d.ts +50 -7
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/dist/utils/azureAuth.d.ts +51 -0
- package/dist/utils/azureAuth.d.ts.map +1 -0
- package/dist/utils/azureAuth.js +172 -0
- package/dist/utils/azureAuth.js.map +1 -0
- package/dist/utils/git.d.ts +19 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +45 -8
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/gitOps.d.ts +125 -0
- package/dist/utils/gitOps.d.ts.map +1 -0
- package/dist/utils/gitOps.js +396 -0
- package/dist/utils/gitOps.js.map +1 -0
- package/dist/utils/lockFile.d.ts +13 -0
- package/dist/utils/lockFile.d.ts.map +1 -0
- package/dist/utils/lockFile.js +54 -0
- package/dist/utils/lockFile.js.map +1 -0
- package/dist/utils/retry.d.ts +10 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +31 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/workflows/implement.d.ts +41 -0
- package/dist/workflows/implement.d.ts.map +1 -0
- package/dist/workflows/implement.js +219 -0
- package/dist/workflows/implement.js.map +1 -0
- package/dist/workflows/pr.d.ts +41 -0
- package/dist/workflows/pr.d.ts.map +1 -0
- package/dist/workflows/pr.js +291 -0
- package/dist/workflows/pr.js.map +1 -0
- package/dist/workflows/prAddress.d.ts +55 -0
- package/dist/workflows/prAddress.d.ts.map +1 -0
- package/dist/workflows/prAddress.js +349 -0
- package/dist/workflows/prAddress.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azure.js","sourceRoot":"","sources":["../../src/providers/azure.ts"],"names":[],"mappings":"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","sourcesContent":["import axios, { type AxiosInstance, isAxiosError } from \"axios\";\nimport { withRetry } from \"../utils/retry.js\";\nimport { GitxError } from \"../utils/errors.js\";\nimport type {\n CreatePrOptions,\n GitProvider,\n MergePrOptions,\n PullRequest,\n PullRequestComment,\n SubmitReviewOptions,\n} from \"./base.js\";\n\n/**\n * Azure DevOps slug format expected by this provider: \"org/project/repo\"\n *\n * Remote URL patterns handled upstream in utils/git.ts:\n * https://dev.azure.com/{org}/{project}/_git/{repo}\n * {org}@vs-ssh.visualstudio.com:v3/{org}/{project}/{repo}\n */\n\n// ─── Raw Azure DevOps API shapes ──────────────────────────────────────────────\ninterface AzPr {\n pullRequestId: number;\n title: string;\n description?: string;\n status: string; // \"active\" | \"completed\" | \"abandoned\"\n sourceRefName: string;\n targetRefName: string;\n url: string;\n createdBy: { displayName: string } | null;\n creationDate: string;\n lastMergeSourceCommit?: { author?: { date?: string } };\n}\n\ninterface AzComment {\n id: number;\n content: string;\n author: { displayName: string };\n publishedDate: string;\n commentType: string; // \"text\" | \"system\" | ...\n}\n\ninterface AzThread {\n comments: AzComment[];\n threadContext?: { filePath?: string; rightFileStart?: { line?: number } };\n}\n\ninterface AzListResponse<T> {\n value: T[];\n}\n\ninterface AzRepo {\n defaultBranch?: string;\n}\n\n// ─── Azure Provider ───────────────────────────────────────────────────────────\nexport class AzureProvider implements GitProvider {\n private readonly http: AxiosInstance;\n private readonly org: string;\n private readonly project: string;\n private readonly repoName: string;\n\n /**\n * @param token PAT string or OAuth Bearer token (from GCM).\n * @param repoSlug \"org/project/repo\" slug.\n * @param tokenType \"pat\" (default) → Basic auth; \"bearer\" → Bearer auth.\n */\n constructor(token: string, repoSlug: string, tokenType: \"pat\" | \"bearer\" = \"pat\") {\n // Expect \"org/project/repo\"\n const parts = repoSlug.split(\"/\");\n this.org = parts[0] ?? \"unknown\";\n this.project = parts[1] ?? \"unknown\";\n this.repoName = parts[2] ?? parts[1] ?? \"unknown\";\n\n // PAT auth: Basic base64(:<pat>)\n // GCM OAuth auth: Bearer <oauth_token>\n const authHeader =\n tokenType === \"bearer\"\n ? `Bearer ${token}`\n : `Basic ${Buffer.from(`:${token}`).toString(\"base64\")}`;\n\n this.http = axios.create({\n baseURL: `https://dev.azure.com/${this.org}/${this.project}/_apis`,\n headers: {\n Authorization: authHeader,\n \"Content-Type\": \"application/json\",\n },\n timeout: 20_000,\n });\n }\n\n private apiParams(extra?: Record<string, string>): Record<string, string> {\n return { \"api-version\": \"7.1-preview.1\", ...extra };\n }\n\n async listPRs(_repoSlug: string): Promise<PullRequest[]> {\n try {\n const { data } = await this.http.get<AzListResponse<AzPr>>(\n `/git/repositories/${this.repoName}/pullrequests`,\n {\n params: this.apiParams({ \"searchCriteria.status\": \"active\", $top: \"50\" }),\n }\n );\n return (data.value ?? []).map(mapAzPr);\n } catch (err) {\n throw wrapAzError(err, \"list PRs\");\n }\n }\n\n async getPR(_repoSlug: string, prNumber: number): Promise<PullRequest> {\n try {\n const { data } = await this.http.get<AzPr>(\n `/git/repositories/${this.repoName}/pullrequests/${prNumber}`,\n { params: this.apiParams() }\n );\n return mapAzPr(data);\n } catch (err) {\n throw wrapAzError(err, `get PR #${prNumber}`);\n }\n }\n\n async createPR(_repoSlug: string, opts: CreatePrOptions): Promise<PullRequest> {\n try {\n const { data } = await this.http.post<AzPr>(\n `/git/repositories/${this.repoName}/pullrequests`,\n {\n title: opts.title,\n description: opts.body,\n sourceRefName: `refs/heads/${opts.head}`,\n targetRefName: `refs/heads/${opts.base}`,\n isDraft: opts.draft ?? false,\n },\n { params: this.apiParams() }\n );\n return mapAzPr(data);\n } catch (err) {\n throw wrapAzError(err, \"create PR\");\n }\n }\n\n async getPRComments(_repoSlug: string, prNumber: number): Promise<PullRequestComment[]> {\n try {\n const { data } = await this.http.get<AzListResponse<AzThread>>(\n `/git/repositories/${this.repoName}/pullrequests/${prNumber}/threads`,\n { params: this.apiParams() }\n );\n const result: PullRequestComment[] = [];\n for (const thread of data.value ?? []) {\n for (const c of thread.comments ?? []) {\n if (c.commentType !== \"system\") {\n result.push({\n id: c.id,\n body: c.content,\n author: c.author?.displayName ?? \"unknown\",\n path: thread.threadContext?.filePath,\n line: thread.threadContext?.rightFileStart?.line,\n createdAt: c.publishedDate,\n });\n }\n }\n }\n return result;\n } catch (err) {\n throw wrapAzError(err, `get PR #${prNumber} threads`);\n }\n }\n\n async addPRComment(_repoSlug: string, prNumber: number, body: string): Promise<void> {\n try {\n await this.http.post(\n `/git/repositories/${this.repoName}/pullrequests/${prNumber}/threads`,\n {\n comments: [{ parentCommentId: 0, content: body, commentType: 1 }],\n status: 1,\n },\n { params: this.apiParams() }\n );\n } catch (err) {\n throw wrapAzError(err, `comment on PR #${prNumber}`);\n }\n }\n\n\n async getPRDiff(_repoSlug: string, prNumber: number): Promise<string> {\n try {\n // Get latest iteration first\n const iterRes = await this.http.get<{ value: Array<{ id: number }> }>(\n `/git/repositories/${this.repoName}/pullRequests/${prNumber}/iterations`,\n { params: this.apiParams() }\n );\n const iterations = iterRes.data.value ?? [];\n if (iterations.length === 0) return \"\";\n const latestId = iterations[iterations.length - 1]!.id;\n\n const { data } = await this.http.get<{ changeEntries: Array<{ item: { path: string }; changeType: number }> }>(\n `/git/repositories/${this.repoName}/pullRequests/${prNumber}/iterations/${latestId}/changes`,\n { params: this.apiParams() }\n );\n const paths = (data.changeEntries ?? []).map((e) => e.item?.path).filter(Boolean);\n return paths.length > 0 ? `Changed files:\\n${paths.join(\"\\n\")}` : \"\";\n } catch {\n return \"\";\n }\n }\n\n async mergePR(_repoSlug: string, prNumber: number, opts: MergePrOptions): Promise<void> {\n // Azure requires the latest source commit SHA to complete a PR\n let lastMergeSourceCommit: { commitId: string } | undefined;\n try {\n const { data } = await this.http.get<AzPr>(\n `/git/repositories/${this.repoName}/pullrequests/${prNumber}`,\n { params: this.apiParams() }\n );\n // Azure puts the head commit on the PR object\n const pr = data as AzPr & { lastMergeSourceCommit?: { commitId: string } };\n lastMergeSourceCommit = pr.lastMergeSourceCommit;\n } catch (err) {\n throw wrapAzError(err, `get PR #${prNumber} for merge`);\n }\n\n // Map our method to Azure's mergeStrategy\n const strategyMap: Record<MergePrOptions[\"method\"], string> = {\n squash: \"squash\",\n merge: \"noFastForward\",\n rebase: \"rebase\",\n };\n\n try {\n await this.http.patch(\n `/git/repositories/${this.repoName}/pullrequests/${prNumber}`,\n {\n status: \"completed\",\n lastMergeSourceCommit,\n completionOptions: {\n mergeStrategy: strategyMap[opts.method],\n deleteSourceBranch: opts.deleteSourceBranch ?? false,\n squashMerge: opts.method === \"squash\",\n },\n },\n { params: this.apiParams() }\n );\n } catch (err) {\n throw wrapAzError(err, `merge PR #${prNumber}`);\n }\n }\n\n async closePR(_repoSlug: string, prNumber: number): Promise<void> {\n try {\n await this.http.patch(\n `/git/repositories/${this.repoName}/pullrequests/${prNumber}`,\n { status: \"abandoned\" },\n { params: this.apiParams() }\n );\n } catch (err) {\n throw wrapAzError(err, `abandon PR #${prNumber}`);\n }\n }\n\n async submitPRReview(_repoSlug: string, prNumber: number, opts: SubmitReviewOptions): Promise<void> {\n const verdictPrefix =\n opts.event === \"approve\" ? \"✅ APPROVED\" :\n opts.event === \"request_changes\" ? \"🔴 CHANGES REQUESTED\" : \"💬 REVIEW\";\n\n try {\n // Post the summary as a PR thread\n await this.http.post(\n `/git/repositories/${this.repoName}/pullrequests/${prNumber}/threads`,\n {\n comments: [{ parentCommentId: 0, content: `${verdictPrefix}\\n\\n${opts.body}`, commentType: 1 }],\n status: 1,\n },\n { params: this.apiParams() }\n );\n\n // Post inline comments as file-level threads\n for (const c of opts.comments ?? []) {\n await this.http.post(\n `/git/repositories/${this.repoName}/pullrequests/${prNumber}/threads`,\n {\n comments: [{ parentCommentId: 0, content: c.body, commentType: 1 }],\n threadContext: {\n filePath: `/${c.path}`,\n rightFileStart: { line: c.line, offset: 1 },\n rightFileEnd: { line: c.line, offset: 120 },\n },\n status: 1,\n },\n { params: this.apiParams() }\n ).catch(() => {});\n }\n } catch (err) {\n throw wrapAzError(err, `submit review on PR #${prNumber}`);\n }\n }\n\n async replyToComment(_repoSlug: string, prNumber: number, commentId: number, body: string): Promise<void> {\n try {\n // Azure DevOps: add a comment to an existing thread\n // We don't have the threadId stored separately, so post a new general comment\n const replyBody = `*(in reply to comment #${commentId})*\\n\\n${body}`;\n await this.http.post(\n `/git/repositories/${this.repoName}/pullRequests/${prNumber}/threads`,\n {\n comments: [{ parentCommentId: 0, content: replyBody, commentType: 1 }],\n status: 4, // Fixed\n },\n { params: this.apiParams() }\n );\n } catch (err) {\n throw wrapAzError(err, `reply to comment #${commentId}`);\n }\n }\n\n async getDefaultBranch(_repoSlug: string): Promise<string> {\n try {\n const { data } = await this.http.get<AzRepo>(\n `/git/repositories/${this.repoName}`,\n { params: this.apiParams() }\n );\n return (data.defaultBranch ?? \"refs/heads/main\").replace(\"refs/heads/\", \"\");\n } catch (err) {\n throw wrapAzError(err, \"get default branch\");\n }\n }\n}\n\n// ─── Mappers ──────────────────────────────────────────────────────────────────\nfunction mapAzPr(d: AzPr): PullRequest {\n let state: \"open\" | \"closed\" | \"merged\";\n if (d.status === \"completed\") state = \"merged\";\n else if (d.status === \"active\") state = \"open\";\n else state = \"closed\";\n\n return {\n id: d.pullRequestId,\n number: d.pullRequestId,\n title: d.title,\n body: d.description ?? \"\",\n state,\n head: (d.sourceRefName ?? \"\").replace(\"refs/heads/\", \"\"),\n base: (d.targetRefName ?? \"\").replace(\"refs/heads/\", \"\"),\n url: d.url ?? \"\",\n author: d.createdBy?.displayName ?? \"unknown\",\n createdAt: d.creationDate ?? \"\",\n updatedAt: d.lastMergeSourceCommit?.author?.date ?? d.creationDate ?? \"\",\n };\n}\n\nfunction wrapAzError(err: unknown, action: string): GitxError {\n if (isAxiosError(err)) {\n const status = err.response?.status;\n const msg = (err.response?.data as Record<string, string> | undefined)?.message ?? err.message;\n if (status === 401 || status === 203) {\n return new GitxError(\n `Azure DevOps authentication failed while trying to ${action}.\\n` +\n ` If using PAT: run \\`gitx config set azure\\` to update your token.\\n` +\n ` If using GCM: run \\`git pull\\` in your repo to trigger a fresh login.`,\n { exitCode: 1, cause: err }\n );\n }\n if (status === 404) {\n return new GitxError(\n `Azure DevOps resource not found while trying to ${action}. Verify org/project/repo slug and token scopes.`,\n { exitCode: 1, cause: err }\n );\n }\n return new GitxError(\n `Azure DevOps API error (${status ?? \"network\"}) while trying to ${action}: ${msg}`,\n { exitCode: 1, cause: err }\n );\n }\n return new GitxError(`Unexpected error while trying to ${action}: ${String(err)}`, {\n exitCode: 1,\n cause: err,\n });\n}\n"]}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export interface PullRequest {
|
|
2
|
+
id: number;
|
|
3
|
+
/** Human-facing PR / MR number (used in URLs) */
|
|
4
|
+
number: number;
|
|
5
|
+
title: string;
|
|
6
|
+
body: string;
|
|
7
|
+
state: "open" | "closed" | "merged";
|
|
8
|
+
/** Source branch */
|
|
9
|
+
head: string;
|
|
10
|
+
/** Target / base branch */
|
|
11
|
+
base: string;
|
|
12
|
+
url: string;
|
|
13
|
+
author: string;
|
|
14
|
+
createdAt: string;
|
|
15
|
+
updatedAt: string;
|
|
16
|
+
}
|
|
17
|
+
export interface PullRequestComment {
|
|
18
|
+
id: number;
|
|
19
|
+
body: string;
|
|
20
|
+
author: string;
|
|
21
|
+
/** File path if the comment is on a specific file */
|
|
22
|
+
path?: string;
|
|
23
|
+
/** Line number if the comment is on a specific line */
|
|
24
|
+
line?: number;
|
|
25
|
+
/**
|
|
26
|
+
* If this comment is a reply in a thread, the ID of the parent comment.
|
|
27
|
+
* Undefined for root / top-level comments.
|
|
28
|
+
*/
|
|
29
|
+
inReplyToId?: number;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
}
|
|
32
|
+
export interface CreatePrOptions {
|
|
33
|
+
title: string;
|
|
34
|
+
body: string;
|
|
35
|
+
/** Source branch name */
|
|
36
|
+
head: string;
|
|
37
|
+
/** Target branch name */
|
|
38
|
+
base: string;
|
|
39
|
+
draft?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** A single inline review comment tied to a specific file + line. */
|
|
42
|
+
export interface ReviewComment {
|
|
43
|
+
/** Relative file path */
|
|
44
|
+
path: string;
|
|
45
|
+
/** Line number in the NEW version of the file (right side) */
|
|
46
|
+
line: number;
|
|
47
|
+
/** Markdown comment body */
|
|
48
|
+
body: string;
|
|
49
|
+
}
|
|
50
|
+
/** Options for submitting a formal PR review (with optional inline comments). */
|
|
51
|
+
export interface SubmitReviewOptions {
|
|
52
|
+
/** Overall review body (markdown) */
|
|
53
|
+
body: string;
|
|
54
|
+
/** Review verdict */
|
|
55
|
+
event: "approve" | "request_changes" | "comment";
|
|
56
|
+
/** Inline file+line comments to post */
|
|
57
|
+
comments?: ReviewComment[];
|
|
58
|
+
}
|
|
59
|
+
export interface MergePrOptions {
|
|
60
|
+
/** How to merge. Providers map this to their own enum. Default: "squash" */
|
|
61
|
+
method: "squash" | "merge" | "rebase";
|
|
62
|
+
/** Optional merge/squash commit title (falls back to PR title) */
|
|
63
|
+
commitTitle?: string;
|
|
64
|
+
/** Optional merge/squash commit message body */
|
|
65
|
+
commitMessage?: string;
|
|
66
|
+
/** Delete the source branch after a successful merge */
|
|
67
|
+
deleteSourceBranch?: boolean;
|
|
68
|
+
}
|
|
69
|
+
export interface GitProvider {
|
|
70
|
+
/** List open pull requests for the repo */
|
|
71
|
+
listPRs(repoSlug: string): Promise<PullRequest[]>;
|
|
72
|
+
/** Get a single pull request by its number */
|
|
73
|
+
getPR(repoSlug: string, prNumber: number): Promise<PullRequest>;
|
|
74
|
+
/** Create a new pull request */
|
|
75
|
+
createPR(repoSlug: string, opts: CreatePrOptions): Promise<PullRequest>;
|
|
76
|
+
/** Get review comments on a pull request */
|
|
77
|
+
getPRComments(repoSlug: string, prNumber: number): Promise<PullRequestComment[]>;
|
|
78
|
+
/** Post a comment on a pull request */
|
|
79
|
+
addPRComment(repoSlug: string, prNumber: number, body: string): Promise<void>;
|
|
80
|
+
/** Resolve the repo's default branch (e.g. "main", "master") */
|
|
81
|
+
getDefaultBranch(repoSlug: string): Promise<string>;
|
|
82
|
+
/** Get the unified diff of a pull request (all file changes) */
|
|
83
|
+
getPRDiff(repoSlug: string, prNumber: number): Promise<string>;
|
|
84
|
+
/**
|
|
85
|
+
* Close (or abandon on Azure) a pull request.
|
|
86
|
+
* GitHub/GitLab → closed; Azure DevOps → abandoned.
|
|
87
|
+
* PRs cannot be hard-deleted via any provider's public API.
|
|
88
|
+
*/
|
|
89
|
+
closePR(repoSlug: string, prNumber: number): Promise<void>;
|
|
90
|
+
/** Merge a pull request using the specified strategy. */
|
|
91
|
+
mergePR(repoSlug: string, prNumber: number, opts: MergePrOptions): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Submit a formal review (approve / request_changes / comment) with optional
|
|
94
|
+
* inline file-level comments. Falls back to a plain comment if the provider
|
|
95
|
+
* does not support formal reviews.
|
|
96
|
+
*/
|
|
97
|
+
submitPRReview(repoSlug: string, prNumber: number, opts: SubmitReviewOptions): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Reply to a specific review comment thread (to mark it as addressed).
|
|
100
|
+
* Falls back to a general PR comment if thread replies aren't supported.
|
|
101
|
+
*/
|
|
102
|
+
replyToComment(repoSlug: string, prNumber: number, commentId: number, body: string): Promise<void>;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/providers/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ─── Provider abstraction ────────────────────────────────────────────────────
|
|
2
|
+
// Every git-hosting provider (GitHub, GitLab, Azure DevOps) implements this
|
|
3
|
+
// interface so the rest of the codebase can remain provider-agnostic.
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/providers/base.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,4EAA4E;AAC5E,sEAAsE","sourcesContent":["// ─── Provider abstraction ────────────────────────────────────────────────────\n// Every git-hosting provider (GitHub, GitLab, Azure DevOps) implements this\n// interface so the rest of the codebase can remain provider-agnostic.\n\nexport interface PullRequest {\n id: number;\n /** Human-facing PR / MR number (used in URLs) */\n number: number;\n title: string;\n body: string;\n state: \"open\" | \"closed\" | \"merged\";\n /** Source branch */\n head: string;\n /** Target / base branch */\n base: string;\n url: string;\n author: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface PullRequestComment {\n id: number;\n body: string;\n author: string;\n /** File path if the comment is on a specific file */\n path?: string;\n /** Line number if the comment is on a specific line */\n line?: number;\n /**\n * If this comment is a reply in a thread, the ID of the parent comment.\n * Undefined for root / top-level comments.\n */\n inReplyToId?: number;\n createdAt: string;\n}\n\nexport interface CreatePrOptions {\n title: string;\n body: string;\n /** Source branch name */\n head: string;\n /** Target branch name */\n base: string;\n draft?: boolean;\n}\n\n/** A single inline review comment tied to a specific file + line. */\nexport interface ReviewComment {\n /** Relative file path */\n path: string;\n /** Line number in the NEW version of the file (right side) */\n line: number;\n /** Markdown comment body */\n body: string;\n}\n\n/** Options for submitting a formal PR review (with optional inline comments). */\nexport interface SubmitReviewOptions {\n /** Overall review body (markdown) */\n body: string;\n /** Review verdict */\n event: \"approve\" | \"request_changes\" | \"comment\";\n /** Inline file+line comments to post */\n comments?: ReviewComment[];\n}\n\nexport interface MergePrOptions {\n /** How to merge. Providers map this to their own enum. Default: \"squash\" */\n method: \"squash\" | \"merge\" | \"rebase\";\n /** Optional merge/squash commit title (falls back to PR title) */\n commitTitle?: string;\n /** Optional merge/squash commit message body */\n commitMessage?: string;\n /** Delete the source branch after a successful merge */\n deleteSourceBranch?: boolean;\n}\n\nexport interface GitProvider {\n /** List open pull requests for the repo */\n listPRs(repoSlug: string): Promise<PullRequest[]>;\n\n /** Get a single pull request by its number */\n getPR(repoSlug: string, prNumber: number): Promise<PullRequest>;\n\n /** Create a new pull request */\n createPR(repoSlug: string, opts: CreatePrOptions): Promise<PullRequest>;\n\n /** Get review comments on a pull request */\n getPRComments(repoSlug: string, prNumber: number): Promise<PullRequestComment[]>;\n\n /** Post a comment on a pull request */\n addPRComment(repoSlug: string, prNumber: number, body: string): Promise<void>;\n\n /** Resolve the repo's default branch (e.g. \"main\", \"master\") */\n getDefaultBranch(repoSlug: string): Promise<string>;\n\n /** Get the unified diff of a pull request (all file changes) */\n getPRDiff(repoSlug: string, prNumber: number): Promise<string>;\n\n /**\n * Close (or abandon on Azure) a pull request.\n * GitHub/GitLab → closed; Azure DevOps → abandoned.\n * PRs cannot be hard-deleted via any provider's public API.\n */\n closePR(repoSlug: string, prNumber: number): Promise<void>;\n\n /** Merge a pull request using the specified strategy. */\n mergePR(repoSlug: string, prNumber: number, opts: MergePrOptions): Promise<void>;\n\n /**\n * Submit a formal review (approve / request_changes / comment) with optional\n * inline file-level comments. Falls back to a plain comment if the provider\n * does not support formal reviews.\n */\n submitPRReview(repoSlug: string, prNumber: number, opts: SubmitReviewOptions): Promise<void>;\n\n /**\n * Reply to a specific review comment thread (to mark it as addressed).\n * Falls back to a general PR comment if thread replies aren't supported.\n */\n replyToComment(repoSlug: string, prNumber: number, commentId: number, body: string): Promise<void>;\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RepoContext } from "../core/context.js";
|
|
2
|
+
import type { GitProvider } from "./base.js";
|
|
3
|
+
/**
|
|
4
|
+
* Instantiate the correct {@link GitProvider} for the given repo context.
|
|
5
|
+
* The provider reads the token from `ctx.token` and the slug from `ctx.repoSlug`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createProvider(ctx: RepoContext): GitProvider;
|
|
8
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAM7C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW,CAe5D"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { GitHubProvider } from "./github.js";
|
|
2
|
+
import { GitLabProvider } from "./gitlab.js";
|
|
3
|
+
import { AzureProvider } from "./azure.js";
|
|
4
|
+
import { GitxError } from "../utils/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Instantiate the correct {@link GitProvider} for the given repo context.
|
|
7
|
+
* The provider reads the token from `ctx.token` and the slug from `ctx.repoSlug`.
|
|
8
|
+
*/
|
|
9
|
+
export function createProvider(ctx) {
|
|
10
|
+
switch (ctx.provider) {
|
|
11
|
+
case "github":
|
|
12
|
+
return new GitHubProvider(ctx.token);
|
|
13
|
+
case "gitlab":
|
|
14
|
+
return new GitLabProvider(ctx.token);
|
|
15
|
+
case "azure":
|
|
16
|
+
// Azure needs org/project/repo parsed from the slug.
|
|
17
|
+
// tokenType distinguishes PAT (Basic auth) from GCM OAuth (Bearer auth).
|
|
18
|
+
return new AzureProvider(ctx.token, ctx.repoSlug, ctx.tokenType ?? "pat");
|
|
19
|
+
default: {
|
|
20
|
+
const p = ctx.provider;
|
|
21
|
+
throw new GitxError(`Unsupported provider: ${String(p)}`, { exitCode: 2 });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,GAAgB;IAC7C,QAAQ,GAAG,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK,OAAO;YACV,qDAAqD;YACrD,yEAAyE;YACzE,OAAO,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;QAC5E,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,CAAC,GAAU,GAAG,CAAC,QAAQ,CAAC;YAC9B,MAAM,IAAI,SAAS,CAAC,yBAAyB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import type { RepoContext } from \"../core/context.js\";\nimport type { GitProvider } from \"./base.js\";\nimport { GitHubProvider } from \"./github.js\";\nimport { GitLabProvider } from \"./gitlab.js\";\nimport { AzureProvider } from \"./azure.js\";\nimport { GitxError } from \"../utils/errors.js\";\n\n/**\n * Instantiate the correct {@link GitProvider} for the given repo context.\n * The provider reads the token from `ctx.token` and the slug from `ctx.repoSlug`.\n */\nexport function createProvider(ctx: RepoContext): GitProvider {\n switch (ctx.provider) {\n case \"github\":\n return new GitHubProvider(ctx.token);\n case \"gitlab\":\n return new GitLabProvider(ctx.token);\n case \"azure\":\n // Azure needs org/project/repo parsed from the slug.\n // tokenType distinguishes PAT (Basic auth) from GCM OAuth (Bearer auth).\n return new AzureProvider(ctx.token, ctx.repoSlug, ctx.tokenType ?? \"pat\");\n default: {\n const p: never = ctx.provider;\n throw new GitxError(`Unsupported provider: ${String(p)}`, { exitCode: 2 });\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CreatePrOptions, GitProvider, MergePrOptions, PullRequest, PullRequestComment, SubmitReviewOptions } from "./base.js";
|
|
2
|
+
export declare class GitHubProvider implements GitProvider {
|
|
3
|
+
private readonly http;
|
|
4
|
+
constructor(token: string);
|
|
5
|
+
listPRs(repoSlug: string): Promise<PullRequest[]>;
|
|
6
|
+
getPR(repoSlug: string, prNumber: number): Promise<PullRequest>;
|
|
7
|
+
createPR(repoSlug: string, opts: CreatePrOptions): Promise<PullRequest>;
|
|
8
|
+
getPRComments(repoSlug: string, prNumber: number): Promise<PullRequestComment[]>;
|
|
9
|
+
addPRComment(repoSlug: string, prNumber: number, body: string): Promise<void>;
|
|
10
|
+
/** Find an existing open PR for head→base, returns undefined if none. */
|
|
11
|
+
findExistingPR(repoSlug: string, head: string, base: string): Promise<PullRequest | undefined>;
|
|
12
|
+
getPRDiff(repoSlug: string, prNumber: number): Promise<string>;
|
|
13
|
+
mergePR(repoSlug: string, prNumber: number, opts: MergePrOptions): Promise<void>;
|
|
14
|
+
closePR(repoSlug: string, prNumber: number): Promise<void>;
|
|
15
|
+
submitPRReview(repoSlug: string, prNumber: number, opts: SubmitReviewOptions): Promise<void>;
|
|
16
|
+
replyToComment(repoSlug: string, prNumber: number, commentId: number, body: string): Promise<void>;
|
|
17
|
+
getDefaultBranch(repoSlug: string): Promise<string>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,cAAc,EACd,WAAW,EACX,kBAAkB,EAElB,mBAAmB,EACpB,MAAM,WAAW,CAAC;AAkCnB,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;gBAEzB,KAAK,EAAE,MAAM;IAYnB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAWjD,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAS/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAevE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAuChF,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnF,yEAAyE;IACnE,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAc7B,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAe9D,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYhF,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1D,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoE5F,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAclG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAQ1D"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import axios, { isAxiosError } from "axios";
|
|
2
|
+
import { withRetry } from "../utils/retry.js";
|
|
3
|
+
import { GitxError } from "../utils/errors.js";
|
|
4
|
+
// ─── GitHub Provider ──────────────────────────────────────────────────────────
|
|
5
|
+
export class GitHubProvider {
|
|
6
|
+
http;
|
|
7
|
+
constructor(token) {
|
|
8
|
+
this.http = axios.create({
|
|
9
|
+
baseURL: "https://api.github.com",
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `Bearer ${token}`,
|
|
12
|
+
Accept: "application/vnd.github+json",
|
|
13
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
14
|
+
},
|
|
15
|
+
timeout: 20_000,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async listPRs(repoSlug) {
|
|
19
|
+
try {
|
|
20
|
+
const { data } = await withRetry(() => this.http.get(`/repos/${repoSlug}/pulls`, {
|
|
21
|
+
params: { state: "open", per_page: 50 },
|
|
22
|
+
}));
|
|
23
|
+
return data.map(mapGhPr);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
throw wrapGhError(err, "list PRs");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async getPR(repoSlug, prNumber) {
|
|
30
|
+
try {
|
|
31
|
+
const { data } = await withRetry(() => this.http.get(`/repos/${repoSlug}/pulls/${prNumber}`));
|
|
32
|
+
return mapGhPr(data);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
throw wrapGhError(err, `get PR #${prNumber}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async createPR(repoSlug, opts) {
|
|
39
|
+
try {
|
|
40
|
+
const { data } = await this.http.post(`/repos/${repoSlug}/pulls`, {
|
|
41
|
+
title: opts.title,
|
|
42
|
+
body: opts.body,
|
|
43
|
+
head: opts.head,
|
|
44
|
+
base: opts.base,
|
|
45
|
+
draft: opts.draft ?? false,
|
|
46
|
+
});
|
|
47
|
+
return mapGhPr(data);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
throw wrapGhError(err, "create PR");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async getPRComments(repoSlug, prNumber) {
|
|
54
|
+
try {
|
|
55
|
+
// Fetch both review comments (on code) and issue comments (general)
|
|
56
|
+
const [reviewRes, issueRes] = await Promise.all([
|
|
57
|
+
this.http.get(`/repos/${repoSlug}/pulls/${prNumber}/comments`, {
|
|
58
|
+
params: { per_page: 100 },
|
|
59
|
+
}),
|
|
60
|
+
this.http.get(`/repos/${repoSlug}/issues/${prNumber}/comments`, {
|
|
61
|
+
params: { per_page: 100 },
|
|
62
|
+
}),
|
|
63
|
+
]);
|
|
64
|
+
// Map review comments normally (they already carry path + line)
|
|
65
|
+
const reviewComments = reviewRes.data.map(mapGhComment);
|
|
66
|
+
// For issue comments, reconstruct path + line from gitx's fallback format:
|
|
67
|
+
// 📍 **`path/to/file.ts:42`**\n\nactual comment body
|
|
68
|
+
// These are posted when GitHub rejects inline review comments with 422.
|
|
69
|
+
const issueComments = issueRes.data.map((c) => {
|
|
70
|
+
const mapped = mapGhComment(c);
|
|
71
|
+
if (!mapped.path) {
|
|
72
|
+
const m = c.body.match(/^📍 \*\*`([^:`]+):(\d+)`\*\*\n\n([\s\S]+)$/);
|
|
73
|
+
if (m) {
|
|
74
|
+
mapped.path = m[1];
|
|
75
|
+
mapped.line = parseInt(m[2], 10);
|
|
76
|
+
// Expose the real comment body (without the 📍 header) so the AI
|
|
77
|
+
// gets clean text to work with, not the path:line decoration.
|
|
78
|
+
mapped.body = m[3].trim();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return mapped;
|
|
82
|
+
});
|
|
83
|
+
return [...reviewComments, ...issueComments];
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
throw wrapGhError(err, `get PR #${prNumber} comments`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async addPRComment(repoSlug, prNumber, body) {
|
|
90
|
+
try {
|
|
91
|
+
await this.http.post(`/repos/${repoSlug}/issues/${prNumber}/comments`, { body });
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
throw wrapGhError(err, `comment on PR #${prNumber}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Find an existing open PR for head→base, returns undefined if none. */
|
|
98
|
+
async findExistingPR(repoSlug, head, base) {
|
|
99
|
+
try {
|
|
100
|
+
const { data } = await withRetry(() => this.http.get(`/repos/${repoSlug}/pulls`, {
|
|
101
|
+
params: { state: "open", head: `${repoSlug.split("/")[0]}:${head}`, base, per_page: 5 },
|
|
102
|
+
}));
|
|
103
|
+
return data.length > 0 ? mapGhPr(data[0]) : undefined;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async getPRDiff(repoSlug, prNumber) {
|
|
110
|
+
try {
|
|
111
|
+
const { data } = await withRetry(() => this.http.get(`/repos/${repoSlug}/pulls/${prNumber}`, {
|
|
112
|
+
headers: { Accept: "application/vnd.github.diff" },
|
|
113
|
+
responseType: "text",
|
|
114
|
+
}));
|
|
115
|
+
return typeof data === "string" ? data : "";
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
// Non-fatal — review can proceed without diff
|
|
119
|
+
return "";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async mergePR(repoSlug, prNumber, opts) {
|
|
123
|
+
try {
|
|
124
|
+
await this.http.put(`/repos/${repoSlug}/pulls/${prNumber}/merge`, {
|
|
125
|
+
merge_method: opts.method, // "squash" | "merge" | "rebase"
|
|
126
|
+
commit_title: opts.commitTitle,
|
|
127
|
+
commit_message: opts.commitMessage ?? "",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
throw wrapGhError(err, `merge PR #${prNumber}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async closePR(repoSlug, prNumber) {
|
|
135
|
+
try {
|
|
136
|
+
await this.http.patch(`/repos/${repoSlug}/pulls/${prNumber}`, { state: "closed" });
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
throw wrapGhError(err, `close PR #${prNumber}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async submitPRReview(repoSlug, prNumber, opts) {
|
|
143
|
+
const eventMap = {
|
|
144
|
+
approve: "APPROVE",
|
|
145
|
+
request_changes: "REQUEST_CHANGES",
|
|
146
|
+
comment: "COMMENT",
|
|
147
|
+
};
|
|
148
|
+
const ghComments = (opts.comments ?? [])
|
|
149
|
+
.filter((c) => c.line > 0)
|
|
150
|
+
.map((c) => ({
|
|
151
|
+
path: c.path,
|
|
152
|
+
line: c.line,
|
|
153
|
+
side: "RIGHT",
|
|
154
|
+
body: c.body,
|
|
155
|
+
}));
|
|
156
|
+
// ── Attempt 1: formal review with all inline comments ─────────────────
|
|
157
|
+
// GitHub only accepts inline comments on lines that actually appear in
|
|
158
|
+
// the diff (changed lines + context lines within hunks). If any comment
|
|
159
|
+
// references a line outside the diff, GitHub rejects the entire request
|
|
160
|
+
// with 422 "Line could not be resolved".
|
|
161
|
+
if (ghComments.length > 0) {
|
|
162
|
+
try {
|
|
163
|
+
await this.http.post(`/repos/${repoSlug}/pulls/${prNumber}/reviews`, {
|
|
164
|
+
body: opts.body,
|
|
165
|
+
event: eventMap[opts.event],
|
|
166
|
+
comments: ghComments,
|
|
167
|
+
});
|
|
168
|
+
return; // success — all inline comments accepted
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
if (!isAxiosError(err) || err.response?.status !== 422) {
|
|
172
|
+
throw wrapGhError(err, `submit review on PR #${prNumber}`);
|
|
173
|
+
}
|
|
174
|
+
// 422 → some inline comments are on lines outside the diff.
|
|
175
|
+
// Fall through to attempt 2.
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// ── Attempt 2: formal review without inline comments ──────────────────
|
|
179
|
+
// Posts the verdict (APPROVE / REQUEST_CHANGES / COMMENT) and summary
|
|
180
|
+
// body as a proper review, then posts each inline comment as a separate
|
|
181
|
+
// plain PR comment so the text is never lost.
|
|
182
|
+
try {
|
|
183
|
+
await this.http.post(`/repos/${repoSlug}/pulls/${prNumber}/reviews`, {
|
|
184
|
+
body: opts.body,
|
|
185
|
+
event: eventMap[opts.event],
|
|
186
|
+
// Omit `comments` entirely — avoid sending an empty array which
|
|
187
|
+
// can also trigger a 422 on some GitHub versions.
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// ── Attempt 3: plain issue comment (last resort) ───────────────────
|
|
192
|
+
// If even a comment-free review fails (permissions, draft PR, etc.),
|
|
193
|
+
// fall back to a regular PR comment so the review text still lands.
|
|
194
|
+
await this.http.post(`/repos/${repoSlug}/issues/${prNumber}/comments`, {
|
|
195
|
+
body: opts.body,
|
|
196
|
+
}).catch((e) => {
|
|
197
|
+
throw wrapGhError(e, `submit review on PR #${prNumber}`);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// Post each inline comment as a plain PR comment with file:line prefix
|
|
201
|
+
for (const c of ghComments) {
|
|
202
|
+
const body = `📍 **\`${c.path}:${c.line}\`**\n\n${c.body}`;
|
|
203
|
+
await this.http.post(`/repos/${repoSlug}/issues/${prNumber}/comments`, { body })
|
|
204
|
+
.catch(() => { }); // best-effort — don't abort if one comment fails
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async replyToComment(repoSlug, prNumber, commentId, body) {
|
|
208
|
+
try {
|
|
209
|
+
// GitHub REST: reply directly to a pull request review comment thread
|
|
210
|
+
await this.http.post(`/repos/${repoSlug}/pulls/${prNumber}/comments/${commentId}/replies`, { body });
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Fallback: post as a plain issue comment if the thread reply fails
|
|
214
|
+
await this.http.post(`/repos/${repoSlug}/issues/${prNumber}/comments`, { body })
|
|
215
|
+
.catch((e) => { throw wrapGhError(e, `reply to comment #${commentId}`); });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async getDefaultBranch(repoSlug) {
|
|
219
|
+
try {
|
|
220
|
+
const { data } = await withRetry(() => this.http.get(`/repos/${repoSlug}`));
|
|
221
|
+
return data.default_branch ?? "main";
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
throw wrapGhError(err, "get default branch");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// ─── Mappers ──────────────────────────────────────────────────────────────────
|
|
229
|
+
function mapGhPr(d) {
|
|
230
|
+
return {
|
|
231
|
+
id: d.id,
|
|
232
|
+
number: d.number,
|
|
233
|
+
title: d.title,
|
|
234
|
+
body: d.body ?? "",
|
|
235
|
+
state: d.merged_at ? "merged" : (d.state === "open" ? "open" : "closed"),
|
|
236
|
+
head: d.head.ref,
|
|
237
|
+
base: d.base.ref,
|
|
238
|
+
url: d.html_url,
|
|
239
|
+
author: d.user?.login ?? "unknown",
|
|
240
|
+
createdAt: d.created_at,
|
|
241
|
+
updatedAt: d.updated_at,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function mapGhComment(c) {
|
|
245
|
+
return {
|
|
246
|
+
id: c.id,
|
|
247
|
+
body: c.body,
|
|
248
|
+
author: c.user?.login ?? "unknown",
|
|
249
|
+
path: c.path,
|
|
250
|
+
line: c.line,
|
|
251
|
+
inReplyToId: c.in_reply_to_id,
|
|
252
|
+
createdAt: c.created_at,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function wrapGhError(err, action) {
|
|
256
|
+
if (isAxiosError(err)) {
|
|
257
|
+
const status = err.response?.status;
|
|
258
|
+
const data = err.response?.data;
|
|
259
|
+
const msg = data?.message ?? err.message;
|
|
260
|
+
// Extract detailed validation errors from GitHub's response body
|
|
261
|
+
const errors = Array.isArray(data?.errors)
|
|
262
|
+
? data.errors
|
|
263
|
+
.map((e) => e.message ?? e.code ?? JSON.stringify(e))
|
|
264
|
+
.filter(Boolean)
|
|
265
|
+
.join("; ")
|
|
266
|
+
: undefined;
|
|
267
|
+
const detail = errors ? `${msg} — ${errors}` : msg;
|
|
268
|
+
if (status === 401 || status === 403) {
|
|
269
|
+
return new GitxError(`GitHub authentication failed while trying to ${action}. Check your token with \`gitx config set-provider github\`.`, { exitCode: 1, cause: err });
|
|
270
|
+
}
|
|
271
|
+
if (status === 404) {
|
|
272
|
+
return new GitxError(`GitHub resource not found while trying to ${action}. Verify the repo slug and that your token has the right scopes.`, { exitCode: 1, cause: err });
|
|
273
|
+
}
|
|
274
|
+
if (status === 422) {
|
|
275
|
+
return new GitxError(`GitHub rejected the request while trying to ${action}: ${detail}\n` +
|
|
276
|
+
` Common causes:\n` +
|
|
277
|
+
` • Head branch not pushed to remote yet → run: git push -u origin HEAD\n` +
|
|
278
|
+
` • A PR for this branch already exists\n` +
|
|
279
|
+
` • No commits between head and base branch`, { exitCode: 1, cause: err });
|
|
280
|
+
}
|
|
281
|
+
return new GitxError(`GitHub API error (${status ?? "network"}) while trying to ${action}: ${detail}`, {
|
|
282
|
+
exitCode: 1,
|
|
283
|
+
cause: err,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return new GitxError(`Unexpected error while trying to ${action}: ${String(err)}`, {
|
|
287
|
+
exitCode: 1,
|
|
288
|
+
cause: err,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"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","sourcesContent":["import axios, { type AxiosInstance, isAxiosError } from \"axios\";\nimport { withRetry } from \"../utils/retry.js\";\nimport { GitxError } from \"../utils/errors.js\";\nimport type {\n CreatePrOptions,\n GitProvider,\n MergePrOptions,\n PullRequest,\n PullRequestComment,\n ReviewComment,\n SubmitReviewOptions,\n} from \"./base.js\";\n\n// ─── Raw GitHub API shapes ────────────────────────────────────────────────────\ninterface GhPr {\n id: number;\n number: number;\n title: string;\n body: string | null;\n state: string;\n merged_at: string | null;\n head: { ref: string };\n base: { ref: string };\n html_url: string;\n user: { login: string } | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface GhComment {\n id: number;\n body: string;\n user: { login: string } | null;\n path?: string;\n line?: number;\n /** Present on review comment replies — the ID of the comment being replied to */\n in_reply_to_id?: number;\n created_at: string;\n}\n\ninterface GhRepo {\n default_branch: string;\n}\n\n// ─── GitHub Provider ──────────────────────────────────────────────────────────\nexport class GitHubProvider implements GitProvider {\n private readonly http: AxiosInstance;\n\n constructor(token: string) {\n this.http = axios.create({\n baseURL: \"https://api.github.com\",\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n },\n timeout: 20_000,\n });\n }\n\n async listPRs(repoSlug: string): Promise<PullRequest[]> {\n try {\n const { data } = await withRetry(() => this.http.get<GhPr[]>(`/repos/${repoSlug}/pulls`, {\n params: { state: \"open\", per_page: 50 },\n }));\n return data.map(mapGhPr);\n } catch (err) {\n throw wrapGhError(err, \"list PRs\");\n }\n }\n\n async getPR(repoSlug: string, prNumber: number): Promise<PullRequest> {\n try {\n const { data } = await withRetry(() => this.http.get<GhPr>(`/repos/${repoSlug}/pulls/${prNumber}`));\n return mapGhPr(data);\n } catch (err) {\n throw wrapGhError(err, `get PR #${prNumber}`);\n }\n }\n\n async createPR(repoSlug: string, opts: CreatePrOptions): Promise<PullRequest> {\n try {\n const { data } = await this.http.post<GhPr>(`/repos/${repoSlug}/pulls`, {\n title: opts.title,\n body: opts.body,\n head: opts.head,\n base: opts.base,\n draft: opts.draft ?? false,\n });\n return mapGhPr(data);\n } catch (err) {\n throw wrapGhError(err, \"create PR\");\n }\n }\n\n async getPRComments(repoSlug: string, prNumber: number): Promise<PullRequestComment[]> {\n try {\n // Fetch both review comments (on code) and issue comments (general)\n const [reviewRes, issueRes] = await Promise.all([\n this.http.get<GhComment[]>(`/repos/${repoSlug}/pulls/${prNumber}/comments`, {\n params: { per_page: 100 },\n }),\n this.http.get<GhComment[]>(`/repos/${repoSlug}/issues/${prNumber}/comments`, {\n params: { per_page: 100 },\n }),\n ]);\n\n // Map review comments normally (they already carry path + line)\n const reviewComments = reviewRes.data.map(mapGhComment);\n\n // For issue comments, reconstruct path + line from gitx's fallback format:\n // 📍 **`path/to/file.ts:42`**\\n\\nactual comment body\n // These are posted when GitHub rejects inline review comments with 422.\n const issueComments = issueRes.data.map((c) => {\n const mapped = mapGhComment(c);\n if (!mapped.path) {\n const m = c.body.match(/^📍 \\*\\*`([^:`]+):(\\d+)`\\*\\*\\n\\n([\\s\\S]+)$/);\n if (m) {\n mapped.path = m[1]!;\n mapped.line = parseInt(m[2]!, 10);\n // Expose the real comment body (without the 📍 header) so the AI\n // gets clean text to work with, not the path:line decoration.\n mapped.body = m[3]!.trim();\n }\n }\n return mapped;\n });\n\n return [...reviewComments, ...issueComments];\n } catch (err) {\n throw wrapGhError(err, `get PR #${prNumber} comments`);\n }\n }\n\n async addPRComment(repoSlug: string, prNumber: number, body: string): Promise<void> {\n try {\n await this.http.post(`/repos/${repoSlug}/issues/${prNumber}/comments`, { body });\n } catch (err) {\n throw wrapGhError(err, `comment on PR #${prNumber}`);\n }\n }\n\n /** Find an existing open PR for head→base, returns undefined if none. */\n async findExistingPR(\n repoSlug: string,\n head: string,\n base: string\n ): Promise<PullRequest | undefined> {\n try {\n const { data } = await withRetry(() =>\n this.http.get<GhPr[]>(`/repos/${repoSlug}/pulls`, {\n params: { state: \"open\", head: `${repoSlug.split(\"/\")[0]}:${head}`, base, per_page: 5 },\n })\n );\n return data.length > 0 ? mapGhPr(data[0]!) : undefined;\n } catch {\n return undefined;\n }\n }\n\n\n async getPRDiff(repoSlug: string, prNumber: number): Promise<string> {\n try {\n const { data } = await withRetry(() =>\n this.http.get<string>(`/repos/${repoSlug}/pulls/${prNumber}`, {\n headers: { Accept: \"application/vnd.github.diff\" },\n responseType: \"text\",\n })\n );\n return typeof data === \"string\" ? data : \"\";\n } catch (err) {\n // Non-fatal — review can proceed without diff\n return \"\";\n }\n }\n\n async mergePR(repoSlug: string, prNumber: number, opts: MergePrOptions): Promise<void> {\n try {\n await this.http.put(`/repos/${repoSlug}/pulls/${prNumber}/merge`, {\n merge_method: opts.method, // \"squash\" | \"merge\" | \"rebase\"\n commit_title: opts.commitTitle,\n commit_message: opts.commitMessage ?? \"\",\n });\n } catch (err) {\n throw wrapGhError(err, `merge PR #${prNumber}`);\n }\n }\n\n async closePR(repoSlug: string, prNumber: number): Promise<void> {\n try {\n await this.http.patch(`/repos/${repoSlug}/pulls/${prNumber}`, { state: \"closed\" });\n } catch (err) {\n throw wrapGhError(err, `close PR #${prNumber}`);\n }\n }\n\n async submitPRReview(repoSlug: string, prNumber: number, opts: SubmitReviewOptions): Promise<void> {\n const eventMap: Record<SubmitReviewOptions[\"event\"], string> = {\n approve: \"APPROVE\",\n request_changes: \"REQUEST_CHANGES\",\n comment: \"COMMENT\",\n };\n\n const ghComments = (opts.comments ?? [])\n .filter((c) => c.line > 0)\n .map((c: ReviewComment) => ({\n path: c.path,\n line: c.line,\n side: \"RIGHT\" as const,\n body: c.body,\n }));\n\n // ── Attempt 1: formal review with all inline comments ─────────────────\n // GitHub only accepts inline comments on lines that actually appear in\n // the diff (changed lines + context lines within hunks). If any comment\n // references a line outside the diff, GitHub rejects the entire request\n // with 422 \"Line could not be resolved\".\n if (ghComments.length > 0) {\n try {\n await this.http.post(`/repos/${repoSlug}/pulls/${prNumber}/reviews`, {\n body: opts.body,\n event: eventMap[opts.event],\n comments: ghComments,\n });\n return; // success — all inline comments accepted\n } catch (err) {\n if (!isAxiosError(err) || err.response?.status !== 422) {\n throw wrapGhError(err, `submit review on PR #${prNumber}`);\n }\n // 422 → some inline comments are on lines outside the diff.\n // Fall through to attempt 2.\n }\n }\n\n // ── Attempt 2: formal review without inline comments ──────────────────\n // Posts the verdict (APPROVE / REQUEST_CHANGES / COMMENT) and summary\n // body as a proper review, then posts each inline comment as a separate\n // plain PR comment so the text is never lost.\n try {\n await this.http.post(`/repos/${repoSlug}/pulls/${prNumber}/reviews`, {\n body: opts.body,\n event: eventMap[opts.event],\n // Omit `comments` entirely — avoid sending an empty array which\n // can also trigger a 422 on some GitHub versions.\n });\n } catch {\n // ── Attempt 3: plain issue comment (last resort) ───────────────────\n // If even a comment-free review fails (permissions, draft PR, etc.),\n // fall back to a regular PR comment so the review text still lands.\n await this.http.post(`/repos/${repoSlug}/issues/${prNumber}/comments`, {\n body: opts.body,\n }).catch((e: unknown) => {\n throw wrapGhError(e, `submit review on PR #${prNumber}`);\n });\n }\n\n // Post each inline comment as a plain PR comment with file:line prefix\n for (const c of ghComments) {\n const body = `📍 **\\`${c.path}:${c.line}\\`**\\n\\n${c.body}`;\n await this.http.post(`/repos/${repoSlug}/issues/${prNumber}/comments`, { body })\n .catch(() => {}); // best-effort — don't abort if one comment fails\n }\n }\n\n async replyToComment(repoSlug: string, prNumber: number, commentId: number, body: string): Promise<void> {\n try {\n // GitHub REST: reply directly to a pull request review comment thread\n await this.http.post(\n `/repos/${repoSlug}/pulls/${prNumber}/comments/${commentId}/replies`,\n { body }\n );\n } catch {\n // Fallback: post as a plain issue comment if the thread reply fails\n await this.http.post(`/repos/${repoSlug}/issues/${prNumber}/comments`, { body })\n .catch((e: unknown) => { throw wrapGhError(e, `reply to comment #${commentId}`); });\n }\n }\n\n async getDefaultBranch(repoSlug: string): Promise<string> {\n try {\n const { data } = await withRetry(() => this.http.get<GhRepo>(`/repos/${repoSlug}`));\n return data.default_branch ?? \"main\";\n } catch (err) {\n throw wrapGhError(err, \"get default branch\");\n }\n }\n}\n\n// ─── Mappers ──────────────────────────────────────────────────────────────────\nfunction mapGhPr(d: GhPr): PullRequest {\n return {\n id: d.id,\n number: d.number,\n title: d.title,\n body: d.body ?? \"\",\n state: d.merged_at ? \"merged\" : (d.state === \"open\" ? \"open\" : \"closed\"),\n head: d.head.ref,\n base: d.base.ref,\n url: d.html_url,\n author: d.user?.login ?? \"unknown\",\n createdAt: d.created_at,\n updatedAt: d.updated_at,\n };\n}\n\nfunction mapGhComment(c: GhComment): PullRequestComment {\n return {\n id: c.id,\n body: c.body,\n author: c.user?.login ?? \"unknown\",\n path: c.path,\n line: c.line,\n inReplyToId: c.in_reply_to_id,\n createdAt: c.created_at,\n };\n}\n\nfunction wrapGhError(err: unknown, action: string): GitxError {\n if (isAxiosError(err)) {\n const status = err.response?.status;\n const data = err.response?.data as Record<string, unknown> | undefined;\n const msg = (data?.message as string | undefined) ?? err.message;\n // Extract detailed validation errors from GitHub's response body\n const errors = Array.isArray(data?.errors)\n ? (data.errors as Array<Record<string, string>>)\n .map((e) => e.message ?? e.code ?? JSON.stringify(e))\n .filter(Boolean)\n .join(\"; \")\n : undefined;\n const detail = errors ? `${msg} — ${errors}` : msg;\n\n if (status === 401 || status === 403) {\n return new GitxError(\n `GitHub authentication failed while trying to ${action}. Check your token with \\`gitx config set-provider github\\`.`,\n { exitCode: 1, cause: err }\n );\n }\n if (status === 404) {\n return new GitxError(\n `GitHub resource not found while trying to ${action}. Verify the repo slug and that your token has the right scopes.`,\n { exitCode: 1, cause: err }\n );\n }\n if (status === 422) {\n return new GitxError(\n `GitHub rejected the request while trying to ${action}: ${detail}\\n` +\n ` Common causes:\\n` +\n ` • Head branch not pushed to remote yet → run: git push -u origin HEAD\\n` +\n ` • A PR for this branch already exists\\n` +\n ` • No commits between head and base branch`,\n { exitCode: 1, cause: err }\n );\n }\n return new GitxError(`GitHub API error (${status ?? \"network\"}) while trying to ${action}: ${detail}`, {\n exitCode: 1,\n cause: err,\n });\n }\n return new GitxError(`Unexpected error while trying to ${action}: ${String(err)}`, {\n exitCode: 1,\n cause: err,\n });\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CreatePrOptions, GitProvider, MergePrOptions, PullRequest, PullRequestComment, SubmitReviewOptions } from "./base.js";
|
|
2
|
+
export declare class GitLabProvider implements GitProvider {
|
|
3
|
+
private readonly http;
|
|
4
|
+
constructor(token: string);
|
|
5
|
+
/** GitLab requires URL-encoded namespace/project slugs */
|
|
6
|
+
private enc;
|
|
7
|
+
listPRs(repoSlug: string): Promise<PullRequest[]>;
|
|
8
|
+
getPR(repoSlug: string, prNumber: number): Promise<PullRequest>;
|
|
9
|
+
createPR(repoSlug: string, opts: CreatePrOptions): Promise<PullRequest>;
|
|
10
|
+
getPRComments(repoSlug: string, prNumber: number): Promise<PullRequestComment[]>;
|
|
11
|
+
addPRComment(repoSlug: string, prNumber: number, body: string): Promise<void>;
|
|
12
|
+
getPRDiff(repoSlug: string, prNumber: number): Promise<string>;
|
|
13
|
+
mergePR(repoSlug: string, prNumber: number, opts: MergePrOptions): Promise<void>;
|
|
14
|
+
closePR(repoSlug: string, prNumber: number): Promise<void>;
|
|
15
|
+
submitPRReview(repoSlug: string, prNumber: number, opts: SubmitReviewOptions): Promise<void>;
|
|
16
|
+
replyToComment(repoSlug: string, prNumber: number, commentId: number, body: string): Promise<void>;
|
|
17
|
+
getDefaultBranch(repoSlug: string): Promise<string>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=gitlab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../../src/providers/gitlab.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,cAAc,EACd,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,WAAW,CAAC;AA8BnB,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;gBAEzB,KAAK,EAAE,MAAM;IAWzB,0DAA0D;IAC1D,OAAO,CAAC,GAAG;IAIL,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAYjD,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAW/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAkBvE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAmBhF,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAW9D,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAehF,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1D,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B5F,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAalG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAU1D"}
|