@ipul-labs/forge 1.16.8 → 1.17.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/README.md +39 -21
- package/lib/bin/cli/analyze.d.ts +9 -0
- package/lib/bin/cli/analyze.d.ts.map +1 -0
- package/lib/bin/cli/analyze.js +491 -0
- package/lib/bin/cli/analyze.js.map +1 -0
- package/lib/bin/cli/apply.d.ts +2 -0
- package/lib/bin/cli/apply.d.ts.map +1 -0
- package/lib/bin/cli/apply.js +262 -0
- package/lib/bin/cli/apply.js.map +1 -0
- package/lib/bin/cli/cifix.d.ts +2 -0
- package/lib/bin/cli/cifix.d.ts.map +1 -0
- package/lib/bin/cli/cifix.js +310 -0
- package/lib/bin/cli/cifix.js.map +1 -0
- package/lib/bin/cli/close.d.ts +2 -0
- package/lib/bin/cli/close.d.ts.map +1 -0
- package/lib/bin/cli/close.js +113 -0
- package/lib/bin/cli/close.js.map +1 -0
- package/lib/bin/cli/createIssue.d.ts +2 -0
- package/lib/bin/cli/createIssue.d.ts.map +1 -0
- package/lib/bin/cli/createIssue.js +108 -0
- package/lib/bin/cli/createIssue.js.map +1 -0
- package/lib/bin/cli/doctor.d.ts +2 -0
- package/lib/bin/cli/doctor.d.ts.map +1 -0
- package/lib/bin/cli/doctor.js +145 -0
- package/lib/bin/cli/doctor.js.map +1 -0
- package/lib/bin/cli/init.d.ts +4 -0
- package/lib/bin/cli/init.d.ts.map +1 -0
- package/lib/bin/cli/init.js +288 -0
- package/lib/bin/cli/init.js.map +1 -0
- package/lib/bin/cli/ink.d.ts +23 -0
- package/lib/bin/cli/ink.d.ts.map +1 -0
- package/{bin → lib/bin}/cli/ink.js +18 -19
- package/lib/bin/cli/ink.js.map +1 -0
- package/lib/bin/cli/issue.d.ts +2 -0
- package/lib/bin/cli/issue.d.ts.map +1 -0
- package/lib/bin/cli/issue.js +114 -0
- package/lib/bin/cli/issue.js.map +1 -0
- package/lib/bin/cli/issues.d.ts +2 -0
- package/lib/bin/cli/issues.d.ts.map +1 -0
- package/lib/bin/cli/issues.js +149 -0
- package/lib/bin/cli/issues.js.map +1 -0
- package/lib/bin/cli/merge.d.ts +2 -0
- package/lib/bin/cli/merge.d.ts.map +1 -0
- package/lib/bin/cli/merge.js +162 -0
- package/lib/bin/cli/merge.js.map +1 -0
- package/lib/bin/cli/refine.d.ts +2 -0
- package/lib/bin/cli/refine.d.ts.map +1 -0
- package/lib/bin/cli/refine.js +249 -0
- package/lib/bin/cli/refine.js.map +1 -0
- package/lib/bin/cli/repl.d.ts +2 -0
- package/lib/bin/cli/repl.d.ts.map +1 -0
- package/lib/bin/cli/repl.js +309 -0
- package/lib/bin/cli/repl.js.map +1 -0
- package/lib/bin/cli/repos.d.ts +2 -0
- package/lib/bin/cli/repos.d.ts.map +1 -0
- package/lib/bin/cli/repos.js +86 -0
- package/lib/bin/cli/repos.js.map +1 -0
- package/lib/bin/cli/resolution.d.ts +2 -0
- package/lib/bin/cli/resolution.d.ts.map +1 -0
- package/lib/bin/cli/resolution.js +139 -0
- package/lib/bin/cli/resolution.js.map +1 -0
- package/lib/bin/cli/serverClient.d.ts +26 -0
- package/lib/bin/cli/serverClient.d.ts.map +1 -0
- package/lib/bin/cli/serverClient.js +111 -0
- package/lib/bin/cli/serverClient.js.map +1 -0
- package/lib/bin/cli/session.d.ts +8 -0
- package/lib/bin/cli/session.d.ts.map +1 -0
- package/lib/bin/cli/session.js +212 -0
- package/lib/bin/cli/session.js.map +1 -0
- package/lib/bin/cli/sessionStore.d.ts +69 -0
- package/lib/bin/cli/sessionStore.d.ts.map +1 -0
- package/lib/bin/cli/sessionStore.js +196 -0
- package/lib/bin/cli/sessionStore.js.map +1 -0
- package/lib/bin/cli/ship.d.ts +33 -0
- package/lib/bin/cli/ship.d.ts.map +1 -0
- package/lib/bin/cli/ship.js +737 -0
- package/lib/bin/cli/ship.js.map +1 -0
- package/lib/bin/cli/types.d.ts +59 -0
- package/lib/bin/cli/types.d.ts.map +1 -0
- package/lib/bin/cli/types.js +2 -0
- package/lib/bin/cli/types.js.map +1 -0
- package/lib/bin/cli/update.d.ts +2 -0
- package/lib/bin/cli/update.d.ts.map +1 -0
- package/lib/bin/cli/update.js +87 -0
- package/lib/bin/cli/update.js.map +1 -0
- package/lib/bin/cli/utils.d.ts +43 -0
- package/lib/bin/cli/utils.d.ts.map +1 -0
- package/lib/bin/cli/utils.js +171 -0
- package/lib/bin/cli/utils.js.map +1 -0
- package/lib/bin/cli/validate.d.ts +2 -0
- package/lib/bin/cli/validate.d.ts.map +1 -0
- package/lib/bin/cli/validate.js +283 -0
- package/lib/bin/cli/validate.js.map +1 -0
- package/lib/bin/cli/watch.d.ts +5 -0
- package/lib/bin/cli/watch.d.ts.map +1 -0
- package/lib/bin/cli/watch.js +263 -0
- package/lib/bin/cli/watch.js.map +1 -0
- package/lib/bin/forge-agent.d.ts +3 -0
- package/lib/bin/forge-agent.d.ts.map +1 -0
- package/{bin → lib/bin}/forge-agent.js +104 -105
- package/lib/bin/forge-agent.js.map +1 -0
- package/lib/server/forge/core/ForgeAgent.d.ts +260 -0
- package/lib/server/forge/core/ForgeAgent.d.ts.map +1 -0
- package/lib/server/forge/core/ForgeAgent.js +995 -0
- package/lib/server/forge/core/ForgeAgent.js.map +1 -0
- package/lib/server/forge/core/agentClient.d.ts +39 -0
- package/lib/server/forge/core/agentClient.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/agentClient.js +7 -12
- package/lib/server/forge/core/agentClient.js.map +1 -0
- package/lib/server/forge/core/branchName.d.ts +20 -0
- package/lib/server/forge/core/branchName.d.ts.map +1 -0
- package/lib/server/forge/core/branchName.js +39 -0
- package/lib/server/forge/core/branchName.js.map +1 -0
- package/lib/server/forge/core/claudeClient.d.ts +60 -0
- package/lib/server/forge/core/claudeClient.d.ts.map +1 -0
- package/lib/server/forge/core/claudeClient.js +347 -0
- package/lib/server/forge/core/claudeClient.js.map +1 -0
- package/lib/server/forge/core/configStore.d.ts +76 -0
- package/lib/server/forge/core/configStore.d.ts.map +1 -0
- package/lib/server/forge/core/configStore.js +213 -0
- package/lib/server/forge/core/configStore.js.map +1 -0
- package/lib/server/forge/core/gitlabClient.d.ts +144 -0
- package/lib/server/forge/core/gitlabClient.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/gitlabClient.js +98 -180
- package/lib/server/forge/core/gitlabClient.js.map +1 -0
- package/lib/server/forge/core/jobs.d.ts +67 -0
- package/lib/server/forge/core/jobs.d.ts.map +1 -0
- package/lib/server/forge/core/jobs.js +185 -0
- package/lib/server/forge/core/jobs.js.map +1 -0
- package/lib/server/forge/core/k8s.d.ts +18 -0
- package/lib/server/forge/core/k8s.d.ts.map +1 -0
- package/lib/server/forge/core/k8s.js +49 -0
- package/lib/server/forge/core/k8s.js.map +1 -0
- package/lib/server/forge/core/localRepo.d.ts +36 -0
- package/lib/server/forge/core/localRepo.d.ts.map +1 -0
- package/lib/server/forge/core/localRepo.js +165 -0
- package/lib/server/forge/core/localRepo.js.map +1 -0
- package/lib/server/forge/core/openclawClient.d.ts +61 -0
- package/lib/server/forge/core/openclawClient.d.ts.map +1 -0
- package/lib/server/forge/core/openclawClient.js +111 -0
- package/lib/server/forge/core/openclawClient.js.map +1 -0
- package/lib/server/forge/core/prompts.d.ts +96 -0
- package/lib/server/forge/core/prompts.d.ts.map +1 -0
- package/lib/server/forge/core/prompts.js +450 -0
- package/lib/server/forge/core/prompts.js.map +1 -0
- package/lib/server/forge/core/providers/azuredevops.d.ts +134 -0
- package/lib/server/forge/core/providers/azuredevops.d.ts.map +1 -0
- package/lib/server/forge/core/providers/azuredevops.js +360 -0
- package/lib/server/forge/core/providers/azuredevops.js.map +1 -0
- package/lib/server/forge/core/providers/base.d.ts +114 -0
- package/lib/server/forge/core/providers/base.d.ts.map +1 -0
- package/lib/server/forge/core/providers/base.js +98 -0
- package/lib/server/forge/core/providers/base.js.map +1 -0
- package/lib/server/forge/core/providers/github.d.ts +133 -0
- package/lib/server/forge/core/providers/github.d.ts.map +1 -0
- package/lib/server/forge/core/providers/github.js +307 -0
- package/lib/server/forge/core/providers/github.js.map +1 -0
- package/lib/server/forge/core/providers/gitlab.d.ts +144 -0
- package/lib/server/forge/core/providers/gitlab.d.ts.map +1 -0
- package/lib/server/forge/core/providers/gitlab.js +407 -0
- package/lib/server/forge/core/providers/gitlab.js.map +1 -0
- package/lib/server/forge/core/providers/index.d.ts +21 -0
- package/lib/server/forge/core/providers/index.d.ts.map +1 -0
- package/lib/server/forge/core/providers/index.js +43 -0
- package/lib/server/forge/core/providers/index.js.map +1 -0
- package/lib/server/forge/core/providers/types.d.ts +80 -0
- package/lib/server/forge/core/providers/types.d.ts.map +1 -0
- package/lib/server/forge/core/providers/types.js +2 -0
- package/lib/server/forge/core/providers/types.js.map +1 -0
- package/lib/server/forge/core/quotaClient.d.ts +48 -0
- package/lib/server/forge/core/quotaClient.d.ts.map +1 -0
- package/lib/server/forge/core/quotaClient.js +88 -0
- package/lib/server/forge/core/quotaClient.js.map +1 -0
- package/lib/server/forge/core/types.d.ts +160 -0
- package/lib/server/forge/core/types.d.ts.map +1 -0
- package/lib/server/forge/core/types.js +2 -0
- package/lib/server/forge/core/types.js.map +1 -0
- package/lib/server/forge/core/validator/attribute.d.ts +31 -0
- package/lib/server/forge/core/validator/attribute.d.ts.map +1 -0
- package/lib/server/forge/core/validator/attribute.js +82 -0
- package/lib/server/forge/core/validator/attribute.js.map +1 -0
- package/lib/server/forge/core/validator/clone.d.ts +14 -0
- package/lib/server/forge/core/validator/clone.d.ts.map +1 -0
- package/lib/server/forge/core/validator/clone.js +99 -0
- package/lib/server/forge/core/validator/clone.js.map +1 -0
- package/lib/server/forge/core/validator/cmd.d.ts +23 -0
- package/lib/server/forge/core/validator/cmd.d.ts.map +1 -0
- package/lib/server/forge/core/validator/cmd.js +87 -0
- package/lib/server/forge/core/validator/cmd.js.map +1 -0
- package/lib/server/forge/core/validator/fs.d.ts +5 -0
- package/lib/server/forge/core/validator/fs.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/validator/fs.js +8 -3
- package/lib/server/forge/core/validator/fs.js.map +1 -0
- package/lib/server/forge/core/validator/overlay.d.ts +13 -0
- package/lib/server/forge/core/validator/overlay.d.ts.map +1 -0
- package/lib/server/forge/core/validator/overlay.js +53 -0
- package/lib/server/forge/core/validator/overlay.js.map +1 -0
- package/lib/server/forge/core/validator/projectType.d.ts +20 -0
- package/lib/server/forge/core/validator/projectType.d.ts.map +1 -0
- package/lib/server/forge/core/validator/projectType.js +94 -0
- package/lib/server/forge/core/validator/projectType.js.map +1 -0
- package/lib/server/forge/core/validator/runners/go.d.ts +21 -0
- package/lib/server/forge/core/validator/runners/go.d.ts.map +1 -0
- package/lib/server/forge/core/validator/runners/go.js +99 -0
- package/lib/server/forge/core/validator/runners/go.js.map +1 -0
- package/lib/server/forge/core/validator/runners/node.d.ts +12 -0
- package/lib/server/forge/core/validator/runners/node.d.ts.map +1 -0
- package/lib/server/forge/core/validator/runners/node.js +75 -0
- package/lib/server/forge/core/validator/runners/node.js.map +1 -0
- package/lib/server/forge/core/validator/tdd.d.ts +30 -0
- package/lib/server/forge/core/validator/tdd.d.ts.map +1 -0
- package/lib/server/forge/core/validator/tdd.js +96 -0
- package/lib/server/forge/core/validator/tdd.js.map +1 -0
- package/lib/server/forge/core/validator.d.ts +58 -0
- package/lib/server/forge/core/validator.d.ts.map +1 -0
- package/lib/server/forge/core/validator.js +150 -0
- package/lib/server/forge/core/validator.js.map +1 -0
- package/lib/server/forge/routes.d.ts +22 -0
- package/lib/server/forge/routes.d.ts.map +1 -0
- package/lib/server/forge/routes.js +984 -0
- package/lib/server/forge/routes.js.map +1 -0
- package/lib/server.d.ts +2 -0
- package/lib/server.d.ts.map +1 -0
- package/lib/server.js +52 -0
- package/lib/server.js.map +1 -0
- package/lib/shared/events.d.ts +12 -0
- package/lib/shared/events.d.ts.map +1 -0
- package/lib/shared/events.js +12 -0
- package/lib/shared/events.js.map +1 -0
- package/package.json +15 -13
- package/scripts/fix-shebang.cjs +10 -0
- package/bin/cli/analyze.js +0 -516
- package/bin/cli/apply.js +0 -264
- package/bin/cli/cifix.js +0 -300
- package/bin/cli/close.js +0 -125
- package/bin/cli/createIssue.js +0 -112
- package/bin/cli/doctor.js +0 -161
- package/bin/cli/init.js +0 -306
- package/bin/cli/issue.js +0 -116
- package/bin/cli/issues.js +0 -155
- package/bin/cli/merge.js +0 -175
- package/bin/cli/refine.js +0 -253
- package/bin/cli/repl.js +0 -301
- package/bin/cli/repos.js +0 -91
- package/bin/cli/resolution.js +0 -126
- package/bin/cli/session.js +0 -230
- package/bin/cli/sessionStore.js +0 -211
- package/bin/cli/ship.js +0 -762
- package/bin/cli/update.js +0 -95
- package/bin/cli/utils.js +0 -145
- package/bin/cli/validate.js +0 -280
- package/bin/cli/watch.js +0 -274
- package/server/forge/core/ForgeAgent.js +0 -1179
- package/server/forge/core/ForgeAgent.test.js +0 -179
- package/server/forge/core/branchName.js +0 -41
- package/server/forge/core/claudeClient.js +0 -378
- package/server/forge/core/configStore.js +0 -229
- package/server/forge/core/configStore.test.js +0 -89
- package/server/forge/core/jobs.js +0 -180
- package/server/forge/core/k8s.js +0 -54
- package/server/forge/core/localRepo.js +0 -163
- package/server/forge/core/openclawClient.js +0 -125
- package/server/forge/core/prompts.js +0 -483
- package/server/forge/core/prompts.test.js +0 -219
- package/server/forge/core/providers/azuredevops.js +0 -409
- package/server/forge/core/providers/base.js +0 -208
- package/server/forge/core/providers/github.js +0 -348
- package/server/forge/core/providers/gitlab.js +0 -529
- package/server/forge/core/providers/index.js +0 -47
- package/server/forge/core/quotaClient.js +0 -101
- package/server/forge/core/validator/attribute.js +0 -84
- package/server/forge/core/validator/clone.js +0 -116
- package/server/forge/core/validator/cmd.js +0 -98
- package/server/forge/core/validator/overlay.js +0 -52
- package/server/forge/core/validator/projectType.js +0 -87
- package/server/forge/core/validator/runners/go.js +0 -107
- package/server/forge/core/validator/runners/node.js +0 -84
- package/server/forge/core/validator/tdd.js +0 -105
- package/server/forge/core/validator.js +0 -167
- package/server/forge/routes.js +0 -1027
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* server/forge/core/providers/base.js
|
|
3
|
-
*
|
|
4
|
-
* Abstract base class that defines the interface every SCM provider must
|
|
5
|
-
* implement. Methods throw "not implemented" by default so subclasses get
|
|
6
|
-
* a clear error rather than a silent no-op when something is missing.
|
|
7
|
-
*
|
|
8
|
-
* All data shapes returned by provider methods are normalised so that
|
|
9
|
-
* ForgeAgent and routes.js never need to know which provider is active.
|
|
10
|
-
*
|
|
11
|
-
* Normalised shapes (JSDoc):
|
|
12
|
-
*
|
|
13
|
-
* @typedef {{ iid: number, title: string, description: string|null,
|
|
14
|
-
* labels: string[], author: { name: string },
|
|
15
|
-
* created_at: string, web_url: string }} NormalIssue
|
|
16
|
-
*
|
|
17
|
-
* @typedef {{ iid: number, title: string, web_url: string,
|
|
18
|
-
* source_branch: string, target_branch: string,
|
|
19
|
-
* state: string, has_conflicts: boolean,
|
|
20
|
-
* rebase_in_progress: boolean, merge_status: string,
|
|
21
|
-
* detailed_merge_status: string|null,
|
|
22
|
-
* draft: boolean,
|
|
23
|
-
* head_pipeline: { status: string, web_url: string }|null,
|
|
24
|
-
* author: { name: string }, created_at: string,
|
|
25
|
-
* merged_at: string|null,
|
|
26
|
-
* merge_commit_sha: string|null }} NormalMR
|
|
27
|
-
*
|
|
28
|
-
* @typedef {{ id: number, status: string, web_url: string,
|
|
29
|
-
* created_at: string }} NormalPipeline
|
|
30
|
-
*
|
|
31
|
-
* @typedef {{ id: number, name: string, stage: string, status: string,
|
|
32
|
-
* web_url: string, duration: number|null }} NormalJob
|
|
33
|
-
*
|
|
34
|
-
* @typedef {{ old_path: string, new_path: string, diff: string,
|
|
35
|
-
* new_file: boolean, renamed_file: boolean,
|
|
36
|
-
* deleted_file: boolean }} NormalDiff
|
|
37
|
-
*
|
|
38
|
-
* @typedef {{ action: 'create'|'modify'|'delete',
|
|
39
|
-
* file_path: string, content: string }} CommitAction
|
|
40
|
-
*
|
|
41
|
-
* @typedef {{ id: number, name: string,
|
|
42
|
-
* state: 'available'|'stopping'|'stopped'|string,
|
|
43
|
-
* external_url: string|null, ref: string|null,
|
|
44
|
-
* updated_at: string|null, web_url: string|null }} NormalEnvironment
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
export class ScmProvider {
|
|
48
|
-
/** @returns {string} Provider identifier */
|
|
49
|
-
get name() { return "base"; }
|
|
50
|
-
|
|
51
|
-
/** @returns {boolean} Whether the provider supports server-side rebase */
|
|
52
|
-
get supportsRebase() { return false; }
|
|
53
|
-
|
|
54
|
-
// ─── Issues ────────────────────────────────────────────────────────────────
|
|
55
|
-
|
|
56
|
-
/** @returns {Promise<NormalIssue[]>} */
|
|
57
|
-
async listOpenIssues() { throw new Error(`${this.name}: listOpenIssues not implemented`); }
|
|
58
|
-
|
|
59
|
-
/** @param {number|string} iid @returns {Promise<NormalIssue>} */
|
|
60
|
-
async getIssue(iid) { throw new Error(`${this.name}: getIssue not implemented`); }
|
|
61
|
-
|
|
62
|
-
/** @returns {Promise<NormalIssue>} */
|
|
63
|
-
async createIssue(title, description) { throw new Error(`${this.name}: createIssue not implemented`); }
|
|
64
|
-
|
|
65
|
-
/** @returns {Promise<NormalIssue>} */
|
|
66
|
-
async updateIssue(iid, { title, description }) { throw new Error(`${this.name}: updateIssue not implemented`); }
|
|
67
|
-
|
|
68
|
-
/** @returns {Promise<NormalIssue>} */
|
|
69
|
-
async closeIssue(iid) { throw new Error(`${this.name}: closeIssue not implemented`); }
|
|
70
|
-
|
|
71
|
-
// ─── Repository ────────────────────────────────────────────────────────────
|
|
72
|
-
|
|
73
|
-
/** @returns {Promise<string[]>} File paths */
|
|
74
|
-
async getFileTree(srcPath, ref) { throw new Error(`${this.name}: getFileTree not implemented`); }
|
|
75
|
-
|
|
76
|
-
/** @returns {Promise<string>} File content */
|
|
77
|
-
async getFileContent(filePath, ref) { throw new Error(`${this.name}: getFileContent not implemented`); }
|
|
78
|
-
|
|
79
|
-
// ─── Mutations ─────────────────────────────────────────────────────────────
|
|
80
|
-
|
|
81
|
-
async createBranch(branchName, ref) { throw new Error(`${this.name}: createBranch not implemented`); }
|
|
82
|
-
|
|
83
|
-
/** @param {string} branchName @returns {Promise<void>} */
|
|
84
|
-
async deleteBranch(branchName) { throw new Error(`${this.name}: deleteBranch not implemented`); }
|
|
85
|
-
|
|
86
|
-
/** @param {CommitAction[]} actions */
|
|
87
|
-
async commitFiles(branch, message, actions) { throw new Error(`${this.name}: commitFiles not implemented`); }
|
|
88
|
-
|
|
89
|
-
/** @returns {Promise<NormalMR>} */
|
|
90
|
-
async createMR({ sourceBranch, targetBranch, title, description }) { throw new Error(`${this.name}: createMR not implemented`); }
|
|
91
|
-
|
|
92
|
-
// ─── MR / PR queries ───────────────────────────────────────────────────────
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* @param {"open"|"merged"|"closed"} [state="open"] Lifecycle filter
|
|
96
|
-
* @returns {Promise<NormalMR[]>} Forge-created MRs in the requested state
|
|
97
|
-
*/
|
|
98
|
-
async listAllForgeMRs(_state = "open") { throw new Error(`${this.name}: listAllForgeMRs not implemented`); }
|
|
99
|
-
|
|
100
|
-
/** @returns {Promise<NormalMR[]>} Open Forge MRs for a specific issue */
|
|
101
|
-
async listForgeMRsForIssue(issueIid) { throw new Error(`${this.name}: listForgeMRsForIssue not implemented`); }
|
|
102
|
-
|
|
103
|
-
/** @returns {Promise<NormalMR[]>} Merged Forge MRs for a specific issue */
|
|
104
|
-
async listMergedForgeMRsForIssue(issueIid) { throw new Error(`${this.name}: listMergedForgeMRsForIssue not implemented`); }
|
|
105
|
-
|
|
106
|
-
/** @returns {Promise<NormalMR>} */
|
|
107
|
-
async getMR(mrIid) { throw new Error(`${this.name}: getMR not implemented`); }
|
|
108
|
-
|
|
109
|
-
/** @returns {Promise<NormalDiff[]>} */
|
|
110
|
-
async getMRDiffs(mrIid) { throw new Error(`${this.name}: getMRDiffs not implemented`); }
|
|
111
|
-
|
|
112
|
-
/** @returns {Promise<void>} */
|
|
113
|
-
async rebaseMR(mrIid) { throw new Error(`${this.name}: rebase not supported`); }
|
|
114
|
-
|
|
115
|
-
/** Merge the MR immediately. @returns {Promise<void>} */
|
|
116
|
-
async mergeMR(_mrIid) { throw new Error(`${this.name}: mergeMR not supported`); }
|
|
117
|
-
|
|
118
|
-
/** Close the MR without merging. @returns {Promise<void>} */
|
|
119
|
-
async closeMR(_mrIid) { throw new Error(`${this.name}: closeMR not supported`); }
|
|
120
|
-
|
|
121
|
-
/** Reopen a closed MR. @returns {Promise<void>} */
|
|
122
|
-
async reopenMR(_mrIid) { throw new Error(`${this.name}: reopenMR not supported`); }
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Toggle draft / work-in-progress state on the MR.
|
|
126
|
-
* @param {number} _mrIid
|
|
127
|
-
* @param {boolean} _draft true → mark as draft, false → mark as ready
|
|
128
|
-
* @returns {Promise<void>}
|
|
129
|
-
*/
|
|
130
|
-
async setMRDraft(_mrIid, _draft) { throw new Error(`${this.name}: setMRDraft not supported`); }
|
|
131
|
-
|
|
132
|
-
// ─── CI / Pipelines ────────────────────────────────────────────────────────
|
|
133
|
-
|
|
134
|
-
/** @returns {Promise<NormalPipeline[]>} */
|
|
135
|
-
async getMRPipelines(mrIid) { throw new Error(`${this.name}: getMRPipelines not implemented`); }
|
|
136
|
-
|
|
137
|
-
/** @returns {Promise<NormalPipeline>} */
|
|
138
|
-
async getPipeline(pipelineId) { throw new Error(`${this.name}: getPipeline not implemented`); }
|
|
139
|
-
|
|
140
|
-
/** @returns {Promise<NormalJob[]>} */
|
|
141
|
-
async getPipelineJobs(pipelineId) { throw new Error(`${this.name}: getPipelineJobs not implemented`); }
|
|
142
|
-
|
|
143
|
-
/** @returns {Promise<string>} Plain-text log */
|
|
144
|
-
async getJobTrace(jobId) { throw new Error(`${this.name}: getJobTrace not implemented`); }
|
|
145
|
-
|
|
146
|
-
/** @returns {Promise<NormalPipeline[]>} Pipelines that ran on a specific commit SHA */
|
|
147
|
-
async getPipelinesBySha(_sha) { return []; }
|
|
148
|
-
|
|
149
|
-
/** @returns {Promise<NormalPipeline[]>} Pipelines that ran on a specific branch ref */
|
|
150
|
-
async getPipelinesByRef(_ref) { return []; }
|
|
151
|
-
|
|
152
|
-
/** @returns {Promise<string[]>} Branch names starting with the given prefix */
|
|
153
|
-
async listBranchesByPrefix(_prefix) { return []; }
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Count commits reachable from `toRef` but not from `fromRef`. Used to detect
|
|
157
|
-
* stale / empty forge branches (aheadCount === 0 means the branch has no
|
|
158
|
-
* pending changes vs. main). Return `null` when the provider can't compute it
|
|
159
|
-
* so callers can distinguish "no divergence" from "unknown".
|
|
160
|
-
*
|
|
161
|
-
* @param {string} _fromRef base ref (typically "main")
|
|
162
|
-
* @param {string} _toRef ref under test (e.g. "forge/issue-10-…")
|
|
163
|
-
* @returns {Promise<{aheadCount: number}|null>}
|
|
164
|
-
*/
|
|
165
|
-
async compareRefs(_fromRef, _toRef) { return null; }
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Scan recently merged MRs so callers can badge open issues whose fix
|
|
169
|
-
* already shipped. Two attribution paths the consumer can use:
|
|
170
|
-
* 1. `closedIssueIids` — issues named by `Closes #N` / `Fixes #N` /
|
|
171
|
-
* `Resolves #N` trailers in the MR description (primary signal).
|
|
172
|
-
* 2. `sourceBranch` — the MR's source branch; lets the consumer recover
|
|
173
|
-
* issue IDs from branch names like `forge/issue-42-foo` when the MR
|
|
174
|
-
* description has no closing keyword.
|
|
175
|
-
* Returned entries are NOT pre-filtered on `closedIssueIids` — drop noise
|
|
176
|
-
* in the caller if you only want one of the two signals. One bulk call per
|
|
177
|
-
* issue-list render — do NOT call per-issue.
|
|
178
|
-
*
|
|
179
|
-
* @param {number} _limit cap on MRs to scan (default 50)
|
|
180
|
-
* @returns {Promise<Array<{mrIid: number, webUrl: string, mergedAt: string|null, sourceBranch: string|null, closedIssueIids: number[]}>>}
|
|
181
|
-
*/
|
|
182
|
-
async listRecentMergedMRIssueLinks(_limit) { return []; }
|
|
183
|
-
|
|
184
|
-
// ─── Environments (ephemeral review apps) ─────────────────────────────────
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* List environments attached to a branch. Used to surface per-issue
|
|
188
|
-
* ephemeral URLs + status next to the pipeline on the issue detail view.
|
|
189
|
-
*
|
|
190
|
-
* Implementations that don't support environments should return `[]` so
|
|
191
|
-
* the UI simply doesn't render the section.
|
|
192
|
-
*
|
|
193
|
-
* @param {string} _branchName
|
|
194
|
-
* @returns {Promise<NormalEnvironment[]>}
|
|
195
|
-
*/
|
|
196
|
-
async listEnvironmentsForBranch(_branchName) { return []; }
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Trigger teardown of an environment. GitLab supports this natively via the
|
|
200
|
-
* environments/:id/stop action; GitHub has no equivalent and typically
|
|
201
|
-
* needs a repository_dispatch event to a cleanup workflow. Implementations
|
|
202
|
-
* that can't stop should throw so the caller can surface the limitation.
|
|
203
|
-
*
|
|
204
|
-
* @param {number|string} _envId
|
|
205
|
-
* @returns {Promise<void>}
|
|
206
|
-
*/
|
|
207
|
-
async stopEnvironment(_envId) { throw new Error(`${this.name}: stopEnvironment not implemented`); }
|
|
208
|
-
}
|
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* server/forge/core/providers/github.js
|
|
3
|
-
*
|
|
4
|
-
* GitHub REST API v3 implementation of ScmProvider.
|
|
5
|
-
* Multi-file commits use the Git Data API (blob → tree → commit → ref).
|
|
6
|
-
*
|
|
7
|
-
* Required env vars:
|
|
8
|
-
* GITHUB_TOKEN — personal access token (repo + workflow scopes)
|
|
9
|
-
* GITHUB_OWNER — default org or user, e.g. "ipul-labs"
|
|
10
|
-
* GITHUB_REPO — default repository name, e.g. "web-app"
|
|
11
|
-
*
|
|
12
|
-
* Optional:
|
|
13
|
-
* GITHUB_BASE_BRANCH — default target branch (default: "main")
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { getConnection } from "../configStore.js";
|
|
17
|
-
import { ScmProvider } from "./base.js";
|
|
18
|
-
|
|
19
|
-
export class GitHubProvider extends ScmProvider {
|
|
20
|
-
/**
|
|
21
|
-
* @param {string} [repo] "owner/repo" format — overrides env vars
|
|
22
|
-
*/
|
|
23
|
-
constructor(repo) {
|
|
24
|
-
super();
|
|
25
|
-
if (repo && repo.includes("/")) {
|
|
26
|
-
const [owner, repoName] = repo.split("/");
|
|
27
|
-
this._owner = owner;
|
|
28
|
-
this._repo = repoName;
|
|
29
|
-
} else {
|
|
30
|
-
this._owner = process.env.GITHUB_OWNER ?? "";
|
|
31
|
-
this._repo = repo ?? process.env.GITHUB_REPO ?? "";
|
|
32
|
-
}
|
|
33
|
-
this._base = "https://api.github.com";
|
|
34
|
-
this._defaultBranch = process.env.GITHUB_BASE_BRANCH ?? "main";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
get name() { return "github"; }
|
|
38
|
-
get supportsRebase() { return false; }
|
|
39
|
-
|
|
40
|
-
// ─── Internal helpers ──────────────────────────────────────────────────────
|
|
41
|
-
|
|
42
|
-
_headers() {
|
|
43
|
-
return {
|
|
44
|
-
Authorization: `Bearer ${getConnection("github").token}`,
|
|
45
|
-
Accept: "application/vnd.github+json",
|
|
46
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
47
|
-
"Content-Type": "application/json",
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
_repoBase() {
|
|
52
|
-
return `${this._base}/repos/${this._owner}/${this._repo}`;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async _req(path, options = {}) {
|
|
56
|
-
const url = path.startsWith("http") ? path : `${this._repoBase()}${path}`;
|
|
57
|
-
const res = await fetch(url, {
|
|
58
|
-
...options,
|
|
59
|
-
headers: { ...this._headers(), ...options.headers },
|
|
60
|
-
});
|
|
61
|
-
if (res.status === 204) return null;
|
|
62
|
-
if (!res.ok) {
|
|
63
|
-
const text = await res.text().catch(() => "");
|
|
64
|
-
throw new Error(`GitHub ${res.status} on ${path}: ${text}`);
|
|
65
|
-
}
|
|
66
|
-
return res.json();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ─── Normalizers ──────────────────────────────────────────────────────────
|
|
70
|
-
|
|
71
|
-
/** GitHub issues map closely to NormalIssue */
|
|
72
|
-
_issue(raw) {
|
|
73
|
-
return {
|
|
74
|
-
iid: raw.number,
|
|
75
|
-
title: raw.title,
|
|
76
|
-
description: raw.body ?? null,
|
|
77
|
-
labels: (raw.labels ?? []).map((l) => l.name),
|
|
78
|
-
author: { name: raw.user?.login ?? "" },
|
|
79
|
-
created_at: raw.created_at,
|
|
80
|
-
web_url: raw.html_url,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/** GitHub PRs → NormalMR. GitHub has no server-side rebase API. */
|
|
85
|
-
_mr(raw) {
|
|
86
|
-
return {
|
|
87
|
-
iid: raw.number,
|
|
88
|
-
title: raw.title,
|
|
89
|
-
web_url: raw.html_url,
|
|
90
|
-
source_branch: raw.head?.ref ?? "",
|
|
91
|
-
target_branch: raw.base?.ref ?? "",
|
|
92
|
-
state: raw.merged_at ? "merged" : raw.state,
|
|
93
|
-
has_conflicts: raw.mergeable === false,
|
|
94
|
-
rebase_in_progress: false,
|
|
95
|
-
merge_status: raw.mergeable_state ?? "",
|
|
96
|
-
detailed_merge_status: null,
|
|
97
|
-
draft: raw.draft ?? false,
|
|
98
|
-
head_pipeline: raw.head?.sha
|
|
99
|
-
? null // populated separately via getCheckRuns if needed
|
|
100
|
-
: null,
|
|
101
|
-
author: { name: raw.user?.login ?? "" },
|
|
102
|
-
created_at: raw.created_at,
|
|
103
|
-
merged_at: raw.merged_at ?? null,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** GitHub Actions workflow runs → NormalPipeline */
|
|
108
|
-
_pipeline(raw) {
|
|
109
|
-
return {
|
|
110
|
-
id: raw.id,
|
|
111
|
-
status: this._runStatus(raw),
|
|
112
|
-
web_url: raw.html_url,
|
|
113
|
-
created_at: raw.created_at,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
_runStatus(run) {
|
|
118
|
-
if (run.conclusion) return run.conclusion; // success / failure / cancelled
|
|
119
|
-
if (run.status === "in_progress") return "running";
|
|
120
|
-
return run.status ?? "unknown";
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/** GitHub Actions jobs → NormalJob */
|
|
124
|
-
_job(raw) {
|
|
125
|
-
return {
|
|
126
|
-
id: raw.id,
|
|
127
|
-
name: raw.name,
|
|
128
|
-
stage: raw.workflow_name ?? "",
|
|
129
|
-
status: raw.conclusion ?? raw.status ?? "unknown",
|
|
130
|
-
web_url: raw.html_url,
|
|
131
|
-
duration: raw.completed_at && raw.started_at
|
|
132
|
-
? Math.round((new Date(raw.completed_at) - new Date(raw.started_at)) / 1000)
|
|
133
|
-
: null,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
_diff(raw) {
|
|
138
|
-
return {
|
|
139
|
-
old_path: raw.previous_filename ?? raw.filename,
|
|
140
|
-
new_path: raw.filename,
|
|
141
|
-
diff: raw.patch ?? "",
|
|
142
|
-
new_file: raw.status === "added",
|
|
143
|
-
renamed_file: raw.status === "renamed",
|
|
144
|
-
deleted_file: raw.status === "removed",
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// ─── Issues ───────────────────────────────────────────────────────────────
|
|
149
|
-
|
|
150
|
-
async listOpenIssues() {
|
|
151
|
-
const raw = await this._req(
|
|
152
|
-
`/issues?state=open&sort=updated&per_page=25&pulls=false`,
|
|
153
|
-
);
|
|
154
|
-
// GitHub returns PRs as issues; filter them out
|
|
155
|
-
return (raw ?? []).filter((i) => !i.pull_request).map((i) => this._issue(i));
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async getIssue(iid) {
|
|
159
|
-
const raw = await this._req(`/issues/${iid}`);
|
|
160
|
-
return this._issue(raw);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async createIssue(title, description = "") {
|
|
164
|
-
const raw = await this._req("/issues", {
|
|
165
|
-
method: "POST",
|
|
166
|
-
body: JSON.stringify({ title, body: description }),
|
|
167
|
-
});
|
|
168
|
-
return this._issue(raw);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async updateIssue(iid, { title, description }) {
|
|
172
|
-
const raw = await this._req(`/issues/${iid}`, {
|
|
173
|
-
method: "PATCH",
|
|
174
|
-
body: JSON.stringify({ title, body: description }),
|
|
175
|
-
});
|
|
176
|
-
return this._issue(raw);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async closeIssue(iid) {
|
|
180
|
-
const raw = await this._req(`/issues/${iid}`, {
|
|
181
|
-
method: "PATCH",
|
|
182
|
-
body: JSON.stringify({ state: "closed" }),
|
|
183
|
-
});
|
|
184
|
-
return this._issue(raw);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// ─── Repository ───────────────────────────────────────────────────────────
|
|
188
|
-
|
|
189
|
-
async getFileTree(srcPath = "", ref = this._defaultBranch) {
|
|
190
|
-
const data = await this._req(`/git/trees/${ref}?recursive=1`);
|
|
191
|
-
return (data.tree ?? [])
|
|
192
|
-
.filter((item) => item.type === "blob")
|
|
193
|
-
.filter((item) => !srcPath || item.path.startsWith(srcPath + "/") || item.path === srcPath)
|
|
194
|
-
.filter((item) => /\.(ts|tsx|js|jsx|json|css|yaml|yml|md|go|py|rs|java|rb|sh|toml)$/.test(item.path))
|
|
195
|
-
.map((item) => item.path);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async getFileContent(filePath, ref = this._defaultBranch) {
|
|
199
|
-
const encoded = encodeURIComponent(filePath);
|
|
200
|
-
const data = await this._req(`/contents/${encoded}?ref=${ref}`);
|
|
201
|
-
return Buffer.from(data.content, "base64").toString("utf-8");
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// ─── Mutations ────────────────────────────────────────────────────────────
|
|
205
|
-
|
|
206
|
-
async createBranch(branchName, ref = this._defaultBranch) {
|
|
207
|
-
// Resolve ref to SHA
|
|
208
|
-
const refData = await this._req(`/git/refs/heads/${ref}`);
|
|
209
|
-
const sha = refData.object.sha;
|
|
210
|
-
return this._req("/git/refs", {
|
|
211
|
-
method: "POST",
|
|
212
|
-
body: JSON.stringify({ ref: `refs/heads/${branchName}`, sha }),
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Multi-file commit using GitHub Git Data API.
|
|
218
|
-
* @param {string} branch
|
|
219
|
-
* @param {string} message
|
|
220
|
-
* @param {import('./base.js').CommitAction[]} actions
|
|
221
|
-
*/
|
|
222
|
-
async commitFiles(branch, message, actions) {
|
|
223
|
-
// 1. Get current HEAD
|
|
224
|
-
const refData = await this._req(`/git/refs/heads/${branch}`);
|
|
225
|
-
const headSha = refData.object.sha;
|
|
226
|
-
|
|
227
|
-
// 2. Get base tree SHA from commit
|
|
228
|
-
const commitData = await this._req(`/git/commits/${headSha}`);
|
|
229
|
-
const baseTreeSha = commitData.tree.sha;
|
|
230
|
-
|
|
231
|
-
// 3. Create blobs for each file (skip deletes)
|
|
232
|
-
const treeEntries = await Promise.all(
|
|
233
|
-
actions.map(async (action) => {
|
|
234
|
-
if (action.action === "delete") {
|
|
235
|
-
return { path: action.file_path, mode: "100644", type: "blob", sha: null };
|
|
236
|
-
}
|
|
237
|
-
const blob = await this._req("/git/blobs", {
|
|
238
|
-
method: "POST",
|
|
239
|
-
body: JSON.stringify({ content: action.content, encoding: "utf-8" }),
|
|
240
|
-
});
|
|
241
|
-
return { path: action.file_path, mode: "100644", type: "blob", sha: blob.sha };
|
|
242
|
-
}),
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
// 4. Create new tree
|
|
246
|
-
const tree = await this._req("/git/trees", {
|
|
247
|
-
method: "POST",
|
|
248
|
-
body: JSON.stringify({ base_tree: baseTreeSha, tree: treeEntries }),
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// 5. Create commit
|
|
252
|
-
const newCommit = await this._req("/git/commits", {
|
|
253
|
-
method: "POST",
|
|
254
|
-
body: JSON.stringify({ message, tree: tree.sha, parents: [headSha] }),
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
// 6. Update ref
|
|
258
|
-
return this._req(`/git/refs/heads/${branch}`, {
|
|
259
|
-
method: "PATCH",
|
|
260
|
-
body: JSON.stringify({ sha: newCommit.sha }),
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
async createMR({ sourceBranch, targetBranch = this._defaultBranch, title, description = "" }) {
|
|
265
|
-
const raw = await this._req("/pulls", {
|
|
266
|
-
method: "POST",
|
|
267
|
-
body: JSON.stringify({
|
|
268
|
-
head: sourceBranch,
|
|
269
|
-
base: targetBranch,
|
|
270
|
-
title,
|
|
271
|
-
body: description,
|
|
272
|
-
}),
|
|
273
|
-
});
|
|
274
|
-
return this._mr(raw);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// ─── PR queries ───────────────────────────────────────────────────────────
|
|
278
|
-
|
|
279
|
-
async listAllForgeMRs(state = "open") {
|
|
280
|
-
const ghState = state === "open" ? "open" : "closed";
|
|
281
|
-
const all = await this._req(`/pulls?state=${ghState}&per_page=50`);
|
|
282
|
-
const forge = (all ?? []).filter((pr) => pr.head?.ref?.startsWith("forge/"));
|
|
283
|
-
// GitHub rolls merged + closed-without-merge into `state=closed`; split
|
|
284
|
-
// them apart on merged_at so the UI tabs stay meaningful.
|
|
285
|
-
const filtered =
|
|
286
|
-
state === "merged" ? forge.filter((pr) => pr.merged_at)
|
|
287
|
-
: state === "closed" ? forge.filter((pr) => !pr.merged_at)
|
|
288
|
-
: forge;
|
|
289
|
-
return filtered.map((pr) => this._mr(pr));
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
async listForgeMRsForIssue(issueIid) {
|
|
293
|
-
const all = await this._req("/pulls?state=open&per_page=50");
|
|
294
|
-
return (all ?? [])
|
|
295
|
-
.filter((pr) => pr.head?.ref?.startsWith(`forge/issue-${issueIid}-`))
|
|
296
|
-
.map((pr) => this._mr(pr));
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
async listMergedForgeMRsForIssue(issueIid) {
|
|
300
|
-
const all = await this._req("/pulls?state=closed&per_page=50");
|
|
301
|
-
return (all ?? [])
|
|
302
|
-
.filter((pr) => pr.merged_at && pr.head?.ref?.startsWith(`forge/issue-${issueIid}-`))
|
|
303
|
-
.map((pr) => this._mr(pr));
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
async getMR(mrIid) {
|
|
307
|
-
const raw = await this._req(`/pulls/${mrIid}`);
|
|
308
|
-
return this._mr(raw);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async getMRDiffs(mrIid) {
|
|
312
|
-
const raw = await this._req(`/pulls/${mrIid}/files?per_page=100`);
|
|
313
|
-
return (raw ?? []).map((f) => this._diff(f));
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// rebaseMR not supported — supportsRebase is false
|
|
317
|
-
|
|
318
|
-
// ─── CI / Pipelines (GitHub Actions) ─────────────────────────────────────
|
|
319
|
-
|
|
320
|
-
async getMRPipelines(mrIid) {
|
|
321
|
-
const pr = await this._req(`/pulls/${mrIid}`);
|
|
322
|
-
const sha = pr.head?.sha;
|
|
323
|
-
if (!sha) return [];
|
|
324
|
-
const data = await this._req(`/actions/runs?head_sha=${sha}&per_page=10`);
|
|
325
|
-
return (data.workflow_runs ?? []).map((r) => this._pipeline(r));
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
async getPipeline(pipelineId) {
|
|
329
|
-
const raw = await this._req(`/actions/runs/${pipelineId}`);
|
|
330
|
-
return this._pipeline(raw);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
async getPipelineJobs(pipelineId) {
|
|
334
|
-
const data = await this._req(`/actions/runs/${pipelineId}/jobs`);
|
|
335
|
-
return (data.jobs ?? []).map((j) => this._job(j));
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
async getJobTrace(jobId) {
|
|
339
|
-
const url = `${this._repoBase()}/actions/jobs/${jobId}/logs`;
|
|
340
|
-
const res = await fetch(url, { headers: this._headers() });
|
|
341
|
-
if (!res.ok) {
|
|
342
|
-
const text = await res.text().catch(() => "");
|
|
343
|
-
throw new Error(`GitHub ${res.status} on jobs/${jobId}/logs: ${text}`);
|
|
344
|
-
}
|
|
345
|
-
// GitHub redirects to a pre-signed S3 URL; fetch follows it automatically
|
|
346
|
-
return res.text();
|
|
347
|
-
}
|
|
348
|
-
}
|