archicore 0.3.2 → 0.3.4
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.
|
@@ -554,7 +554,7 @@ async function handleIndexCommand() {
|
|
|
554
554
|
});
|
|
555
555
|
if (response.ok) {
|
|
556
556
|
const data = await response.json();
|
|
557
|
-
state.projectId = data.id || data.project
|
|
557
|
+
state.projectId = data.id || (data.project && data.project.id) || null;
|
|
558
558
|
registerSpinner.succeed('Project registered');
|
|
559
559
|
}
|
|
560
560
|
else {
|
|
@@ -693,7 +693,7 @@ async function handleIndexCommand() {
|
|
|
693
693
|
});
|
|
694
694
|
if (reRegisterResponse.ok) {
|
|
695
695
|
const reData = await reRegisterResponse.json();
|
|
696
|
-
state.projectId = reData.id || reData.project
|
|
696
|
+
state.projectId = reData.id || (reData.project && reData.project.id) || null;
|
|
697
697
|
printInfo('Project re-registered. Run /index again to complete indexing.');
|
|
698
698
|
// Обновляем локальный конфиг
|
|
699
699
|
const localProjectRetry = await getLocalProject(state.projectPath);
|
|
@@ -21,6 +21,140 @@ export const gitlabRouter = Router();
|
|
|
21
21
|
const gitlabService = new GitLabService();
|
|
22
22
|
const projectService = new ProjectService();
|
|
23
23
|
const authService = AuthService.getInstance();
|
|
24
|
+
// ===== SIMPLIFIED CONNECT (for frontend) =====
|
|
25
|
+
/**
|
|
26
|
+
* POST /api/gitlab/connect
|
|
27
|
+
* Simplified endpoint to connect a GitLab repository in one step
|
|
28
|
+
* Creates instance if needed, then connects repository
|
|
29
|
+
*/
|
|
30
|
+
gitlabRouter.post('/connect', authMiddleware, async (req, res) => {
|
|
31
|
+
try {
|
|
32
|
+
if (!req.user) {
|
|
33
|
+
res.status(401).json({ error: 'Not authenticated' });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const { gitlabUrl, repoPath, branch, token, autoAnalyze, analyzeMRs } = req.body;
|
|
37
|
+
if (!repoPath) {
|
|
38
|
+
res.status(400).json({ error: 'Repository path is required (e.g., owner/repo)' });
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const instanceUrl = gitlabUrl || 'https://gitlab.com';
|
|
42
|
+
// Check if we have an existing instance for this URL
|
|
43
|
+
let instances = await gitlabService.getInstances(req.user.id);
|
|
44
|
+
let instance = instances.find(i => i.instanceUrl === instanceUrl);
|
|
45
|
+
// If no instance and no token provided, return error
|
|
46
|
+
if (!instance && !token) {
|
|
47
|
+
res.status(400).json({
|
|
48
|
+
error: 'GitLab access token required for first connection',
|
|
49
|
+
message: 'Please provide a Personal Access Token with api scope'
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Create instance if needed
|
|
54
|
+
if (!instance && token) {
|
|
55
|
+
try {
|
|
56
|
+
instance = await gitlabService.addInstance(req.user.id, instanceUrl, token, { name: instanceUrl.replace('https://', '').replace('http://', '') });
|
|
57
|
+
Logger.info(`Created GitLab instance for ${instanceUrl}`);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
Logger.error('Failed to create GitLab instance:', e);
|
|
61
|
+
res.status(400).json({
|
|
62
|
+
error: 'Failed to connect to GitLab',
|
|
63
|
+
message: e instanceof Error ? e.message : 'Invalid token or GitLab URL'
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!instance) {
|
|
69
|
+
res.status(400).json({ error: 'No GitLab instance available' });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Find the project by path
|
|
73
|
+
const projects = await gitlabService.listProjects(req.user.id, instance.id, { search: repoPath });
|
|
74
|
+
const project = projects.find(p => p.path_with_namespace === repoPath);
|
|
75
|
+
if (!project) {
|
|
76
|
+
res.status(404).json({
|
|
77
|
+
error: 'Repository not found',
|
|
78
|
+
message: `Could not find repository "${repoPath}" on ${instanceUrl}`
|
|
79
|
+
});
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Check usage limit
|
|
83
|
+
const usageResult = await authService.checkAndUpdateUsage(req.user.id, 'project');
|
|
84
|
+
if (!usageResult.allowed) {
|
|
85
|
+
res.status(429).json({
|
|
86
|
+
error: 'Project limit reached',
|
|
87
|
+
message: `You have reached your daily project limit (${usageResult.limit})`,
|
|
88
|
+
usage: { used: usageResult.limit, limit: usageResult.limit, remaining: 0 }
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Connect repository
|
|
93
|
+
const connectedRepo = await gitlabService.connectRepository(req.user.id, instance.id, project.id, { autoAnalyze: autoAnalyze !== false, analyzeMRs: analyzeMRs !== false });
|
|
94
|
+
// Download and create ArchiCore project
|
|
95
|
+
const targetBranch = branch || project.default_branch || 'main';
|
|
96
|
+
Logger.progress(`Downloading GitLab repository: ${project.path_with_namespace} (branch: ${targetBranch})`);
|
|
97
|
+
const zipBuffer = await gitlabService.downloadRepository(req.user.id, instance.id, project.id, targetBranch);
|
|
98
|
+
// Create projects directory
|
|
99
|
+
const projectsDir = process.env.PROJECTS_DIR || join('.archicore', 'projects');
|
|
100
|
+
await mkdir(projectsDir, { recursive: true });
|
|
101
|
+
// Extract to project directory
|
|
102
|
+
const projectPath = join(projectsDir, project.name);
|
|
103
|
+
await mkdir(projectPath, { recursive: true });
|
|
104
|
+
const zip = new AdmZip(zipBuffer);
|
|
105
|
+
const zipEntries = zip.getEntries();
|
|
106
|
+
// Extract files
|
|
107
|
+
for (const entry of zipEntries) {
|
|
108
|
+
if (entry.isDirectory) {
|
|
109
|
+
const dirPath = join(projectPath, entry.entryName);
|
|
110
|
+
await mkdir(dirPath, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const filePath = join(projectPath, entry.entryName);
|
|
114
|
+
const fileDir = join(projectPath, entry.entryName.split('/').slice(0, -1).join('/'));
|
|
115
|
+
await mkdir(fileDir, { recursive: true });
|
|
116
|
+
const content = entry.getData();
|
|
117
|
+
const { writeFile } = await import('fs/promises');
|
|
118
|
+
await writeFile(filePath, content);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// GitLab creates a folder like "project-branch" inside, find it
|
|
122
|
+
const { readdir, stat } = await import('fs/promises');
|
|
123
|
+
const contents = await readdir(projectPath);
|
|
124
|
+
let actualPath = projectPath;
|
|
125
|
+
if (contents.length === 1) {
|
|
126
|
+
const innerPath = join(projectPath, contents[0]);
|
|
127
|
+
const stats = await stat(innerPath);
|
|
128
|
+
if (stats.isDirectory()) {
|
|
129
|
+
actualPath = innerPath;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
Logger.success(`Downloaded and extracted to: ${actualPath}`);
|
|
133
|
+
// Create ArchiCore project
|
|
134
|
+
const archiProject = await projectService.createProject(project.name, actualPath, req.user.id);
|
|
135
|
+
// Update connected repo with project ID
|
|
136
|
+
await gitlabService.updateRepositoryProjectId(connectedRepo.id, archiProject.id);
|
|
137
|
+
await gitlabService.updateRepositoryStatus(connectedRepo.id, 'active');
|
|
138
|
+
res.json({
|
|
139
|
+
success: true,
|
|
140
|
+
project: {
|
|
141
|
+
id: archiProject.id,
|
|
142
|
+
name: archiProject.name,
|
|
143
|
+
path: actualPath
|
|
144
|
+
},
|
|
145
|
+
repository: {
|
|
146
|
+
id: connectedRepo.id,
|
|
147
|
+
fullPath: project.path_with_namespace,
|
|
148
|
+
branch: targetBranch
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
Logger.error('GitLab connect error:', error);
|
|
154
|
+
const message = error instanceof Error ? error.message : 'Failed to connect GitLab repository';
|
|
155
|
+
res.status(500).json({ error: message });
|
|
156
|
+
}
|
|
157
|
+
});
|
|
24
158
|
// ===== INSTANCE MANAGEMENT =====
|
|
25
159
|
/**
|
|
26
160
|
* POST /api/gitlab/instances
|