@diff-review-system/drs 1.0.0
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/.opencode/agent/github-reviewer.md +62 -0
- package/.opencode/agent/gitlab-reviewer.md +62 -0
- package/.opencode/agent/local-reviewer.md +71 -0
- package/.opencode/agent/review/performance.md +151 -0
- package/.opencode/agent/review/quality.md +127 -0
- package/.opencode/agent/review/security.md +115 -0
- package/.opencode/agent/review/style.md +116 -0
- package/.opencode/opencode.jsonc +52 -0
- package/LICENSE +201 -0
- package/README.md +361 -0
- package/dist/ci/runner.d.ts +21 -0
- package/dist/ci/runner.d.ts.map +1 -0
- package/dist/ci/runner.js +82 -0
- package/dist/ci/runner.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +137 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +5 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +166 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/review-local.d.ts +9 -0
- package/dist/cli/review-local.d.ts.map +1 -0
- package/dist/cli/review-local.js +105 -0
- package/dist/cli/review-local.js.map +1 -0
- package/dist/cli/review-mr.d.ts +11 -0
- package/dist/cli/review-mr.d.ts.map +1 -0
- package/dist/cli/review-mr.js +128 -0
- package/dist/cli/review-mr.js.map +1 -0
- package/dist/cli/review-pr.d.ts +12 -0
- package/dist/cli/review-pr.d.ts.map +1 -0
- package/dist/cli/review-pr.js +125 -0
- package/dist/cli/review-pr.js.map +1 -0
- package/dist/github/client.d.ts +1346 -0
- package/dist/github/client.d.ts.map +1 -0
- package/dist/github/client.js +137 -0
- package/dist/github/client.js.map +1 -0
- package/dist/gitlab/client.d.ts +55 -0
- package/dist/gitlab/client.d.ts.map +1 -0
- package/dist/gitlab/client.js +86 -0
- package/dist/gitlab/client.js.map +1 -0
- package/dist/gitlab/comment-formatter.d.ts +36 -0
- package/dist/gitlab/comment-formatter.d.ts.map +1 -0
- package/dist/gitlab/comment-formatter.js +118 -0
- package/dist/gitlab/comment-formatter.js.map +1 -0
- package/dist/gitlab/diff-parser.d.ts +41 -0
- package/dist/gitlab/diff-parser.d.ts.map +1 -0
- package/dist/gitlab/diff-parser.js +147 -0
- package/dist/gitlab/diff-parser.js.map +1 -0
- package/dist/lib/config.d.ts +42 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +144 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/opencode/agent-loader.d.ts +31 -0
- package/dist/opencode/agent-loader.d.ts.map +1 -0
- package/dist/opencode/agent-loader.js +115 -0
- package/dist/opencode/agent-loader.js.map +1 -0
- package/dist/opencode/client.d.ts +82 -0
- package/dist/opencode/client.d.ts.map +1 -0
- package/dist/opencode/client.js +184 -0
- package/dist/opencode/client.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { createGitLabClient } from '../gitlab/client.js';
|
|
3
|
+
import { createOpencodeClientInstance } from '../opencode/client.js';
|
|
4
|
+
import { parseDiff, getChangedFiles } from '../gitlab/diff-parser.js';
|
|
5
|
+
import { formatSummaryComment, formatIssueComment, calculateSummary, } from '../gitlab/comment-formatter.js';
|
|
6
|
+
/**
|
|
7
|
+
* Review a GitLab merge request
|
|
8
|
+
*/
|
|
9
|
+
export async function reviewMR(config, options) {
|
|
10
|
+
console.log(chalk.bold.cyan('\nš DRS GitLab MR Review\n'));
|
|
11
|
+
// Initialize GitLab client
|
|
12
|
+
const gitlab = createGitLabClient();
|
|
13
|
+
// Fetch MR details
|
|
14
|
+
console.log(chalk.gray(`Fetching MR !${options.mrIid} from project ${options.projectId}...\n`));
|
|
15
|
+
const mr = await gitlab.getMergeRequest(options.projectId, options.mrIid);
|
|
16
|
+
const changes = await gitlab.getMRChanges(options.projectId, options.mrIid);
|
|
17
|
+
console.log(chalk.bold(`MR: ${mr.title}`));
|
|
18
|
+
console.log(chalk.gray(`Author: ${mr.author?.name || 'Unknown'}`));
|
|
19
|
+
console.log(chalk.gray(`Branch: ${mr.source_branch} ā ${mr.target_branch}`));
|
|
20
|
+
console.log(chalk.gray(`Files changed: ${changes.length}\n`));
|
|
21
|
+
if (changes.length === 0) {
|
|
22
|
+
console.log(chalk.yellow('ā No changes to review\n'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Parse diffs
|
|
26
|
+
const diffs = changes.map(change => parseDiff(change.diff)).flat();
|
|
27
|
+
const changedFiles = getChangedFiles(diffs);
|
|
28
|
+
// Connect to OpenCode (or start in-process if serverUrl is empty)
|
|
29
|
+
console.log(chalk.gray('Connecting to OpenCode server...\n'));
|
|
30
|
+
const opencode = await createOpencodeClientInstance({
|
|
31
|
+
baseUrl: config.opencode.serverUrl || undefined,
|
|
32
|
+
});
|
|
33
|
+
// Create review session
|
|
34
|
+
console.log(chalk.gray('Starting AI review...\n'));
|
|
35
|
+
const agentsList = config.review.agents.join(',');
|
|
36
|
+
const session = await opencode.createSession({
|
|
37
|
+
agent: 'gitlab-reviewer',
|
|
38
|
+
message: `Review MR !${options.mrIid} in project ${options.projectId}. Agents: ${agentsList}. Files: ${changedFiles.join(', ')}`,
|
|
39
|
+
context: {
|
|
40
|
+
projectId: options.projectId,
|
|
41
|
+
mrIid: options.mrIid,
|
|
42
|
+
files: changedFiles,
|
|
43
|
+
agents: config.review.agents,
|
|
44
|
+
mr: {
|
|
45
|
+
title: mr.title,
|
|
46
|
+
description: mr.description,
|
|
47
|
+
author: mr.author?.name,
|
|
48
|
+
sourceBranch: mr.source_branch,
|
|
49
|
+
targetBranch: mr.target_branch,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
// Stream and collect results
|
|
54
|
+
const issues = [];
|
|
55
|
+
try {
|
|
56
|
+
for await (const message of opencode.streamMessages(session.id)) {
|
|
57
|
+
if (message.role === 'assistant') {
|
|
58
|
+
// Parse issues from assistant messages
|
|
59
|
+
// TODO: Implement structured output parsing once OpenCode SDK supports it
|
|
60
|
+
console.log(message.content);
|
|
61
|
+
// For now, we'll display raw output
|
|
62
|
+
// In production, parse structured JSON responses from agents
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Display and post summary
|
|
66
|
+
const summary = calculateSummary(changedFiles.length, issues);
|
|
67
|
+
console.log(chalk.bold('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
68
|
+
console.log(chalk.bold('š Review Summary'));
|
|
69
|
+
console.log(chalk.bold('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
70
|
+
console.log(` Files reviewed: ${chalk.cyan(summary.filesReviewed)}`);
|
|
71
|
+
console.log(` Issues found: ${chalk.yellow(summary.issuesFound)}`);
|
|
72
|
+
if (summary.issuesFound > 0) {
|
|
73
|
+
console.log(` š“ Critical: ${chalk.red(summary.bySeverity.CRITICAL)}`);
|
|
74
|
+
console.log(` š” High: ${chalk.yellow(summary.bySeverity.HIGH)}`);
|
|
75
|
+
console.log(` š Medium: ${chalk.hex('#FFA500')(summary.bySeverity.MEDIUM)}`);
|
|
76
|
+
console.log(` āŖ Low: ${chalk.gray(summary.bySeverity.LOW)}`);
|
|
77
|
+
}
|
|
78
|
+
console.log('');
|
|
79
|
+
// Post comments to GitLab if requested
|
|
80
|
+
if (options.postComments) {
|
|
81
|
+
console.log(chalk.gray('Posting review comments to GitLab...\n'));
|
|
82
|
+
// Post summary comment
|
|
83
|
+
const summaryComment = formatSummaryComment(summary, issues);
|
|
84
|
+
await gitlab.createMRComment(options.projectId, options.mrIid, summaryComment);
|
|
85
|
+
// Post individual issue comments as discussion threads
|
|
86
|
+
for (const issue of issues) {
|
|
87
|
+
const diffRefs = mr.diff_refs;
|
|
88
|
+
if (issue.line && diffRefs && diffRefs.base_sha && diffRefs.head_sha && diffRefs.start_sha) {
|
|
89
|
+
try {
|
|
90
|
+
await gitlab.createMRDiscussionThread(options.projectId, options.mrIid, formatIssueComment(issue), {
|
|
91
|
+
baseSha: diffRefs.base_sha,
|
|
92
|
+
headSha: diffRefs.head_sha,
|
|
93
|
+
startSha: diffRefs.start_sha,
|
|
94
|
+
newPath: issue.file,
|
|
95
|
+
newLine: issue.line,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
// If line-specific comment fails, post as general comment
|
|
100
|
+
console.warn(chalk.yellow(`Warning: Could not post line comment for ${issue.file}:${issue.line}`));
|
|
101
|
+
await gitlab.createMRComment(options.projectId, options.mrIid, formatIssueComment(issue));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Post as general comment if no line number
|
|
106
|
+
await gitlab.createMRComment(options.projectId, options.mrIid, formatIssueComment(issue));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Add ai-reviewed label
|
|
110
|
+
await gitlab.addLabel(options.projectId, options.mrIid, ['ai-reviewed']);
|
|
111
|
+
console.log(chalk.green('ā Review posted to GitLab MR\n'));
|
|
112
|
+
}
|
|
113
|
+
// Exit with error code if critical issues found
|
|
114
|
+
if (summary.bySeverity.CRITICAL > 0) {
|
|
115
|
+
console.log(chalk.red.bold('ā ļø Critical issues found!\n'));
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
else if (summary.issuesFound === 0) {
|
|
119
|
+
console.log(chalk.green('ā No issues found! MR looks good.\n'));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
// Clean up session and shutdown in-process server if applicable
|
|
124
|
+
await opencode.closeSession(session.id);
|
|
125
|
+
await opencode.shutdown();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=review-mr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-mr.js","sourceRoot":"","sources":["../../src/cli/review-mr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,GAEjB,MAAM,gCAAgC,CAAC;AAQxC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAiB,EAAE,OAAwB;IACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAE5D,2BAA2B;IAC3B,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;IAEpC,mBAAmB;IACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,KAAK,iBAAiB,OAAO,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC;IAEhG,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAE5E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,aAAa,MAAM,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAE9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IAED,cAAc;IACd,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACnE,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAE5C,kEAAkE;IAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC,CAAC;IAE9D,MAAM,QAAQ,GAAG,MAAM,4BAA4B,CAAC;QAClD,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,IAAI,SAAS;KAChD,CAAC,CAAC;IAEH,wBAAwB;IACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;IAEnD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC;QAC3C,KAAK,EAAE,iBAAiB;QACxB,OAAO,EAAE,cAAc,OAAO,CAAC,KAAK,eAAe,OAAO,CAAC,SAAS,aAAa,UAAU,YAAY,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAChI,OAAO,EAAE;YACP,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM;YAC5B,EAAE,EAAE;gBACF,KAAK,EAAE,EAAE,CAAC,KAAK;gBACf,WAAW,EAAE,EAAE,CAAC,WAAW;gBAC3B,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,IAAI;gBACvB,YAAY,EAAE,EAAE,CAAC,aAAa;gBAC9B,YAAY,EAAE,EAAE,CAAC,aAAa;aAC/B;SACF;KACF,CAAC,CAAC;IAEH,6BAA6B;IAC7B,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,OAAO,IAAI,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;YAChE,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACjC,uCAAuC;gBACvC,0EAA0E;gBAC1E,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAE7B,oCAAoC;gBACpC,6DAA6D;YAC/D,CAAC;QACH,CAAC;QAED,2BAA2B;QAC3B,MAAM,OAAO,GAAG,gBAAgB,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAE9D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC,CAAC;QAEnE,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAEpE,IAAI,OAAO,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC1E,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACrE,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACjF,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,uCAAuC;QACvC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC,CAAC;YAElE,uBAAuB;YACvB,MAAM,cAAc,GAAG,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC7D,MAAM,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;YAE/E,uDAAuD;YACvD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,QAAQ,GAAQ,EAAE,CAAC,SAAS,CAAC;gBACnC,IAAI,KAAK,CAAC,IAAI,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;oBAC3F,IAAI,CAAC;wBACH,MAAM,MAAM,CAAC,wBAAwB,CACnC,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,KAAK,EACb,kBAAkB,CAAC,KAAK,CAAC,EACzB;4BACE,OAAO,EAAE,QAAQ,CAAC,QAAQ;4BAC1B,OAAO,EAAE,QAAQ,CAAC,QAAQ;4BAC1B,QAAQ,EAAE,QAAQ,CAAC,SAAS;4BAC5B,OAAO,EAAE,KAAK,CAAC,IAAI;4BACnB,OAAO,EAAE,KAAK,CAAC,IAAI;yBACpB,CACF,CAAC;oBACJ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,0DAA0D;wBAC1D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,4CAA4C,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;wBACnG,MAAM,MAAM,CAAC,eAAe,CAC1B,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,KAAK,EACb,kBAAkB,CAAC,KAAK,CAAC,CAC1B,CAAC;oBACJ,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,4CAA4C;oBAC5C,MAAM,MAAM,CAAC,eAAe,CAC1B,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,KAAK,EACb,kBAAkB,CAAC,KAAK,CAAC,CAC1B,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,wBAAwB;YACxB,MAAM,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;YAEzE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC7D,CAAC;QAED,gDAAgD;QAChD,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC,CAAC;YAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,OAAO,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;YAAS,CAAC;QACT,gEAAgE;QAChE,MAAM,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DRSConfig } from '../lib/config.js';
|
|
2
|
+
export interface ReviewPROptions {
|
|
3
|
+
owner: string;
|
|
4
|
+
repo: string;
|
|
5
|
+
prNumber: number;
|
|
6
|
+
postComments: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Review a GitHub pull request
|
|
10
|
+
*/
|
|
11
|
+
export declare function reviewPR(config: DRSConfig, options: ReviewPROptions): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=review-pr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-pr.d.ts","sourceRoot":"","sources":["../../src/cli/review-pr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAWlD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA0JzF"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { createGitHubClient } from '../github/client.js';
|
|
3
|
+
import { createOpencodeClientInstance } from '../opencode/client.js';
|
|
4
|
+
import { parseDiff, getChangedFiles } from '../gitlab/diff-parser.js';
|
|
5
|
+
import { formatSummaryComment, formatIssueComment, calculateSummary, } from '../gitlab/comment-formatter.js';
|
|
6
|
+
/**
|
|
7
|
+
* Review a GitHub pull request
|
|
8
|
+
*/
|
|
9
|
+
export async function reviewPR(config, options) {
|
|
10
|
+
console.log(chalk.bold.cyan('\nš DRS GitHub PR Review\n'));
|
|
11
|
+
// Initialize GitHub client
|
|
12
|
+
const github = createGitHubClient();
|
|
13
|
+
// Fetch PR details
|
|
14
|
+
console.log(chalk.gray(`Fetching PR #${options.prNumber} from ${options.owner}/${options.repo}...\n`));
|
|
15
|
+
const pr = await github.getPullRequest(options.owner, options.repo, options.prNumber);
|
|
16
|
+
const files = await github.getPRFiles(options.owner, options.repo, options.prNumber);
|
|
17
|
+
console.log(chalk.bold(`PR: ${pr.title}`));
|
|
18
|
+
console.log(chalk.gray(`Author: ${pr.user?.login || 'Unknown'}`));
|
|
19
|
+
console.log(chalk.gray(`Branch: ${pr.head.ref} ā ${pr.base.ref}`));
|
|
20
|
+
console.log(chalk.gray(`Files changed: ${files.length}\n`));
|
|
21
|
+
if (files.length === 0) {
|
|
22
|
+
console.log(chalk.yellow('ā No changes to review\n'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Parse diffs
|
|
26
|
+
const diffs = files
|
|
27
|
+
.filter(file => file.patch) // Only files with diffs
|
|
28
|
+
.map(file => parseDiff(file.patch || ''))
|
|
29
|
+
.flat();
|
|
30
|
+
const changedFiles = getChangedFiles(diffs);
|
|
31
|
+
// Connect to OpenCode (or start in-process if serverUrl is empty)
|
|
32
|
+
console.log(chalk.gray('Connecting to OpenCode server...\n'));
|
|
33
|
+
const opencode = await createOpencodeClientInstance({
|
|
34
|
+
baseUrl: config.opencode.serverUrl || undefined,
|
|
35
|
+
});
|
|
36
|
+
// Create review session
|
|
37
|
+
console.log(chalk.gray('Starting AI review...\n'));
|
|
38
|
+
const agentsList = config.review.agents.join(',');
|
|
39
|
+
const session = await opencode.createSession({
|
|
40
|
+
agent: 'github-reviewer',
|
|
41
|
+
message: `Review PR #${options.prNumber} in ${options.owner}/${options.repo}. Agents: ${agentsList}. Files: ${changedFiles.join(', ')}`,
|
|
42
|
+
context: {
|
|
43
|
+
owner: options.owner,
|
|
44
|
+
repo: options.repo,
|
|
45
|
+
prNumber: options.prNumber,
|
|
46
|
+
files: changedFiles,
|
|
47
|
+
agents: config.review.agents,
|
|
48
|
+
pr: {
|
|
49
|
+
title: pr.title,
|
|
50
|
+
description: pr.body,
|
|
51
|
+
author: pr.user?.login,
|
|
52
|
+
headRef: pr.head.ref,
|
|
53
|
+
baseRef: pr.base.ref,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
// Stream and collect results
|
|
58
|
+
const issues = [];
|
|
59
|
+
try {
|
|
60
|
+
for await (const message of opencode.streamMessages(session.id)) {
|
|
61
|
+
if (message.role === 'assistant') {
|
|
62
|
+
// Parse issues from assistant messages
|
|
63
|
+
// TODO: Implement structured output parsing once OpenCode SDK supports it
|
|
64
|
+
console.log(message.content);
|
|
65
|
+
// For now, we'll display raw output
|
|
66
|
+
// In production, parse structured JSON responses from agents
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Display and post summary
|
|
70
|
+
const summary = calculateSummary(changedFiles.length, issues);
|
|
71
|
+
console.log(chalk.bold('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
72
|
+
console.log(chalk.bold('š Review Summary'));
|
|
73
|
+
console.log(chalk.bold('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
74
|
+
console.log(` Files reviewed: ${chalk.cyan(summary.filesReviewed)}`);
|
|
75
|
+
console.log(` Issues found: ${chalk.yellow(summary.issuesFound)}`);
|
|
76
|
+
if (summary.issuesFound > 0) {
|
|
77
|
+
console.log(` š“ Critical: ${chalk.red(summary.bySeverity.CRITICAL)}`);
|
|
78
|
+
console.log(` š” High: ${chalk.yellow(summary.bySeverity.HIGH)}`);
|
|
79
|
+
console.log(` š Medium: ${chalk.hex('#FFA500')(summary.bySeverity.MEDIUM)}`);
|
|
80
|
+
console.log(` āŖ Low: ${chalk.gray(summary.bySeverity.LOW)}`);
|
|
81
|
+
}
|
|
82
|
+
console.log('');
|
|
83
|
+
// Post comments to GitHub if requested
|
|
84
|
+
if (options.postComments) {
|
|
85
|
+
console.log(chalk.gray('Posting review comments to GitHub...\n'));
|
|
86
|
+
// Post summary comment
|
|
87
|
+
const summaryComment = formatSummaryComment(summary, issues);
|
|
88
|
+
await github.createPRComment(options.owner, options.repo, options.prNumber, summaryComment);
|
|
89
|
+
// Post individual issue comments as review comments
|
|
90
|
+
for (const issue of issues) {
|
|
91
|
+
if (issue.line && pr.head.sha) {
|
|
92
|
+
try {
|
|
93
|
+
await github.createPRReviewComment(options.owner, options.repo, options.prNumber, formatIssueComment(issue), pr.head.sha, issue.file, issue.line);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
// If line-specific comment fails, post as general comment
|
|
97
|
+
console.warn(chalk.yellow(`Warning: Could not post line comment for ${issue.file}:${issue.line}`));
|
|
98
|
+
await github.createPRComment(options.owner, options.repo, options.prNumber, formatIssueComment(issue));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// Post as general comment if no line number
|
|
103
|
+
await github.createPRComment(options.owner, options.repo, options.prNumber, formatIssueComment(issue));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Add ai-reviewed label
|
|
107
|
+
await github.addLabels(options.owner, options.repo, options.prNumber, ['ai-reviewed']);
|
|
108
|
+
console.log(chalk.green('ā Review posted to GitHub PR\n'));
|
|
109
|
+
}
|
|
110
|
+
// Exit with error code if critical issues found
|
|
111
|
+
if (summary.bySeverity.CRITICAL > 0) {
|
|
112
|
+
console.log(chalk.red.bold('ā ļø Critical issues found!\n'));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
else if (summary.issuesFound === 0) {
|
|
116
|
+
console.log(chalk.green('ā No issues found! PR looks good.\n'));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
// Clean up session and shutdown in-process server if applicable
|
|
121
|
+
await opencode.closeSession(session.id);
|
|
122
|
+
await opencode.shutdown();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=review-pr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-pr.js","sourceRoot":"","sources":["../../src/cli/review-pr.ts"],"names":[],"mappings":"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"}
|