@manojkmfsi/monodog 1.1.0 → 1.1.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -0
- package/dist/config-loader.js +9 -10
- package/dist/constants/security.js +1 -1
- package/dist/controllers/commit-controller.js +5 -4
- package/dist/controllers/config-controller.js +4 -3
- package/dist/controllers/health-controller.js +2 -1
- package/dist/controllers/package-controller.js +4 -3
- package/dist/middleware/logger.js +8 -2
- package/dist/middleware/server-startup.js +2 -2
- package/dist/middleware/swagger-middleware.js +3 -2
- package/dist/repositories/commit-repository.js +4 -3
- package/dist/repositories/dependency-repository.js +4 -3
- package/dist/services/commit-service.js +7 -7
- package/dist/services/config-service.js +12 -11
- package/dist/services/git-service.js +9 -8
- package/dist/services/health-service.js +5 -4
- package/dist/services/package-service.js +5 -4
- package/dist/utils/ci-status.js +3 -2
- package/dist/utils/db-utils.js +87 -0
- package/dist/utils/monorepo-scanner.js +8 -7
- package/dist/utils/utilities.js +21 -18
- package/monodog-config.example.json +2 -2
- package/monodog-config.json +5 -4
- package/package.json +1 -1
- package/src/config-loader.ts +11 -13
- package/src/constants/security.ts +1 -1
- package/src/controllers/commit-controller.ts +5 -4
- package/src/controllers/config-controller.ts +4 -3
- package/src/controllers/health-controller.ts +2 -1
- package/src/controllers/package-controller.ts +4 -3
- package/src/middleware/logger.ts +9 -2
- package/src/middleware/server-startup.ts +2 -2
- package/src/middleware/swagger-middleware.ts +3 -2
- package/src/repositories/commit-repository.ts +4 -3
- package/src/repositories/dependency-repository.ts +4 -3
- package/src/services/commit-service.ts +7 -7
- package/src/services/config-service.ts +12 -11
- package/src/services/git-service.ts +9 -8
- package/src/services/health-service.ts +5 -4
- package/src/services/package-service.ts +5 -4
- package/src/utils/ci-status.ts +3 -2
- package/src/utils/db-utils.ts +92 -0
- package/src/utils/monorepo-scanner.ts +8 -10
- package/src/utils/utilities.ts +22 -20
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.storePackage = storePackage;
|
|
4
|
+
const logger_1 = require("../middleware/logger");
|
|
5
|
+
const repositories_1 = require("../repositories");
|
|
6
|
+
const config_loader_1 = require("../config-loader");
|
|
7
|
+
// Default settings
|
|
8
|
+
const DEFAULT_PORT = 4000;
|
|
9
|
+
const port = config_loader_1.appConfig.server.port ?? DEFAULT_PORT; //Default port
|
|
10
|
+
const host = config_loader_1.appConfig.server.host ?? 'localhost'; //Default host
|
|
11
|
+
const API_BASE = `http://${host}:${port}/api`;
|
|
12
|
+
async function getCommits(path) {
|
|
13
|
+
const res = await fetch(API_BASE + `/commits/` + encodeURIComponent(path));
|
|
14
|
+
if (!res.ok)
|
|
15
|
+
throw new Error('Failed to fetch commits');
|
|
16
|
+
return (await res.json());
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get package dependencies
|
|
20
|
+
*/
|
|
21
|
+
function getPackageDependenciesInfo(pkg) {
|
|
22
|
+
const allDeps = [];
|
|
23
|
+
Object.keys(pkg.dependencies || {}).forEach(depName => {
|
|
24
|
+
allDeps.push({
|
|
25
|
+
name: depName,
|
|
26
|
+
version: pkg.dependencies[depName],
|
|
27
|
+
type: 'dependency',
|
|
28
|
+
latest: '',
|
|
29
|
+
outdated: false,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
Object.keys(pkg.devDependencies || {}).forEach(depName => {
|
|
33
|
+
allDeps.push({
|
|
34
|
+
name: depName,
|
|
35
|
+
version: pkg.devDependencies[depName],
|
|
36
|
+
type: 'devDependency',
|
|
37
|
+
latest: '',
|
|
38
|
+
outdated: false,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
Object.keys(pkg.peerDependencies || {}).forEach(depName => {
|
|
42
|
+
allDeps.push({
|
|
43
|
+
name: depName,
|
|
44
|
+
version: pkg.peerDependencies[depName],
|
|
45
|
+
type: 'peerDependency',
|
|
46
|
+
latest: '',
|
|
47
|
+
outdated: false,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
return allDeps;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Store packages in database using repository pattern
|
|
54
|
+
*/
|
|
55
|
+
async function storePackage(pkg) {
|
|
56
|
+
try {
|
|
57
|
+
// Create or update package using repository
|
|
58
|
+
await repositories_1.PackageRepository.upsert({
|
|
59
|
+
name: pkg.name,
|
|
60
|
+
version: pkg.version,
|
|
61
|
+
type: pkg.type,
|
|
62
|
+
path: pkg.path,
|
|
63
|
+
description: pkg.description,
|
|
64
|
+
license: pkg.license,
|
|
65
|
+
repository: pkg.repository,
|
|
66
|
+
scripts: pkg.scripts,
|
|
67
|
+
dependencies: pkg.dependencies,
|
|
68
|
+
devDependencies: pkg.devDependencies,
|
|
69
|
+
peerDependencies: pkg.peerDependencies,
|
|
70
|
+
maintainers: pkg.maintainers.join(','),
|
|
71
|
+
status: '',
|
|
72
|
+
});
|
|
73
|
+
// Store commits using repository
|
|
74
|
+
const commits = await getCommits(pkg.path ?? '');
|
|
75
|
+
if (commits.length) {
|
|
76
|
+
await repositories_1.CommitRepository.storeMany(pkg.name, commits);
|
|
77
|
+
}
|
|
78
|
+
// Store dependencies using repository
|
|
79
|
+
const dependenciesInfo = getPackageDependenciesInfo(pkg);
|
|
80
|
+
if (dependenciesInfo.length) {
|
|
81
|
+
await repositories_1.DependencyRepository.storeMany(pkg.name, dependenciesInfo);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
logger_1.AppLogger.warn(`Failed to store report for ${pkg.name}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -15,6 +15,7 @@ exports.funCheckSecurityAudit = funCheckSecurityAudit;
|
|
|
15
15
|
const fs_1 = __importDefault(require("fs"));
|
|
16
16
|
const path_1 = __importDefault(require("path"));
|
|
17
17
|
const child_process_1 = require("child_process");
|
|
18
|
+
const logger_1 = require("../middleware/logger");
|
|
18
19
|
const utilities_1 = require("./utilities");
|
|
19
20
|
class MonorepoScanner {
|
|
20
21
|
constructor(rootDir = process.cwd()) {
|
|
@@ -34,10 +35,10 @@ class MonorepoScanner {
|
|
|
34
35
|
if (cached) {
|
|
35
36
|
return cached;
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
+
logger_1.AppLogger.debug('Starting monorepo scan...');
|
|
38
39
|
// Scan all packages
|
|
39
40
|
const packages = (0, utilities_1.scanMonorepo)(this.rootDir);
|
|
40
|
-
|
|
41
|
+
logger_1.AppLogger.debug(`Found ${packages.length} packages`);
|
|
41
42
|
// Generate statistics
|
|
42
43
|
const stats = (0, utilities_1.generateMonorepoStats)(packages);
|
|
43
44
|
// Generate dependency graph
|
|
@@ -57,11 +58,11 @@ class MonorepoScanner {
|
|
|
57
58
|
};
|
|
58
59
|
// Cache the result
|
|
59
60
|
this.setCache(cacheKey, result);
|
|
60
|
-
|
|
61
|
+
logger_1.AppLogger.debug(`Scan completed in ${result.scanDuration}ms`);
|
|
61
62
|
return result;
|
|
62
63
|
}
|
|
63
64
|
catch (error) {
|
|
64
|
-
|
|
65
|
+
logger_1.AppLogger.error('Error during scan', error);
|
|
65
66
|
throw error;
|
|
66
67
|
}
|
|
67
68
|
}
|
|
@@ -77,7 +78,7 @@ class MonorepoScanner {
|
|
|
77
78
|
reports.push(report);
|
|
78
79
|
}
|
|
79
80
|
catch (error) {
|
|
80
|
-
|
|
81
|
+
logger_1.AppLogger.error(`Error generating report for ${pkg.name}`, error);
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
return reports;
|
|
@@ -169,7 +170,7 @@ class MonorepoScanner {
|
|
|
169
170
|
0);
|
|
170
171
|
}
|
|
171
172
|
catch (error) {
|
|
172
|
-
|
|
173
|
+
logger_1.AppLogger.warn(`Error parsing coverage file for ${pkg.name}`);
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
// If we find any coverage file but can't parse it, assume coverage exists
|
|
@@ -189,7 +190,7 @@ class MonorepoScanner {
|
|
|
189
190
|
return 0;
|
|
190
191
|
}
|
|
191
192
|
catch (error) {
|
|
192
|
-
|
|
193
|
+
logger_1.AppLogger.warn(`Error checking coverage for ${pkg.name}`);
|
|
193
194
|
return 0;
|
|
194
195
|
}
|
|
195
196
|
}
|
package/dist/utils/utilities.js
CHANGED
|
@@ -51,6 +51,7 @@ exports.findMonorepoRoot = findMonorepoRoot;
|
|
|
51
51
|
const fs = __importStar(require("fs"));
|
|
52
52
|
const path_1 = __importDefault(require("path"));
|
|
53
53
|
const config_loader_1 = require("../config-loader");
|
|
54
|
+
const logger_1 = require("../middleware/logger");
|
|
54
55
|
const health_utils_1 = require("./health-utils");
|
|
55
56
|
Object.defineProperty(exports, "calculatePackageHealth", { enumerable: true, get: function () { return health_utils_1.calculatePackageHealth; } });
|
|
56
57
|
const yaml = __importStar(require("js-yaml"));
|
|
@@ -103,7 +104,7 @@ function getWorkspacesFromPnpmYaml(rootDir) {
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
catch (e) {
|
|
106
|
-
|
|
107
|
+
logger_1.AppLogger.error(`Error parsing pnpm-workspace.yaml at ${workspaceYamlPath}:`, e);
|
|
107
108
|
}
|
|
108
109
|
return undefined;
|
|
109
110
|
}
|
|
@@ -119,28 +120,28 @@ function getWorkspacesFromRoot(rootDir) {
|
|
|
119
120
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
120
121
|
// Handle both standard array and object format (used by yarn/pnpm)
|
|
121
122
|
if (Array.isArray(packageJson.workspaces)) {
|
|
122
|
-
|
|
123
|
+
logger_1.AppLogger.info('Workspace configuration found in package.json');
|
|
123
124
|
return packageJson.workspaces;
|
|
124
125
|
}
|
|
125
126
|
else if (packageJson.workspaces && Array.isArray(packageJson.workspaces.packages)) {
|
|
126
|
-
|
|
127
|
+
logger_1.AppLogger.info('Workspace configuration found in package.json');
|
|
127
128
|
return packageJson.workspaces.packages;
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
catch (e) {
|
|
131
|
-
|
|
132
|
+
logger_1.AppLogger.error(`Error parsing package.json at ${packageJsonPath}. Attempting to read pnpm-workspace.yaml...`, e);
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
else {
|
|
135
|
-
|
|
136
|
+
logger_1.AppLogger.warn(`No package.json found at root directory: ${rootDir}`);
|
|
136
137
|
}
|
|
137
138
|
// Fallback to pnpm-workspace.yaml
|
|
138
139
|
const pnpmWorkspaces = getWorkspacesFromPnpmYaml(rootDir);
|
|
139
140
|
if (pnpmWorkspaces && pnpmWorkspaces.length > 0) {
|
|
140
|
-
|
|
141
|
+
logger_1.AppLogger.info('Workspace configuration found in pnpm-workspace.yaml');
|
|
141
142
|
return pnpmWorkspaces;
|
|
142
143
|
}
|
|
143
|
-
|
|
144
|
+
logger_1.AppLogger.warn('No workspace configuration found in package.json or pnpm-workspace.yaml');
|
|
144
145
|
return undefined;
|
|
145
146
|
}
|
|
146
147
|
/**
|
|
@@ -148,27 +149,29 @@ function getWorkspacesFromRoot(rootDir) {
|
|
|
148
149
|
*/
|
|
149
150
|
function scanMonorepo(rootDir) {
|
|
150
151
|
const packages = [];
|
|
151
|
-
|
|
152
|
+
logger_1.AppLogger.debug('rootDir: ' + rootDir);
|
|
152
153
|
const workspacesGlobs = config_loader_1.appConfig.workspaces;
|
|
153
154
|
// Use provided workspaces globs if given, otherwise attempt to detect from root package.json or pnpm-workspace.yaml
|
|
154
155
|
const detectedWorkspacesGlobs = workspacesGlobs.length > 0 ? workspacesGlobs : getWorkspacesFromRoot(rootDir);
|
|
155
156
|
if (detectedWorkspacesGlobs && detectedWorkspacesGlobs.length > 0) {
|
|
156
157
|
if (workspacesGlobs.length) {
|
|
157
|
-
|
|
158
|
+
logger_1.AppLogger.info(`Using provided workspaces globs: ${detectedWorkspacesGlobs.join(', ')}`);
|
|
158
159
|
}
|
|
159
160
|
else {
|
|
160
|
-
|
|
161
|
+
logger_1.AppLogger.info(`Detected Monorepo Workspaces Globs: ${detectedWorkspacesGlobs.join(', ')}`);
|
|
161
162
|
}
|
|
162
163
|
// 1. Resolve the globs into concrete package directory paths
|
|
163
164
|
const resolvedPackagePaths = resolveWorkspaceGlobs(rootDir, detectedWorkspacesGlobs);
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
logger_1.AppLogger.debug(`Resolved package directories (Total ${resolvedPackagePaths.length})`);
|
|
166
|
+
if (resolvedPackagePaths.length < workspacesGlobs.length) {
|
|
167
|
+
logger_1.AppLogger.warn('Some workspaces globs provided are invalid.');
|
|
168
|
+
}
|
|
166
169
|
// 2. Integration of the requested loop structure for package scanning
|
|
167
170
|
for (const workspacePath of resolvedPackagePaths) {
|
|
168
171
|
const fullPackagePath = path_1.default.join(rootDir, workspacePath);
|
|
169
172
|
// The package name would be read from the package.json inside this path
|
|
170
173
|
const packageName = path_1.default.basename(fullPackagePath);
|
|
171
|
-
|
|
174
|
+
logger_1.AppLogger.debug(`- Scanning path: ${workspacePath} (Package: ${packageName})`);
|
|
172
175
|
const packageInfo = parsePackageInfo(fullPackagePath, packageName);
|
|
173
176
|
if (packageInfo) {
|
|
174
177
|
packages.push(packageInfo);
|
|
@@ -176,7 +179,7 @@ function scanMonorepo(rootDir) {
|
|
|
176
179
|
}
|
|
177
180
|
}
|
|
178
181
|
else {
|
|
179
|
-
|
|
182
|
+
logger_1.AppLogger.warn('No workspace globs provided or detected. Returning empty package list.');
|
|
180
183
|
}
|
|
181
184
|
return packages;
|
|
182
185
|
}
|
|
@@ -215,7 +218,7 @@ function parsePackageInfo(packagePath, packageName, forcedType) {
|
|
|
215
218
|
};
|
|
216
219
|
}
|
|
217
220
|
catch (error) {
|
|
218
|
-
|
|
221
|
+
logger_1.AppLogger.error(`Error parsing package.json for ${packageName}`, error);
|
|
219
222
|
return null;
|
|
220
223
|
}
|
|
221
224
|
}
|
|
@@ -380,7 +383,7 @@ function findMonorepoRoot() {
|
|
|
380
383
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
381
384
|
// If it has workspaces or is the root monorepo package
|
|
382
385
|
if (packageJson.workspaces || fs.existsSync(pnpmWorkspacePath)) {
|
|
383
|
-
|
|
386
|
+
logger_1.AppLogger.debug('Found monorepo root: ' + currentDir);
|
|
384
387
|
return currentDir;
|
|
385
388
|
}
|
|
386
389
|
}
|
|
@@ -391,7 +394,7 @@ function findMonorepoRoot() {
|
|
|
391
394
|
// Check if we're at the git root
|
|
392
395
|
const gitPath = path_1.default.join(currentDir, '.git');
|
|
393
396
|
if (fs.existsSync(gitPath)) {
|
|
394
|
-
|
|
397
|
+
logger_1.AppLogger.debug('Found git root (likely monorepo root): ' + currentDir);
|
|
395
398
|
return currentDir;
|
|
396
399
|
}
|
|
397
400
|
// Go up one directory
|
|
@@ -401,6 +404,6 @@ function findMonorepoRoot() {
|
|
|
401
404
|
currentDir = parentDir;
|
|
402
405
|
}
|
|
403
406
|
// Fallback to process.cwd() if we can't find the root
|
|
404
|
-
|
|
407
|
+
logger_1.AppLogger.warn('Could not find monorepo root, using process.cwd(): ' + process.cwd());
|
|
405
408
|
return process.cwd();
|
|
406
409
|
}
|
package/monodog-config.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
|
-
"workspaces": [
|
|
2
|
+
"workspaces": [
|
|
3
|
+
],
|
|
3
4
|
"database": {
|
|
4
5
|
"path": "file:./monodog.db"
|
|
5
6
|
},
|
|
6
7
|
"dashboard": {
|
|
7
|
-
"host": "
|
|
8
|
+
"host": "localhost",
|
|
8
9
|
"port": "3010"
|
|
9
10
|
},
|
|
10
11
|
"server": {
|
|
11
|
-
"host": "
|
|
12
|
+
"host": "localhost",
|
|
12
13
|
"port": 8999
|
|
13
14
|
}
|
|
14
|
-
}
|
|
15
|
+
}
|
package/package.json
CHANGED
package/src/config-loader.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
import { AppLogger } from './middleware/logger';
|
|
3
4
|
|
|
4
5
|
import type { MonodogConfig } from './types';
|
|
5
6
|
|
|
@@ -24,7 +25,7 @@ function loadConfig(): MonodogConfig {
|
|
|
24
25
|
createConfigFileIfMissing(rootPath);
|
|
25
26
|
|
|
26
27
|
if (!fs.existsSync(configPath)) {
|
|
27
|
-
|
|
28
|
+
AppLogger.error(`Configuration file not found at ${configPath}`);
|
|
28
29
|
process.exit(1);
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -35,11 +36,9 @@ function loadConfig(): MonodogConfig {
|
|
|
35
36
|
|
|
36
37
|
// Cache and return
|
|
37
38
|
config = parsedConfig;
|
|
38
|
-
process.stderr.write('[Config] Loaded configuration from: ...\n');
|
|
39
39
|
return config;
|
|
40
40
|
} catch (error) {
|
|
41
|
-
|
|
42
|
-
console.error(error);
|
|
41
|
+
AppLogger.error('Failed to read or parse monodog-config.json.', error as Error);
|
|
43
42
|
process.exit(1);
|
|
44
43
|
}
|
|
45
44
|
}
|
|
@@ -56,11 +55,11 @@ function createConfigFileIfMissing(rootPath: string): void {
|
|
|
56
55
|
path: 'file:./monodog.db', // SQLite database file path, relative to prisma schema location
|
|
57
56
|
},
|
|
58
57
|
dashboard: {
|
|
59
|
-
host: '
|
|
58
|
+
host: 'localhost',
|
|
60
59
|
port: '3010',
|
|
61
60
|
},
|
|
62
61
|
server: {
|
|
63
|
-
host: '
|
|
62
|
+
host: 'localhost', // Default host for the API server
|
|
64
63
|
port: 8999, // Default port for the API server
|
|
65
64
|
},
|
|
66
65
|
};
|
|
@@ -68,17 +67,17 @@ function createConfigFileIfMissing(rootPath: string): void {
|
|
|
68
67
|
const contentString = JSON.stringify(defaultContent, null, 2);
|
|
69
68
|
// ---------------------
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
AppLogger.info(`\n[monodog] Checking for ${configFileName}...`);
|
|
72
71
|
|
|
73
72
|
if (fs.existsSync(configFilePath)) {
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
AppLogger.info(
|
|
74
|
+
`\n[monodog] ${configFileName} already exists at ${configFilePath}. Skipping creation.`
|
|
76
75
|
);
|
|
77
76
|
} else {
|
|
78
77
|
try {
|
|
79
78
|
// Write the default content to the file
|
|
80
79
|
fs.writeFileSync(configFilePath, contentString, 'utf-8');
|
|
81
|
-
|
|
80
|
+
AppLogger.info(
|
|
82
81
|
`[monodog] Successfully generated default ${configFileName} in the workspace root.`
|
|
83
82
|
);
|
|
84
83
|
process.stderr.write(
|
|
@@ -86,9 +85,8 @@ function createConfigFileIfMissing(rootPath: string): void {
|
|
|
86
85
|
);
|
|
87
86
|
} catch (err: unknown) {
|
|
88
87
|
const message = err instanceof Error ? err.message : String(err);
|
|
89
|
-
|
|
90
|
-
`
|
|
91
|
-
message
|
|
88
|
+
AppLogger.error(
|
|
89
|
+
`Failed to generate ${configFileName}: ${message}`
|
|
92
90
|
);
|
|
93
91
|
process.exit(1);
|
|
94
92
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
import { Request, Response } from 'express';
|
|
5
|
+
import { AppLogger } from '../middleware/logger';
|
|
5
6
|
import { getCommitsByPathService } from '../services/commit-service';
|
|
6
7
|
|
|
7
8
|
export const getCommitsByPath = async (_req: Request, res: Response) => {
|
|
@@ -10,17 +11,17 @@ export const getCommitsByPath = async (_req: Request, res: Response) => {
|
|
|
10
11
|
const { packagePath } = _req.params;
|
|
11
12
|
const decodedPath = decodeURIComponent(packagePath);
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
AppLogger.debug('Fetching commits for path: ' + decodedPath);
|
|
15
|
+
AppLogger.debug('Current working directory: ' + process.cwd());
|
|
15
16
|
|
|
16
17
|
const commits = await getCommitsByPathService(decodedPath);
|
|
17
|
-
|
|
18
|
+
AppLogger.info(
|
|
18
19
|
`Successfully fetched ${commits.length} commits for ${decodedPath}`
|
|
19
20
|
);
|
|
20
21
|
res.json(commits);
|
|
21
22
|
} catch (error: unknown) {
|
|
22
23
|
const err = error as Error & { message?: string; stack?: string };
|
|
23
|
-
|
|
24
|
+
AppLogger.error('Error fetching commit details', err);
|
|
24
25
|
res.status(500).json({
|
|
25
26
|
error: 'Failed to fetch commit details',
|
|
26
27
|
message: err?.message,
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { Request, Response } from 'express';
|
|
2
|
+
import { AppLogger } from '../middleware/logger';
|
|
2
3
|
import { getConfigurationFilesService, updateConfigFileService, updatePackageConfigurationService } from '../services/config-service';
|
|
3
4
|
|
|
4
5
|
export const getConfigurationFiles = async (_req: Request, res: Response) => {
|
|
5
6
|
try {
|
|
6
7
|
const rootDir = _req.app.locals.rootPath;
|
|
7
|
-
|
|
8
|
+
AppLogger.debug('Monorepo root directory: ' + rootDir);
|
|
8
9
|
|
|
9
10
|
const configFiles = await getConfigurationFilesService(rootDir);
|
|
10
11
|
res.json(configFiles);
|
|
11
12
|
} catch (error) {
|
|
12
|
-
|
|
13
|
+
AppLogger.error('Error fetching configuration files', error as Error);
|
|
13
14
|
res.status(500).json({
|
|
14
15
|
success: false,
|
|
15
16
|
error: 'Failed to fetch configuration files',
|
|
@@ -32,7 +33,7 @@ export const updateConfigFile = async (_req: Request, res: Response) => {
|
|
|
32
33
|
const result = await updateConfigFileService(id, rootDir, content);
|
|
33
34
|
res.json(result);
|
|
34
35
|
} catch (error) {
|
|
35
|
-
|
|
36
|
+
AppLogger.error('Error saving configuration file', error as Error);
|
|
36
37
|
res.status(500).json({
|
|
37
38
|
success: false,
|
|
38
39
|
error: 'Failed to save configuration file',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Request, Response } from 'express';
|
|
2
|
+
import { AppLogger } from '../middleware/logger';
|
|
2
3
|
import { getHealthSummaryService, healthRefreshService } from '../services/health-service';
|
|
3
4
|
|
|
4
5
|
export const getPackagesHealth = async (_req: Request, res: Response) => {
|
|
@@ -6,7 +7,7 @@ export const getPackagesHealth = async (_req: Request, res: Response) => {
|
|
|
6
7
|
const health = await getHealthSummaryService();
|
|
7
8
|
res.json(health);
|
|
8
9
|
} catch (error) {
|
|
9
|
-
|
|
10
|
+
AppLogger.error('Error fetching health data from database:', error as Error);
|
|
10
11
|
res
|
|
11
12
|
.status(500)
|
|
12
13
|
.json({ error: 'Failed to fetch health data from database' });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Request, Response } from 'express';
|
|
2
|
+
import { AppLogger } from '../middleware/logger';
|
|
2
3
|
import { updatePackageConfigurationService } from '../services/config-service';
|
|
3
4
|
import { getPackageDetailService, getPackagesService, refreshPackagesService } from '../services/package-service';
|
|
4
5
|
|
|
@@ -12,7 +13,7 @@ export const getPackages = async (_req: Request, res: Response) => {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export const refreshPackages = async (_req: Request, res: Response) => {
|
|
15
|
-
|
|
16
|
+
AppLogger.info('Refreshing packages from source: ' + _req.app.locals.rootPath);
|
|
16
17
|
|
|
17
18
|
try {
|
|
18
19
|
const packages = await refreshPackagesService(_req.app.locals.rootPath);
|
|
@@ -43,8 +44,8 @@ export const updatePackageConfig = async (req: Request, res: Response) => {
|
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
AppLogger.info('Updating package configuration for: ' + packageName);
|
|
48
|
+
AppLogger.debug('Package path: ' + packagePath);
|
|
48
49
|
|
|
49
50
|
const updatedPackage = await updatePackageConfigurationService(packagePath, packageName, config);
|
|
50
51
|
|
package/src/middleware/logger.ts
CHANGED
|
@@ -3,11 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import morgan from 'morgan';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
|
|
9
|
+
const accessLogStream = fs.createWriteStream(path.join(__dirname, '../../','access.log'),{flags : 'a'});
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
|
-
* HTTP request logger middleware using Morgan
|
|
12
|
+
* HTTP request logger middleware using Morgan, only log error responses
|
|
9
13
|
*/
|
|
10
|
-
export const httpLogger = morgan('
|
|
14
|
+
export const httpLogger = morgan('combined', {
|
|
15
|
+
stream : accessLogStream,
|
|
16
|
+
// skip: function (req, res) { return res.statusCode < 400 }
|
|
17
|
+
});
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* Application logger for non-HTTP events
|
|
@@ -111,13 +111,13 @@ export function startServer(rootPath: string): void {
|
|
|
111
111
|
console.log(SUCCESS_SERVER_START(host, validatedPort));
|
|
112
112
|
AppLogger.info('API endpoints available:', {
|
|
113
113
|
endpoints: [
|
|
114
|
-
'
|
|
115
|
-
'GET /api/packages/refresh',
|
|
114
|
+
'POST /api/packages/refresh',
|
|
116
115
|
'GET /api/packages',
|
|
117
116
|
'GET /api/packages/:name',
|
|
118
117
|
'PUT /api/packages/update-config',
|
|
119
118
|
'GET /api/commits/:packagePath',
|
|
120
119
|
'GET /api/health/packages',
|
|
120
|
+
'POST /api/health/refresh',
|
|
121
121
|
'PUT /api/config/files/:id',
|
|
122
122
|
'GET /api/config/files',
|
|
123
123
|
],
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import swaggerUi from 'swagger-ui-express';
|
|
7
7
|
import swaggerJsDoc from 'swagger-jsdoc';
|
|
8
8
|
import type { Express, Request, Response } from 'express';
|
|
9
|
+
import { AppLogger } from './logger';
|
|
9
10
|
import { swaggerOptions } from '../config/swagger-config';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -50,8 +51,8 @@ export function setupSwaggerDocs(app: Express): void {
|
|
|
50
51
|
})
|
|
51
52
|
);
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
AppLogger.info('Swagger documentation available at /api-docs');
|
|
54
55
|
} catch (error) {
|
|
55
|
-
|
|
56
|
+
AppLogger.error('Failed to setup Swagger documentation', error as Error);
|
|
56
57
|
}
|
|
57
58
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getPrismaClient, getPrismaErrors } from './prisma-client';
|
|
2
|
+
import { AppLogger } from '../middleware/logger';
|
|
2
3
|
import type { Commit } from '../types';
|
|
3
4
|
|
|
4
5
|
const prisma = getPrismaClient();
|
|
@@ -71,9 +72,9 @@ export class CommitRepository {
|
|
|
71
72
|
err instanceof Prisma.PrismaClientKnownRequestError &&
|
|
72
73
|
err.code === 'P2002'
|
|
73
74
|
) {
|
|
74
|
-
|
|
75
|
+
AppLogger.warn(`Skipping commit: ${data.hash} (Commit already exists)`);
|
|
75
76
|
} else {
|
|
76
|
-
|
|
77
|
+
AppLogger.error(`Failed to store commit: ${data.hash}`, err);
|
|
77
78
|
throw err;
|
|
78
79
|
}
|
|
79
80
|
}
|
|
@@ -83,7 +84,7 @@ export class CommitRepository {
|
|
|
83
84
|
* Store multiple commits
|
|
84
85
|
*/
|
|
85
86
|
static async storeMany(packageName: string, commits: Commit[]) {
|
|
86
|
-
|
|
87
|
+
AppLogger.debug('Storing commits for: ' + packageName);
|
|
87
88
|
for (const commit of commits) {
|
|
88
89
|
await this.upsert({
|
|
89
90
|
hash: commit.hash,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getPrismaClient, getPrismaErrors } from './prisma-client';
|
|
2
|
+
import { AppLogger } from '../middleware/logger';
|
|
2
3
|
import type { DependencyInfo } from '../types';
|
|
3
4
|
|
|
4
5
|
const prisma = getPrismaClient();
|
|
@@ -71,11 +72,11 @@ export class DependencyRepository {
|
|
|
71
72
|
err instanceof Prisma.PrismaClientKnownRequestError &&
|
|
72
73
|
err.code === 'P2002'
|
|
73
74
|
) {
|
|
74
|
-
|
|
75
|
+
AppLogger.warn(
|
|
75
76
|
`Skipping dependency: ${data.name} (Dependency already exists)`
|
|
76
77
|
);
|
|
77
78
|
} else {
|
|
78
|
-
|
|
79
|
+
AppLogger.error(`Failed to store dependency: ${data.name}`, err);
|
|
79
80
|
throw err;
|
|
80
81
|
}
|
|
81
82
|
}
|
|
@@ -85,7 +86,7 @@ export class DependencyRepository {
|
|
|
85
86
|
* Store multiple dependencies
|
|
86
87
|
*/
|
|
87
88
|
static async storeMany(packageName: string, dependencies: DependencyInfo[]) {
|
|
88
|
-
|
|
89
|
+
AppLogger.debug('Storing Dependencies for: ' + packageName);
|
|
89
90
|
for (const dep of dependencies) {
|
|
90
91
|
await this.upsert({
|
|
91
92
|
name: dep.name,
|