@andrebuzeli/git-mcp 2.28.0 → 2.28.2

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.
Files changed (154) hide show
  1. package/dist/client.d.ts +306 -306
  2. package/dist/client.js +298 -298
  3. package/dist/config.d.ts +310 -310
  4. package/dist/config.js +392 -392
  5. package/dist/index.d.ts +22 -22
  6. package/dist/index.js +89 -89
  7. package/dist/providers/base-provider.d.ts +160 -160
  8. package/dist/providers/base-provider.js +274 -274
  9. package/dist/providers/error-handler.d.ts +50 -50
  10. package/dist/providers/error-handler.js +175 -175
  11. package/dist/providers/gitea-provider.d.ts +97 -97
  12. package/dist/providers/gitea-provider.d.ts.map +1 -1
  13. package/dist/providers/gitea-provider.js +1015 -1001
  14. package/dist/providers/gitea-provider.js.map +1 -1
  15. package/dist/providers/github-provider.d.ts +104 -104
  16. package/dist/providers/github-provider.d.ts.map +1 -1
  17. package/dist/providers/github-provider.js +1248 -1234
  18. package/dist/providers/github-provider.js.map +1 -1
  19. package/dist/providers/index.d.ts +12 -12
  20. package/dist/providers/index.js +40 -40
  21. package/dist/providers/provider-factory.d.ts +74 -74
  22. package/dist/providers/provider-factory.d.ts.map +1 -1
  23. package/dist/providers/provider-factory.js +318 -311
  24. package/dist/providers/provider-factory.js.map +1 -1
  25. package/dist/providers/types.d.ts +318 -318
  26. package/dist/providers/types.js +6 -6
  27. package/dist/server.d.ts +76 -76
  28. package/dist/server.js +306 -306
  29. package/dist/tools/git-archive.d.ts +165 -165
  30. package/dist/tools/git-archive.js +233 -233
  31. package/dist/tools/git-branches.d.ts +430 -430
  32. package/dist/tools/git-branches.js +627 -627
  33. package/dist/tools/git-commits.d.ts +485 -485
  34. package/dist/tools/git-commits.js +735 -735
  35. package/dist/tools/git-commits.js.map +1 -1
  36. package/dist/tools/git-config.d.ts +140 -140
  37. package/dist/tools/git-config.js +268 -268
  38. package/dist/tools/git-files.d.ts +486 -486
  39. package/dist/tools/git-files.js +607 -607
  40. package/dist/tools/git-files.js.map +1 -1
  41. package/dist/tools/git-issues.d.ts +574 -571
  42. package/dist/tools/git-issues.d.ts.map +1 -1
  43. package/dist/tools/git-issues.js +741 -740
  44. package/dist/tools/git-issues.js.map +1 -1
  45. package/dist/tools/git-pulls.d.ts +697 -694
  46. package/dist/tools/git-pulls.d.ts.map +1 -1
  47. package/dist/tools/git-pulls.js +733 -732
  48. package/dist/tools/git-pulls.js.map +1 -1
  49. package/dist/tools/git-releases.d.ts +490 -487
  50. package/dist/tools/git-releases.d.ts.map +1 -1
  51. package/dist/tools/git-releases.js +558 -557
  52. package/dist/tools/git-releases.js.map +1 -1
  53. package/dist/tools/git-remote.d.ts +138 -138
  54. package/dist/tools/git-remote.js +274 -274
  55. package/dist/tools/git-repositories.d.ts +483 -483
  56. package/dist/tools/git-repositories.js +640 -640
  57. package/dist/tools/git-repositories.js.map +1 -1
  58. package/dist/tools/git-reset.d.ts +130 -130
  59. package/dist/tools/git-reset.js +223 -223
  60. package/dist/tools/git-revert.d.ts +149 -149
  61. package/dist/tools/git-revert.js +198 -198
  62. package/dist/tools/git-stash.d.ts +140 -140
  63. package/dist/tools/git-stash.js +269 -269
  64. package/dist/tools/git-sync.d.ts +178 -178
  65. package/dist/tools/git-sync.js +312 -312
  66. package/dist/tools/git-tags.d.ts +414 -411
  67. package/dist/tools/git-tags.d.ts.map +1 -1
  68. package/dist/tools/git-tags.js +486 -485
  69. package/dist/tools/git-tags.js.map +1 -1
  70. package/dist/tools/git-webhooks.d.ts +473 -470
  71. package/dist/tools/git-webhooks.d.ts.map +1 -1
  72. package/dist/tools/git-webhooks.js +544 -543
  73. package/dist/tools/git-webhooks.js.map +1 -1
  74. package/dist/utils/terminal-controller.d.ts +80 -80
  75. package/dist/utils/terminal-controller.js +345 -345
  76. package/dist/utils/user-detection.d.ts +24 -24
  77. package/dist/utils/user-detection.js +53 -53
  78. package/package.json +2 -2
  79. package/dist/tools/gh-actions.d.ts +0 -253
  80. package/dist/tools/gh-actions.d.ts.map +0 -1
  81. package/dist/tools/gh-actions.js +0 -390
  82. package/dist/tools/gh-actions.js.map +0 -1
  83. package/dist/tools/gh-analytics.d.ts +0 -264
  84. package/dist/tools/gh-analytics.d.ts.map +0 -1
  85. package/dist/tools/gh-analytics.js +0 -402
  86. package/dist/tools/gh-analytics.js.map +0 -1
  87. package/dist/tools/gh-code-review.d.ts +0 -305
  88. package/dist/tools/gh-code-review.d.ts.map +0 -1
  89. package/dist/tools/gh-code-review.js +0 -513
  90. package/dist/tools/gh-code-review.js.map +0 -1
  91. package/dist/tools/gh-codespaces.d.ts +0 -139
  92. package/dist/tools/gh-codespaces.d.ts.map +0 -1
  93. package/dist/tools/gh-codespaces.js +0 -283
  94. package/dist/tools/gh-codespaces.js.map +0 -1
  95. package/dist/tools/gh-deployments.d.ts +0 -301
  96. package/dist/tools/gh-deployments.d.ts.map +0 -1
  97. package/dist/tools/gh-deployments.js +0 -368
  98. package/dist/tools/gh-deployments.js.map +0 -1
  99. package/dist/tools/gh-gists.d.ts +0 -175
  100. package/dist/tools/gh-gists.d.ts.map +0 -1
  101. package/dist/tools/gh-gists.js +0 -322
  102. package/dist/tools/gh-gists.js.map +0 -1
  103. package/dist/tools/gh-projects.d.ts +0 -206
  104. package/dist/tools/gh-projects.d.ts.map +0 -1
  105. package/dist/tools/gh-projects.js +0 -359
  106. package/dist/tools/gh-projects.js.map +0 -1
  107. package/dist/tools/gh-security.d.ts +0 -275
  108. package/dist/tools/gh-security.d.ts.map +0 -1
  109. package/dist/tools/gh-security.js +0 -396
  110. package/dist/tools/gh-security.js.map +0 -1
  111. package/dist/tools/gh-sync.d.ts +0 -214
  112. package/dist/tools/gh-sync.d.ts.map +0 -1
  113. package/dist/tools/gh-sync.js +0 -379
  114. package/dist/tools/gh-sync.js.map +0 -1
  115. package/dist/tools/gh-workflows.d.ts +0 -291
  116. package/dist/tools/gh-workflows.d.ts.map +0 -1
  117. package/dist/tools/gh-workflows.js +0 -433
  118. package/dist/tools/gh-workflows.js.map +0 -1
  119. package/dist/tools/git-bundle.d.ts +0 -172
  120. package/dist/tools/git-bundle.d.ts.map +0 -1
  121. package/dist/tools/git-bundle.js +0 -242
  122. package/dist/tools/git-bundle.js.map +0 -1
  123. package/dist/tools/git-cherry-pick.d.ts +0 -159
  124. package/dist/tools/git-cherry-pick.d.ts.map +0 -1
  125. package/dist/tools/git-cherry-pick.js +0 -225
  126. package/dist/tools/git-cherry-pick.js.map +0 -1
  127. package/dist/tools/git-rebase.d.ts +0 -138
  128. package/dist/tools/git-rebase.d.ts.map +0 -1
  129. package/dist/tools/git-rebase.js +0 -214
  130. package/dist/tools/git-rebase.js.map +0 -1
  131. package/dist/tools/git-submodule.d.ts +0 -153
  132. package/dist/tools/git-submodule.d.ts.map +0 -1
  133. package/dist/tools/git-submodule.js +0 -290
  134. package/dist/tools/git-submodule.js.map +0 -1
  135. package/dist/tools/git-worktree.d.ts +0 -160
  136. package/dist/tools/git-worktree.d.ts.map +0 -1
  137. package/dist/tools/git-worktree.js +0 -270
  138. package/dist/tools/git-worktree.js.map +0 -1
  139. package/dist/tools/repositories.d.ts +0 -406
  140. package/dist/tools/repositories.d.ts.map +0 -1
  141. package/dist/tools/repositories.js +0 -570
  142. package/dist/tools/repositories.js.map +0 -1
  143. package/dist/tools/users.d.ts +0 -373
  144. package/dist/tools/users.d.ts.map +0 -1
  145. package/dist/tools/users.js +0 -500
  146. package/dist/tools/users.js.map +0 -1
  147. package/dist/tools/validator.d.ts +0 -171
  148. package/dist/tools/validator.d.ts.map +0 -1
  149. package/dist/tools/validator.js +0 -195
  150. package/dist/tools/validator.js.map +0 -1
  151. package/dist/tools/version-control.d.ts +0 -137
  152. package/dist/tools/version-control.d.ts.map +0 -1
  153. package/dist/tools/version-control.js +0 -165
  154. package/dist/tools/version-control.js.map +0 -1
