@manojkmfsi/monodog 1.0.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.
Files changed (61) hide show
  1. package/.eslintrc.cjs +15 -0
  2. package/.turbo/turbo-build.log +4 -0
  3. package/CHANGELOG.md +79 -0
  4. package/LICENCE +21 -0
  5. package/README.md +55 -0
  6. package/dist/config-loader.js +116 -0
  7. package/dist/get-db-url.js +10 -0
  8. package/dist/gitService.js +242 -0
  9. package/dist/index.js +1370 -0
  10. package/dist/serve.js +103 -0
  11. package/dist/setup.js +155 -0
  12. package/dist/utils/ci-status.js +446 -0
  13. package/dist/utils/helpers.js +237 -0
  14. package/dist/utils/monorepo-scanner.js +486 -0
  15. package/dist/utils/utilities.js +414 -0
  16. package/monodog-conf.example.json +16 -0
  17. package/monodog-conf.json +16 -0
  18. package/monodog-dashboard/README.md +58 -0
  19. package/monodog-dashboard/dist/assets/index-2d967652.js +71 -0
  20. package/monodog-dashboard/dist/assets/index-504dc418.css +1 -0
  21. package/monodog-dashboard/dist/index.html +15 -0
  22. package/package.json +50 -0
  23. package/prisma/migrations/20251017041048_init/migration.sql +19 -0
  24. package/prisma/migrations/20251017083007_add_package/migration.sql +21 -0
  25. package/prisma/migrations/20251021083705_alter_package/migration.sql +37 -0
  26. package/prisma/migrations/20251022085155_test/migration.sql +2 -0
  27. package/prisma/migrations/20251022160841_/migration.sql +35 -0
  28. package/prisma/migrations/20251023130158_rename_column_name/migration.sql +34 -0
  29. package/prisma/migrations/20251023174837_/migration.sql +34 -0
  30. package/prisma/migrations/20251023175830_uodate_schema/migration.sql +32 -0
  31. package/prisma/migrations/20251024103700_add_dependency_info/migration.sql +13 -0
  32. package/prisma/migrations/20251025192150_add_dependency_info/migration.sql +19 -0
  33. package/prisma/migrations/20251025192342_add_dependency_info/migration.sql +40 -0
  34. package/prisma/migrations/20251025204613_add_dependency_info/migration.sql +8 -0
  35. package/prisma/migrations/20251026071336_add_dependency_info/migration.sql +25 -0
  36. package/prisma/migrations/20251027062626_add_commit/migration.sql +10 -0
  37. package/prisma/migrations/20251027062748_add_commit/migration.sql +23 -0
  38. package/prisma/migrations/20251027092741_add_commit/migration.sql +17 -0
  39. package/prisma/migrations/20251027112736_add_health_status/migration.sql +16 -0
  40. package/prisma/migrations/20251027140546_init_packages/migration.sql +16 -0
  41. package/prisma/migrations/20251029073436_added_package_heath_key/migration.sql +34 -0
  42. package/prisma/migrations/20251029073830_added_package_health_key/migration.sql +49 -0
  43. package/prisma/migrations/20251111091920_/migration.sql +16 -0
  44. package/prisma/migrations/20251211155036_cascade_on_auto_delete/migration.sql +48 -0
  45. package/prisma/migrations/migration_lock.toml +3 -0
  46. package/prisma/schema.prisma +114 -0
  47. package/release.config.js +41 -0
  48. package/src/config-loader.ts +119 -0
  49. package/src/get-db-url.ts +11 -0
  50. package/src/gitService.ts +277 -0
  51. package/src/index.ts +1554 -0
  52. package/src/serve.ts +87 -0
  53. package/src/setup.ts +164 -0
  54. package/src/types/monorepo-scanner.d.ts +32 -0
  55. package/src/utils/ci-status.ts +639 -0
  56. package/src/utils/helpers.js +203 -0
  57. package/src/utils/helpers.js.map +1 -0
  58. package/src/utils/helpers.ts +238 -0
  59. package/src/utils/monorepo-scanner.ts +599 -0
  60. package/src/utils/utilities.ts +483 -0
  61. package/tsconfig.json +16 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * GitService.ts
