deepdebug-local-agent 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +24 -0
- package/.idea/deepdebug-local-agent.iml +12 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/Dockerfile +46 -0
- package/cloudbuild.yaml +42 -0
- package/index.js +42 -0
- package/mcp-server.js +533 -0
- package/package.json +22 -0
- package/src/ai-engine.js +861 -0
- package/src/analyzers/config-analyzer.js +446 -0
- package/src/analyzers/controller-analyzer.js +429 -0
- package/src/analyzers/dto-analyzer.js +455 -0
- package/src/detectors/build-tool-detector.js +0 -0
- package/src/detectors/framework-detector.js +91 -0
- package/src/detectors/language-detector.js +89 -0
- package/src/detectors/multi-project-detector.js +191 -0
- package/src/detectors/service-detector.js +244 -0
- package/src/detectors.js +30 -0
- package/src/exec-utils.js +215 -0
- package/src/fs-utils.js +34 -0
- package/src/git/base-git-provider.js +384 -0
- package/src/git/git-provider-registry.js +110 -0
- package/src/git/github-provider.js +502 -0
- package/src/mcp-http-server.js +313 -0
- package/src/patch/patch-engine.js +339 -0
- package/src/patch-manager.js +816 -0
- package/src/patch.js +607 -0
- package/src/patch_bkp.js +154 -0
- package/src/ports.js +69 -0
- package/src/routes/workspace.route.js +528 -0
- package/src/runtimes/base-runtime.js +290 -0
- package/src/runtimes/java/gradle-runtime.js +378 -0
- package/src/runtimes/java/java-integrations.js +339 -0
- package/src/runtimes/java/maven-runtime.js +418 -0
- package/src/runtimes/node/node-integrations.js +247 -0
- package/src/runtimes/node/npm-runtime.js +466 -0
- package/src/runtimes/node/yarn-runtime.js +354 -0
- package/src/runtimes/runtime-registry.js +256 -0
- package/src/server-local.js +576 -0
- package/src/server.js +4565 -0
- package/src/utils/environment-diagnostics.js +666 -0
- package/src/utils/exec-utils.js +264 -0
- package/src/utils/fs-utils.js +218 -0
- package/src/workspace/detect-port.js +176 -0
- package/src/workspace/file-reader.js +54 -0
- package/src/workspace/git-client.js +0 -0
- package/src/workspace/process-manager.js +619 -0
- package/src/workspace/scanner.js +72 -0
- package/src/workspace-manager.js +172 -0
package/src/fs-utils.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { promisify } from "util";
|
|
4
|
+
|
|
5
|
+
export const stat = promisify(fs.stat);
|
|
6
|
+
export const readdir = promisify(fs.readdir);
|
|
7
|
+
export const readFile = promisify(fs.readFile);
|
|
8
|
+
export const writeFile = promisify(fs.writeFile);
|
|
9
|
+
export const access = promisify(fs.access);
|
|
10
|
+
|
|
11
|
+
export async function exists(p) {
|
|
12
|
+
try { await access(p, fs.constants.F_OK); return true; }
|
|
13
|
+
catch { return false; }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function listRecursive(root, { maxFiles = 5000, includeHidden = false } = {}) {
|
|
17
|
+
const results = [];
|
|
18
|
+
async function walk(dir) {
|
|
19
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
20
|
+
for (const e of entries) {
|
|
21
|
+
if (!includeHidden && e.name.startsWith(".")) continue;
|
|
22
|
+
const full = path.join(dir, e.name);
|
|
23
|
+
if (e.isDirectory()) {
|
|
24
|
+
results.push({ type: "dir", path: path.relative(root, full) });
|
|
25
|
+
await walk(full);
|
|
26
|
+
} else {
|
|
27
|
+
results.push({ type: "file", path: path.relative(root, full) });
|
|
28
|
+
if (results.length >= maxFiles) return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
await walk(root);
|
|
33
|
+
return results;
|
|
34
|
+
}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BaseGitProvider
|
|
3
|
+
*
|
|
4
|
+
* Interface abstrata para Git providers (GitHub, GitLab, Bitbucket).
|
|
5
|
+
* Cada provider deve implementar esta interface.
|
|
6
|
+
*
|
|
7
|
+
* @abstract
|
|
8
|
+
*/
|
|
9
|
+
export class BaseGitProvider {
|
|
10
|
+
|
|
11
|
+
constructor(config = {}) {
|
|
12
|
+
if (this.constructor === BaseGitProvider) {
|
|
13
|
+
throw new Error('BaseGitProvider is abstract and cannot be instantiated directly');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.accessToken = config.accessToken || null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ==========================================
|
|
21
|
+
// IDENTIFICATION
|
|
22
|
+
// ==========================================
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Identificador único do provider
|
|
26
|
+
* @returns {string} Ex: 'github', 'gitlab', 'bitbucket'
|
|
27
|
+
*/
|
|
28
|
+
getId() {
|
|
29
|
+
throw new Error('Method getId() must be implemented');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Nome amigável do provider
|
|
34
|
+
* @returns {string} Ex: 'GitHub', 'GitLab', 'Bitbucket'
|
|
35
|
+
*/
|
|
36
|
+
getName() {
|
|
37
|
+
throw new Error('Method getName() must be implemented');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* URL base da API
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
getApiBaseUrl() {
|
|
45
|
+
throw new Error('Method getApiBaseUrl() must be implemented');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ==========================================
|
|
49
|
+
// AUTHENTICATION
|
|
50
|
+
// ==========================================
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Define o token de acesso
|
|
54
|
+
* @param {string} token
|
|
55
|
+
*/
|
|
56
|
+
setAccessToken(token) {
|
|
57
|
+
this.accessToken = token;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Retorna URL para OAuth authorization
|
|
62
|
+
* @param {string} redirectUri - URI de callback
|
|
63
|
+
* @param {string} state - State para CSRF protection
|
|
64
|
+
* @returns {string}
|
|
65
|
+
*/
|
|
66
|
+
getAuthorizationUrl(redirectUri, state) {
|
|
67
|
+
throw new Error('Method getAuthorizationUrl() must be implemented');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Troca authorization code por access token
|
|
72
|
+
* @param {string} code - Authorization code
|
|
73
|
+
* @param {string} redirectUri - URI de callback
|
|
74
|
+
* @returns {Promise<TokenResponse>}
|
|
75
|
+
*/
|
|
76
|
+
async exchangeCodeForToken(code, redirectUri) {
|
|
77
|
+
throw new Error('Method exchangeCodeForToken() must be implemented');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Valida se o token ainda é válido
|
|
82
|
+
* @returns {Promise<boolean>}
|
|
83
|
+
*/
|
|
84
|
+
async validateToken() {
|
|
85
|
+
throw new Error('Method validateToken() must be implemented');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ==========================================
|
|
89
|
+
// USER
|
|
90
|
+
// ==========================================
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Obtém informações do usuário autenticado
|
|
94
|
+
* @returns {Promise<UserInfo>}
|
|
95
|
+
*/
|
|
96
|
+
async getCurrentUser() {
|
|
97
|
+
throw new Error('Method getCurrentUser() must be implemented');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ==========================================
|
|
101
|
+
// REPOSITORIES
|
|
102
|
+
// ==========================================
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Lista repositórios do usuário
|
|
106
|
+
* @param {object} options - { page, perPage, sort }
|
|
107
|
+
* @returns {Promise<Repository[]>}
|
|
108
|
+
*/
|
|
109
|
+
async listRepositories(options = {}) {
|
|
110
|
+
throw new Error('Method listRepositories() must be implemented');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Obtém informações de um repositório
|
|
115
|
+
* @param {string} owner - Owner do repo
|
|
116
|
+
* @param {string} repo - Nome do repo
|
|
117
|
+
* @returns {Promise<Repository>}
|
|
118
|
+
*/
|
|
119
|
+
async getRepository(owner, repo) {
|
|
120
|
+
throw new Error('Method getRepository() must be implemented');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Clona um repositório
|
|
125
|
+
* @param {string} owner - Owner do repo
|
|
126
|
+
* @param {string} repo - Nome do repo
|
|
127
|
+
* @param {string} destPath - Caminho de destino
|
|
128
|
+
* @param {object} options - { branch, depth }
|
|
129
|
+
* @returns {Promise<CloneResult>}
|
|
130
|
+
*/
|
|
131
|
+
async cloneRepository(owner, repo, destPath, options = {}) {
|
|
132
|
+
throw new Error('Method cloneRepository() must be implemented');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ==========================================
|
|
136
|
+
// BRANCHES
|
|
137
|
+
// ==========================================
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Lista branches do repositório
|
|
141
|
+
* @param {string} owner - Owner do repo
|
|
142
|
+
* @param {string} repo - Nome do repo
|
|
143
|
+
* @returns {Promise<Branch[]>}
|
|
144
|
+
*/
|
|
145
|
+
async listBranches(owner, repo) {
|
|
146
|
+
throw new Error('Method listBranches() must be implemented');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Cria uma nova branch
|
|
151
|
+
* @param {string} owner - Owner do repo
|
|
152
|
+
* @param {string} repo - Nome do repo
|
|
153
|
+
* @param {string} branchName - Nome da nova branch
|
|
154
|
+
* @param {string} fromRef - Ref de origem (sha ou branch)
|
|
155
|
+
* @returns {Promise<Branch>}
|
|
156
|
+
*/
|
|
157
|
+
async createBranch(owner, repo, branchName, fromRef) {
|
|
158
|
+
throw new Error('Method createBranch() must be implemented');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Obtém informações de uma branch
|
|
163
|
+
* @param {string} owner - Owner do repo
|
|
164
|
+
* @param {string} repo - Nome do repo
|
|
165
|
+
* @param {string} branch - Nome da branch
|
|
166
|
+
* @returns {Promise<Branch>}
|
|
167
|
+
*/
|
|
168
|
+
async getBranch(owner, repo, branch) {
|
|
169
|
+
throw new Error('Method getBranch() must be implemented');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ==========================================
|
|
173
|
+
// COMMITS
|
|
174
|
+
// ==========================================
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Lista commits de uma branch
|
|
178
|
+
* @param {string} owner - Owner do repo
|
|
179
|
+
* @param {string} repo - Nome do repo
|
|
180
|
+
* @param {string} branch - Nome da branch
|
|
181
|
+
* @param {object} options - { page, perPage }
|
|
182
|
+
* @returns {Promise<Commit[]>}
|
|
183
|
+
*/
|
|
184
|
+
async listCommits(owner, repo, branch, options = {}) {
|
|
185
|
+
throw new Error('Method listCommits() must be implemented');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Cria um commit com mudanças
|
|
190
|
+
* @param {string} owner - Owner do repo
|
|
191
|
+
* @param {string} repo - Nome do repo
|
|
192
|
+
* @param {string} branch - Nome da branch
|
|
193
|
+
* @param {string} message - Mensagem do commit
|
|
194
|
+
* @param {FileChange[]} changes - Lista de mudanças
|
|
195
|
+
* @returns {Promise<Commit>}
|
|
196
|
+
*/
|
|
197
|
+
async createCommit(owner, repo, branch, message, changes) {
|
|
198
|
+
throw new Error('Method createCommit() must be implemented');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ==========================================
|
|
202
|
+
// FILES
|
|
203
|
+
// ==========================================
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Obtém conteúdo de um arquivo
|
|
207
|
+
* @param {string} owner - Owner do repo
|
|
208
|
+
* @param {string} repo - Nome do repo
|
|
209
|
+
* @param {string} path - Caminho do arquivo
|
|
210
|
+
* @param {string} ref - Branch ou sha
|
|
211
|
+
* @returns {Promise<FileContent>}
|
|
212
|
+
*/
|
|
213
|
+
async getFileContent(owner, repo, path, ref = 'main') {
|
|
214
|
+
throw new Error('Method getFileContent() must be implemented');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Cria ou atualiza um arquivo
|
|
219
|
+
* @param {string} owner - Owner do repo
|
|
220
|
+
* @param {string} repo - Nome do repo
|
|
221
|
+
* @param {string} path - Caminho do arquivo
|
|
222
|
+
* @param {string} content - Conteúdo (base64 ou texto)
|
|
223
|
+
* @param {string} message - Mensagem do commit
|
|
224
|
+
* @param {string} branch - Branch
|
|
225
|
+
* @param {string} sha - SHA atual (para update)
|
|
226
|
+
* @returns {Promise<FileCommit>}
|
|
227
|
+
*/
|
|
228
|
+
async createOrUpdateFile(owner, repo, path, content, message, branch, sha = null) {
|
|
229
|
+
throw new Error('Method createOrUpdateFile() must be implemented');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ==========================================
|
|
233
|
+
// PULL REQUESTS
|
|
234
|
+
// ==========================================
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Lista pull requests
|
|
238
|
+
* @param {string} owner - Owner do repo
|
|
239
|
+
* @param {string} repo - Nome do repo
|
|
240
|
+
* @param {object} options - { state, page, perPage }
|
|
241
|
+
* @returns {Promise<PullRequest[]>}
|
|
242
|
+
*/
|
|
243
|
+
async listPullRequests(owner, repo, options = {}) {
|
|
244
|
+
throw new Error('Method listPullRequests() must be implemented');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Cria um pull request
|
|
249
|
+
* @param {string} owner - Owner do repo
|
|
250
|
+
* @param {string} repo - Nome do repo
|
|
251
|
+
* @param {object} pr - { title, body, head, base }
|
|
252
|
+
* @returns {Promise<PullRequest>}
|
|
253
|
+
*/
|
|
254
|
+
async createPullRequest(owner, repo, pr) {
|
|
255
|
+
throw new Error('Method createPullRequest() must be implemented');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Obtém informações de um pull request
|
|
260
|
+
* @param {string} owner - Owner do repo
|
|
261
|
+
* @param {string} repo - Nome do repo
|
|
262
|
+
* @param {number} prNumber - Número do PR
|
|
263
|
+
* @returns {Promise<PullRequest>}
|
|
264
|
+
*/
|
|
265
|
+
async getPullRequest(owner, repo, prNumber) {
|
|
266
|
+
throw new Error('Method getPullRequest() must be implemented');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ==========================================
|
|
270
|
+
// WEBHOOKS
|
|
271
|
+
// ==========================================
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Cria um webhook
|
|
275
|
+
* @param {string} owner - Owner do repo
|
|
276
|
+
* @param {string} repo - Nome do repo
|
|
277
|
+
* @param {object} webhook - { url, events, secret }
|
|
278
|
+
* @returns {Promise<Webhook>}
|
|
279
|
+
*/
|
|
280
|
+
async createWebhook(owner, repo, webhook) {
|
|
281
|
+
throw new Error('Method createWebhook() must be implemented');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ==========================================
|
|
285
|
+
// HELPER METHODS
|
|
286
|
+
// ==========================================
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Constrói URL de clone
|
|
290
|
+
* @param {string} owner - Owner do repo
|
|
291
|
+
* @param {string} repo - Nome do repo
|
|
292
|
+
* @param {boolean} useHttps - Usar HTTPS (default) ou SSH
|
|
293
|
+
* @returns {string}
|
|
294
|
+
*/
|
|
295
|
+
getCloneUrl(owner, repo, useHttps = true) {
|
|
296
|
+
throw new Error('Method getCloneUrl() must be implemented');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Parsea URL de repositório para extrair owner e repo
|
|
301
|
+
* @param {string} url - URL do repositório
|
|
302
|
+
* @returns {{ owner: string, repo: string }}
|
|
303
|
+
*/
|
|
304
|
+
parseRepositoryUrl(url) {
|
|
305
|
+
throw new Error('Method parseRepositoryUrl() must be implemented');
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ==========================================
|
|
310
|
+
// TYPE DEFINITIONS
|
|
311
|
+
// ==========================================
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* @typedef {object} TokenResponse
|
|
315
|
+
* @property {string} accessToken
|
|
316
|
+
* @property {string} tokenType
|
|
317
|
+
* @property {string} [refreshToken]
|
|
318
|
+
* @property {number} [expiresIn]
|
|
319
|
+
*/
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* @typedef {object} UserInfo
|
|
323
|
+
* @property {string} id
|
|
324
|
+
* @property {string} username
|
|
325
|
+
* @property {string} email
|
|
326
|
+
* @property {string} name
|
|
327
|
+
* @property {string} avatarUrl
|
|
328
|
+
*/
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @typedef {object} Repository
|
|
332
|
+
* @property {string} id
|
|
333
|
+
* @property {string} name
|
|
334
|
+
* @property {string} fullName
|
|
335
|
+
* @property {string} description
|
|
336
|
+
* @property {string} defaultBranch
|
|
337
|
+
* @property {boolean} private
|
|
338
|
+
* @property {string} cloneUrl
|
|
339
|
+
* @property {string} htmlUrl
|
|
340
|
+
*/
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* @typedef {object} Branch
|
|
344
|
+
* @property {string} name
|
|
345
|
+
* @property {string} sha
|
|
346
|
+
* @property {boolean} protected
|
|
347
|
+
*/
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* @typedef {object} Commit
|
|
351
|
+
* @property {string} sha
|
|
352
|
+
* @property {string} message
|
|
353
|
+
* @property {string} authorName
|
|
354
|
+
* @property {string} authorEmail
|
|
355
|
+
* @property {Date} date
|
|
356
|
+
*/
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* @typedef {object} FileChange
|
|
360
|
+
* @property {string} path
|
|
361
|
+
* @property {string} content
|
|
362
|
+
* @property {string} action - 'create' | 'update' | 'delete'
|
|
363
|
+
*/
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* @typedef {object} FileContent
|
|
367
|
+
* @property {string} path
|
|
368
|
+
* @property {string} content
|
|
369
|
+
* @property {string} sha
|
|
370
|
+
* @property {string} encoding
|
|
371
|
+
*/
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* @typedef {object} PullRequest
|
|
375
|
+
* @property {number} number
|
|
376
|
+
* @property {string} title
|
|
377
|
+
* @property {string} body
|
|
378
|
+
* @property {string} state
|
|
379
|
+
* @property {string} head
|
|
380
|
+
* @property {string} base
|
|
381
|
+
* @property {string} htmlUrl
|
|
382
|
+
*/
|
|
383
|
+
|
|
384
|
+
export default BaseGitProvider;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { GitHubProvider } from './github-provider.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GitProviderRegistry
|
|
5
|
+
*
|
|
6
|
+
* Factory/Registry para gerenciar Git providers.
|
|
7
|
+
*/
|
|
8
|
+
export class GitProviderRegistry {
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.providers = new Map();
|
|
12
|
+
this.registerDefaults();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
registerDefaults() {
|
|
16
|
+
// Registrar providers disponíveis
|
|
17
|
+
this.register('github', GitHubProvider);
|
|
18
|
+
|
|
19
|
+
// GitLab e Bitbucket serão implementados depois
|
|
20
|
+
// this.register('gitlab', GitLabProvider);
|
|
21
|
+
// this.register('bitbucket', BitbucketProvider);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Registra um provider
|
|
26
|
+
* @param {string} id - ID do provider
|
|
27
|
+
* @param {class} ProviderClass - Classe do provider
|
|
28
|
+
*/
|
|
29
|
+
register(id, ProviderClass) {
|
|
30
|
+
this.providers.set(id, ProviderClass);
|
|
31
|
+
console.log(`📦 Registered git provider: ${id}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Cria instância de um provider
|
|
36
|
+
* @param {string} id - ID do provider
|
|
37
|
+
* @param {object} config - Configuração do provider
|
|
38
|
+
* @returns {BaseGitProvider}
|
|
39
|
+
*/
|
|
40
|
+
create(id, config = {}) {
|
|
41
|
+
const ProviderClass = this.providers.get(id);
|
|
42
|
+
|
|
43
|
+
if (!ProviderClass) {
|
|
44
|
+
throw new Error(`Git provider not found: ${id}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return new ProviderClass(config);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Lista IDs dos providers disponíveis
|
|
52
|
+
* @returns {string[]}
|
|
53
|
+
*/
|
|
54
|
+
listProviders() {
|
|
55
|
+
return Array.from(this.providers.keys());
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Detecta provider a partir da URL
|
|
60
|
+
* @param {string} url - URL do repositório
|
|
61
|
+
* @returns {string|null} - ID do provider
|
|
62
|
+
*/
|
|
63
|
+
detectProviderFromUrl(url) {
|
|
64
|
+
if (url.includes('github.com')) {
|
|
65
|
+
return 'github';
|
|
66
|
+
}
|
|
67
|
+
if (url.includes('gitlab.com') || url.includes('gitlab')) {
|
|
68
|
+
return 'gitlab';
|
|
69
|
+
}
|
|
70
|
+
if (url.includes('bitbucket.org') || url.includes('bitbucket')) {
|
|
71
|
+
return 'bitbucket';
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Cria provider a partir da URL do repositório
|
|
78
|
+
* @param {string} url - URL do repositório
|
|
79
|
+
* @param {object} config - Configuração
|
|
80
|
+
* @returns {BaseGitProvider}
|
|
81
|
+
*/
|
|
82
|
+
createFromUrl(url, config = {}) {
|
|
83
|
+
const providerId = this.detectProviderFromUrl(url);
|
|
84
|
+
|
|
85
|
+
if (!providerId) {
|
|
86
|
+
throw new Error(`Unable to detect git provider from URL: ${url}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return this.create(providerId, config);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ==========================================
|
|
94
|
+
// SINGLETON INSTANCE
|
|
95
|
+
// ==========================================
|
|
96
|
+
|
|
97
|
+
let instance = null;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Obtém instância singleton do GitProviderRegistry
|
|
101
|
+
* @returns {GitProviderRegistry}
|
|
102
|
+
*/
|
|
103
|
+
export function getGitProviderRegistry() {
|
|
104
|
+
if (!instance) {
|
|
105
|
+
instance = new GitProviderRegistry();
|
|
106
|
+
}
|
|
107
|
+
return instance;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default GitProviderRegistry;
|