@manojkmfsi/monodog 1.2.0 → 1.2.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/dist/routes/release-api.js +0 -20
- package/dist/services/change-tracker-service.js +57 -1
- package/dist/services/npm-publish-service.js +0 -21
- package/dist/services/publish-controller.js +57 -11
- package/dist/services/publish-pipeline-service.js +62 -0
- package/dist/setup.js +0 -0
- package/monodog-dashboard/dist/assets/{index-CfZ1i92y.js → index-9leUZfeE.js} +10 -10
- package/monodog-dashboard/dist/index.html +1 -1
- package/package.json +19 -18
- package/prisma/migrations/20260305182947_release/migration.sql +162 -0
- package/prisma/schema/change-track.prisma +29 -59
- package/prisma/schema/monodog.db +0 -0
- package/prisma/schema/publish-pipeline.prisma +36 -96
- package/monodog-dashboard/README.md +0 -58
|
@@ -16,26 +16,6 @@ const npm_publish_service_1 = require("../services/npm-publish-service");
|
|
|
16
16
|
const fs_1 = __importDefault(require("fs"));
|
|
17
17
|
const path_1 = __importDefault(require("path"));
|
|
18
18
|
const router = (0, express_1.Router)();
|
|
19
|
-
/**
|
|
20
|
-
* GET /api/releases/packages
|
|
21
|
-
* Get list of packages available in workspace
|
|
22
|
-
*/
|
|
23
|
-
router.get('/packages', async (req, res) => {
|
|
24
|
-
try {
|
|
25
|
-
const packages = publish_controller_1.publishController.getAvailablePackages(process.cwd());
|
|
26
|
-
res.json({
|
|
27
|
-
success: true,
|
|
28
|
-
packages,
|
|
29
|
-
count: packages.length,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
res.status(500).json({
|
|
34
|
-
success: false,
|
|
35
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
19
|
/**
|
|
40
20
|
* POST /api/releases/analyze
|
|
41
21
|
* Analyze changes for packages without publishing
|
|
@@ -8,10 +8,63 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
8
8
|
exports.changeTrackerService = exports.ChangeTrackerService = void 0;
|
|
9
9
|
const child_process_1 = require("child_process");
|
|
10
10
|
const util_1 = require("util");
|
|
11
|
+
const client_1 = require("@prisma/client");
|
|
11
12
|
// NOTE: ChangeTrack and CommitChange types will be imported from @prisma/client after DB integration
|
|
12
13
|
// Currently using inline types below for service implementation
|
|
13
14
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
15
|
+
const prisma = new client_1.PrismaClient();
|
|
14
16
|
class ChangeTrackerService {
|
|
17
|
+
/**
|
|
18
|
+
* Save a ChangeTrack record and its related commits to the database
|
|
19
|
+
*/
|
|
20
|
+
async saveChangeTrack(result) {
|
|
21
|
+
// Save ChangeTrack
|
|
22
|
+
const changeTrack = await prisma.changeTrack.create({
|
|
23
|
+
data: {
|
|
24
|
+
packageName: result.packageName,
|
|
25
|
+
packageVersion: result.currentVersion,
|
|
26
|
+
detectionMethod: 'git',
|
|
27
|
+
detectionTimestamp: new Date(),
|
|
28
|
+
filesChanged: JSON.stringify(result.filesChanged.map(f => f.path)),
|
|
29
|
+
linesAdded: result.filesChanged.reduce((sum, f) => sum + (f.linesAdded || 0), 0),
|
|
30
|
+
linesRemoved: result.filesChanged.reduce((sum, f) => sum + (f.linesRemoved || 0), 0),
|
|
31
|
+
changeType: result.changeType,
|
|
32
|
+
affectedDependents: JSON.stringify(result.affectedDependents),
|
|
33
|
+
isReleaseReady: result.isReleaseReady,
|
|
34
|
+
lastAnalyzedCommit: result.commits[0]?.hash || '',
|
|
35
|
+
previousVersion: result.currentVersion,
|
|
36
|
+
proposedVersion: result.proposedVersion,
|
|
37
|
+
// createdAt, updatedAt auto
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
// Save related commits
|
|
41
|
+
for (const commit of result.commits) {
|
|
42
|
+
await prisma.commitChange.create({
|
|
43
|
+
data: {
|
|
44
|
+
changeTrackId: changeTrack.id,
|
|
45
|
+
hash: commit.hash,
|
|
46
|
+
message: commit.message,
|
|
47
|
+
author: commit.author,
|
|
48
|
+
authorEmail: commit.authorEmail,
|
|
49
|
+
type: commit.type,
|
|
50
|
+
scope: commit.scope,
|
|
51
|
+
isBreaking: commit.isBreaking,
|
|
52
|
+
bodyText: commit.body,
|
|
53
|
+
committedAt: commit.committedAt,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Load the latest ChangeTrack for a package
|
|
60
|
+
*/
|
|
61
|
+
async getLatestChangeTrack(packageName) {
|
|
62
|
+
return prisma.changeTrack.findFirst({
|
|
63
|
+
where: { packageName },
|
|
64
|
+
orderBy: { createdAt: 'desc' },
|
|
65
|
+
include: { commits: true },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
15
68
|
/**
|
|
16
69
|
* Analyze changes for a package since last release
|
|
17
70
|
*/
|
|
@@ -25,7 +78,7 @@ class ChangeTrackerService {
|
|
|
25
78
|
const changeType = this.determineChangeType(commits);
|
|
26
79
|
// 4. Identify affected dependents
|
|
27
80
|
const affectedDependents = await this.identifyAffectedDependents(packageName);
|
|
28
|
-
|
|
81
|
+
const result = {
|
|
29
82
|
packageName,
|
|
30
83
|
currentVersion,
|
|
31
84
|
changeType,
|
|
@@ -35,6 +88,9 @@ class ChangeTrackerService {
|
|
|
35
88
|
proposedVersion: this.calculateNextVersion(currentVersion, changeType),
|
|
36
89
|
isReleaseReady: changeType !== 'none',
|
|
37
90
|
};
|
|
91
|
+
// Save to DB
|
|
92
|
+
await this.saveChangeTrack(result);
|
|
93
|
+
return result;
|
|
38
94
|
}
|
|
39
95
|
catch (error) {
|
|
40
96
|
console.error(`Failed to analyze changes for ${packageName}:`, error);
|
|
@@ -161,12 +161,6 @@ class NpmPublishService {
|
|
|
161
161
|
const integrity = this.calculateSRI(tarballData);
|
|
162
162
|
const pkgJsonPath = (0, path_1.join)('package.json');
|
|
163
163
|
const pkgJson = JSON.parse(await readFileAsync((0, path_1.join)(tarballPath, '..', pkgJsonPath), 'utf8'));
|
|
164
|
-
// const tarballBuffer = await fs.readFile(tarballPath, null, (err, data) => {
|
|
165
|
-
// if (err) {
|
|
166
|
-
// throw new Error(`Failed to read tarball for upload: ${err.message}`);
|
|
167
|
-
// }
|
|
168
|
-
// return data;
|
|
169
|
-
// });
|
|
170
164
|
const doc = {
|
|
171
165
|
_id: packageName,
|
|
172
166
|
name: packageName,
|
|
@@ -194,21 +188,6 @@ class NpmPublishService {
|
|
|
194
188
|
},
|
|
195
189
|
},
|
|
196
190
|
};
|
|
197
|
-
// Prepare document for npm registry
|
|
198
|
-
// const doc = {
|
|
199
|
-
// _id: `${packageName}@${version}`,
|
|
200
|
-
// name: packageName,
|
|
201
|
-
// version,
|
|
202
|
-
// description: pkgJson.description || '',
|
|
203
|
-
// dist: {
|
|
204
|
-
// tarball: `${registry}/${packageName}/-/${basename(tarballPath)}`,
|
|
205
|
-
// shasum,
|
|
206
|
-
// integrity,
|
|
207
|
-
// },
|
|
208
|
-
// // Add minimal required metadata
|
|
209
|
-
// _rev: '',
|
|
210
|
-
// dependencies: {},
|
|
211
|
-
// };
|
|
212
191
|
const encodedName = packageName.replace('/', '%2f');
|
|
213
192
|
// Publish via npm registry REST API
|
|
214
193
|
const response = await fetch(`${registry}/${encodedName}`, {
|
|
@@ -15,6 +15,7 @@ const release_readiness_service_1 = require("./release-readiness-service");
|
|
|
15
15
|
const secure_token_service_1 = require("./secure-token-service");
|
|
16
16
|
const fs_1 = __importDefault(require("fs"));
|
|
17
17
|
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const publish_pipeline_service_1 = require("./publish-pipeline-service");
|
|
18
19
|
class PublishController {
|
|
19
20
|
constructor() {
|
|
20
21
|
this.pipelines = new Map();
|
|
@@ -61,6 +62,23 @@ class PublishController {
|
|
|
61
62
|
*/
|
|
62
63
|
async publish(request) {
|
|
63
64
|
const pipelineId = this.generatePipelineId();
|
|
65
|
+
// Create pipeline in DB
|
|
66
|
+
const pipelineRecord = await publish_pipeline_service_1.publishPipelineService.createPipeline({
|
|
67
|
+
id: pipelineId,
|
|
68
|
+
packageNames: JSON.stringify(request.packageNames),
|
|
69
|
+
method: request.method || 'auto',
|
|
70
|
+
status: 'pending',
|
|
71
|
+
triggeredBy: request.userId || 'system',
|
|
72
|
+
triggeredAt: new Date(),
|
|
73
|
+
createdAt: new Date(),
|
|
74
|
+
updatedAt: new Date(),
|
|
75
|
+
releaseVersion: request.versionMap ? Object.values(request.versionMap).join(',') : undefined,
|
|
76
|
+
releaseNotes: undefined, // Could be set if changelog is generated
|
|
77
|
+
conclusion: undefined,
|
|
78
|
+
completedAt: undefined,
|
|
79
|
+
errorMessage: undefined,
|
|
80
|
+
errorDetails: undefined,
|
|
81
|
+
});
|
|
64
82
|
const status = {
|
|
65
83
|
pipelineId,
|
|
66
84
|
status: 'pending',
|
|
@@ -72,20 +90,22 @@ class PublishController {
|
|
|
72
90
|
try {
|
|
73
91
|
status.startedAt = new Date().toISOString();
|
|
74
92
|
status.status = 'validating';
|
|
75
|
-
|
|
93
|
+
await publish_pipeline_service_1.publishPipelineService.updatePipeline(pipelineId, { status: 'validating', updatedAt: new Date() });
|
|
94
|
+
// 1. Get readiness
|
|
76
95
|
const prep = await this.preparePublish(request);
|
|
77
96
|
if (!prep.valid && !request.dryRun) {
|
|
97
|
+
await publish_pipeline_service_1.publishPipelineService.updatePipeline(pipelineId, { status: 'failed', updatedAt: new Date() });
|
|
78
98
|
throw new Error(`Packages not ready for publishing. Fix blockers and try again.`);
|
|
79
99
|
}
|
|
80
100
|
status.status = 'ready';
|
|
81
101
|
status.progress = 20;
|
|
102
|
+
await publish_pipeline_service_1.publishPipelineService.updatePipeline(pipelineId, { status: 'ready', updatedAt: new Date() });
|
|
82
103
|
// 2. Get credentials
|
|
83
104
|
const npmToken = await secure_token_service_1.secureTokenService.getToken('npm', 'env');
|
|
84
|
-
const githubToken = request.method !== 'node'
|
|
85
|
-
? await secure_token_service_1.secureTokenService.getToken('github', 'env')
|
|
86
|
-
: undefined;
|
|
105
|
+
const githubToken = request.method !== 'node' ? await secure_token_service_1.secureTokenService.getToken('github', 'env') : undefined;
|
|
87
106
|
// 3. Publish each package
|
|
88
107
|
status.status = 'publishing';
|
|
108
|
+
await publish_pipeline_service_1.publishPipelineService.updatePipeline(pipelineId, { status: 'publishing', updatedAt: new Date() });
|
|
89
109
|
const publisherCount = request.packageNames.length;
|
|
90
110
|
for (let i = 0; i < request.packageNames.length; i++) {
|
|
91
111
|
const packageName = request.packageNames[i];
|
|
@@ -94,6 +114,23 @@ class PublishController {
|
|
|
94
114
|
const result = await this.publishPackage(packageName, packagePath, request.versionMap?.[packageName], npmToken, githubToken, request);
|
|
95
115
|
status.results[packageName] = result;
|
|
96
116
|
status.progress = 20 + ((i + 1) / publisherCount) * 80;
|
|
117
|
+
// Store result in DB
|
|
118
|
+
await publish_pipeline_service_1.publishPipelineService.addPublishResult(pipelineId, {
|
|
119
|
+
packageName,
|
|
120
|
+
currentVersion: result.version,
|
|
121
|
+
newVersion: result.version,
|
|
122
|
+
status: result.success ? 'completed' : 'failed',
|
|
123
|
+
result: result.success ? 'published' : 'error',
|
|
124
|
+
error: result.errors?.join('\n') || undefined,
|
|
125
|
+
errorDetails: result.errors?.join('\n') || undefined,
|
|
126
|
+
npmPackageId: result.packageId,
|
|
127
|
+
publishedAt: result.success ? new Date() : undefined,
|
|
128
|
+
// tarballUrl: result.tarballUrl || undefined, // Not present in result
|
|
129
|
+
gitTagCreated: result.gitTag || undefined,
|
|
130
|
+
// gitCommitSha: result.gitCommitSha || undefined, // Not present in result
|
|
131
|
+
// gitPushCompleted: result.gitPushCompleted || false, // Not present in result
|
|
132
|
+
githubReleaseUrl: result.gitHubReleaseUrl || undefined,
|
|
133
|
+
});
|
|
97
134
|
}
|
|
98
135
|
// 4. Generate changelog entries
|
|
99
136
|
if (!request.dryRun) {
|
|
@@ -103,12 +140,28 @@ class PublishController {
|
|
|
103
140
|
status.status = 'completed';
|
|
104
141
|
status.progress = 100;
|
|
105
142
|
status.completedAt = new Date().toISOString();
|
|
143
|
+
await publish_pipeline_service_1.publishPipelineService.updatePipeline(pipelineId, {
|
|
144
|
+
status: 'completed',
|
|
145
|
+
completedAt: new Date(),
|
|
146
|
+
updatedAt: new Date(),
|
|
147
|
+
conclusion: 'success',
|
|
148
|
+
errorMessage: undefined,
|
|
149
|
+
errorDetails: undefined,
|
|
150
|
+
});
|
|
106
151
|
console.info(`\n✅ Publish pipeline completed: ${pipelineId}`);
|
|
107
152
|
}
|
|
108
153
|
catch (error) {
|
|
109
154
|
status.status = 'failed';
|
|
110
155
|
status.error = error instanceof Error ? error.message : String(error);
|
|
111
156
|
status.completedAt = new Date().toISOString();
|
|
157
|
+
await publish_pipeline_service_1.publishPipelineService.updatePipeline(pipelineId, {
|
|
158
|
+
status: 'failed',
|
|
159
|
+
errorMessage: status.error,
|
|
160
|
+
errorDetails: status.error,
|
|
161
|
+
completedAt: new Date(),
|
|
162
|
+
updatedAt: new Date(),
|
|
163
|
+
conclusion: 'failure',
|
|
164
|
+
});
|
|
112
165
|
console.error(`\n❌ Publish pipeline failed: ${status.error}`);
|
|
113
166
|
}
|
|
114
167
|
return status;
|
|
@@ -191,13 +244,6 @@ class PublishController {
|
|
|
191
244
|
getAllPipelines() {
|
|
192
245
|
return Array.from(this.pipelines.values());
|
|
193
246
|
}
|
|
194
|
-
/**
|
|
195
|
-
* Get list of available packages
|
|
196
|
-
*/
|
|
197
|
-
getAvailablePackages(workspacePath) {
|
|
198
|
-
// Would scan packages directory and return available packages
|
|
199
|
-
return [];
|
|
200
|
-
}
|
|
201
247
|
/**
|
|
202
248
|
* Get detailed pipeline information
|
|
203
249
|
*/
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.publishPipelineService = exports.PublishPipelineService = void 0;
|
|
4
|
+
const client_1 = require("@prisma/client");
|
|
5
|
+
const prisma = new client_1.PrismaClient();
|
|
6
|
+
class PublishPipelineService {
|
|
7
|
+
/**
|
|
8
|
+
* Create a new publish pipeline record
|
|
9
|
+
*/
|
|
10
|
+
async createPipeline(data) {
|
|
11
|
+
return prisma.publishPipeline.create({ data: data });
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Update a publish pipeline record
|
|
15
|
+
*/
|
|
16
|
+
async updatePipeline(id, data) {
|
|
17
|
+
return prisma.publishPipeline.update({ where: { id }, data: data });
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get a publish pipeline by ID
|
|
21
|
+
*/
|
|
22
|
+
async getPipeline(id) {
|
|
23
|
+
return prisma.publishPipeline.findUnique({ where: { id } });
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* List all pipelines (optionally filter by status)
|
|
27
|
+
*/
|
|
28
|
+
async listPipelines(status) {
|
|
29
|
+
return prisma.publishPipeline.findMany({
|
|
30
|
+
where: status ? { status } : undefined,
|
|
31
|
+
orderBy: { createdAt: 'desc' },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Add a publish result to a pipeline
|
|
36
|
+
*/
|
|
37
|
+
async addPublishResult(pipelineId, result) {
|
|
38
|
+
return prisma.publishResult.create({
|
|
39
|
+
data: {
|
|
40
|
+
...result,
|
|
41
|
+
publishPipelineId: pipelineId,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get all results for a pipeline
|
|
47
|
+
*/
|
|
48
|
+
async getResultsForPipeline(pipelineId) {
|
|
49
|
+
return prisma.publishResult.findMany({
|
|
50
|
+
where: { publishPipelineId: pipelineId },
|
|
51
|
+
orderBy: { newVersion: 'desc' },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Log a token usage event
|
|
56
|
+
*/
|
|
57
|
+
async logTokenUsage(data) {
|
|
58
|
+
return prisma.tokenUsageLog.create({ data: data });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.PublishPipelineService = PublishPipelineService;
|
|
62
|
+
exports.publishPipelineService = new PublishPipelineService();
|
package/dist/setup.js
CHANGED
|
File without changes
|