3
+ *
4
+ * This service executes native 'git' commands using Node.js's child_process
5
+ * to retrieve the commit history of the local repository.
6
+ */
7
+
8
+ import { exec } from 'child_process';
9
+ import { promisify } from 'util';
10
+ import path from 'path';
11
+
12
+ // Promisify the standard 'exec' function for easy async/await usage
13
+ const execPromise = promisify(exec);
14
+
15
+ /**
16
+ * Interface representing a single commit object with key metadata.
17
+ */
18
+ interface GitCommit {
19
+ hash: string;
20
+ author: string;
21
+ packageName: string;
22
+ date: Date;
23
+ message: string;
24
+ type: string;
25
+ }
26
+ /**
27
+ * List of standard Conventional Commit types for validation.
28
+ * Any extracted type not in this list will be set to 'other'.
29
+ */
30
+ const VALID_COMMIT_TYPES: string[] = [
31
+ 'feat', // New feature
32
+ 'fix', // Bug fix
33
+ 'docs', // Documentation changes
34
+ 'style', // Code style changes (formatting, etc)
35
+ 'refactor', // Code refactoring
36
+ 'perf', // Performance improvements
37
+ 'test', // Adding or updating tests
38
+ 'chore', // Maintenance tasks (e.g., build scripts, dependency updates)
39
+ 'ci', // CI/CD changes
40
+ 'build', // Build system changes (e.g., pnpm/npm scripts)
41
+ 'revert', // Reverting changes
42
+ ];
43
+
44
+ /**
45
+ * The delimiter used to separate individual commit records in the git log output.
46
+ * We use a unique string to ensure reliable splitting.
47
+ */
48
+ // const COMMIT_DELIMITER = '|---COMMIT-END---|';
49
+
50
+ /**
51
+ * The custom format string passed to 'git log'.
52
+ * It uses JSON structure and our unique delimiter to make parsing consistent.
53
+ * * %H: Commit hash
54
+ * %pn: packageName name
55
+ * %ae: Author email
56
+ * %ad: Author date (ISO 8601 format)
57
+ * %s: Subject (commit message's first line - used for 'message' and 'type' fields)
58
+ */
59
+ // const GIT_LOG_FORMAT = `{"hash": "%H", "author": "%ae", "packageName": "%pn", "date": "%ad", "message": "%s", "type": "%s"}${COMMIT_DELIMITER}`;
60
+
61
+ // export class GitService {
62
+ // private repoPath: string;
63
+
64
+ // constructor(repoPath: string = process.cwd()) {
65
+ // // Allows specifying a custom path to the monorepo root
66
+ // this.repoPath = repoPath;
67
+ // }
68
+
69
+ // /**
70
+ // * Retrieves commit history for the repository, optionally filtered by a package path.
71
+ // * @param pathFilter The path to a package directory (e.g., 'packages/server').
72
+ // * If provided, only commits affecting that path are returned.
73
+ // * @returns A Promise resolving to an array of GitCommit objects.
74
+ // */
75
+ // public async getAllCommits(pathFilter?: string): Promise<GitCommit[]> {
76
+ // const pathArgument = pathFilter ? ` -- ${pathFilter}` : '';
77
+
78
+ // const command = `git log --pretty=format:'${GIT_LOG_FORMAT}' --date=iso-strict${pathArgument}`;
79
+
80
+ // try {
81
+ // console.log(`Executing Git command: ${command}`);
82
+ // const { stdout } = await execPromise(command, {
83
+ // cwd: this.repoPath,
84
+ // maxBuffer: 1024 * 5000,
85
+ // }); // Increase buffer for large repos
86
+ // // console.log(stdout)
87
+ // console.log(stdout, '--', this.repoPath);
88
+ // const escapedDelimiter = COMMIT_DELIMITER.replace(
89
+ // /[.*+?^${}()|[\]\\]/g,
90
+ // '\\$&'
91
+ // );
92
+
93
+ // // 1. Remove the final trailing delimiter, as it creates an empty string at the end of the array
94
+ // const cleanedOutput = stdout
95
+ // .trim()
96
+ // .replace(new RegExp(`${escapedDelimiter}$`), '');
97
+ // console.log(cleanedOutput);
98
+
99
+ // if (!cleanedOutput) {
100
+ // return [];
101
+ // }
102
+ // // 2. Split the output by our custom delimiter to get an array of JSON strings
103
+ // const jsonStrings = cleanedOutput.split(COMMIT_DELIMITER);
104
+ // // 3. Parse each string into a GitCommit object
105
+ // const commits: GitCommit[] = jsonStrings
106
+ // .map(jsonString => {
107
+ // try {
108
+ // // JSON.parse is necessary because the output starts as a string
109
+ // const commit = JSON.parse(jsonString);
110
+ // console.log(commit.type, commit['hash']);
111
+ // try {
112
+ // // FIX: Updated Regex to handle optional scope (e.g., 'feat(scope):')
113
+ // // Matches:
114
+ // // 1. (^(\w+)) - The commit type (e.g., 'feat')
115
+ // // 2. (\([^)]+\))? - The optional scope (e.g., '(setup)')
116
+ // // 3. (:|!) - Ends with a colon or an exclamation point (for breaking changes)
117
+ // const typeMatch = commit.type.match(/^(\w+)(\([^)]+\))?([:!])/);
118
+ // let extractedType = 'other';
119
+ // if (typeMatch) {
120
+ // const rawType = typeMatch[1];
121
+ // // NEW: Validate the extracted type against the list of known types
122
+ // if (VALID_COMMIT_TYPES.includes(rawType)) {
123
+ // extractedType = rawType;
124
+ // }
125
+ // }
126
+ // commit.type = extractedType;
127
+ // } catch (e) {
128
+ // console.error('Failed to match commit type:', commit, e);
129
+ // // Skip malformed entries
130
+ // return null;
131
+ // }
132
+ // // // Set type to 'other' if the conventional format is not found
133
+ // // commit.type = typeMatch ? typeMatch[1] : 'other';
134
+ // return commit;
135
+ // } catch (e) {
136
+ // // console.log(jsonString)
137
+ // console.error('Failed to parse commit JSON:', jsonString, e);
138
+ // // Skip malformed entries
139
+ // return null;
140
+ // }
141
+ // })
142
+ // .filter((commit): commit is GitCommit => commit !== null);
143
+
144
+ // return commits;
145
+ // } catch (error) {
146
+ // console.error('Error fetching Git history:', error);
147
+ // // In a real application, you would handle this gracefully (e.g., throwing a custom error)
148
+ // throw new Error(
149
+ // 'Failed to retrieve Git commit history. Is Git installed and is the path correct?'
150
+ // );
151
+ // }
152
+ // }
153
+ // }
154
+
155
+ export class GitService {
156
+ private repoPath: string;
157
+
158
+ constructor(repoPath: string = process.cwd()) {
159
+ this.repoPath = repoPath;
160
+ }
161
+
162
+ /**
163
+ * Retrieves commit history for the repository, optionally filtered by a package path.
164
+ */
165
+ public async getAllCommits(pathFilter?: string): Promise<GitCommit[]> {
166
+ try {
167
+
168
+ let pathArgument = '';
169
+ if (pathFilter) {
170
+ // Normalize the path and ensure it's relative to the repo root
171
+ const normalizedPath = this.normalizePath(pathFilter);
172
+ if (normalizedPath) {
173
+ pathArgument = ` -C ${normalizedPath}`;
174
+ }
175
+ }
176
+
177
+ // First, validate we're in a git repo
178
+ await this.validateGitRepository(pathArgument);
179
+
180
+ // Use a simpler git log format
181
+ const command = `git ${pathArgument} log --pretty=format:"%H|%an|%ad|%s" --date=iso-strict`;
182
+
183
+ console.log(`🔧 Executing Git command in: ${this.repoPath}`);
184
+ console.log(`📝 Git command: ${command}`);
185
+
186
+ const { stdout, stderr } = await execPromise(command, {
187
+ cwd: this.repoPath,
188
+ maxBuffer: 1024 * 5000,
189
+ });
190
+
191
+ if (stderr) {
192
+ console.warn('Git stderr:', stderr);
193
+ }
194
+
195
+ if (!stdout.trim()) {
196
+ console.log('📭 No commits found for path:', pathFilter);
197
+ return [];
198
+ }
199
+
200
+ // Parse the output
201
+ const commits: GitCommit[] = [];
202
+ const lines = stdout.trim().split('\n');
203
+
204
+ for (const line of lines) {
205
+ try {
206
+ const [hash, author, date, message] = line.split('|');
207
+
208
+ const commit: GitCommit = {
209
+ hash: hash.trim(),
210
+ author: author.trim(),
211
+ packageName: pathFilter || 'root',
212
+ date: new Date(date.trim()),
213
+ message: message.trim(),
214
+ type: this.extractCommitType(message.trim()),
215
+ };
216
+
217
+ commits.push(commit);
218
+ } catch (parseError) {
219
+ console.error('❌ Failed to parse commit line:', line, parseError);
220
+ }
221
+ }
222
+
223
+ console.log(`✅ Successfully parsed ${commits.length} commits`);
224
+ return commits;
225
+ } catch (error) {
226
+ console.error('💥 Error in getAllCommits:', error);
227
+ throw error;
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Normalize path to be relative to git repo root
233
+ */
234
+ private normalizePath(inputPath: string): string {
235
+ // If it's an absolute path, make it relative to repo root
236
+ if (path.isAbsolute(inputPath)) {
237
+ return path.relative(this.repoPath, inputPath);
238
+ }
239
+
240
+ // If it's already relative, return as-is
241
+ return inputPath;
242
+ }
243
+
244
+ /**
245
+ * Extract commit type from message
246
+ */
247
+ private extractCommitType(message: string): string {
248
+ try {
249
+ const typeMatch = message.match(/^(\w+)(\([^)]+\))?!?:/);
250
+ if (typeMatch) {
251
+ const rawType = typeMatch[1].toLowerCase();
252
+ if (VALID_COMMIT_TYPES.includes(rawType)) {
253
+ return rawType;
254
+ }
255
+ }
256
+ return 'other';
257
+ } catch (error) {
258
+ return 'other';
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Validate that we're in a git repository
264
+ */
265
+ private async validateGitRepository(pathArgument: string): Promise<void> {
266
+ try {
267
+ await execPromise('git '+pathArgument+' rev-parse --is-inside-work-tree', {
268
+ cwd: this.repoPath,
269
+ });
270
+ console.log('✅ Valid git repository');
271
+ } catch (error) {
272
+ throw new Error(
273
+ 'Not a git repository (or any of the parent directories)'
274
+ );
275
+ }
276
+ }
277
+ }