@intranefr/superbackend 1.6.7 → 1.7.8
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/.beads/.br_history/issues.20260314_212352_900045509.jsonl +0 -0
- package/.beads/.br_history/issues.20260314_212352_900045509.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_087140743.jsonl +1 -0
- package/.beads/.br_history/issues.20260314_212353_087140743.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_285881504.jsonl +2 -0
- package/.beads/.br_history/issues.20260314_212353_285881504.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_473915419.jsonl +3 -0
- package/.beads/.br_history/issues.20260314_212353_473915419.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_659476307.jsonl +4 -0
- package/.beads/.br_history/issues.20260314_212353_659476307.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_869998925.jsonl +5 -0
- package/.beads/.br_history/issues.20260314_212353_869998925.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212354_054785029.jsonl +6 -0
- package/.beads/.br_history/issues.20260314_212354_054785029.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_175893691.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_175893691.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_338509797.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_338509797.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_515443192.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_515443192.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_676417592.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_676417592.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_839182422.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_839182422.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213337_004349113.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213337_004349113.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213337_179824080.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213337_179824080.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213701_705075332.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213701_705075332.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213706_783128702.jsonl +8 -0
- package/.beads/.br_history/issues.20260314_213706_783128702.jsonl.meta.json +1 -0
- package/.beads/config.yaml +4 -0
- package/.beads/issues.jsonl +8 -0
- package/.beads/metadata.json +4 -0
- package/.env.example +8 -0
- package/autochangelog/.env.example +36 -0
- package/autochangelog/README.md +412 -0
- package/autochangelog/config/database.js +27 -0
- package/autochangelog/package.json +47 -0
- package/autochangelog/public/landing.html +581 -0
- package/autochangelog/server.js +104 -0
- package/autochangelog/src/app.js +181 -0
- package/autochangelog/src/config/database.js +26 -0
- package/autochangelog/src/controllers/auth.js +488 -0
- package/autochangelog/src/controllers/changelog.js +682 -0
- package/autochangelog/src/controllers/project.js +580 -0
- package/autochangelog/src/controllers/repository.js +780 -0
- package/autochangelog/src/middleware/auth.js +386 -0
- package/autochangelog/src/models/Changelog.js +443 -0
- package/autochangelog/src/models/Project.js +226 -0
- package/autochangelog/src/models/Repository.js +366 -0
- package/autochangelog/src/models/User.js +223 -0
- package/autochangelog/src/routes/auth.routes.js +32 -0
- package/autochangelog/src/routes/changelog.routes.js +42 -0
- package/autochangelog/src/routes/github-auth.routes.js +102 -0
- package/autochangelog/src/routes/project.routes.js +50 -0
- package/autochangelog/src/routes/repository.routes.js +54 -0
- package/autochangelog/src/services/changelog.js +722 -0
- package/autochangelog/src/services/github.js +243 -0
- package/autochangelog/utils/logger.js +77 -0
- package/autochangelog/views/404.ejs +18 -0
- package/autochangelog/views/dashboard.ejs +596 -0
- package/autochangelog/views/index.ejs +231 -0
- package/autochangelog/views/layouts/main.ejs +44 -0
- package/autochangelog/views/login.ejs +104 -0
- package/autochangelog/views/partials/footer.ejs +20 -0
- package/autochangelog/views/partials/navbar.ejs +51 -0
- package/autochangelog/views/register.ejs +109 -0
- package/autochangelog-cli/README.md +266 -0
- package/autochangelog-cli/bin/autochangelog +120 -0
- package/autochangelog-cli/package.json +46 -0
- package/autochangelog-cli/src/cli/commands/auth.js +291 -0
- package/autochangelog-cli/src/cli/commands/changelog.js +619 -0
- package/autochangelog-cli/src/cli/commands/project.js +427 -0
- package/autochangelog-cli/src/cli/commands/repo.js +557 -0
- package/autochangelog-cli/src/cli/commands/stats.js +706 -0
- package/autochangelog-cli/src/cli/utils/config.js +277 -0
- package/autochangelog-cli/src/cli/utils/errors.js +307 -0
- package/autochangelog-cli/src/cli/utils/logger.js +75 -0
- package/autochangelog-cli/src/cli/utils/output.js +357 -0
- package/package.json +9 -3
- package/plugins/supercli/README.md +108 -0
- package/plugins/supercli/plugin.json +123 -0
- package/server.js +1 -1
- package/src/cli/api.js +380 -0
- package/src/cli/direct/agent-utils.js +61 -0
- package/src/cli/direct/cli-utils.js +112 -0
- package/src/cli/direct/data-seeding.js +307 -0
- package/src/cli/direct/db-admin.js +84 -0
- package/src/cli/direct/db-advanced.js +372 -0
- package/src/cli/direct/db-utils.js +558 -0
- package/src/cli/direct/help.js +195 -0
- package/src/cli/direct/migration.js +107 -0
- package/src/cli/direct/rbac-advanced.js +132 -0
- package/src/cli/direct/resources-additional.js +400 -0
- package/src/cli/direct/resources-cms-advanced.js +173 -0
- package/src/cli/direct/resources-cms.js +247 -0
- package/src/cli/direct/resources-core.js +253 -0
- package/src/cli/direct/resources-execution.js +367 -0
- package/src/cli/direct/resources-health.js +152 -0
- package/src/cli/direct/resources-integrations.js +182 -0
- package/src/cli/direct/resources-logs.js +204 -0
- package/src/cli/direct/resources-org-rbac.js +187 -0
- package/src/cli/direct/resources-system.js +236 -0
- package/src/cli/direct.js +556 -0
- package/src/controllers/admin.controller.js +4 -0
- package/src/controllers/auth.controller.js +148 -1
- package/src/controllers/waitingList.controller.js +130 -1
- package/src/models/RbacRole.js +1 -1
- package/src/models/User.js +39 -5
- package/src/routes/auth.routes.js +6 -0
- package/src/routes/waitingList.routes.js +12 -2
- package/src/routes/waitingListAdmin.routes.js +3 -0
- package/src/services/email.service.js +1 -0
- package/src/services/github.service.js +255 -0
- package/src/services/rateLimiter.service.js +29 -1
- package/src/services/waitingListJson.service.js +32 -3
- package/views/admin-waiting-list.ejs +386 -3
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
const { Command } = require('commander');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const { output } = require('../utils/output');
|
|
4
|
+
const { handleCliError, validateRequiredArgs, ERROR_CODES } = require('../utils/errors');
|
|
5
|
+
const { loadConfig, getAuthToken } = require('../utils/config');
|
|
6
|
+
const { setupLogger } = require('../utils/logger');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Repository management commands for AutoChangelog CLI
|
|
10
|
+
* Handles GitHub repository connection and management
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
function setupRepoCommands(program) {
|
|
14
|
+
const repo = program
|
|
15
|
+
.command('repo')
|
|
16
|
+
.description('Repository management');
|
|
17
|
+
|
|
18
|
+
// Connect repository command
|
|
19
|
+
repo
|
|
20
|
+
.command('connect')
|
|
21
|
+
.description('Connect a GitHub repository')
|
|
22
|
+
.option('--project-id <id>', 'Project ID')
|
|
23
|
+
.option('--owner <owner>', 'Repository owner (username or organization)')
|
|
24
|
+
.option('--name <name>', 'Repository name')
|
|
25
|
+
.option('--url <url>', 'Repository URL (alternative to owner/name)')
|
|
26
|
+
.option('--branch <branch>', 'Default branch to track', 'main')
|
|
27
|
+
.action(async (options) => {
|
|
28
|
+
const logger = setupLogger();
|
|
29
|
+
const config = loadConfig();
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// Validate required arguments
|
|
33
|
+
if (!options.projectId) {
|
|
34
|
+
output.error('Project ID is required. Use --project-id');
|
|
35
|
+
process.exit(ERROR_CODES.INVALID_ARGUMENT);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const token = getAuthToken();
|
|
39
|
+
if (!token) {
|
|
40
|
+
output.error('Not authenticated. Run "autochangelog auth login" first.');
|
|
41
|
+
process.exit(ERROR_CODES.AUTHENTICATION_FAILED);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Parse repository information
|
|
45
|
+
let owner, name;
|
|
46
|
+
if (options.url) {
|
|
47
|
+
const parsed = parseRepoUrl(options.url);
|
|
48
|
+
owner = parsed.owner;
|
|
49
|
+
name = parsed.name;
|
|
50
|
+
} else if (options.owner && options.name) {
|
|
51
|
+
owner = options.owner;
|
|
52
|
+
name = options.name;
|
|
53
|
+
} else {
|
|
54
|
+
output.error('Repository information required. Use --owner and --name, or --url');
|
|
55
|
+
process.exit(ERROR_CODES.INVALID_ARGUMENT);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const repoData = {
|
|
59
|
+
projectId: options.projectId,
|
|
60
|
+
owner,
|
|
61
|
+
name,
|
|
62
|
+
defaultBranch: options.branch,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const result = await connectRepository(repoData, token, logger);
|
|
66
|
+
|
|
67
|
+
output.output({
|
|
68
|
+
success: true,
|
|
69
|
+
message: 'Repository connected successfully',
|
|
70
|
+
data: result,
|
|
71
|
+
metadata: {
|
|
72
|
+
timestamp: new Date().toISOString(),
|
|
73
|
+
action: 'repository_connect',
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
} catch (error) {
|
|
78
|
+
handleCliError(error, output);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// List repositories command
|
|
83
|
+
repo
|
|
84
|
+
.command('list [project-id]')
|
|
85
|
+
.description('List repositories for a project')
|
|
86
|
+
.option('--limit <limit>', 'Limit number of results', parseInt)
|
|
87
|
+
.option('--offset <offset>', 'Offset for pagination', parseInt)
|
|
88
|
+
.action(async (projectId, options) => {
|
|
89
|
+
const logger = setupLogger();
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const token = getAuthToken();
|
|
93
|
+
if (!token) {
|
|
94
|
+
output.error('Not authenticated. Run "autochangelog auth login" first.');
|
|
95
|
+
process.exit(ERROR_CODES.AUTHENTICATION_FAILED);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!projectId) {
|
|
99
|
+
output.error('Project ID is required');
|
|
100
|
+
process.exit(ERROR_CODES.INVALID_ARGUMENT);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const result = await listRepositories(projectId, options, token, logger);
|
|
104
|
+
|
|
105
|
+
if (output.isJsonMode()) {
|
|
106
|
+
output.output({
|
|
107
|
+
success: true,
|
|
108
|
+
data: result,
|
|
109
|
+
metadata: {
|
|
110
|
+
projectId,
|
|
111
|
+
total: result.length,
|
|
112
|
+
limit: options.limit,
|
|
113
|
+
offset: options.offset || 0,
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
} else {
|
|
117
|
+
if (result.length === 0) {
|
|
118
|
+
output.info('No repositories found for this project');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
output.info(`Found ${result.length} repository(ies):`);
|
|
123
|
+
console.log('');
|
|
124
|
+
|
|
125
|
+
const headers = ['ID', 'Owner', 'Name', 'Branch', 'Status', 'Last Sync'];
|
|
126
|
+
const rows = result.map(repo => [
|
|
127
|
+
repo.id || repo._id,
|
|
128
|
+
repo.owner,
|
|
129
|
+
repo.name,
|
|
130
|
+
repo.defaultBranch,
|
|
131
|
+
repo.status || 'active',
|
|
132
|
+
repo.lastSync ? new Date(repo.lastSync).toLocaleDateString() : 'Never',
|
|
133
|
+
]);
|
|
134
|
+
|
|
135
|
+
output.table(headers, rows);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
} catch (error) {
|
|
139
|
+
handleCliError(error, output);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Sync repository command
|
|
144
|
+
repo
|
|
145
|
+
.command('sync <id>')
|
|
146
|
+
.description('Sync repository data from GitHub')
|
|
147
|
+
.option('--force', 'Force full resync')
|
|
148
|
+
.action(async (id, options) => {
|
|
149
|
+
const logger = setupLogger();
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const token = getAuthToken();
|
|
153
|
+
if (!token) {
|
|
154
|
+
output.error('Not authenticated. Run "autochangelog auth login" first.');
|
|
155
|
+
process.exit(ERROR_CODES.AUTHENTICATION_FAILED);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
output.progress('Starting repository sync...', 0);
|
|
159
|
+
|
|
160
|
+
const result = await syncRepository(id, options.force, token, logger);
|
|
161
|
+
|
|
162
|
+
output.progress('Repository sync completed', 100);
|
|
163
|
+
|
|
164
|
+
output.output({
|
|
165
|
+
success: true,
|
|
166
|
+
message: 'Repository synced successfully',
|
|
167
|
+
data: result,
|
|
168
|
+
metadata: {
|
|
169
|
+
timestamp: new Date().toISOString(),
|
|
170
|
+
action: 'repository_sync',
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
} catch (error) {
|
|
175
|
+
handleCliError(error, output);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Validate repository command
|
|
180
|
+
repo
|
|
181
|
+
.command('validate <id>')
|
|
182
|
+
.description('Validate repository access and configuration')
|
|
183
|
+
.action(async (id) => {
|
|
184
|
+
const logger = setupLogger();
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const token = getAuthToken();
|
|
188
|
+
if (!token) {
|
|
189
|
+
output.error('Not authenticated. Run "autochangelog auth login" first.');
|
|
190
|
+
process.exit(ERROR_CODES.AUTHENTICATION_FAILED);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
output.progress('Validating repository access...');
|
|
194
|
+
|
|
195
|
+
const result = await validateRepository(id, token, logger);
|
|
196
|
+
|
|
197
|
+
output.output({
|
|
198
|
+
success: true,
|
|
199
|
+
message: 'Repository validation completed',
|
|
200
|
+
data: result,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
} catch (error) {
|
|
204
|
+
handleCliError(error, output);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Get repository details command
|
|
209
|
+
repo
|
|
210
|
+
.command('get <id>')
|
|
211
|
+
.description('Get repository details')
|
|
212
|
+
.action(async (id) => {
|
|
213
|
+
const logger = setupLogger();
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const token = getAuthToken();
|
|
217
|
+
if (!token) {
|
|
218
|
+
output.error('Not authenticated. Run "autochangelog auth login" first.');
|
|
219
|
+
process.exit(ERROR_CODES.AUTHENTICATION_FAILED);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const result = await getRepository(id, token, logger);
|
|
223
|
+
|
|
224
|
+
output.output({
|
|
225
|
+
success: true,
|
|
226
|
+
message: 'Repository details retrieved',
|
|
227
|
+
data: result,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
} catch (error) {
|
|
231
|
+
handleCliError(error, output);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Connect a GitHub repository
|
|
238
|
+
* @param {Object} repoData - Repository data
|
|
239
|
+
* @param {string} token - Authentication token
|
|
240
|
+
* @param {Object} logger - Logger instance
|
|
241
|
+
* @returns {Promise<Object>} Connected repository
|
|
242
|
+
*/
|
|
243
|
+
async function connectRepository(repoData, token, logger) {
|
|
244
|
+
try {
|
|
245
|
+
const mongoose = require('mongoose');
|
|
246
|
+
const Repository = require('../../autochangelog/src/models/Repository');
|
|
247
|
+
const GitHubService = require('../../autochangelog/src/services/github');
|
|
248
|
+
|
|
249
|
+
await mongoose.connect(loadConfig().mongodb_uri);
|
|
250
|
+
|
|
251
|
+
// Validate repository access on GitHub
|
|
252
|
+
const githubService = new GitHubService(token);
|
|
253
|
+
const repoInfo = await githubService.getRepository(repoData.owner, repoData.name);
|
|
254
|
+
|
|
255
|
+
if (!repoInfo) {
|
|
256
|
+
const error = new Error('Repository not found or access denied');
|
|
257
|
+
error.code = ERROR_CODES.PERMISSION_DENIED;
|
|
258
|
+
error.type = 'permission_denied';
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Create repository record
|
|
263
|
+
const repository = new Repository({
|
|
264
|
+
projectId: repoData.projectId,
|
|
265
|
+
owner: repoData.owner,
|
|
266
|
+
name: repoData.name,
|
|
267
|
+
fullName: repoInfo.full_name,
|
|
268
|
+
defaultBranch: repoData.defaultBranch || 'main',
|
|
269
|
+
githubId: repoInfo.id,
|
|
270
|
+
private: repoInfo.private,
|
|
271
|
+
description: repoInfo.description,
|
|
272
|
+
url: repoInfo.html_url,
|
|
273
|
+
cloneUrl: repoInfo.clone_url,
|
|
274
|
+
status: 'active',
|
|
275
|
+
lastSync: new Date(),
|
|
276
|
+
createdAt: new Date(),
|
|
277
|
+
updatedAt: new Date(),
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
await repository.save();
|
|
281
|
+
|
|
282
|
+
logger.info(`Repository connected: ${repoInfo.full_name} (${repository._id})`);
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
id: repository._id,
|
|
286
|
+
owner: repository.owner,
|
|
287
|
+
name: repository.name,
|
|
288
|
+
fullName: repository.fullName,
|
|
289
|
+
defaultBranch: repository.defaultBranch,
|
|
290
|
+
status: repository.status,
|
|
291
|
+
createdAt: repository.createdAt,
|
|
292
|
+
updatedAt: repository.updatedAt,
|
|
293
|
+
githubInfo: {
|
|
294
|
+
id: repoInfo.id,
|
|
295
|
+
private: repoInfo.private,
|
|
296
|
+
description: repoInfo.description,
|
|
297
|
+
url: repoInfo.html_url,
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
} catch (error) {
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* List repositories for a project
|
|
308
|
+
* @param {string} projectId - Project ID
|
|
309
|
+
* @param {Object} options - Query options
|
|
310
|
+
* @param {string} token - Authentication token
|
|
311
|
+
* @param {Object} logger - Logger instance
|
|
312
|
+
* @returns {Promise<Array>} List of repositories
|
|
313
|
+
*/
|
|
314
|
+
async function listRepositories(projectId, options, token, logger) {
|
|
315
|
+
try {
|
|
316
|
+
const mongoose = require('mongoose');
|
|
317
|
+
const Repository = require('../../autochangelog/src/models/Repository');
|
|
318
|
+
|
|
319
|
+
await mongoose.connect(loadConfig().mongodb_uri);
|
|
320
|
+
|
|
321
|
+
const query = { projectId };
|
|
322
|
+
const limit = options.limit || 50;
|
|
323
|
+
const offset = options.offset || 0;
|
|
324
|
+
|
|
325
|
+
const repositories = await Repository.find(query)
|
|
326
|
+
.sort({ createdAt: -1 })
|
|
327
|
+
.skip(offset)
|
|
328
|
+
.limit(limit)
|
|
329
|
+
.lean();
|
|
330
|
+
|
|
331
|
+
logger.info(`Retrieved ${repositories.length} repositories for project ${projectId}`);
|
|
332
|
+
|
|
333
|
+
return repositories.map(repo => ({
|
|
334
|
+
id: repo._id,
|
|
335
|
+
owner: repo.owner,
|
|
336
|
+
name: repo.name,
|
|
337
|
+
fullName: repo.fullName,
|
|
338
|
+
defaultBranch: repo.defaultBranch,
|
|
339
|
+
status: repo.status,
|
|
340
|
+
private: repo.private,
|
|
341
|
+
description: repo.description,
|
|
342
|
+
url: repo.url,
|
|
343
|
+
lastSync: repo.lastSync,
|
|
344
|
+
createdAt: repo.createdAt,
|
|
345
|
+
updatedAt: repo.updatedAt,
|
|
346
|
+
}));
|
|
347
|
+
|
|
348
|
+
} catch (error) {
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Sync repository data from GitHub
|
|
355
|
+
* @param {string} id - Repository ID
|
|
356
|
+
* @param {boolean} force - Force full resync
|
|
357
|
+
* @param {string} token - Authentication token
|
|
358
|
+
* @param {Object} logger - Logger instance
|
|
359
|
+
* @returns {Promise<Object>} Sync result
|
|
360
|
+
*/
|
|
361
|
+
async function syncRepository(id, force, token, logger) {
|
|
362
|
+
try {
|
|
363
|
+
const mongoose = require('mongoose');
|
|
364
|
+
const Repository = require('../../autochangelog/src/models/Repository');
|
|
365
|
+
const GitHubService = require('../../autochangelog/src/services/github');
|
|
366
|
+
|
|
367
|
+
await mongoose.connect(loadConfig().mongodb_uri);
|
|
368
|
+
|
|
369
|
+
const repository = await Repository.findById(id);
|
|
370
|
+
if (!repository) {
|
|
371
|
+
const error = new Error('Repository not found');
|
|
372
|
+
error.code = ERROR_CODES.RESOURCE_NOT_FOUND;
|
|
373
|
+
error.type = 'resource_not_found';
|
|
374
|
+
throw error;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const githubService = new GitHubService(token);
|
|
378
|
+
|
|
379
|
+
// Update last sync time
|
|
380
|
+
repository.lastSync = new Date();
|
|
381
|
+
repository.updatedAt = new Date();
|
|
382
|
+
await repository.save();
|
|
383
|
+
|
|
384
|
+
// Sync repository info
|
|
385
|
+
const repoInfo = await githubService.getRepository(repository.owner, repository.name);
|
|
386
|
+
|
|
387
|
+
if (repoInfo) {
|
|
388
|
+
repository.fullName = repoInfo.full_name;
|
|
389
|
+
repository.private = repoInfo.private;
|
|
390
|
+
repository.description = repoInfo.description;
|
|
391
|
+
repository.url = repoInfo.html_url;
|
|
392
|
+
repository.cloneUrl = repoInfo.clone_url;
|
|
393
|
+
repository.updatedAt = new Date();
|
|
394
|
+
await repository.save();
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
logger.info(`Repository synced: ${repository.fullName}`);
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
id: repository._id,
|
|
401
|
+
fullName: repository.fullName,
|
|
402
|
+
lastSync: repository.lastSync,
|
|
403
|
+
status: 'synced',
|
|
404
|
+
changes: {
|
|
405
|
+
description: repoInfo ? repoInfo.description : repository.description,
|
|
406
|
+
private: repoInfo ? repoInfo.private : repository.private,
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
} catch (error) {
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Validate repository access and configuration
|
|
417
|
+
* @param {string} id - Repository ID
|
|
418
|
+
* @param {string} token - Authentication token
|
|
419
|
+
* @param {Object} logger - Logger instance
|
|
420
|
+
* @returns {Promise<Object>} Validation result
|
|
421
|
+
*/
|
|
422
|
+
async function validateRepository(id, token, logger) {
|
|
423
|
+
try {
|
|
424
|
+
const mongoose = require('mongoose');
|
|
425
|
+
const Repository = require('../../autochangelog/src/models/Repository');
|
|
426
|
+
const GitHubService = require('../../autochangelog/src/services/github');
|
|
427
|
+
|
|
428
|
+
await mongoose.connect(loadConfig().mongodb_uri);
|
|
429
|
+
|
|
430
|
+
const repository = await Repository.findById(id);
|
|
431
|
+
if (!repository) {
|
|
432
|
+
const error = new Error('Repository not found');
|
|
433
|
+
error.code = ERROR_CODES.RESOURCE_NOT_FOUND;
|
|
434
|
+
error.type = 'resource_not_found';
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const githubService = new GitHubService(token);
|
|
439
|
+
|
|
440
|
+
// Test repository access
|
|
441
|
+
const repoInfo = await githubService.getRepository(repository.owner, repository.name);
|
|
442
|
+
|
|
443
|
+
const validation = {
|
|
444
|
+
repositoryId: repository._id,
|
|
445
|
+
fullName: repository.fullName,
|
|
446
|
+
access: {
|
|
447
|
+
granted: !!repoInfo,
|
|
448
|
+
message: repoInfo ? 'Access granted' : 'Access denied or repository not found',
|
|
449
|
+
},
|
|
450
|
+
configuration: {
|
|
451
|
+
owner: repository.owner,
|
|
452
|
+
name: repository.name,
|
|
453
|
+
defaultBranch: repository.defaultBranch,
|
|
454
|
+
private: repository.private,
|
|
455
|
+
},
|
|
456
|
+
lastSync: repository.lastSync,
|
|
457
|
+
status: repository.status,
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
if (repoInfo) {
|
|
461
|
+
validation.githubInfo = {
|
|
462
|
+
id: repoInfo.id,
|
|
463
|
+
fullName: repoInfo.full_name,
|
|
464
|
+
private: repoInfo.private,
|
|
465
|
+
description: repoInfo.description,
|
|
466
|
+
defaultBranch: repoInfo.default_branch,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
logger.info(`Repository validation completed: ${repository.fullName}`);
|
|
471
|
+
|
|
472
|
+
return validation;
|
|
473
|
+
|
|
474
|
+
} catch (error) {
|
|
475
|
+
throw error;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Get repository details
|
|
481
|
+
* @param {string} id - Repository ID
|
|
482
|
+
* @param {string} token - Authentication token
|
|
483
|
+
* @param {Object} logger - Logger instance
|
|
484
|
+
* @returns {Promise<Object>} Repository details
|
|
485
|
+
*/
|
|
486
|
+
async function getRepository(id, token, logger) {
|
|
487
|
+
try {
|
|
488
|
+
const mongoose = require('mongoose');
|
|
489
|
+
const Repository = require('../../autochangelog/src/models/Repository');
|
|
490
|
+
|
|
491
|
+
await mongoose.connect(loadConfig().mongodb_uri);
|
|
492
|
+
|
|
493
|
+
const repository = await Repository.findById(id).lean();
|
|
494
|
+
|
|
495
|
+
if (!repository) {
|
|
496
|
+
const error = new Error('Repository not found');
|
|
497
|
+
error.code = ERROR_CODES.RESOURCE_NOT_FOUND;
|
|
498
|
+
error.type = 'resource_not_found';
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
logger.info(`Retrieved repository details: ${repository.fullName}`);
|
|
503
|
+
|
|
504
|
+
return {
|
|
505
|
+
id: repository._id,
|
|
506
|
+
projectId: repository.projectId,
|
|
507
|
+
owner: repository.owner,
|
|
508
|
+
name: repository.name,
|
|
509
|
+
fullName: repository.fullName,
|
|
510
|
+
defaultBranch: repository.defaultBranch,
|
|
511
|
+
status: repository.status,
|
|
512
|
+
private: repository.private,
|
|
513
|
+
description: repository.description,
|
|
514
|
+
url: repository.url,
|
|
515
|
+
cloneUrl: repository.cloneUrl,
|
|
516
|
+
githubId: repository.githubId,
|
|
517
|
+
lastSync: repository.lastSync,
|
|
518
|
+
createdAt: repository.createdAt,
|
|
519
|
+
updatedAt: repository.updatedAt,
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
} catch (error) {
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Parse repository URL to extract owner and name
|
|
529
|
+
* @param {string} url - Repository URL
|
|
530
|
+
* @returns {Object} Parsed owner and name
|
|
531
|
+
*/
|
|
532
|
+
function parseRepoUrl(url) {
|
|
533
|
+
try {
|
|
534
|
+
// Handle various GitHub URL formats
|
|
535
|
+
const patterns = [
|
|
536
|
+
/^https?:\/\/github\.com\/([^/]+)\/([^/]+)(?:\.git)?$/i,
|
|
537
|
+
/^git@github\.com:([^/]+)\/([^/]+)(?:\.git)?$/i,
|
|
538
|
+
/^github:([^/]+)\/([^/]+)$/i,
|
|
539
|
+
];
|
|
540
|
+
|
|
541
|
+
for (const pattern of patterns) {
|
|
542
|
+
const match = url.match(pattern);
|
|
543
|
+
if (match) {
|
|
544
|
+
return {
|
|
545
|
+
owner: match[1],
|
|
546
|
+
name: match[2],
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
throw new Error('Invalid repository URL format');
|
|
552
|
+
} catch (error) {
|
|
553
|
+
throw new Error(`Failed to parse repository URL: ${error.message}`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
module.exports = setupRepoCommands;
|