@@ -1,1235 +1,1249 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.GitHubProvider = void 0;
37
- const base_provider_js_1 = require("./base-provider.js");
38
- /**
39
- * Provider específico para GitHub
40
- * Implementa todas as operações VCS usando a API REST do GitHub
41
- */
42
- class GitHubProvider extends base_provider_js_1.BaseVcsProvider {
43
- constructor(config) {
44
- super(config);
45
- }
46
- getBaseUrl(config) {
47
- return 'https://api.github.com';
48
- }
49
- getHeaders(config) {
50
- return {
51
- 'Authorization': `Bearer ${config.token}`,
52
- 'Content-Type': 'application/json',
53
- 'Accept': 'application/vnd.github.v3+json',
54
- 'User-Agent': 'Gitea-MCP-MultiProvider/2.3.0'
55
- };
56
- }
57
- // Usando normalizeError padrão do BaseVcsProvider
58
- normalizeRepository(data) {
59
- return {
60
- id: data.id,
61
- name: data.name,
62
- full_name: data.full_name,
63
- description: data.description,
64
- private: data.private,
65
- html_url: data.html_url,
66
- clone_url: data.clone_url,
67
- default_branch: data.default_branch,
68
- created_at: data.created_at,
69
- updated_at: data.updated_at,
70
- owner: {
71
- login: data.owner?.login,
72
- type: data.owner?.type || 'User'
73
- },
74
- raw: data
75
- };
76
- }
77
- normalizeBranch(data) {
78
- return {
79
- name: data.name,
80
- commit: {
81
- sha: data.commit?.sha,
82
- url: data.commit?.url
83
- },
84
- protected: data.protected,
85
- raw: data
86
- };
87
- }
88
- normalizeFile(data) {
89
- return {
90
- name: data.name,
91
- path: data.path,
92
- sha: data.sha,
93
- size: data.size,
94
- url: data.url,
95
- html_url: data.html_url,
96
- git_url: data.git_url,
97
- download_url: data.download_url,
98
- type: data.type,
99
- content: data.content,
100
- encoding: data.encoding,
101
- raw: data
102
- };
103
- }
104
- normalizeCommit(data) {
105
- return {
106
- sha: data.sha,
107
- message: data.commit?.message || data.message,
108
- author: {
109
- name: data.commit?.author?.name || data.author?.login,
110
- email: data.commit?.author?.email,
111
- date: data.commit?.author?.date
112
- },
113
- committer: {
114
- name: data.commit?.committer?.name || data.committer?.login,
115
- email: data.commit?.committer?.email,
116
- date: data.commit?.committer?.date
117
- },
118
- url: data.url,
119
- html_url: data.html_url,
120
- raw: data
121
- };
122
- }
123
- normalizeIssue(data) {
124
- return {
125
- id: data.id,
126
- number: data.number,
127
- title: data.title,
128
- body: data.body,
129
- state: data.state,
130
- user: {
131
- login: data.user?.login,
132
- id: data.user?.id
133
- },
134
- assignees: data.assignees?.map((a) => ({
135
- login: a.login,
136
- id: a.id
137
- })),
138
- labels: data.labels?.map((l) => ({
139
- name: l.name,
140
- color: l.color
141
- })),
142
- created_at: data.created_at,
143
- updated_at: data.updated_at,
144
- closed_at: data.closed_at,
145
- raw: data
146
- };
147
- }
148
- normalizePullRequest(data) {
149
- return {
150
- id: data.id,
151
- number: data.number,
152
- title: data.title,
153
- body: data.body,
154
- state: data.state,
155
- user: {
156
- login: data.user?.login,
157
- id: data.user?.id
158
- },
159
- head: {
160
- ref: data.head?.ref,
161
- sha: data.head?.sha,
162
- repo: {
163
- name: data.head?.repo?.name,
164
- full_name: data.head?.repo?.full_name
165
- }
166
- },
167
- base: {
168
- ref: data.base?.ref,
169
- sha: data.base?.sha,
170
- repo: {
171
- name: data.base?.repo?.name,
172
- full_name: data.base?.repo?.full_name
173
- }
174
- },
175
- created_at: data.created_at,
176
- updated_at: data.updated_at,
177
- closed_at: data.closed_at,
178
- merged_at: data.merged_at,
179
- mergeable: data.mergeable,
180
- raw: data
181
- };
182
- }
183
- normalizeRelease(data) {
184
- return {
185
- id: data.id,
186
- tag_name: data.tag_name,
187
- name: data.name,
188
- body: data.body,
189
- draft: data.draft,
190
- prerelease: data.prerelease,
191
- created_at: data.created_at,
192
- published_at: data.published_at,
193
- html_url: data.html_url,
194
- tarball_url: data.tarball_url,
195
- zipball_url: data.zipball_url,
196
- raw: data
197
- };
198
- }
199
- normalizeTag(data) {
200
- return {
201
- name: data.name,
202
- commit: {
203
- sha: data.commit?.sha,
204
- url: data.commit?.url
205
- },
206
- zipball_url: data.zipball_url,
207
- tarball_url: data.tarball_url,
208
- raw: data
209
- };
210
- }
211
- normalizeUser(data) {
212
- return {
213
- id: data.id,
214
- login: data.login,
215
- name: data.name,
216
- email: data.email,
217
- avatar_url: data.avatar_url,
218
- html_url: data.html_url,
219
- type: data.type,
220
- raw: data
221
- };
222
- }
223
- normalizeOrganization(data) {
224
- return {
225
- id: data.id,
226
- login: data.login,
227
- name: data.name,
228
- description: data.description,
229
- avatar_url: data.avatar_url,
230
- html_url: data.html_url,
231
- location: data.location,
232
- website: data.blog,
233
- public_repos: data.public_repos,
234
- public_members: data.public_members,
235
- raw: data
236
- };
237
- }
238
- normalizeWebhook(data) {
239
- return {
240
- id: data.id,
241
- type: data.type,
242
- name: data.name,
243
- active: data.active,
244
- events: data.events,
245
- config: {
246
- url: data.config?.url,
247
- content_type: data.config?.content_type,
248
- secret: data.config?.secret
249
- },
250
- created_at: data.created_at,
251
- updated_at: data.updated_at,
252
- raw: data
253
- };
254
- }
255
- // Implementações específicas do GitHub
256
- async listRepositories(username, page = 1, limit = 30) {
257
- const url = username ? `/users/${username}/repos` : '/user/repos';
258
- const data = await this.get(url, { page, per_page: limit, sort: 'updated' });
259
- return data.map(repo => this.normalizeRepository(repo));
260
- }
261
- async getRepository(owner, repo) {
262
- const data = await this.get(`/repos/${owner}/${repo}`);
263
- return this.normalizeRepository(data);
264
- }
265
- async createRepository(name, description, privateRepo = false) {
266
- const data = await this.post('/user/repos', {
267
- name,
268
- description,
269
- private: privateRepo,
270
- auto_init: true
271
- });
272
- return this.normalizeRepository(data);
273
- }
274
- async updateRepository(owner, repo, updates) {
275
- const data = await this.patch(`/repos/${owner}/${repo}`, updates);
276
- return this.normalizeRepository(data);
277
- }
278
- async deleteRepository(owner, repo) {
279
- await this.delete(`/repos/${owner}/${repo}`);
280
- return true;
281
- }
282
- async forkRepository(owner, repo, organization) {
283
- const payload = organization ? { organization } : {};
284
- const data = await this.post(`/repos/${owner}/${repo}/forks`, payload);
285
- return this.normalizeRepository(data);
286
- }
287
- async searchRepositories(query, page = 1, limit = 30) {
288
- const data = await this.get('/search/repositories', {
289
- q: query,
290
- page,
291
- per_page: limit,
292
- sort: 'stars',
293
- order: 'desc'
294
- });
295
- return data.items.map((repo) => this.normalizeRepository(repo));
296
- }
297
- async listBranches(owner, repo, page = 1, limit = 30) {
298
- const data = await this.get(`/repos/${owner}/${repo}/branches`, { page, per_page: limit });
299
- return data.map(branch => this.normalizeBranch(branch));
300
- }
301
- async getBranch(owner, repo, branch) {
302
- const data = await this.get(`/repos/${owner}/${repo}/branches/${branch}`);
303
- return this.normalizeBranch(data);
304
- }
305
- async createBranch(owner, repo, branchName, fromBranch) {
306
- // GitHub não tem endpoint direto para criar branch, mas podemos usar o endpoint de arquivos
307
- // Para simplicidade, retornamos um mock por enquanto
308
- return {
309
- name: branchName,
310
- commit: {
311
- sha: 'mock-sha',
312
- url: `https://api.github.com/repos/${owner}/${repo}/git/commits/mock-sha`
313
- },
314
- protected: false,
315
- raw: { name: branchName, from: fromBranch }
316
- };
317
- }
318
- async deleteBranch(owner, repo, branch) {
319
- // GitHub não tem endpoint direto para deletar branch
320
- // Retornamos true para simplicidade
321
- return true;
322
- }
323
- async getFile(owner, repo, path, ref) {
324
- const params = ref ? { ref } : {};
325
- const data = await this.get(`/repos/${owner}/${repo}/contents/${path}`, params);
326
- return this.normalizeFile(data);
327
- }
328
- async createFile(owner, repo, path, content, message, branch) {
329
- const payload = {
330
- message,
331
- content: Buffer.from(content).toString('base64')
332
- };
333
- if (branch) {
334
- payload.branch = branch;
335
- }
336
- const data = await this.put(`/repos/${owner}/${repo}/contents/${path}`, payload);
337
- return this.normalizeFile(data.content);
338
- }
339
- async updateFile(owner, repo, path, content, message, sha, branch) {
340
- const payload = {
341
- message,
342
- content: Buffer.from(content).toString('base64'),
343
- sha
344
- };
345
- if (branch) {
346
- payload.branch = branch;
347
- }
348
- const data = await this.put(`/repos/${owner}/${repo}/contents/${path}`, payload);
349
- return this.normalizeFile(data.content);
350
- }
351
- async deleteFile(owner, repo, path, message, sha, branch) {
352
- const payload = {
353
- message,
354
- sha
355
- };
356
- if (branch) {
357
- payload.branch = branch;
358
- }
359
- await this.delete(`/repos/${owner}/${repo}/contents/${path}`, { data: payload });
360
- return true;
361
- }
362
- async listFiles(owner, repo, path, ref) {
363
- const params = ref ? { ref } : {};
364
- const data = await this.get(`/repos/${owner}/${repo}/contents/${path}`, params);
365
- return data.map(file => this.normalizeFile(file));
366
- }
367
- async uploadProject(owner, repo, projectPath, message, branch) {
368
- const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
369
- const path = await Promise.resolve().then(() => __importStar(require('path')));
370
- let uploaded = 0;
371
- const errors = [];
372
- try {
373
- // Função recursiva para processar diretórios
374
- const processDirectory = async (dirPath, relativePath = '') => {
375
- const items = await fs.readdir(dirPath, { withFileTypes: true });
376
- for (const item of items) {
377
- const fullPath = path.join(dirPath, item.name);
378
- const itemRelativePath = relativePath ? path.join(relativePath, item.name) : item.name;
379
- // Pular diretórios que não devem ser enviados
380
- if (item.isDirectory()) {
381
- if (item.name === 'node_modules' || item.name === '.git' || item.name === 'dist') {
382
- continue;
383
- }
384
- await processDirectory(fullPath, itemRelativePath);
385
- }
386
- else {
387
- // Pular arquivos que não devem ser enviados
388
- if (item.name.endsWith('.log') || item.name.endsWith('.tmp') || item.name.startsWith('.')) {
389
- continue;
390
- }
391
- try {
392
- const content = await fs.readFile(fullPath, 'utf-8');
393
- await this.createFile(owner, repo, itemRelativePath, content, message, branch);
394
- uploaded++;
395
- }
396
- catch (error) {
397
- errors.push(`Erro ao enviar ${itemRelativePath}: ${error instanceof Error ? error.message : String(error)}`);
398
- }
399
- }
400
- }
401
- };
402
- await processDirectory(projectPath);
403
- return { uploaded, errors };
404
- }
405
- catch (error) {
406
- throw new Error(`Falha ao fazer upload do projeto: ${error instanceof Error ? error.message : String(error)}`);
407
- }
408
- }
409
- async listCommits(owner, repo, branch, page = 1, limit = 30) {
410
- const params = { page, per_page: limit };
411
- if (branch)
412
- params.sha = branch;
413
- const data = await this.get(`/repos/${owner}/${repo}/commits`, params);
414
- return data.map(commit => this.normalizeCommit(commit));
415
- }
416
- async getCommit(owner, repo, sha) {
417
- const data = await this.get(`/repos/${owner}/${repo}/git/commits/${sha}`);
418
- return this.normalizeCommit(data);
419
- }
420
- async listIssues(owner, repo, state = 'open', page = 1, limit = 30) {
421
- const data = await this.get(`/repos/${owner}/${repo}/issues`, {
422
- state,
423
- page,
424
- per_page: limit,
425
- filter: 'all'
426
- });
427
- return data.map(issue => this.normalizeIssue(issue));
428
- }
429
- async getIssue(owner, repo, issueNumber) {
430
- const data = await this.get(`/repos/${owner}/${repo}/issues/${issueNumber}`);
431
- return this.normalizeIssue(data);
432
- }
433
- async createIssue(owner, repo, title, body, assignees, labels) {
434
- const payload = { title };
435
- if (body)
436
- payload.body = body;
437
- if (assignees)
438
- payload.assignees = assignees;
439
- if (labels)
440
- payload.labels = labels;
441
- const data = await this.post(`/repos/${owner}/${repo}/issues`, payload);
442
- return this.normalizeIssue(data);
443
- }
444
- async updateIssue(owner, repo, issueNumber, updates) {
445
- const data = await this.patch(`/repos/${owner}/${repo}/issues/${issueNumber}`, updates);
446
- return this.normalizeIssue(data);
447
- }
448
- async closeIssue(owner, repo, issueNumber) {
449
- return this.updateIssue(owner, repo, issueNumber, { state: 'closed' });
450
- }
451
- async listPullRequests(owner, repo, state = 'open', page = 1, limit = 30) {
452
- const data = await this.get(`/repos/${owner}/${repo}/pulls`, {
453
- state,
454
- page,
455
- per_page: limit,
456
- sort: 'updated',
457
- direction: 'desc'
458
- });
459
- return data.map(pr => this.normalizePullRequest(pr));
460
- }
461
- async getPullRequest(owner, repo, pullNumber) {
462
- const data = await this.get(`/repos/${owner}/${repo}/pulls/${pullNumber}`);
463
- return this.normalizePullRequest(data);
464
- }
465
- async createPullRequest(owner, repo, title, body, head, base) {
466
- const data = await this.post(`/repos/${owner}/${repo}/pulls`, {
467
- title,
468
- body,
469
- head,
470
- base
471
- });
472
- return this.normalizePullRequest(data);
473
- }
474
- async updatePullRequest(owner, repo, pullNumber, updates) {
475
- const data = await this.patch(`/repos/${owner}/${repo}/pulls/${pullNumber}`, updates);
476
- return this.normalizePullRequest(data);
477
- }
478
- async mergePullRequest(owner, repo, pullNumber, mergeMethod = 'merge') {
479
- await this.put(`/repos/${owner}/${repo}/pulls/${pullNumber}/merge`, {
480
- merge_method: mergeMethod
481
- });
482
- return true;
483
- }
484
- async listReleases(owner, repo, page = 1, limit = 30) {
485
- const data = await this.get(`/repos/${owner}/${repo}/releases`, { page, per_page: limit });
486
- return data.map(release => this.normalizeRelease(release));
487
- }
488
- async getRelease(owner, repo, releaseId) {
489
- const data = await this.get(`/repos/${owner}/${repo}/releases/${releaseId}`);
490
- return this.normalizeRelease(data);
491
- }
492
- async createRelease(owner, repo, releaseData) {
493
- try {
494
- const data = await this.post(`/repos/${owner}/${repo}/releases`, {
495
- tag_name: releaseData.tag_name,
496
- name: releaseData.name || releaseData.tag_name,
497
- body: releaseData.body || '',
498
- draft: releaseData.draft || false,
499
- prerelease: releaseData.prerelease || false,
500
- target_commitish: releaseData.target_commitish || 'main'
501
- });
502
- return this.normalizeRelease(data);
503
- }
504
- catch (error) {
505
- console.warn('[GITHUB] Falha ao criar release:', error.message);
506
- // Retorna release mock se falhar
507
- return {
508
- id: Date.now(),
509
- tag_name: releaseData.tag_name,
510
- name: releaseData.name || releaseData.tag_name,
511
- body: releaseData.body || '',
512
- draft: releaseData.draft || false,
513
- prerelease: releaseData.prerelease || false,
514
- created_at: new Date().toISOString(),
515
- published_at: releaseData.draft ? undefined : new Date().toISOString(),
516
- html_url: `https://github.com/${owner}/${repo}/releases/tag/${releaseData.tag_name}`,
517
- tarball_url: `https://api.github.com/repos/${owner}/${repo}/tarball/${releaseData.tag_name}`,
518
- zipball_url: `https://api.github.com/repos/${owner}/${repo}/zipball/${releaseData.tag_name}`,
519
- raw: { mock: true, error: error.message }
520
- };
521
- }
522
- }
523
- async updateRelease(releaseId, updates) {
524
- const data = await this.patch(`/repos/releases/${releaseId}`, updates);
525
- return this.normalizeRelease(data);
526
- }
527
- async deleteRelease(releaseId) {
528
- await this.delete(`/repos/releases/${releaseId}`);
529
- return true;
530
- }
531
- async listTags(owner, repo, page = 1, limit = 30) {
532
- const data = await this.get(`/repos/${owner}/${repo}/tags`, { page, per_page: limit });
533
- return data.map(tag => this.normalizeTag(tag));
534
- }
535
- async getTag(owner, repo, tag) {
536
- const data = await this.get(`/repos/${owner}/${repo}/git/refs/tags/${tag}`);
537
- return this.normalizeTag(data);
538
- }
539
- async createTag(owner, repo, tagData) {
540
- try {
541
- // Primeiro cria o objeto tag
542
- const tagObject = await this.post(`/repos/${owner}/${repo}/git/tags`, {
543
- tag: tagData.tag_name,
544
- message: tagData.message || `Tag ${tagData.tag_name}`,
545
- object: tagData.target,
546
- type: 'commit'
547
- });
548
- // Depois cria a referência da tag
549
- const tagRef = await this.post(`/repos/${owner}/${repo}/git/refs`, {
550
- ref: `refs/tags/${tagData.tag_name}`,
551
- sha: tagObject.sha
552
- });
553
- return this.normalizeTag({
554
- name: tagData.tag_name,
555
- commit: {
556
- sha: tagObject.sha,
557
- url: tagObject.url
558
- },
559
- zipball_url: `https://api.github.com/repos/${owner}/${repo}/zipball/${tagData.tag_name}`,
560
- tarball_url: `https://api.github.com/repos/${owner}/${repo}/tarball/${tagData.tag_name}`,
561
- ...tagObject
562
- });
563
- }
564
- catch (error) {
565
- console.warn('[GITHUB] Falha ao criar tag:', error.message);
566
- // Retorna tag mock se falhar
567
- return {
568
- name: tagData.tag_name,
569
- commit: {
570
- sha: 'mock-sha-' + Date.now(),
571
- url: `https://api.github.com/repos/${owner}/${repo}/git/commits/mock-sha`
572
- },
573
- zipball_url: `https://api.github.com/repos/${owner}/${repo}/zipball/${tagData.tag_name}`,
574
- tarball_url: `https://api.github.com/repos/${owner}/${repo}/tarball/${tagData.tag_name}`,
575
- raw: { mock: true, error: error.message }
576
- };
577
- }
578
- }
579
- async deleteTag(owner, repo, tag) {
580
- await this.delete(`/repos/${owner}/${repo}/git/refs/tags/${tag}`);
581
- return true;
582
- }
583
- async getCurrentUser() {
584
- try {
585
- const data = await this.get('/user');
586
- return this.normalizeUser(data);
587
- }
588
- catch (error) {
589
- // Se falhar, retorna usuário mock para evitar falhas em cascata
590
- console.warn('[GITHUB] Falha ao obter usuário atual:', error.message);
591
- return {
592
- id: 1,
593
- login: 'current-user',
594
- name: 'Usuário Atual',
595
- email: 'user@example.com',
596
- avatar_url: 'https://example.com/avatar.png',
597
- html_url: 'https://example.com/user',
598
- type: 'User',
599
- raw: { mock: true, error: error.message }
600
- };
601
- }
602
- }
603
- async getUser(username) {
604
- const data = await this.get(`/users/${username}`);
605
- return this.normalizeUser(data);
606
- }
607
- async listUsers(page = 1, limit = 30) {
608
- const data = await this.get('/users', { since: (page - 1) * limit, per_page: limit });
609
- return data.map(user => this.normalizeUser(user));
610
- }
611
- async searchUsers(query, page = 1, limit = 30) {
612
- const data = await this.get('/search/users', {
613
- q: query,
614
- page,
615
- per_page: limit,
616
- sort: 'followers',
617
- order: 'desc'
618
- });
619
- return data.items.map((user) => this.normalizeUser(user));
620
- }
621
- async getUserOrganizations(username, page = 1, limit = 30) {
622
- try {
623
- const data = await this.get(`/users/${username}/orgs`, { page, per_page: limit });
624
- return data.map((org) => this.normalizeOrganization(org));
625
- }
626
- catch (error) {
627
- console.warn('[GITHUB] getUserOrganizations falhou:', error.message);
628
- // Retorna dados mockados se falhar
629
- return [{
630
- id: 1,
631
- login: 'mock-org',
632
- name: 'Organização Mock',
633
- description: 'Organização de exemplo',
634
- avatar_url: 'https://example.com/org-avatar.png',
635
- html_url: 'https://example.com/org',
636
- location: 'São Paulo',
637
- website: 'https://example.com',
638
- public_repos: 5,
639
- public_members: 3,
640
- raw: { mock: true, error: error.message }
641
- }];
642
- }
643
- }
644
- async getUserRepositories(username, page = 1, limit = 30) {
645
- try {
646
- const data = await this.get(`/users/${username}/repos`, {
647
- page,
648
- per_page: limit,
649
- sort: 'updated',
650
- direction: 'desc'
651
- });
652
- return data.map((repo) => this.normalizeRepository(repo));
653
- }
654
- catch (error) {
655
- console.warn('[GITHUB] getUserRepositories falhou:', error.message);
656
- // Retorna dados mockados se falhar
657
- return [{
658
- id: 1,
659
- name: 'mock-repo',
660
- full_name: `${username}/mock-repo`,
661
- description: 'Repositório mockado',
662
- private: false,
663
- html_url: 'https://example.com/repo',
664
- clone_url: 'https://example.com/repo.git',
665
- default_branch: 'main',
666
- created_at: new Date().toISOString(),
667
- updated_at: new Date().toISOString(),
668
- owner: {
669
- login: username,
670
- type: 'User'
671
- },
672
- raw: { mock: true, error: error.message }
673
- }];
674
- }
675
- }
676
- async listWebhooks(owner, repo, page = 1, limit = 30) {
677
- const data = await this.get(`/repos/${owner}/${repo}/hooks`, { page, per_page: limit });
678
- return data.map(webhook => this.normalizeWebhook(webhook));
679
- }
680
- async getWebhook(owner, repo, webhookId) {
681
- const data = await this.get(`/repos/${owner}/${repo}/hooks/${webhookId}`);
682
- return this.normalizeWebhook(data);
683
- }
684
- async createWebhook(owner, repo, url, events, secret) {
685
- const data = await this.post(`/repos/${owner}/${repo}/hooks`, {
686
- name: 'web',
687
- active: true,
688
- events,
689
- config: {
690
- url,
691
- content_type: 'json',
692
- secret
693
- }
694
- });
695
- return this.normalizeWebhook(data);
696
- }
697
- async updateWebhook(owner, repo, webhookId, updates) {
698
- const data = await this.patch(`/repos/${owner}/${repo}/hooks/${webhookId}`, updates);
699
- return this.normalizeWebhook(data);
700
- }
701
- async deleteWebhook(owner, repo, webhookId) {
702
- await this.delete(`/repos/${owner}/${repo}/hooks/${webhookId}`);
703
- return true;
704
- }
705
- async createCommit(owner, repo, message, branch, changes) {
706
- // Para criar um commit no GitHub, precisamos:
707
- // 1. Obter o último commit da branch
708
- // 2. Criar uma nova árvore com as mudanças
709
- // 3. Criar o commit
710
- // 4. Atualizar a referência da branch
711
- try {
712
- // Obter informações da branch
713
- const branchData = await this.getBranch(owner, repo, branch);
714
- // Para simplificar, vamos usar o endpoint de criação de commit direto
715
- const commitData = {
716
- message,
717
- tree: changes?.tree_sha || branchData.commit.sha,
718
- parents: [branchData.commit.sha]
719
- };
720
- const data = await this.post(`/repos/${owner}/${repo}/git/commits`, commitData);
721
- // Atualizar a referência da branch
722
- await this.post(`/repos/${owner}/${repo}/git/refs/heads/${branch}`, {
723
- sha: data.sha,
724
- force: false
725
- });
726
- return this.normalizeCommit(data);
727
- }
728
- catch (error) {
729
- console.error('Erro ao criar commit:', error);
730
- throw new Error(`Falha ao criar commit: ${error instanceof Error ? error.message : String(error)}`);
731
- }
732
- }
733
- // Implementações básicas para funcionalidades suportadas pelo GitHub
734
- async listWorkflows(params) {
735
- const { owner, repo } = params;
736
- const data = await this.get(`/repos/${owner}/${repo}/actions/workflows`);
737
- return data;
738
- }
739
- async listWorkflowRuns(params) {
740
- const { owner, repo } = params;
741
- const data = await this.get(`/repos/${owner}/${repo}/actions/runs`);
742
- return data;
743
- }
744
- async listDeployments(params) {
745
- const { owner, repo } = params;
746
- const data = await this.get(`/repos/${owner}/${repo}/deployments`);
747
- return data;
748
- }
749
- async runSecurityScan(params) {
750
- const { owner, repo } = params;
751
- // GitHub Security tab - basic implementation
752
- const data = await this.get(`/repos/${owner}/${repo}`);
753
- return {
754
- security: {
755
- enabled: data.security_and_analysis?.advanced_security?.status === 'enabled',
756
- secret_scanning: data.security_and_analysis?.secret_scanning?.status === 'enabled',
757
- dependabot: data.security_and_analysis?.dependabot_security_updates?.status === 'enabled'
758
- }
759
- };
760
- }
761
- async getTrafficStats(params) {
762
- const { owner, repo, metricType } = params;
763
- try {
764
- let endpoint = '';
765
- switch (metricType) {
766
- case 'views':
767
- endpoint = `/repos/${owner}/${repo}/traffic/views`;
768
- break;
769
- case 'clones':
770
- endpoint = `/repos/${owner}/${repo}/traffic/clones`;
771
- break;
772
- case 'popular':
773
- endpoint = `/repos/${owner}/${repo}/traffic/popular/paths`;
774
- break;
775
- case 'referrers':
776
- endpoint = `/repos/${owner}/${repo}/traffic/popular/referrers`;
777
- break;
778
- default:
779
- endpoint = `/repos/${owner}/${repo}/traffic/views`;
780
- }
781
- return await this.get(endpoint);
782
- }
783
- catch (error) {
784
- // GitHub traffic stats requer permissão especial e pode não estar disponível
785
- return {
786
- error: 'Traffic stats not available',
787
- message: 'Repository traffic statistics require special permissions or may not be available for this repository',
788
- metricType,
789
- available: false
790
- };
791
- }
792
- }
793
- async cloneRepository(params) {
794
- throw new Error('Funcionalidade não suportada por este provider: Provider não implementa cloneRepository');
795
- }
796
- async archiveRepository(params) {
797
- throw new Error('Funcionalidade não suportada por este provider: Provider não implementa archiveRepository');
798
- }
799
- async transferRepository(params) {
800
- const { owner, repo, newOwner } = params;
801
- const data = await this.post(`/repos/${owner}/${repo}/transfer`, { new_owner: newOwner });
802
- return data.owner.login === newOwner;
803
- }
804
- async createFromTemplate(params) {
805
- const { templateOwner, templateRepo, name, ...options } = params;
806
- const data = await this.post(`/repos/${templateOwner}/${templateRepo}/generate`, {
807
- name,
808
- ...options
809
- });
810
- return this.normalizeRepository(data);
811
- }
812
- async mirrorRepository(params) {
813
- throw new Error('Funcionalidade não suportada por este provider: Provider não implementa mirrorRepository');
814
- }
815
- // Implementações para analytics e outras funcionalidades
816
- async analyzeContributors(params) {
817
- const { owner, repo } = params;
818
- try {
819
- const contributors = await this.get(`/repos/${owner}/${repo}/contributors`);
820
- return {
821
- totalContributors: contributors.length,
822
- contributors: contributors.map(c => ({
823
- login: c.login,
824
- contributions: c.contributions,
825
- type: c.type
826
- })),
827
- period: 'all_time'
828
- };
829
- }
830
- catch (error) {
831
- return {
832
- error: 'Contributors analysis failed',
833
- message: 'Could not retrieve contributor information',
834
- available: false
835
- };
836
- }
837
- }
838
- async getActivityStats(params) {
839
- const { owner, repo } = params;
840
- try {
841
- const commits = await this.get(`/repos/${owner}/${repo}/commits?per_page=100`);
842
- const issues = await this.get(`/repos/${owner}/${repo}/issues?state=all&per_page=100`);
843
- return {
844
- recentCommits: commits.length,
845
- totalIssues: issues.length,
846
- openIssues: issues.filter(i => i.state === 'open').length,
847
- closedIssues: issues.filter(i => i.state === 'closed').length,
848
- activity: commits.length > 10 ? 'high' : commits.length > 5 ? 'medium' : 'low'
849
- };
850
- }
851
- catch (error) {
852
- return {
853
- error: 'Activity stats failed',
854
- message: 'Could not retrieve activity information',
855
- available: false
856
- };
857
- }
858
- }
859
- async getRepositoryInsights(params) {
860
- const { owner, repo } = params;
861
- try {
862
- const repoData = await this.get(`/repos/${owner}/${repo}`);
863
- return {
864
- insights: {
865
- stars: repoData.stargazers_count,
866
- forks: repoData.forks_count,
867
- watchers: repoData.watchers_count,
868
- language: repoData.language,
869
- size: repoData.size,
870
- created: repoData.created_at,
871
- updated: repoData.updated_at,
872
- isArchived: repoData.archived,
873
- isDisabled: repoData.disabled,
874
- license: repoData.license?.name,
875
- topics: repoData.topics || []
876
- }
877
- };
878
- }
879
- catch (error) {
880
- return {
881
- error: 'Repository insights failed',
882
- message: 'Could not retrieve repository insights',
883
- available: false
884
- };
885
- }
886
- }
887
- // Implementações para funcionalidades faltantes
888
- async createDeployment(params) {
889
- const { owner, repo, ref, environment, description, task, auto_merge, required_contexts, payload } = params;
890
- try {
891
- const deploymentData = {
892
- ref,
893
- environment: environment || 'production',
894
- description: description || 'Deployment created via API',
895
- auto_merge: auto_merge || false,
896
- required_contexts: required_contexts || []
897
- };
898
- if (task)
899
- deploymentData.task = task;
900
- if (payload)
901
- deploymentData.payload = payload;
902
- const data = await this.post(`/repos/${owner}/${repo}/deployments`, deploymentData);
903
- return {
904
- id: data.id,
905
- ref: data.ref,
906
- environment: data.environment,
907
- description: data.description,
908
- created_at: data.created_at,
909
- statuses_url: data.statuses_url,
910
- repository_url: data.repository_url,
911
- url: data.url
912
- };
913
- }
914
- catch (error) {
915
- throw new Error(`Falha ao criar deployment: ${error instanceof Error ? error.message : String(error)}`);
916
- }
917
- }
918
- async updateDeploymentStatus(params) {
919
- const { owner, repo, deployment_id, state, log_url, environment_url, description } = params;
920
- try {
921
- const statusData = {
922
- state,
923
- log_url: log_url || '',
924
- environment_url: environment_url || '',
925
- description: description || `Status updated to ${state}`
926
- };
927
- const data = await this.post(`/repos/${owner}/${repo}/deployments/${deployment_id}/statuses`, statusData);
928
- return {
929
- id: data.id,
930
- state: data.state,
931
- description: data.description,
932
- environment: data.environment,
933
- target_url: data.target_url,
934
- log_url: data.log_url,
935
- environment_url: data.environment_url,
936
- created_at: data.created_at,
937
- updated_at: data.updated_at,
938
- deployment_url: data.deployment_url,
939
- repository_url: data.repository_url
940
- };
941
- }
942
- catch (error) {
943
- throw new Error(`Falha ao atualizar status do deployment: ${error instanceof Error ? error.message : String(error)}`);
944
- }
945
- }
946
- async manageSecurityAlerts(params) {
947
- const { owner, repo, action, alert_number, dismiss_reason, dismiss_comment } = params;
948
- try {
949
- if (action === 'dismiss') {
950
- const dismissData = {
951
- dismissed_reason: dismiss_reason || 'tolerable_risk'
952
- };
953
- if (dismiss_comment)
954
- dismissData.dismissed_comment = dismiss_comment;
955
- const data = await this.patch(`/repos/${owner}/${repo}/dependabot/alerts/${alert_number}`, dismissData);
956
- return {
957
- number: data.number,
958
- state: data.state,
959
- dismissed_reason: data.dismissed_reason,
960
- dismissed_comment: data.dismissed_comment,
961
- dismissed_at: data.dismissed_at,
962
- dismissed_by: data.dismissed_by
963
- };
964
- }
965
- else if (action === 'reopen') {
966
- const data = await this.patch(`/repos/${owner}/${repo}/dependabot/alerts/${alert_number}`, {
967
- state: 'open'
968
- });
969
- return {
970
- number: data.number,
971
- state: data.state,
972
- created_at: data.created_at,
973
- updated_at: data.updated_at
974
- };
975
- }
976
- else {
977
- throw new Error(`Ação não suportada: ${action}`);
978
- }
979
- }
980
- catch (error) {
981
- throw new Error(`Falha ao gerenciar alertas de segurança: ${error instanceof Error ? error.message : String(error)}`);
982
- }
983
- }
984
- async listSecurityVulnerabilities(params) {
985
- const { owner, repo, state, severity, ecosystem, package_name } = params;
986
- try {
987
- const queryParams = {};
988
- if (state)
989
- queryParams.state = state;
990
- if (severity)
991
- queryParams.severity = severity;
992
- if (ecosystem)
993
- queryParams.ecosystem = ecosystem;
994
- if (package_name)
995
- queryParams.package = package_name;
996
- const data = await this.get(`/repos/${owner}/${repo}/dependabot/alerts`, queryParams);
997
- return {
998
- total_count: data.length,
999
- vulnerabilities: data.map(alert => ({
1000
- number: alert.number,
1001
- state: alert.state,
1002
- severity: alert.security_advisory?.severity,
1003
- summary: alert.security_advisory?.summary,
1004
- description: alert.security_advisory?.description,
1005
- created_at: alert.created_at,
1006
- updated_at: alert.updated_at,
1007
- dismissed_at: alert.dismissed_at,
1008
- dismissed_reason: alert.dismissed_reason,
1009
- dismissed_comment: alert.dismissed_comment,
1010
- dismissed_by: alert.dismissed_by,
1011
- dependency: {
1012
- package: alert.dependency?.package?.name,
1013
- ecosystem: alert.dependency?.package?.ecosystem,
1014
- manifest_path: alert.dependency?.manifest_path
1015
- }
1016
- }))
1017
- };
1018
- }
1019
- catch (error) {
1020
- return {
1021
- total_count: 0,
1022
- vulnerabilities: [],
1023
- note: 'Vulnerabilidades não disponíveis neste provider'
1024
- };
1025
- }
1026
- }
1027
- async createWorkflow(params) {
1028
- const { owner, repo, name, description, workflow_content } = params;
1029
- try {
1030
- // Criar o arquivo de workflow
1031
- const workflowPath = `.github/workflows/${name.toLowerCase().replace(/\s+/g, '-')}.yml`;
1032
- const data = await this.createFile(owner, repo, workflowPath, workflow_content, `Add ${name} workflow`);
1033
- return {
1034
- id: `workflow-${Date.now()}`,
1035
- name,
1036
- path: workflowPath,
1037
- state: 'active',
1038
- created_at: new Date().toISOString(),
1039
- updated_at: new Date().toISOString(),
1040
- url: data.html_url,
1041
- html_url: data.html_url
1042
- };
1043
- }
1044
- catch (error) {
1045
- throw new Error(`Falha ao criar workflow: ${error instanceof Error ? error.message : String(error)}`);
1046
- }
1047
- }
1048
- async triggerWorkflow(params) {
1049
- const { owner, repo, workflow_id, ref, inputs } = params;
1050
- try {
1051
- const triggerData = {
1052
- ref: ref || 'main'
1053
- };
1054
- if (inputs)
1055
- triggerData.inputs = inputs;
1056
- const data = await this.post(`/repos/${owner}/${repo}/actions/workflows/${workflow_id}/dispatches`, triggerData);
1057
- return {
1058
- success: true,
1059
- message: 'Workflow triggered successfully',
1060
- workflow_id,
1061
- ref,
1062
- inputs
1063
- };
1064
- }
1065
- catch (error) {
1066
- throw new Error(`Falha ao disparar workflow: ${error instanceof Error ? error.message : String(error)}`);
1067
- }
1068
- }
1069
- async getWorkflowStatus(params) {
1070
- const { owner, repo, run_id } = params;
1071
- try {
1072
- const data = await this.get(`/repos/${owner}/${repo}/actions/runs/${run_id}`);
1073
- return {
1074
- id: data.id,
1075
- name: data.name,
1076
- status: data.status,
1077
- conclusion: data.conclusion,
1078
- workflow_id: data.workflow_id,
1079
- head_branch: data.head_branch,
1080
- head_sha: data.head_sha,
1081
- run_number: data.run_number,
1082
- event: data.event,
1083
- created_at: data.created_at,
1084
- updated_at: data.updated_at,
1085
- run_started_at: data.run_started_at,
1086
- jobs_url: data.jobs_url,
1087
- logs_url: data.logs_url,
1088
- check_suite_url: data.check_suite_url,
1089
- artifacts_url: data.artifacts_url,
1090
- cancel_url: data.cancel_url,
1091
- rerun_url: data.rerun_url,
1092
- workflow_url: data.workflow_url,
1093
- head_commit: data.head_commit,
1094
- repository: data.repository,
1095
- head_repository: data.head_repository
1096
- };
1097
- }
1098
- catch (error) {
1099
- throw new Error(`Falha ao obter status do workflow: ${error instanceof Error ? error.message : String(error)}`);
1100
- }
1101
- }
1102
- async getWorkflowLogs(params) {
1103
- const { owner, repo, run_id, job_id, step_number } = params;
1104
- try {
1105
- let endpoint = `/repos/${owner}/${repo}/actions/runs/${run_id}/logs`;
1106
- if (job_id) {
1107
- endpoint = `/repos/${owner}/${repo}/actions/jobs/${job_id}/logs`;
1108
- if (step_number) {
1109
- endpoint += `?step=${step_number}`;
1110
- }
1111
- }
1112
- const data = await this.get(endpoint);
1113
- return {
1114
- logs: data,
1115
- run_id,
1116
- job_id,
1117
- step_number,
1118
- downloaded_at: new Date().toISOString()
1119
- };
1120
- }
1121
- catch (error) {
1122
- throw new Error(`Falha ao obter logs do workflow: ${error instanceof Error ? error.message : String(error)}`);
1123
- }
1124
- }
1125
- async listWorkflowArtifacts(params) {
1126
- const { owner, repo, run_id } = params;
1127
- try {
1128
- const data = await this.get(`/repos/${owner}/${repo}/actions/runs/${run_id}/artifacts`);
1129
- return {
1130
- total_count: data.total_count,
1131
- artifacts: data.artifacts.map((artifact) => ({
1132
- id: artifact.id,
1133
- node_id: artifact.node_id,
1134
- name: artifact.name,
1135
- size_in_bytes: artifact.size_in_bytes,
1136
- url: artifact.url,
1137
- archive_download_url: artifact.archive_download_url,
1138
- expired: artifact.expired,
1139
- created_at: artifact.created_at,
1140
- updated_at: artifact.updated_at,
1141
- expires_at: artifact.expires_at
1142
- }))
1143
- };
1144
- }
1145
- catch (error) {
1146
- return {
1147
- total_count: 0,
1148
- artifacts: [],
1149
- note: 'Artefatos não disponíveis'
1150
- };
1151
- }
1152
- }
1153
- async downloadArtifact(params) {
1154
- const { owner, repo, artifact_id, download_path } = params;
1155
- try {
1156
- const data = await this.get(`/repos/${owner}/${repo}/actions/artifacts/${artifact_id}/zip`);
1157
- return {
1158
- success: true,
1159
- artifact_id,
1160
- download_path,
1161
- downloaded_at: new Date().toISOString(),
1162
- message: 'Artefato baixado com sucesso'
1163
- };
1164
- }
1165
- catch (error) {
1166
- throw new Error(`Falha ao baixar artefato: ${error instanceof Error ? error.message : String(error)}`);
1167
- }
1168
- }
1169
- async listSecrets(params) {
1170
- const { owner, repo } = params;
1171
- try {
1172
- const data = await this.get(`/repos/${owner}/${repo}/actions/secrets`);
1173
- return {
1174
- total_count: data.total_count,
1175
- secrets: data.secrets.map((secret) => ({
1176
- name: secret.name,
1177
- created_at: secret.created_at,
1178
- updated_at: secret.updated_at
1179
- }))
1180
- };
1181
- }
1182
- catch (error) {
1183
- return {
1184
- total_count: 0,
1185
- secrets: [],
1186
- note: 'Secrets não disponíveis'
1187
- };
1188
- }
1189
- }
1190
- async listJobs(params) {
1191
- const { owner, repo, run_id } = params;
1192
- try {
1193
- const data = await this.get(`/repos/${owner}/${repo}/actions/runs/${run_id}/jobs`);
1194
- return {
1195
- total_count: data.total_count,
1196
- jobs: data.jobs.map((job) => ({
1197
- id: job.id,
1198
- run_id: job.run_id,
1199
- run_url: job.run_url,
1200
- node_id: job.node_id,
1201
- head_sha: job.head_sha,
1202
- url: job.url,
1203
- html_url: job.html_url,
1204
- status: job.status,
1205
- conclusion: job.conclusion,
1206
- started_at: job.started_at,
1207
- completed_at: job.completed_at,
1208
- name: job.name,
1209
- steps: job.steps,
1210
- check_run_url: job.check_run_url,
1211
- labels: job.labels,
1212
- runner_id: job.runner_id,
1213
- runner_name: job.runner_name,
1214
- runner_group_id: job.runner_group_id,
1215
- runner_group_name: job.runner_group_name
1216
- }))
1217
- };
1218
- }
1219
- catch (error) {
1220
- return {
1221
- total_count: 0,
1222
- jobs: [],
1223
- note: 'Jobs não disponíveis'
1224
- };
1225
- }
1226
- }
1227
- /**
1228
- * Obtém URL do repositório GitHub
1229
- */
1230
- getRepositoryUrl(owner, repo) {
1231
- return `https://github.com/${owner}/${repo}.git`;
1232
- }
1233
- }
1234
- exports.GitHubProvider = GitHubProvider;
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.GitHubProvider = void 0;
37
+ const base_provider_js_1 = require("./base-provider.js");
38
+ /**
39
+ * Provider específico para GitHub
40
+ * Implementa todas as operações VCS usando a API REST do GitHub
41
+ */
42
+ class GitHubProvider extends base_provider_js_1.BaseVcsProvider {
43
+ constructor(config) {
44
+ super(config);
45
+ }
46
+ getBaseUrl(config) {
47
+ return 'https://api.github.com';
48
+ }
49
+ getHeaders(config) {
50
+ return {
51
+ 'Authorization': `Bearer ${config.token}`,
52
+ 'Content-Type': 'application/json',
53
+ 'Accept': 'application/vnd.github.v3+json',
54
+ 'User-Agent': 'Gitea-MCP-MultiProvider/2.3.0'
55
+ };
56
+ }
57
+ // Usando normalizeError padrão do BaseVcsProvider
58
+ normalizeRepository(data) {
59
+ return {
60
+ id: data.id,
61
+ name: data.name,
62
+ full_name: data.full_name,
63
+ description: data.description,
64
+ private: data.private,
65
+ html_url: data.html_url,
66
+ clone_url: data.clone_url,
67
+ default_branch: data.default_branch,
68
+ created_at: data.created_at,
69
+ updated_at: data.updated_at,
70
+ owner: {
71
+ login: data.owner?.login,
72
+ type: data.owner?.type || 'User'
73
+ },
74
+ raw: data
75
+ };
76
+ }
77
+ normalizeBranch(data) {
78
+ return {
79
+ name: data.name,
80
+ commit: {
81
+ sha: data.commit?.sha,
82
+ url: data.commit?.url
83
+ },
84
+ protected: data.protected,
85
+ raw: data
86
+ };
87
+ }
88
+ normalizeFile(data) {
89
+ return {
90
+ name: data.name,
91
+ path: data.path,
92
+ sha: data.sha,
93
+ size: data.size,
94
+ url: data.url,
95
+ html_url: data.html_url,
96
+ git_url: data.git_url,
97
+ download_url: data.download_url,
98
+ type: data.type,
99
+ content: data.content,
100
+ encoding: data.encoding,
101
+ raw: data
102
+ };
103
+ }
104
+ normalizeCommit(data) {
105
+ return {
106
+ sha: data.sha,
107
+ message: data.commit?.message || data.message,
108
+ author: {
109
+ name: data.commit?.author?.name || data.author?.login,
110
+ email: data.commit?.author?.email,
111
+ date: data.commit?.author?.date
112
+ },
113
+ committer: {
114
+ name: data.commit?.committer?.name || data.committer?.login,
115
+ email: data.commit?.committer?.email,
116
+ date: data.commit?.committer?.date
117
+ },
118
+ commit: {
119
+ author: {
120
+ name: data.commit?.author?.name || '',
121
+ email: data.commit?.author?.email || '',
122
+ date: data.commit?.author?.date || ''
123
+ },
124
+ committer: {
125
+ name: data.commit?.committer?.name || '',
126
+ email: data.commit?.committer?.email || '',
127
+ date: data.commit?.committer?.date || ''
128
+ },
129
+ message: data.commit?.message || data.message || ''
130
+ },
131
+ url: data.url,
132
+ html_url: data.html_url,
133
+ raw: data
134
+ };
135
+ }
136
+ normalizeIssue(data) {
137
+ return {
138
+ id: data.id,
139
+ number: data.number,
140
+ title: data.title,
141
+ body: data.body,
142
+ state: data.state,
143
+ user: {
144
+ login: data.user?.login,
145
+ id: data.user?.id
146
+ },
147
+ assignees: data.assignees?.map((a) => ({
148
+ login: a.login,
149
+ id: a.id
150
+ })),
151
+ labels: data.labels?.map((l) => ({
152
+ name: l.name,
153
+ color: l.color
154
+ })),
155
+ created_at: data.created_at,
156
+ updated_at: data.updated_at,
157
+ closed_at: data.closed_at,
158
+ raw: data
159
+ };
160
+ }
161
+ normalizePullRequest(data) {
162
+ return {
163
+ id: data.id,
164
+ number: data.number,
165
+ title: data.title,
166
+ body: data.body,
167
+ state: data.state,
168
+ user: {
169
+ login: data.user?.login,
170
+ id: data.user?.id
171
+ },
172
+ head: {
173
+ ref: data.head?.ref,
174
+ sha: data.head?.sha,
175
+ repo: {
176
+ name: data.head?.repo?.name,
177
+ full_name: data.head?.repo?.full_name
178
+ }
179
+ },
180
+ base: {
181
+ ref: data.base?.ref,
182
+ sha: data.base?.sha,
183
+ repo: {
184
+ name: data.base?.repo?.name,
185
+ full_name: data.base?.repo?.full_name
186
+ }
187
+ },
188
+ created_at: data.created_at,
189
+ updated_at: data.updated_at,
190
+ closed_at: data.closed_at,
191
+ merged_at: data.merged_at,
192
+ mergeable: data.mergeable,
193
+ raw: data
194
+ };
195
+ }
196
+ normalizeRelease(data) {
197
+ return {
198
+ id: data.id,
199
+ tag_name: data.tag_name,
200
+ name: data.name,
201
+ body: data.body,
202
+ draft: data.draft,
203
+ prerelease: data.prerelease,
204
+ created_at: data.created_at,
205
+ published_at: data.published_at,
206
+ html_url: data.html_url,
207
+ tarball_url: data.tarball_url,
208
+ zipball_url: data.zipball_url,
209
+ raw: data
210
+ };
211
+ }
212
+ normalizeTag(data) {
213
+ return {
214
+ name: data.name,
215
+ commit: {
216
+ sha: data.commit?.sha,
217
+ url: data.commit?.url
218
+ },
219
+ zipball_url: data.zipball_url,
220
+ tarball_url: data.tarball_url,
221
+ raw: data
222
+ };
223
+ }
224
+ normalizeUser(data) {
225
+ return {
226
+ id: data.id,
227
+ login: data.login,
228
+ name: data.name,
229
+ email: data.email,
230
+ avatar_url: data.avatar_url,
231
+ html_url: data.html_url,
232
+ type: data.type,
233
+ raw: data
234
+ };
235
+ }
236
+ normalizeOrganization(data) {
237
+ return {
238
+ id: data.id,
239
+ login: data.login,
240
+ name: data.name,
241
+ description: data.description,
242
+ avatar_url: data.avatar_url,
243
+ html_url: data.html_url,
244
+ location: data.location,
245
+ website: data.blog,
246
+ public_repos: data.public_repos,
247
+ public_members: data.public_members,
248
+ raw: data
249
+ };
250
+ }
251
+ normalizeWebhook(data) {
252
+ return {
253
+ id: data.id,
254
+ type: data.type,
255
+ name: data.name,
256
+ active: data.active,
257
+ url: data.config?.url || data.url || '',
258
+ events: data.events,
259
+ config: {
260
+ url: data.config?.url,
261
+ content_type: data.config?.content_type,
262
+ secret: data.config?.secret
263
+ },
264
+ created_at: data.created_at,
265
+ updated_at: data.updated_at,
266
+ raw: data
267
+ };
268
+ }
269
+ // Implementações específicas do GitHub
270
+ async listRepositories(username, page = 1, limit = 30) {
271
+ const url = username ? `/users/${username}/repos` : '/user/repos';
272
+ const data = await this.get(url, { page, per_page: limit, sort: 'updated' });
273
+ return data.map(repo => this.normalizeRepository(repo));
274
+ }
275
+ async getRepository(owner, repo) {
276
+ const data = await this.get(`/repos/${owner}/${repo}`);
277
+ return this.normalizeRepository(data);
278
+ }
279
+ async createRepository(name, description, privateRepo = false) {
280
+ const data = await this.post('/user/repos', {
281
+ name,
282
+ description,
283
+ private: privateRepo,
284
+ auto_init: true
285
+ });
286
+ return this.normalizeRepository(data);
287
+ }
288
+ async updateRepository(owner, repo, updates) {
289
+ const data = await this.patch(`/repos/${owner}/${repo}`, updates);
290
+ return this.normalizeRepository(data);
291
+ }
292
+ async deleteRepository(owner, repo) {
293
+ await this.delete(`/repos/${owner}/${repo}`);
294
+ return true;
295
+ }
296
+ async forkRepository(owner, repo, organization) {
297
+ const payload = organization ? { organization } : {};
298
+ const data = await this.post(`/repos/${owner}/${repo}/forks`, payload);
299
+ return this.normalizeRepository(data);
300
+ }
301
+ async searchRepositories(query, page = 1, limit = 30) {
302
+ const data = await this.get('/search/repositories', {
303
+ q: query,
304
+ page,
305
+ per_page: limit,
306
+ sort: 'stars',
307
+ order: 'desc'
308
+ });
309
+ return data.items.map((repo) => this.normalizeRepository(repo));
310
+ }
311
+ async listBranches(owner, repo, page = 1, limit = 30) {
312
+ const data = await this.get(`/repos/${owner}/${repo}/branches`, { page, per_page: limit });
313
+ return data.map(branch => this.normalizeBranch(branch));
314
+ }
315
+ async getBranch(owner, repo, branch) {
316
+ const data = await this.get(`/repos/${owner}/${repo}/branches/${branch}`);
317
+ return this.normalizeBranch(data);
318
+ }
319
+ async createBranch(owner, repo, branchName, fromBranch) {
320
+ // GitHub não tem endpoint direto para criar branch, mas podemos usar o endpoint de arquivos
321
+ // Para simplicidade, retornamos um mock por enquanto
322
+ return {
323
+ name: branchName,
324
+ commit: {
325
+ sha: 'mock-sha',
326
+ url: `https://api.github.com/repos/${owner}/${repo}/git/commits/mock-sha`
327
+ },
328
+ protected: false,
329
+ raw: { name: branchName, from: fromBranch }
330
+ };
331
+ }
332
+ async deleteBranch(owner, repo, branch) {
333
+ // GitHub não tem endpoint direto para deletar branch
334
+ // Retornamos true para simplicidade
335
+ return true;
336
+ }
337
+ async getFile(owner, repo, path, ref) {
338
+ const params = ref ? { ref } : {};
339
+ const data = await this.get(`/repos/${owner}/${repo}/contents/${path}`, params);
340
+ return this.normalizeFile(data);
341
+ }
342
+ async createFile(owner, repo, path, content, message, branch) {
343
+ const payload = {
344
+ message,
345
+ content: Buffer.from(content).toString('base64')
346
+ };
347
+ if (branch) {
348
+ payload.branch = branch;
349
+ }
350
+ const data = await this.put(`/repos/${owner}/${repo}/contents/${path}`, payload);
351
+ return this.normalizeFile(data.content);
352
+ }
353
+ async updateFile(owner, repo, path, content, message, sha, branch) {
354
+ const payload = {
355
+ message,
356
+ content: Buffer.from(content).toString('base64'),
357
+ sha
358
+ };
359
+ if (branch) {
360
+ payload.branch = branch;
361
+ }
362
+ const data = await this.put(`/repos/${owner}/${repo}/contents/${path}`, payload);
363
+ return this.normalizeFile(data.content);
364
+ }
365
+ async deleteFile(owner, repo, path, message, sha, branch) {
366
+ const payload = {
367
+ message,
368
+ sha
369
+ };
370
+ if (branch) {
371
+ payload.branch = branch;
372
+ }
373
+ await this.delete(`/repos/${owner}/${repo}/contents/${path}`, { data: payload });
374
+ return true;
375
+ }
376
+ async listFiles(owner, repo, path, ref) {
377
+ const params = ref ? { ref } : {};
378
+ const data = await this.get(`/repos/${owner}/${repo}/contents/${path}`, params);
379
+ return data.map(file => this.normalizeFile(file));
380
+ }
381
+ async uploadProject(owner, repo, projectPath, message, branch) {
382
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
383
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
384
+ let uploaded = 0;
385
+ const errors = [];
386
+ try {
387
+ // Função recursiva para processar diretórios
388
+ const processDirectory = async (dirPath, relativePath = '') => {
389
+ const items = await fs.readdir(dirPath, { withFileTypes: true });
390
+ for (const item of items) {
391
+ const fullPath = path.join(dirPath, item.name);
392
+ const itemRelativePath = relativePath ? path.join(relativePath, item.name) : item.name;
393
+ // Pular diretórios que não devem ser enviados
394
+ if (item.isDirectory()) {
395
+ if (item.name === 'node_modules' || item.name === '.git' || item.name === 'dist') {
396
+ continue;
397
+ }
398
+ await processDirectory(fullPath, itemRelativePath);
399
+ }
400
+ else {
401
+ // Pular arquivos que não devem ser enviados
402
+ if (item.name.endsWith('.log') || item.name.endsWith('.tmp') || item.name.startsWith('.')) {
403
+ continue;
404
+ }
405
+ try {
406
+ const content = await fs.readFile(fullPath, 'utf-8');
407
+ await this.createFile(owner, repo, itemRelativePath, content, message, branch);
408
+ uploaded++;
409
+ }
410
+ catch (error) {
411
+ errors.push(`Erro ao enviar ${itemRelativePath}: ${error instanceof Error ? error.message : String(error)}`);
412
+ }
413
+ }
414
+ }
415
+ };
416
+ await processDirectory(projectPath);
417
+ return { uploaded, errors };
418
+ }
419
+ catch (error) {
420
+ throw new Error(`Falha ao fazer upload do projeto: ${error instanceof Error ? error.message : String(error)}`);
421
+ }
422
+ }
423
+ async listCommits(owner, repo, branch, page = 1, limit = 30) {
424
+ const params = { page, per_page: limit };
425
+ if (branch)
426
+ params.sha = branch;
427
+ const data = await this.get(`/repos/${owner}/${repo}/commits`, params);
428
+ return data.map(commit => this.normalizeCommit(commit));
429
+ }
430
+ async getCommit(owner, repo, sha) {
431
+ const data = await this.get(`/repos/${owner}/${repo}/git/commits/${sha}`);
432
+ return this.normalizeCommit(data);
433
+ }
434
+ async listIssues(owner, repo, state = 'open', page = 1, limit = 30) {
435
+ const data = await this.get(`/repos/${owner}/${repo}/issues`, {
436
+ state,
437
+ page,
438
+ per_page: limit,
439
+ filter: 'all'
440
+ });
441
+ return data.map(issue => this.normalizeIssue(issue));
442
+ }
443
+ async getIssue(owner, repo, issueNumber) {
444
+ const data = await this.get(`/repos/${owner}/${repo}/issues/${issueNumber}`);
445
+ return this.normalizeIssue(data);
446
+ }
447
+ async createIssue(owner, repo, title, body, assignees, labels) {
448
+ const payload = { title };
449
+ if (body)
450
+ payload.body = body;
451
+ if (assignees)
452
+ payload.assignees = assignees;
453
+ if (labels)
454
+ payload.labels = labels;
455
+ const data = await this.post(`/repos/${owner}/${repo}/issues`, payload);
456
+ return this.normalizeIssue(data);
457
+ }
458
+ async updateIssue(owner, repo, issueNumber, updates) {
459
+ const data = await this.patch(`/repos/${owner}/${repo}/issues/${issueNumber}`, updates);
460
+ return this.normalizeIssue(data);
461
+ }
462
+ async closeIssue(owner, repo, issueNumber) {
463
+ return this.updateIssue(owner, repo, issueNumber, { state: 'closed' });
464
+ }
465
+ async listPullRequests(owner, repo, state = 'open', page = 1, limit = 30) {
466
+ const data = await this.get(`/repos/${owner}/${repo}/pulls`, {
467
+ state,
468
+ page,
469
+ per_page: limit,
470
+ sort: 'updated',
471
+ direction: 'desc'
472
+ });
473
+ return data.map(pr => this.normalizePullRequest(pr));
474
+ }
475
+ async getPullRequest(owner, repo, pullNumber) {
476
+ const data = await this.get(`/repos/${owner}/${repo}/pulls/${pullNumber}`);
477
+ return this.normalizePullRequest(data);
478
+ }
479
+ async createPullRequest(owner, repo, title, body, head, base) {
480
+ const data = await this.post(`/repos/${owner}/${repo}/pulls`, {
481
+ title,
482
+ body,
483
+ head,
484
+ base
485
+ });
486
+ return this.normalizePullRequest(data);
487
+ }
488
+ async updatePullRequest(owner, repo, pullNumber, updates) {
489
+ const data = await this.patch(`/repos/${owner}/${repo}/pulls/${pullNumber}`, updates);
490
+ return this.normalizePullRequest(data);
491
+ }
492
+ async mergePullRequest(owner, repo, pullNumber, mergeMethod = 'merge') {
493
+ await this.put(`/repos/${owner}/${repo}/pulls/${pullNumber}/merge`, {
494
+ merge_method: mergeMethod
495
+ });
496
+ return true;
497
+ }
498
+ async listReleases(owner, repo, page = 1, limit = 30) {
499
+ const data = await this.get(`/repos/${owner}/${repo}/releases`, { page, per_page: limit });
500
+ return data.map(release => this.normalizeRelease(release));
501
+ }
502
+ async getRelease(owner, repo, releaseId) {
503
+ const data = await this.get(`/repos/${owner}/${repo}/releases/${releaseId}`);
504
+ return this.normalizeRelease(data);
505
+ }
506
+ async createRelease(owner, repo, releaseData) {
507
+ try {
508
+ const data = await this.post(`/repos/${owner}/${repo}/releases`, {
509
+ tag_name: releaseData.tag_name,
510
+ name: releaseData.name || releaseData.tag_name,
511
+ body: releaseData.body || '',
512
+ draft: releaseData.draft || false,
513
+ prerelease: releaseData.prerelease || false,
514
+ target_commitish: releaseData.target_commitish || 'main'
515
+ });
516
+ return this.normalizeRelease(data);
517
+ }
518
+ catch (error) {
519
+ console.warn('[GITHUB] Falha ao criar release:', error.message);
520
+ // Retorna release mock se falhar
521
+ return {
522
+ id: Date.now(),
523
+ tag_name: releaseData.tag_name,
524
+ name: releaseData.name || releaseData.tag_name,
525
+ body: releaseData.body || '',
526
+ draft: releaseData.draft || false,
527
+ prerelease: releaseData.prerelease || false,
528
+ created_at: new Date().toISOString(),
529
+ published_at: releaseData.draft ? undefined : new Date().toISOString(),
530
+ html_url: `https://github.com/${owner}/${repo}/releases/tag/${releaseData.tag_name}`,
531
+ tarball_url: `https://api.github.com/repos/${owner}/${repo}/tarball/${releaseData.tag_name}`,
532
+ zipball_url: `https://api.github.com/repos/${owner}/${repo}/zipball/${releaseData.tag_name}`,
533
+ raw: { mock: true, error: error.message }
534
+ };
535
+ }
536
+ }
537
+ async updateRelease(releaseId, updates) {
538
+ const data = await this.patch(`/repos/releases/${releaseId}`, updates);
539
+ return this.normalizeRelease(data);
540
+ }
541
+ async deleteRelease(releaseId) {
542
+ await this.delete(`/repos/releases/${releaseId}`);
543
+ return true;
544
+ }
545
+ async listTags(owner, repo, page = 1, limit = 30) {
546
+ const data = await this.get(`/repos/${owner}/${repo}/tags`, { page, per_page: limit });
547
+ return data.map(tag => this.normalizeTag(tag));
548
+ }
549
+ async getTag(owner, repo, tag) {
550
+ const data = await this.get(`/repos/${owner}/${repo}/git/refs/tags/${tag}`);
551
+ return this.normalizeTag(data);
552
+ }
553
+ async createTag(owner, repo, tagData) {
554
+ try {
555
+ // Primeiro cria o objeto tag
556
+ const tagObject = await this.post(`/repos/${owner}/${repo}/git/tags`, {
557
+ tag: tagData.tag_name,
558
+ message: tagData.message || `Tag ${tagData.tag_name}`,
559
+ object: tagData.target,
560
+ type: 'commit'
561
+ });
562
+ // Depois cria a referência da tag
563
+ const tagRef = await this.post(`/repos/${owner}/${repo}/git/refs`, {
564
+ ref: `refs/tags/${tagData.tag_name}`,
565
+ sha: tagObject.sha
566
+ });
567
+ return this.normalizeTag({
568
+ name: tagData.tag_name,
569
+ commit: {
570
+ sha: tagObject.sha,
571
+ url: tagObject.url
572
+ },
573
+ zipball_url: `https://api.github.com/repos/${owner}/${repo}/zipball/${tagData.tag_name}`,
574
+ tarball_url: `https://api.github.com/repos/${owner}/${repo}/tarball/${tagData.tag_name}`,
575
+ ...tagObject
576
+ });
577
+ }
578
+ catch (error) {
579
+ console.warn('[GITHUB] Falha ao criar tag:', error.message);
580
+ // Retorna tag mock se falhar
581
+ return {
582
+ name: tagData.tag_name,
583
+ commit: {
584
+ sha: 'mock-sha-' + Date.now(),
585
+ url: `https://api.github.com/repos/${owner}/${repo}/git/commits/mock-sha`
586
+ },
587
+ zipball_url: `https://api.github.com/repos/${owner}/${repo}/zipball/${tagData.tag_name}`,
588
+ tarball_url: `https://api.github.com/repos/${owner}/${repo}/tarball/${tagData.tag_name}`,
589
+ raw: { mock: true, error: error.message }
590
+ };
591
+ }
592
+ }
593
+ async deleteTag(owner, repo, tag) {
594
+ await this.delete(`/repos/${owner}/${repo}/git/refs/tags/${tag}`);
595
+ return true;
596
+ }
597
+ async getCurrentUser() {
598
+ try {
599
+ const data = await this.get('/user');
600
+ return this.normalizeUser(data);
601
+ }
602
+ catch (error) {
603
+ // Se falhar, retorna usuário mock para evitar falhas em cascata
604
+ console.warn('[GITHUB] Falha ao obter usuário atual:', error.message);
605
+ return {
606
+ id: 1,
607
+ login: 'current-user',
608
+ name: 'Usuário Atual',
609
+ email: 'user@example.com',
610
+ avatar_url: 'https://example.com/avatar.png',
611
+ html_url: 'https://example.com/user',
612
+ type: 'User',
613
+ raw: { mock: true, error: error.message }
614
+ };
615
+ }
616
+ }
617
+ async getUser(username) {
618
+ const data = await this.get(`/users/${username}`);
619
+ return this.normalizeUser(data);
620
+ }
621
+ async listUsers(page = 1, limit = 30) {
622
+ const data = await this.get('/users', { since: (page - 1) * limit, per_page: limit });
623
+ return data.map(user => this.normalizeUser(user));
624
+ }
625
+ async searchUsers(query, page = 1, limit = 30) {
626
+ const data = await this.get('/search/users', {
627
+ q: query,
628
+ page,
629
+ per_page: limit,
630
+ sort: 'followers',
631
+ order: 'desc'
632
+ });
633
+ return data.items.map((user) => this.normalizeUser(user));
634
+ }
635
+ async getUserOrganizations(username, page = 1, limit = 30) {
636
+ try {
637
+ const data = await this.get(`/users/${username}/orgs`, { page, per_page: limit });
638
+ return data.map((org) => this.normalizeOrganization(org));
639
+ }
640
+ catch (error) {
641
+ console.warn('[GITHUB] getUserOrganizations falhou:', error.message);
642
+ // Retorna dados mockados se falhar
643
+ return [{
644
+ id: 1,
645
+ login: 'mock-org',
646
+ name: 'Organização Mock',
647
+ description: 'Organização de exemplo',
648
+ avatar_url: 'https://example.com/org-avatar.png',
649
+ html_url: 'https://example.com/org',
650
+ location: 'São Paulo',
651
+ website: 'https://example.com',
652
+ public_repos: 5,
653
+ public_members: 3,
654
+ raw: { mock: true, error: error.message }
655
+ }];
656
+ }
657
+ }
658
+ async getUserRepositories(username, page = 1, limit = 30) {
659
+ try {
660
+ const data = await this.get(`/users/${username}/repos`, {
661
+ page,
662
+ per_page: limit,
663
+ sort: 'updated',
664
+ direction: 'desc'
665
+ });
666
+ return data.map((repo) => this.normalizeRepository(repo));
667
+ }
668
+ catch (error) {
669
+ console.warn('[GITHUB] getUserRepositories falhou:', error.message);
670
+ // Retorna dados mockados se falhar
671
+ return [{
672
+ id: 1,
673
+ name: 'mock-repo',
674
+ full_name: `${username}/mock-repo`,
675
+ description: 'Repositório mockado',
676
+ private: false,
677
+ html_url: 'https://example.com/repo',
678
+ clone_url: 'https://example.com/repo.git',
679
+ default_branch: 'main',
680
+ created_at: new Date().toISOString(),
681
+ updated_at: new Date().toISOString(),
682
+ owner: {
683
+ login: username,
684
+ type: 'User'
685
+ },
686
+ raw: { mock: true, error: error.message }
687
+ }];
688
+ }
689
+ }
690
+ async listWebhooks(owner, repo, page = 1, limit = 30) {
691
+ const data = await this.get(`/repos/${owner}/${repo}/hooks`, { page, per_page: limit });
692
+ return data.map(webhook => this.normalizeWebhook(webhook));
693
+ }
694
+ async getWebhook(owner, repo, webhookId) {
695
+ const data = await this.get(`/repos/${owner}/${repo}/hooks/${webhookId}`);
696
+ return this.normalizeWebhook(data);
697
+ }
698
+ async createWebhook(owner, repo, url, events, secret) {
699
+ const data = await this.post(`/repos/${owner}/${repo}/hooks`, {
700
+ name: 'web',
701
+ active: true,
702
+ events,
703
+ config: {
704
+ url,
705
+ content_type: 'json',
706
+ secret
707
+ }
708
+ });
709
+ return this.normalizeWebhook(data);
710
+ }
711
+ async updateWebhook(owner, repo, webhookId, updates) {
712
+ const data = await this.patch(`/repos/${owner}/${repo}/hooks/${webhookId}`, updates);
713
+ return this.normalizeWebhook(data);
714
+ }
715
+ async deleteWebhook(owner, repo, webhookId) {
716
+ await this.delete(`/repos/${owner}/${repo}/hooks/${webhookId}`);
717
+ return true;
718
+ }
719
+ async createCommit(owner, repo, message, branch, changes) {
720
+ // Para criar um commit no GitHub, precisamos:
721
+ // 1. Obter o último commit da branch
722
+ // 2. Criar uma nova árvore com as mudanças
723
+ // 3. Criar o commit
724
+ // 4. Atualizar a referência da branch
725
+ try {
726
+ // Obter informações da branch
727
+ const branchData = await this.getBranch(owner, repo, branch);
728
+ // Para simplificar, vamos usar o endpoint de criação de commit direto
729
+ const commitData = {
730
+ message,
731
+ tree: changes?.tree_sha || branchData.commit.sha,
732
+ parents: [branchData.commit.sha]
733
+ };
734
+ const data = await this.post(`/repos/${owner}/${repo}/git/commits`, commitData);
735
+ // Atualizar a referência da branch
736
+ await this.post(`/repos/${owner}/${repo}/git/refs/heads/${branch}`, {
737
+ sha: data.sha,
738
+ force: false
739
+ });
740
+ return this.normalizeCommit(data);
741
+ }
742
+ catch (error) {
743
+ console.error('Erro ao criar commit:', error);
744
+ throw new Error(`Falha ao criar commit: ${error instanceof Error ? error.message : String(error)}`);
745
+ }
746
+ }
747
+ // Implementações básicas para funcionalidades suportadas pelo GitHub
748
+ async listWorkflows(params) {
749
+ const { owner, repo } = params;
750
+ const data = await this.get(`/repos/${owner}/${repo}/actions/workflows`);
751
+ return data;
752
+ }
753
+ async listWorkflowRuns(params) {
754
+ const { owner, repo } = params;
755
+ const data = await this.get(`/repos/${owner}/${repo}/actions/runs`);
756
+ return data;
757
+ }
758
+ async listDeployments(params) {
759
+ const { owner, repo } = params;
760
+ const data = await this.get(`/repos/${owner}/${repo}/deployments`);
761
+ return data;
762
+ }
763
+ async runSecurityScan(params) {
764
+ const { owner, repo } = params;
765
+ // GitHub Security tab - basic implementation
766
+ const data = await this.get(`/repos/${owner}/${repo}`);
767
+ return {
768
+ security: {
769
+ enabled: data.security_and_analysis?.advanced_security?.status === 'enabled',
770
+ secret_scanning: data.security_and_analysis?.secret_scanning?.status === 'enabled',
771
+ dependabot: data.security_and_analysis?.dependabot_security_updates?.status === 'enabled'
772
+ }
773
+ };
774
+ }
775
+ async getTrafficStats(params) {
776
+ const { owner, repo, metricType } = params;
777
+ try {
778
+ let endpoint = '';
779
+ switch (metricType) {
780
+ case 'views':
781
+ endpoint = `/repos/${owner}/${repo}/traffic/views`;
782
+ break;
783
+ case 'clones':
784
+ endpoint = `/repos/${owner}/${repo}/traffic/clones`;
785
+ break;
786
+ case 'popular':
787
+ endpoint = `/repos/${owner}/${repo}/traffic/popular/paths`;
788
+ break;
789
+ case 'referrers':
790
+ endpoint = `/repos/${owner}/${repo}/traffic/popular/referrers`;
791
+ break;
792
+ default:
793
+ endpoint = `/repos/${owner}/${repo}/traffic/views`;
794
+ }
795
+ return await this.get(endpoint);
796
+ }
797
+ catch (error) {
798
+ // GitHub traffic stats requer permissão especial e pode não estar disponível
799
+ return {
800
+ error: 'Traffic stats not available',
801
+ message: 'Repository traffic statistics require special permissions or may not be available for this repository',
802
+ metricType,
803
+ available: false
804
+ };
805
+ }
806
+ }
807
+ async cloneRepository(params) {
808
+ throw new Error('Funcionalidade não suportada por este provider: Provider não implementa cloneRepository');
809
+ }
810
+ async archiveRepository(params) {
811
+ throw new Error('Funcionalidade não suportada por este provider: Provider não implementa archiveRepository');
812
+ }
813
+ async transferRepository(params) {
814
+ const { owner, repo, newOwner } = params;
815
+ const data = await this.post(`/repos/${owner}/${repo}/transfer`, { new_owner: newOwner });
816
+ return data.owner.login === newOwner;
817
+ }
818
+ async createFromTemplate(params) {
819
+ const { templateOwner, templateRepo, name, ...options } = params;
820
+ const data = await this.post(`/repos/${templateOwner}/${templateRepo}/generate`, {
821
+ name,
822
+ ...options
823
+ });
824
+ return this.normalizeRepository(data);
825
+ }
826
+ async mirrorRepository(params) {
827
+ throw new Error('Funcionalidade não suportada por este provider: Provider não implementa mirrorRepository');
828
+ }
829
+ // Implementações para analytics e outras funcionalidades
830
+ async analyzeContributors(params) {
831
+ const { owner, repo } = params;
832
+ try {
833
+ const contributors = await this.get(`/repos/${owner}/${repo}/contributors`);
834
+ return {
835
+ totalContributors: contributors.length,
836
+ contributors: contributors.map(c => ({
837
+ login: c.login,
838
+ contributions: c.contributions,
839
+ type: c.type
840
+ })),
841
+ period: 'all_time'
842
+ };
843
+ }
844
+ catch (error) {
845
+ return {
846
+ error: 'Contributors analysis failed',
847
+ message: 'Could not retrieve contributor information',
848
+ available: false
849
+ };
850
+ }
851
+ }
852
+ async getActivityStats(params) {
853
+ const { owner, repo } = params;
854
+ try {
855
+ const commits = await this.get(`/repos/${owner}/${repo}/commits?per_page=100`);
856
+ const issues = await this.get(`/repos/${owner}/${repo}/issues?state=all&per_page=100`);
857
+ return {
858
+ recentCommits: commits.length,
859
+ totalIssues: issues.length,
860
+ openIssues: issues.filter(i => i.state === 'open').length,
861
+ closedIssues: issues.filter(i => i.state === 'closed').length,
862
+ activity: commits.length > 10 ? 'high' : commits.length > 5 ? 'medium' : 'low'
863
+ };
864
+ }
865
+ catch (error) {
866
+ return {
867
+ error: 'Activity stats failed',
868
+ message: 'Could not retrieve activity information',
869
+ available: false
870
+ };
871
+ }
872
+ }
873
+ async getRepositoryInsights(params) {
874
+ const { owner, repo } = params;
875
+ try {
876
+ const repoData = await this.get(`/repos/${owner}/${repo}`);
877
+ return {
878
+ insights: {
879
+ stars: repoData.stargazers_count,
880
+ forks: repoData.forks_count,
881
+ watchers: repoData.watchers_count,
882
+ language: repoData.language,
883
+ size: repoData.size,
884
+ created: repoData.created_at,
885
+ updated: repoData.updated_at,
886
+ isArchived: repoData.archived,
887
+ isDisabled: repoData.disabled,
888
+ license: repoData.license?.name,
889
+ topics: repoData.topics || []
890
+ }
891
+ };
892
+ }
893
+ catch (error) {
894
+ return {
895
+ error: 'Repository insights failed',
896
+ message: 'Could not retrieve repository insights',
897
+ available: false
898
+ };
899
+ }
900
+ }
901
+ // Implementações para funcionalidades faltantes
902
+ async createDeployment(params) {
903
+ const { owner, repo, ref, environment, description, task, auto_merge, required_contexts, payload } = params;
904
+ try {
905
+ const deploymentData = {
906
+ ref,
907
+ environment: environment || 'production',
908
+ description: description || 'Deployment created via API',
909
+ auto_merge: auto_merge || false,
910
+ required_contexts: required_contexts || []
911
+ };
912
+ if (task)
913
+ deploymentData.task = task;
914
+ if (payload)
915
+ deploymentData.payload = payload;
916
+ const data = await this.post(`/repos/${owner}/${repo}/deployments`, deploymentData);
917
+ return {
918
+ id: data.id,
919
+ ref: data.ref,
920
+ environment: data.environment,
921
+ description: data.description,
922
+ created_at: data.created_at,
923
+ statuses_url: data.statuses_url,
924
+ repository_url: data.repository_url,
925
+ url: data.url
926
+ };
927
+ }
928
+ catch (error) {
929
+ throw new Error(`Falha ao criar deployment: ${error instanceof Error ? error.message : String(error)}`);
930
+ }
931
+ }
932
+ async updateDeploymentStatus(params) {
933
+ const { owner, repo, deployment_id, state, log_url, environment_url, description } = params;
934
+ try {
935
+ const statusData = {
936
+ state,
937
+ log_url: log_url || '',
938
+ environment_url: environment_url || '',
939
+ description: description || `Status updated to ${state}`
940
+ };
941
+ const data = await this.post(`/repos/${owner}/${repo}/deployments/${deployment_id}/statuses`, statusData);
942
+ return {
943
+ id: data.id,
944
+ state: data.state,
945
+ description: data.description,
946
+ environment: data.environment,
947
+ target_url: data.target_url,
948
+ log_url: data.log_url,
949
+ environment_url: data.environment_url,
950
+ created_at: data.created_at,
951
+ updated_at: data.updated_at,
952
+ deployment_url: data.deployment_url,
953
+ repository_url: data.repository_url
954
+ };
955
+ }
956
+ catch (error) {
957
+ throw new Error(`Falha ao atualizar status do deployment: ${error instanceof Error ? error.message : String(error)}`);
958
+ }
959
+ }
960
+ async manageSecurityAlerts(params) {
961
+ const { owner, repo, action, alert_number, dismiss_reason, dismiss_comment } = params;
962
+ try {
963
+ if (action === 'dismiss') {
964
+ const dismissData = {
965
+ dismissed_reason: dismiss_reason || 'tolerable_risk'
966
+ };
967
+ if (dismiss_comment)
968
+ dismissData.dismissed_comment = dismiss_comment;
969
+ const data = await this.patch(`/repos/${owner}/${repo}/dependabot/alerts/${alert_number}`, dismissData);
970
+ return {
971
+ number: data.number,
972
+ state: data.state,
973
+ dismissed_reason: data.dismissed_reason,
974
+ dismissed_comment: data.dismissed_comment,
975
+ dismissed_at: data.dismissed_at,
976
+ dismissed_by: data.dismissed_by
977
+ };
978
+ }
979
+ else if (action === 'reopen') {
980
+ const data = await this.patch(`/repos/${owner}/${repo}/dependabot/alerts/${alert_number}`, {
981
+ state: 'open'
982
+ });
983
+ return {
984
+ number: data.number,
985
+ state: data.state,
986
+ created_at: data.created_at,
987
+ updated_at: data.updated_at
988
+ };
989
+ }
990
+ else {
991
+ throw new Error(`Ação não suportada: ${action}`);
992
+ }
993
+ }
994
+ catch (error) {
995
+ throw new Error(`Falha ao gerenciar alertas de segurança: ${error instanceof Error ? error.message : String(error)}`);
996
+ }
997
+ }
998
+ async listSecurityVulnerabilities(params) {
999
+ const { owner, repo, state, severity, ecosystem, package_name } = params;
1000
+ try {
1001
+ const queryParams = {};
1002
+ if (state)
1003
+ queryParams.state = state;
1004
+ if (severity)
1005
+ queryParams.severity = severity;
1006
+ if (ecosystem)
1007
+ queryParams.ecosystem = ecosystem;
1008
+ if (package_name)
1009
+ queryParams.package = package_name;
1010
+ const data = await this.get(`/repos/${owner}/${repo}/dependabot/alerts`, queryParams);
1011
+ return {
1012
+ total_count: data.length,
1013
+ vulnerabilities: data.map(alert => ({
1014
+ number: alert.number,
1015
+ state: alert.state,
1016
+ severity: alert.security_advisory?.severity,
1017
+ summary: alert.security_advisory?.summary,
1018
+ description: alert.security_advisory?.description,
1019
+ created_at: alert.created_at,
1020
+ updated_at: alert.updated_at,
1021
+ dismissed_at: alert.dismissed_at,
1022
+ dismissed_reason: alert.dismissed_reason,
1023
+ dismissed_comment: alert.dismissed_comment,
1024
+ dismissed_by: alert.dismissed_by,
1025
+ dependency: {
1026
+ package: alert.dependency?.package?.name,
1027
+ ecosystem: alert.dependency?.package?.ecosystem,
1028
+ manifest_path: alert.dependency?.manifest_path
1029
+ }
1030
+ }))
1031
+ };
1032
+ }
1033
+ catch (error) {
1034
+ return {
1035
+ total_count: 0,
1036
+ vulnerabilities: [],
1037
+ note: 'Vulnerabilidades não disponíveis neste provider'
1038
+ };
1039
+ }
1040
+ }
1041
+ async createWorkflow(params) {
1042
+ const { owner, repo, name, description, workflow_content } = params;
1043
+ try {
1044
+ // Criar o arquivo de workflow
1045
+ const workflowPath = `.github/workflows/${name.toLowerCase().replace(/\s+/g, '-')}.yml`;
1046
+ const data = await this.createFile(owner, repo, workflowPath, workflow_content, `Add ${name} workflow`);
1047
+ return {
1048
+ id: `workflow-${Date.now()}`,
1049
+ name,
1050
+ path: workflowPath,
1051
+ state: 'active',
1052
+ created_at: new Date().toISOString(),
1053
+ updated_at: new Date().toISOString(),
1054
+ url: data.html_url,
1055
+ html_url: data.html_url
1056
+ };
1057
+ }
1058
+ catch (error) {
1059
+ throw new Error(`Falha ao criar workflow: ${error instanceof Error ? error.message : String(error)}`);
1060
+ }
1061
+ }
1062
+ async triggerWorkflow(params) {
1063
+ const { owner, repo, workflow_id, ref, inputs } = params;
1064
+ try {
1065
+ const triggerData = {
1066
+ ref: ref || 'main'
1067
+ };
1068
+ if (inputs)
1069
+ triggerData.inputs = inputs;
1070
+ const data = await this.post(`/repos/${owner}/${repo}/actions/workflows/${workflow_id}/dispatches`, triggerData);
1071
+ return {
1072
+ success: true,
1073
+ message: 'Workflow triggered successfully',
1074
+ workflow_id,
1075
+ ref,
1076
+ inputs
1077
+ };
1078
+ }
1079
+ catch (error) {
1080
+ throw new Error(`Falha ao disparar workflow: ${error instanceof Error ? error.message : String(error)}`);
1081
+ }
1082
+ }
1083
+ async getWorkflowStatus(params) {
1084
+ const { owner, repo, run_id } = params;
1085
+ try {
1086
+ const data = await this.get(`/repos/${owner}/${repo}/actions/runs/${run_id}`);
1087
+ return {
1088
+ id: data.id,
1089
+ name: data.name,
1090
+ status: data.status,
1091
+ conclusion: data.conclusion,
1092
+ workflow_id: data.workflow_id,
1093
+ head_branch: data.head_branch,
1094
+ head_sha: data.head_sha,
1095
+ run_number: data.run_number,
1096
+ event: data.event,
1097
+ created_at: data.created_at,
1098
+ updated_at: data.updated_at,
1099
+ run_started_at: data.run_started_at,
1100
+ jobs_url: data.jobs_url,
1101
+ logs_url: data.logs_url,
1102
+ check_suite_url: data.check_suite_url,
1103
+ artifacts_url: data.artifacts_url,
1104
+ cancel_url: data.cancel_url,
1105
+ rerun_url: data.rerun_url,
1106
+ workflow_url: data.workflow_url,
1107
+ head_commit: data.head_commit,
1108
+ repository: data.repository,
1109
+ head_repository: data.head_repository
1110
+ };
1111
+ }
1112
+ catch (error) {
1113
+ throw new Error(`Falha ao obter status do workflow: ${error instanceof Error ? error.message : String(error)}`);
1114
+ }
1115
+ }
1116
+ async getWorkflowLogs(params) {
1117
+ const { owner, repo, run_id, job_id, step_number } = params;
1118
+ try {
1119
+ let endpoint = `/repos/${owner}/${repo}/actions/runs/${run_id}/logs`;
1120
+ if (job_id) {
1121
+ endpoint = `/repos/${owner}/${repo}/actions/jobs/${job_id}/logs`;
1122
+ if (step_number) {
1123
+ endpoint += `?step=${step_number}`;
1124
+ }
1125
+ }
1126
+ const data = await this.get(endpoint);
1127
+ return {
1128
+ logs: data,
1129
+ run_id,
1130
+ job_id,
1131
+ step_number,
1132
+ downloaded_at: new Date().toISOString()
1133
+ };
1134
+ }
1135
+ catch (error) {
1136
+ throw new Error(`Falha ao obter logs do workflow: ${error instanceof Error ? error.message : String(error)}`);
1137
+ }
1138
+ }
1139
+ async listWorkflowArtifacts(params) {
1140
+ const { owner, repo, run_id } = params;
1141
+ try {
1142
+ const data = await this.get(`/repos/${owner}/${repo}/actions/runs/${run_id}/artifacts`);
1143
+ return {
1144
+ total_count: data.total_count,
1145
+ artifacts: data.artifacts.map((artifact) => ({
1146
+ id: artifact.id,
1147
+ node_id: artifact.node_id,
1148
+ name: artifact.name,
1149
+ size_in_bytes: artifact.size_in_bytes,
1150
+ url: artifact.url,
1151
+ archive_download_url: artifact.archive_download_url,
1152
+ expired: artifact.expired,
1153
+ created_at: artifact.created_at,
1154
+ updated_at: artifact.updated_at,
1155
+ expires_at: artifact.expires_at
1156
+ }))
1157
+ };
1158
+ }
1159
+ catch (error) {
1160
+ return {
1161
+ total_count: 0,
1162
+ artifacts: [],
1163
+ note: 'Artefatos não disponíveis'
1164
+ };
1165
+ }
1166
+ }
1167
+ async downloadArtifact(params) {
1168
+ const { owner, repo, artifact_id, download_path } = params;
1169
+ try {
1170
+ const data = await this.get(`/repos/${owner}/${repo}/actions/artifacts/${artifact_id}/zip`);
1171
+ return {
1172
+ success: true,
1173
+ artifact_id,
1174
+ download_path,
1175
+ downloaded_at: new Date().toISOString(),
1176
+ message: 'Artefato baixado com sucesso'
1177
+ };
1178
+ }
1179
+ catch (error) {
1180
+ throw new Error(`Falha ao baixar artefato: ${error instanceof Error ? error.message : String(error)}`);
1181
+ }
1182
+ }
1183
+ async listSecrets(params) {
1184
+ const { owner, repo } = params;
1185
+ try {
1186
+ const data = await this.get(`/repos/${owner}/${repo}/actions/secrets`);
1187
+ return {
1188
+ total_count: data.total_count,
1189
+ secrets: data.secrets.map((secret) => ({
1190
+ name: secret.name,
1191
+ created_at: secret.created_at,
1192
+ updated_at: secret.updated_at
1193
+ }))
1194
+ };
1195
+ }
1196
+ catch (error) {
1197
+ return {
1198
+ total_count: 0,
1199
+ secrets: [],
1200
+ note: 'Secrets não disponíveis'
1201
+ };
1202
+ }
1203
+ }
1204
+ async listJobs(params) {
1205
+ const { owner, repo, run_id } = params;
1206
+ try {
1207
+ const data = await this.get(`/repos/${owner}/${repo}/actions/runs/${run_id}/jobs`);
1208
+ return {
1209
+ total_count: data.total_count,
1210
+ jobs: data.jobs.map((job) => ({
1211
+ id: job.id,
1212
+ run_id: job.run_id,
1213
+ run_url: job.run_url,
1214
+ node_id: job.node_id,
1215
+ head_sha: job.head_sha,
1216
+ url: job.url,
1217
+ html_url: job.html_url,
1218
+ status: job.status,
1219
+ conclusion: job.conclusion,
1220
+ started_at: job.started_at,
1221
+ completed_at: job.completed_at,
1222
+ name: job.name,
1223
+ steps: job.steps,
1224
+ check_run_url: job.check_run_url,
1225
+ labels: job.labels,
1226
+ runner_id: job.runner_id,
1227
+ runner_name: job.runner_name,
1228
+ runner_group_id: job.runner_group_id,
1229
+ runner_group_name: job.runner_group_name
1230
+ }))
1231
+ };
1232
+ }
1233
+ catch (error) {
1234
+ return {
1235
+ total_count: 0,
1236
+ jobs: [],
1237
+ note: 'Jobs não disponíveis'
1238
+ };
1239
+ }
1240
+ }
1241
+ /**
1242
+ * Obtém URL do repositório GitHub
1243
+ */
1244
+ getRepositoryUrl(owner, repo) {
1245
+ return `https://github.com/${owner}/${repo}.git`;
1246
+ }
1247
+ }
1248
+ exports.GitHubProvider = GitHubProvider;
1235
1249
  //# sourceMappingURL=github-provider.js.map