@manojkmfsi/monodog 1.1.22 → 1.1.24
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/CHANGELOG.md +14 -0
- package/dist/controllers/publish-controller.js +67 -5
- package/dist/middleware/auth-middleware.js +27 -4
- package/dist/routes/auth-routes.js +30 -2
- package/dist/routes/publish-routes.js +8 -2
- package/dist/services/changeset-service.js +4 -40
- package/dist/utils/utilities.js +49 -0
- package/monodog-dashboard/dist/assets/{index-BYVT2h3u.js → index-BMoE990p.js} +9 -8
- package/monodog-dashboard/dist/assets/index-BMoE990p.js.map +1 -0
- package/monodog-dashboard/dist/index.html +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @manojkmfsi/monoapp
|
|
2
2
|
|
|
3
|
+
## 1.1.24
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`fab5078`](https://github.com/manojkmfsi/monodog/commit/fab50783c8ffda7e791e0451072056ee2b92703d) - joijijijijijjjo
|
|
8
|
+
|
|
9
|
+
- [`f1de12e`](https://github.com/manojkmfsi/monodog/commit/f1de12ee71b8228689834fb65e34d16692e48c46) - dsdsvdvdsvdscsdcssdd
|
|
10
|
+
|
|
11
|
+
## 1.1.23
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`b90aa90`](https://github.com/manojkmfsi/monodog/commit/b90aa90bfbf516128af033c883a21ca4d09f713d) - dcdsdsvdvdvxvcxvxvx
|
|
16
|
+
|
|
3
17
|
## 1.1.22
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -7,6 +7,7 @@ exports.createChangeset = createChangeset;
|
|
|
7
7
|
exports.checkPublishStatus = checkPublishStatus;
|
|
8
8
|
exports.triggerPublish = triggerPublish;
|
|
9
9
|
const logger_1 = require("../middleware/logger");
|
|
10
|
+
const auth_middleware_1 = require("../middleware/auth-middleware");
|
|
10
11
|
const changeset_service_1 = require("../services/changeset-service");
|
|
11
12
|
/**
|
|
12
13
|
* Get all workspace packages
|
|
@@ -80,17 +81,34 @@ async function previewPublish(req, res) {
|
|
|
80
81
|
// Perform validation checks
|
|
81
82
|
const errors = [];
|
|
82
83
|
const warnings = [];
|
|
84
|
+
// Get authenticated user
|
|
85
|
+
const session = (0, auth_middleware_1.getSessionFromRequest)(req);
|
|
86
|
+
const authUser = req.user;
|
|
87
|
+
const userPermission = req.permission.permission || 'read';
|
|
83
88
|
// Check 1: Working tree clean
|
|
84
89
|
const workingTreeClean = isClean;
|
|
85
90
|
if (!workingTreeClean) {
|
|
86
91
|
errors.push('Working tree has uncommitted changes');
|
|
87
92
|
}
|
|
88
|
-
// Check 2: User permissions
|
|
89
|
-
const
|
|
93
|
+
// Check 2: User permissions
|
|
94
|
+
const permissionHierarchy = {
|
|
95
|
+
admin: 4,
|
|
96
|
+
maintain: 3,
|
|
97
|
+
write: 2,
|
|
98
|
+
read: 1,
|
|
99
|
+
none: 0,
|
|
100
|
+
};
|
|
101
|
+
const userLevel = permissionHierarchy[userPermission] || 0;
|
|
102
|
+
const requiredLevel = permissionHierarchy['write'] || 0;
|
|
103
|
+
const permissions = userLevel >= requiredLevel;
|
|
104
|
+
if (!permissions) {
|
|
105
|
+
errors.push(`Insufficient permissions. Required: write, Got: ${userPermission}`);
|
|
106
|
+
}
|
|
90
107
|
// Check 3: CI passing (simplified - always true for now)
|
|
91
108
|
const ciPassing = true;
|
|
92
109
|
// Check 4: Version available on npm (simplified - always true for now)
|
|
93
110
|
const versionAvailable = true;
|
|
111
|
+
logger_1.AppLogger.info(`Publishing preview for user: ${authUser?.login} (permission: ${userPermission})`);
|
|
94
112
|
const isValid = errors.length === 0;
|
|
95
113
|
res.json({
|
|
96
114
|
success: true,
|
|
@@ -126,6 +144,8 @@ async function previewPublish(req, res) {
|
|
|
126
144
|
async function createChangeset(req, res) {
|
|
127
145
|
try {
|
|
128
146
|
const { packages: selectedPackageNames, bumps, summary } = req.body;
|
|
147
|
+
const authUser = req.user;
|
|
148
|
+
const userPermission = req.permission.permission || 'read';
|
|
129
149
|
if (!selectedPackageNames || !Array.isArray(selectedPackageNames)) {
|
|
130
150
|
res.status(400).json({
|
|
131
151
|
success: false,
|
|
@@ -142,9 +162,29 @@ async function createChangeset(req, res) {
|
|
|
142
162
|
});
|
|
143
163
|
return;
|
|
144
164
|
}
|
|
165
|
+
// Check permissions
|
|
166
|
+
const permissionHierarchy = {
|
|
167
|
+
admin: 4,
|
|
168
|
+
maintain: 3,
|
|
169
|
+
write: 2,
|
|
170
|
+
read: 1,
|
|
171
|
+
none: 0,
|
|
172
|
+
};
|
|
173
|
+
const userLevel = permissionHierarchy[userPermission] || 0;
|
|
174
|
+
const requiredLevel = permissionHierarchy['write'] || 0;
|
|
175
|
+
if (userLevel < requiredLevel) {
|
|
176
|
+
logger_1.AppLogger.warn(`User ${authUser?.login} attempted to create changeset without write permission`);
|
|
177
|
+
res.status(403).json({
|
|
178
|
+
success: false,
|
|
179
|
+
error: 'Forbidden',
|
|
180
|
+
message: `This action requires write permission. You have: ${userPermission}`,
|
|
181
|
+
});
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
145
184
|
const rootPath = req.app.locals.rootPath;
|
|
185
|
+
logger_1.AppLogger.info(`Creating changeset for user: ${authUser?.login} (permission: ${userPermission})`);
|
|
146
186
|
// Generate the changeset
|
|
147
|
-
const result = await (0, changeset_service_1.generateChangeset)(rootPath, selectedPackageNames, bumps || [], summary);
|
|
187
|
+
const result = await (0, changeset_service_1.generateChangeset)(rootPath, selectedPackageNames, bumps || [], summary, authUser?.login);
|
|
148
188
|
if (!result.success) {
|
|
149
189
|
res.status(400).json({
|
|
150
190
|
success: false,
|
|
@@ -202,6 +242,27 @@ async function checkPublishStatus(req, res) {
|
|
|
202
242
|
async function triggerPublish(req, res) {
|
|
203
243
|
try {
|
|
204
244
|
const rootPath = req.app.locals.rootPath;
|
|
245
|
+
const authUser = req.user;
|
|
246
|
+
const userPermission = req.permission.permission || 'read';
|
|
247
|
+
// Check permissions
|
|
248
|
+
const permissionHierarchy = {
|
|
249
|
+
admin: 4,
|
|
250
|
+
maintain: 3,
|
|
251
|
+
write: 2,
|
|
252
|
+
read: 1,
|
|
253
|
+
none: 0,
|
|
254
|
+
};
|
|
255
|
+
const userLevel = permissionHierarchy[userPermission] || 0;
|
|
256
|
+
const requiredLevel = permissionHierarchy['maintain'] || 0;
|
|
257
|
+
if (userLevel < requiredLevel) {
|
|
258
|
+
logger_1.AppLogger.warn(`User ${authUser?.login} attempted to trigger publish without maintain permission`);
|
|
259
|
+
res.status(403).json({
|
|
260
|
+
success: false,
|
|
261
|
+
error: 'Forbidden',
|
|
262
|
+
message: `This action requires maintain permission. You have: ${userPermission}`,
|
|
263
|
+
});
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
205
266
|
// Check if working tree is clean
|
|
206
267
|
const isClean = true; //await isWorkingTreeClean(rootPath);
|
|
207
268
|
if (!isClean) {
|
|
@@ -222,8 +283,9 @@ async function triggerPublish(req, res) {
|
|
|
222
283
|
});
|
|
223
284
|
return;
|
|
224
285
|
}
|
|
225
|
-
|
|
226
|
-
|
|
286
|
+
logger_1.AppLogger.info(`Triggering publish for user: ${authUser?.login} (permission: ${userPermission})`);
|
|
287
|
+
// Trigger publish pipeline with user context
|
|
288
|
+
const result = await (0, changeset_service_1.triggerPublishPipeline)(rootPath, authUser?.login);
|
|
227
289
|
if (!result.success) {
|
|
228
290
|
res.status(500).json({
|
|
229
291
|
success: false,
|
|
@@ -90,9 +90,30 @@ function authenticationMiddleware(req, res, next) {
|
|
|
90
90
|
});
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
|
-
// Attach session to request
|
|
93
|
+
// Attach session and user info to request
|
|
94
94
|
req.session = session;
|
|
95
|
-
|
|
95
|
+
req.user = {
|
|
96
|
+
login: session.user.login,
|
|
97
|
+
id: session.user.id,
|
|
98
|
+
};
|
|
99
|
+
// Attach permission from session (if available)
|
|
100
|
+
if (session.permission) {
|
|
101
|
+
req.permission = session.permission;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// Default to 'read' if no permission fetched
|
|
105
|
+
req.permission = {
|
|
106
|
+
permission: 'read',
|
|
107
|
+
role: 'Denied',
|
|
108
|
+
userId: session.user.id,
|
|
109
|
+
username: session.user.login,
|
|
110
|
+
owner: '',
|
|
111
|
+
repo: '',
|
|
112
|
+
cachedAt: Date.now(),
|
|
113
|
+
ttl: 0,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
logger_1.AppLogger.debug(`Authenticated request from user: ${session.user.login} with permission: ${req.permission?.permission || 'unknown'}`);
|
|
96
117
|
next();
|
|
97
118
|
}
|
|
98
119
|
/**
|
|
@@ -124,10 +145,12 @@ function repositoryPermissionMiddleware(requiredPermission) {
|
|
|
124
145
|
read: 1,
|
|
125
146
|
none: 0,
|
|
126
147
|
};
|
|
127
|
-
|
|
148
|
+
// Handle both string and object formats for permission
|
|
149
|
+
const userPermissionString = typeof permission === 'string' ? permission : (permission.permission || 'none');
|
|
150
|
+
const userLevel = permissionHierarchy[userPermissionString] || 0;
|
|
128
151
|
const requiredLevel = permissionHierarchy[requiredPermission] || 0;
|
|
129
152
|
if (userLevel < requiredLevel) {
|
|
130
|
-
logger_1.AppLogger.warn(`User ${session.user.login} lacks permission for action requiring ${requiredPermission}`);
|
|
153
|
+
logger_1.AppLogger.warn(`User ${session.user.login} lacks permission for action requiring ${requiredPermission} (has ${userPermissionString})`);
|
|
131
154
|
res.status(403).json({
|
|
132
155
|
error: 'Forbidden',
|
|
133
156
|
message: `This action requires ${requiredPermission} permission`,
|
|
@@ -7,7 +7,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const express_1 = require("express");
|
|
8
8
|
const github_oauth_service_1 = require("../services/github-oauth-service");
|
|
9
9
|
const auth_middleware_1 = require("../middleware/auth-middleware");
|
|
10
|
+
const permission_service_1 = require("../services/permission-service");
|
|
10
11
|
const logger_1 = require("../middleware/logger");
|
|
12
|
+
const utilities_1 = require("../utils/utilities");
|
|
11
13
|
const router = (0, express_1.Router)();
|
|
12
14
|
// OAuth configuration (should come from environment variables)
|
|
13
15
|
// const GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID || '';
|
|
@@ -138,13 +140,34 @@ router.get('/callback', async (req, res) => {
|
|
|
138
140
|
// Get user information
|
|
139
141
|
logger_1.AppLogger.debug('Retrieving authenticated user information');
|
|
140
142
|
const user = await (0, github_oauth_service_1.getAuthenticatedUser)(tokenResponse.access_token);
|
|
141
|
-
//
|
|
143
|
+
// Fetch user's repository permission
|
|
144
|
+
let permission = null;
|
|
145
|
+
try {
|
|
146
|
+
logger_1.AppLogger.debug(`Fetching repository permission for user ${user.login}`);
|
|
147
|
+
// Extract repository info from git remote
|
|
148
|
+
const repoInfo = await (0, utilities_1.getRepositoryInfoFromGit)();
|
|
149
|
+
if (!repoInfo) {
|
|
150
|
+
logger_1.AppLogger.warn('Could not extract repository info from git remote - permission fetch skipped');
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const { owner, repo } = repoInfo;
|
|
154
|
+
permission = await (0, permission_service_1.getUserRepositoryPermission)(tokenResponse.access_token, user.id, user.login, owner, repo);
|
|
155
|
+
logger_1.AppLogger.info(`User ${user.login} has ${permission.permission} permission on ${owner}/${repo}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (permError) {
|
|
159
|
+
logger_1.AppLogger.error(`Failed to fetch repository permission: ${permError}`);
|
|
160
|
+
// Continue without permission - will be checked on protected routes
|
|
161
|
+
permission = null;
|
|
162
|
+
}
|
|
163
|
+
// Create session with permission
|
|
142
164
|
const session = {
|
|
143
165
|
accessToken: tokenResponse.access_token,
|
|
144
166
|
expiresIn: 3600, // 1 hour default
|
|
145
167
|
expiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
|
|
146
168
|
user,
|
|
147
169
|
scopes: tokenResponse.scope.split(','),
|
|
170
|
+
permission, // Include fetched permission in session
|
|
148
171
|
};
|
|
149
172
|
// Store session and get token
|
|
150
173
|
const sessionToken = (0, auth_middleware_1.storeSession)(session);
|
|
@@ -152,7 +175,7 @@ router.get('/callback', async (req, res) => {
|
|
|
152
175
|
const redirectUrl = getRedirectUrl(state) || '/';
|
|
153
176
|
// Clear state
|
|
154
177
|
clearState(state);
|
|
155
|
-
logger_1.AppLogger.info(`User authenticated: ${user.login}`);
|
|
178
|
+
logger_1.AppLogger.info(`User authenticated: ${user.login} with permission: ${permission?.permission || 'unknown'}`);
|
|
156
179
|
res.json({
|
|
157
180
|
success: true,
|
|
158
181
|
message: 'Authentication successful',
|
|
@@ -164,6 +187,10 @@ router.get('/callback', async (req, res) => {
|
|
|
164
187
|
name: user.name,
|
|
165
188
|
avatar_url: user.avatar_url,
|
|
166
189
|
},
|
|
190
|
+
permission: permission ? {
|
|
191
|
+
level: permission.permission,
|
|
192
|
+
role: permission.role,
|
|
193
|
+
} : null,
|
|
167
194
|
});
|
|
168
195
|
}
|
|
169
196
|
catch (error) {
|
|
@@ -203,6 +230,7 @@ router.get('/me', auth_middleware_1.authenticationMiddleware, (req, res) => {
|
|
|
203
230
|
},
|
|
204
231
|
scopes: session.scopes,
|
|
205
232
|
expiresAt: session.expiresAt,
|
|
233
|
+
permission: session.permission || null,
|
|
206
234
|
});
|
|
207
235
|
}
|
|
208
236
|
catch (error) {
|
|
@@ -10,31 +10,37 @@ const publishRouter = express_1.default.Router();
|
|
|
10
10
|
/**
|
|
11
11
|
* GET /api/publish/packages
|
|
12
12
|
* Get all workspace packages for publishing
|
|
13
|
+
* Requires: read permission
|
|
13
14
|
*/
|
|
14
15
|
publishRouter.get('/packages', auth_middleware_1.authenticationMiddleware, publish_controller_1.getPublishPackages);
|
|
15
16
|
/**
|
|
16
17
|
* GET /api/publish/changesets
|
|
17
18
|
* Get existing unpublished changesets
|
|
19
|
+
* Requires: read permission
|
|
18
20
|
*/
|
|
19
21
|
publishRouter.get('/changesets', auth_middleware_1.authenticationMiddleware, publish_controller_1.getPublishChangesets);
|
|
20
22
|
/**
|
|
21
23
|
* POST /api/publish/preview
|
|
22
24
|
* Preview the publish plan (calculate new versions, affected packages)
|
|
25
|
+
* Requires: read permission
|
|
23
26
|
*/
|
|
24
27
|
publishRouter.post('/preview', auth_middleware_1.authenticationMiddleware, publish_controller_1.previewPublish);
|
|
25
28
|
/**
|
|
26
29
|
* POST /api/publish/changesets
|
|
27
30
|
* Create a new changeset for the selected packages
|
|
31
|
+
* Requires: write permission
|
|
28
32
|
*/
|
|
29
|
-
publishRouter.post('/changesets', auth_middleware_1.authenticationMiddleware, publish_controller_1.createChangeset);
|
|
33
|
+
publishRouter.post('/changesets', auth_middleware_1.authenticationMiddleware, (0, auth_middleware_1.repositoryPermissionMiddleware)('write'), publish_controller_1.createChangeset);
|
|
30
34
|
/**
|
|
31
35
|
* GET /api/publish/status
|
|
32
36
|
* Check publish readiness (working tree, changesets, etc.)
|
|
37
|
+
* Requires: read permission
|
|
33
38
|
*/
|
|
34
39
|
publishRouter.get('/status', auth_middleware_1.authenticationMiddleware, publish_controller_1.checkPublishStatus);
|
|
35
40
|
/**
|
|
36
41
|
* POST /api/publish/trigger
|
|
37
42
|
* Trigger the publishing workflow
|
|
43
|
+
* Requires: maintain permission
|
|
38
44
|
*/
|
|
39
|
-
publishRouter.post('/trigger', auth_middleware_1.authenticationMiddleware, publish_controller_1.triggerPublish);
|
|
45
|
+
publishRouter.post('/trigger', auth_middleware_1.authenticationMiddleware, (0, auth_middleware_1.repositoryPermissionMiddleware)('maintain'), publish_controller_1.triggerPublish);
|
|
40
46
|
exports.default = publishRouter;
|
|
@@ -120,7 +120,7 @@ async function validateChangeset(rootPath, packages, summary) {
|
|
|
120
120
|
/**
|
|
121
121
|
* Generate a new changeset
|
|
122
122
|
*/
|
|
123
|
-
async function generateChangeset(rootPath, packages, bumps, summary) {
|
|
123
|
+
async function generateChangeset(rootPath, packages, bumps, summary, createdBy) {
|
|
124
124
|
try {
|
|
125
125
|
// Validate input
|
|
126
126
|
const validation = await validateChangeset(rootPath, packages, summary);
|
|
@@ -154,7 +154,7 @@ async function generateChangeset(rootPath, packages, bumps, summary) {
|
|
|
154
154
|
content += summary;
|
|
155
155
|
// Write changeset file
|
|
156
156
|
await promises_1.default.writeFile(changesetPath, content, 'utf-8');
|
|
157
|
-
logger_1.AppLogger.info(`Changeset created: ${changesetName}`);
|
|
157
|
+
logger_1.AppLogger.info(`Changeset created: ${changesetName} by user: ${createdBy || 'unknown'}`);
|
|
158
158
|
return {
|
|
159
159
|
success: true,
|
|
160
160
|
message: 'Changeset created successfully',
|
|
@@ -186,8 +186,9 @@ async function isWorkingTreeClean(rootPath) {
|
|
|
186
186
|
/**
|
|
187
187
|
* Trigger CI pipeline for publishing
|
|
188
188
|
*/
|
|
189
|
-
async function triggerPublishPipeline(rootPath) {
|
|
189
|
+
async function triggerPublishPipeline(rootPath, publishedBy) {
|
|
190
190
|
try {
|
|
191
|
+
logger_1.AppLogger.info(`Publishing workflow triggered by user: ${publishedBy || 'unknown'}`);
|
|
191
192
|
// Check if publish workflow exists
|
|
192
193
|
const publishWorkflowPath = path_1.default.join(rootPath, '.github', 'workflows', 'release.yml');
|
|
193
194
|
try {
|
|
@@ -228,43 +229,6 @@ async function triggerPublishPipeline(rootPath) {
|
|
|
228
229
|
logger_1.AppLogger.warn(`Git operations failed: ${gitError}`);
|
|
229
230
|
// Continue anyway - changesets might already be committed
|
|
230
231
|
}
|
|
231
|
-
// Trigger the workflow via GitHub API if we have a token
|
|
232
|
-
try {
|
|
233
|
-
const githubToken = process.env.GITHUB_TOKEN;
|
|
234
|
-
if (githubToken) {
|
|
235
|
-
// Get repo info from package.json or git remote
|
|
236
|
-
const { stdout: remoteUrl } = await execPromise('git remote get-url origin', {
|
|
237
|
-
cwd: rootPath,
|
|
238
|
-
});
|
|
239
|
-
// Parse GitHub repo from URL (e.g., git@github.com:user/repo.git)
|
|
240
|
-
const repoMatch = remoteUrl.match(/github\.com[:/]([^/]+)\/(.+?)(\.git)?$/);
|
|
241
|
-
if (repoMatch) {
|
|
242
|
-
const [, owner, repo] = repoMatch;
|
|
243
|
-
const repoName = repo.replace(/\.git$/, '');
|
|
244
|
-
// Trigger the workflow
|
|
245
|
-
const response = await fetch(`https://api.github.com/repos/${owner}/${repoName}/actions/workflows/release.yml/dispatches`, {
|
|
246
|
-
method: 'POST',
|
|
247
|
-
headers: {
|
|
248
|
-
Authorization: `Bearer ${githubToken}`,
|
|
249
|
-
Accept: 'application/vnd.github.v3+json',
|
|
250
|
-
},
|
|
251
|
-
body: JSON.stringify({
|
|
252
|
-
ref: 'main',
|
|
253
|
-
}),
|
|
254
|
-
});
|
|
255
|
-
if (response.ok) {
|
|
256
|
-
logger_1.AppLogger.info('GitHub workflow triggered successfully');
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
logger_1.AppLogger.warn(`Failed to trigger workflow: ${response.statusText}`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
catch (workflowError) {
|
|
265
|
-
logger_1.AppLogger.warn(`Failed to trigger workflow: ${workflowError}`);
|
|
266
|
-
// Still return success as the changeset was created
|
|
267
|
-
}
|
|
268
232
|
logger_1.AppLogger.info('Publish pipeline initiated');
|
|
269
233
|
return {
|
|
270
234
|
success: true,
|
package/dist/utils/utilities.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.calculatePackageHealth = void 0;
|
|
|
40
40
|
exports.resolveWorkspaceGlobs = resolveWorkspaceGlobs;
|
|
41
41
|
exports.getWorkspacesFromRoot = getWorkspacesFromRoot;
|
|
42
42
|
exports.parsePackageInfo = parsePackageInfo;
|
|
43
|
+
exports.getRepositoryInfoFromGit = getRepositoryInfoFromGit;
|
|
43
44
|
exports.scanMonorepo = scanMonorepo;
|
|
44
45
|
exports.generateMonorepoStats = generateMonorepoStats;
|
|
45
46
|
exports.findCircularDependencies = findCircularDependencies;
|
|
@@ -407,3 +408,51 @@ function findMonorepoRoot() {
|
|
|
407
408
|
logger_1.AppLogger.warn('Could not find monorepo root, using process.cwd(): ' + process.cwd());
|
|
408
409
|
return process.cwd();
|
|
409
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* Extracts GitHub repository owner and repo name from git remote URL
|
|
413
|
+
* Supports both SSH (git@github.com:owner/repo.git) and HTTPS (https://github.com/owner/repo.git) formats
|
|
414
|
+
*/
|
|
415
|
+
async function getRepositoryInfoFromGit(repoPath = process.cwd()) {
|
|
416
|
+
try {
|
|
417
|
+
const { exec } = await import('child_process');
|
|
418
|
+
const { promisify } = await import('util');
|
|
419
|
+
const execPromise = promisify(exec);
|
|
420
|
+
// Get the git remote URL
|
|
421
|
+
const { stdout } = await execPromise('git remote get-url origin', {
|
|
422
|
+
cwd: repoPath,
|
|
423
|
+
timeout: 5000,
|
|
424
|
+
});
|
|
425
|
+
const remoteUrl = stdout.trim();
|
|
426
|
+
if (!remoteUrl) {
|
|
427
|
+
logger_1.AppLogger.warn('No git remote found');
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
// Parse different URL formats
|
|
431
|
+
let owner = '';
|
|
432
|
+
let repo = '';
|
|
433
|
+
// SSH format: git@github.com:owner/repo.git
|
|
434
|
+
const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/(.+?)(\.git)?$/);
|
|
435
|
+
if (sshMatch) {
|
|
436
|
+
owner = sshMatch[1];
|
|
437
|
+
repo = sshMatch[2].replace(/\.git$/, '');
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
// HTTPS format: https://github.com/owner/repo.git or https://github.com/owner/repo
|
|
441
|
+
const httpsMatch = remoteUrl.match(/github\.com[:/]([^/]+)\/(.+?)(\.git)?$/);
|
|
442
|
+
if (httpsMatch) {
|
|
443
|
+
owner = httpsMatch[1];
|
|
444
|
+
repo = httpsMatch[2].replace(/\.git$/, '');
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (!owner || !repo) {
|
|
448
|
+
logger_1.AppLogger.warn(`Could not parse repository info from git remote: ${remoteUrl}`);
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
logger_1.AppLogger.debug(`Extracted repository info: owner=${owner}, repo=${repo}`);
|
|
452
|
+
return { owner, repo };
|
|
453
|
+
}
|
|
454
|
+
catch (error) {
|
|
455
|
+
logger_1.AppLogger.error(`Failed to get repository info from git: ${error}`);
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
}
|