@diff-review-system/drs 1.0.0 → 2.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/describe/pr-describer.md +221 -0
- package/.opencode/agent/review/documentation.md +56 -0
- package/.opencode/agent/review/performance.md +32 -130
- package/.opencode/agent/review/quality.md +36 -104
- package/.opencode/agent/review/security.md +32 -94
- package/.opencode/agent/review/style.md +26 -10
- package/.opencode/agent/review/unified-reviewer.md +74 -0
- package/.opencode/opencode.jsonc +4 -41
- package/.opencode/tool/write_json_output.ts +24 -0
- package/README.md +215 -82
- package/dist/ci/runner.d.ts.map +1 -1
- package/dist/ci/runner.js +4 -4
- package/dist/ci/runner.js.map +1 -1
- package/dist/cli/describe-mr.d.ts +11 -0
- package/dist/cli/describe-mr.d.ts.map +1 -0
- package/dist/cli/describe-mr.js +104 -0
- package/dist/cli/describe-mr.js.map +1 -0
- package/dist/cli/describe-pr.d.ts +12 -0
- package/dist/cli/describe-pr.d.ts.map +1 -0
- package/dist/cli/describe-pr.js +105 -0
- package/dist/cli/describe-pr.js.map +1 -0
- package/dist/cli/index.js +234 -20
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +337 -120
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/post-comments.d.ts +15 -0
- package/dist/cli/post-comments.d.ts.map +1 -0
- package/dist/cli/post-comments.js +216 -0
- package/dist/cli/post-comments.js.map +1 -0
- package/dist/cli/review-local.d.ts +3 -0
- package/dist/cli/review-local.d.ts.map +1 -1
- package/dist/cli/review-local.js +46 -63
- package/dist/cli/review-local.js.map +1 -1
- package/dist/cli/review-mr.d.ts +7 -0
- package/dist/cli/review-mr.d.ts.map +1 -1
- package/dist/cli/review-mr.js +88 -117
- package/dist/cli/review-mr.js.map +1 -1
- package/dist/cli/review-pr.d.ts +6 -0
- package/dist/cli/review-pr.d.ts.map +1 -1
- package/dist/cli/review-pr.js +81 -114
- package/dist/cli/review-pr.js.map +1 -1
- package/dist/cli/show-changes.d.ts +15 -0
- package/dist/cli/show-changes.d.ts.map +1 -0
- package/dist/cli/show-changes.js +184 -0
- package/dist/cli/show-changes.js.map +1 -0
- package/dist/github/client.d.ts +199 -4
- package/dist/github/client.d.ts.map +1 -1
- package/dist/github/client.js +37 -2
- package/dist/github/client.js.map +1 -1
- package/dist/github/client.test.d.ts +2 -0
- package/dist/github/client.test.d.ts.map +1 -0
- package/dist/github/client.test.js +206 -0
- package/dist/github/client.test.js.map +1 -0
- package/dist/github/platform-adapter.d.ts +31 -0
- package/dist/github/platform-adapter.d.ts.map +1 -0
- package/dist/github/platform-adapter.js +129 -0
- package/dist/github/platform-adapter.js.map +1 -0
- package/dist/github/platform-adapter.test.d.ts +2 -0
- package/dist/github/platform-adapter.test.d.ts.map +1 -0
- package/dist/github/platform-adapter.test.js +40 -0
- package/dist/github/platform-adapter.test.js.map +1 -0
- package/dist/gitlab/client.d.ts +12 -0
- package/dist/gitlab/client.d.ts.map +1 -1
- package/dist/gitlab/client.js +19 -1
- package/dist/gitlab/client.js.map +1 -1
- package/dist/gitlab/diff-parser.test.d.ts +2 -0
- package/dist/gitlab/diff-parser.test.d.ts.map +1 -0
- package/dist/gitlab/diff-parser.test.js +315 -0
- package/dist/gitlab/diff-parser.test.js.map +1 -0
- package/dist/gitlab/platform-adapter.d.ts +27 -0
- package/dist/gitlab/platform-adapter.d.ts.map +1 -0
- package/dist/gitlab/platform-adapter.js +121 -0
- package/dist/gitlab/platform-adapter.js.map +1 -0
- package/dist/gitlab/platform-adapter.test.d.ts +2 -0
- package/dist/gitlab/platform-adapter.test.d.ts.map +1 -0
- package/dist/gitlab/platform-adapter.test.js +21 -0
- package/dist/gitlab/platform-adapter.test.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +7 -0
- package/dist/index.test.js.map +1 -0
- package/dist/lib/change-summary.d.ts +8 -0
- package/dist/lib/change-summary.d.ts.map +1 -0
- package/dist/lib/change-summary.js +2 -0
- package/dist/lib/change-summary.js.map +1 -0
- package/dist/lib/code-quality-report.d.ts +44 -0
- package/dist/lib/code-quality-report.d.ts.map +1 -0
- package/dist/lib/code-quality-report.js +62 -0
- package/dist/lib/code-quality-report.js.map +1 -0
- package/dist/lib/code-quality-report.test.d.ts +2 -0
- package/dist/lib/code-quality-report.test.d.ts.map +1 -0
- package/dist/lib/code-quality-report.test.js +327 -0
- package/dist/lib/code-quality-report.test.js.map +1 -0
- package/dist/{gitlab → lib}/comment-formatter.d.ts +6 -3
- package/dist/lib/comment-formatter.d.ts.map +1 -0
- package/dist/{gitlab → lib}/comment-formatter.js +63 -16
- package/dist/lib/comment-formatter.js.map +1 -0
- package/dist/lib/comment-formatter.test.d.ts +2 -0
- package/dist/lib/comment-formatter.test.d.ts.map +1 -0
- package/dist/lib/comment-formatter.test.js +607 -0
- package/dist/lib/comment-formatter.test.js.map +1 -0
- package/dist/lib/comment-manager.d.ts +61 -0
- package/dist/lib/comment-manager.d.ts.map +1 -0
- package/dist/lib/comment-manager.js +91 -0
- package/dist/lib/comment-manager.js.map +1 -0
- package/dist/lib/comment-manager.test.d.ts +2 -0
- package/dist/lib/comment-manager.test.d.ts.map +1 -0
- package/dist/lib/comment-manager.test.js +618 -0
- package/dist/lib/comment-manager.test.js.map +1 -0
- package/dist/lib/comment-poster.d.ts +21 -0
- package/dist/lib/comment-poster.d.ts.map +1 -0
- package/dist/lib/comment-poster.js +96 -0
- package/dist/lib/comment-poster.js.map +1 -0
- package/dist/lib/comment-poster.test.d.ts +5 -0
- package/dist/lib/comment-poster.test.d.ts.map +1 -0
- package/dist/lib/comment-poster.test.js +215 -0
- package/dist/lib/comment-poster.test.js.map +1 -0
- package/dist/lib/config-model-overrides.test.d.ts +12 -0
- package/dist/lib/config-model-overrides.test.d.ts.map +1 -0
- package/dist/lib/config-model-overrides.test.js +254 -0
- package/dist/lib/config-model-overrides.test.js.map +1 -0
- package/dist/lib/config.d.ts +93 -8
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +178 -25
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/config.test.d.ts +2 -0
- package/dist/lib/config.test.d.ts.map +1 -0
- package/dist/lib/config.test.js +36 -0
- package/dist/lib/config.test.js.map +1 -0
- package/dist/lib/context-compression.d.ts +19 -0
- package/dist/lib/context-compression.d.ts.map +1 -0
- package/dist/lib/context-compression.js +170 -0
- package/dist/lib/context-compression.js.map +1 -0
- package/dist/lib/context-compression.test.d.ts +2 -0
- package/dist/lib/context-compression.test.d.ts.map +1 -0
- package/dist/lib/context-compression.test.js +33 -0
- package/dist/lib/context-compression.test.js.map +1 -0
- package/dist/lib/context-loader.d.ts +29 -0
- package/dist/lib/context-loader.d.ts.map +1 -0
- package/dist/lib/context-loader.js +75 -0
- package/dist/lib/context-loader.js.map +1 -0
- package/dist/lib/context-loader.test.d.ts +2 -0
- package/dist/lib/context-loader.test.d.ts.map +1 -0
- package/dist/lib/context-loader.test.js +207 -0
- package/dist/lib/context-loader.test.js.map +1 -0
- package/dist/lib/describe-core.d.ts +9 -0
- package/dist/lib/describe-core.d.ts.map +1 -0
- package/dist/lib/describe-core.js +71 -0
- package/dist/lib/describe-core.js.map +1 -0
- package/dist/lib/describe-core.test.d.ts +2 -0
- package/dist/lib/describe-core.test.d.ts.map +1 -0
- package/dist/lib/describe-core.test.js +208 -0
- package/dist/lib/describe-core.test.js.map +1 -0
- package/dist/lib/describe-output-path.test.d.ts +2 -0
- package/dist/lib/describe-output-path.test.d.ts.map +1 -0
- package/dist/lib/describe-output-path.test.js +51 -0
- package/dist/lib/describe-output-path.test.js.map +1 -0
- package/dist/lib/describe-parser.d.ts +3 -0
- package/dist/lib/describe-parser.d.ts.map +1 -0
- package/dist/lib/describe-parser.js +163 -0
- package/dist/lib/describe-parser.js.map +1 -0
- package/dist/lib/describe-parser.test.d.ts +2 -0
- package/dist/lib/describe-parser.test.d.ts.map +1 -0
- package/dist/lib/describe-parser.test.js +282 -0
- package/dist/lib/describe-parser.test.js.map +1 -0
- package/dist/lib/description-executor.d.ts +22 -0
- package/dist/lib/description-executor.d.ts.map +1 -0
- package/dist/lib/description-executor.js +72 -0
- package/dist/lib/description-executor.js.map +1 -0
- package/dist/lib/description-formatter.d.ts +37 -0
- package/dist/lib/description-formatter.d.ts.map +1 -0
- package/dist/lib/description-formatter.js +219 -0
- package/dist/lib/description-formatter.js.map +1 -0
- package/dist/{gitlab → lib}/diff-parser.d.ts +11 -0
- package/dist/lib/diff-parser.d.ts.map +1 -0
- package/dist/{gitlab → lib}/diff-parser.js +40 -3
- package/dist/lib/diff-parser.js.map +1 -0
- package/dist/lib/issue-parser.d.ts +29 -0
- package/dist/lib/issue-parser.d.ts.map +1 -0
- package/dist/lib/issue-parser.js +153 -0
- package/dist/lib/issue-parser.js.map +1 -0
- package/dist/lib/issue-parser.test.d.ts +2 -0
- package/dist/lib/issue-parser.test.d.ts.map +1 -0
- package/dist/lib/issue-parser.test.js +281 -0
- package/dist/lib/issue-parser.test.js.map +1 -0
- package/dist/lib/json-output-schema.d.ts +207 -0
- package/dist/lib/json-output-schema.d.ts.map +1 -0
- package/dist/lib/json-output-schema.js +124 -0
- package/dist/lib/json-output-schema.js.map +1 -0
- package/dist/lib/json-output-schema.test.d.ts +2 -0
- package/dist/lib/json-output-schema.test.d.ts.map +1 -0
- package/dist/lib/json-output-schema.test.js +92 -0
- package/dist/lib/json-output-schema.test.js.map +1 -0
- package/dist/lib/json-output.d.ts +43 -0
- package/dist/lib/json-output.d.ts.map +1 -0
- package/dist/lib/json-output.js +34 -0
- package/dist/lib/json-output.js.map +1 -0
- package/dist/lib/output-paths.d.ts +6 -0
- package/dist/lib/output-paths.d.ts.map +1 -0
- package/dist/lib/output-paths.js +5 -0
- package/dist/lib/output-paths.js.map +1 -0
- package/dist/lib/platform-client.d.ts +130 -0
- package/dist/lib/platform-client.d.ts.map +1 -0
- package/dist/lib/platform-client.js +8 -0
- package/dist/lib/platform-client.js.map +1 -0
- package/dist/lib/position-validator.d.ts +36 -0
- package/dist/lib/position-validator.d.ts.map +1 -0
- package/dist/lib/position-validator.js +43 -0
- package/dist/lib/position-validator.js.map +1 -0
- package/dist/lib/repository-validator.d.ts +52 -0
- package/dist/lib/repository-validator.d.ts.map +1 -0
- package/dist/lib/repository-validator.js +219 -0
- package/dist/lib/repository-validator.js.map +1 -0
- package/dist/lib/repository-validator.test.d.ts +5 -0
- package/dist/lib/repository-validator.test.d.ts.map +1 -0
- package/dist/lib/repository-validator.test.js +341 -0
- package/dist/lib/repository-validator.test.js.map +1 -0
- package/dist/lib/review-core.d.ts +66 -0
- package/dist/lib/review-core.d.ts.map +1 -0
- package/dist/lib/review-core.js +449 -0
- package/dist/lib/review-core.js.map +1 -0
- package/dist/lib/review-core.test.d.ts +2 -0
- package/dist/lib/review-core.test.d.ts.map +1 -0
- package/dist/lib/review-core.test.js +552 -0
- package/dist/lib/review-core.test.js.map +1 -0
- package/dist/lib/review-orchestrator.d.ts +77 -0
- package/dist/lib/review-orchestrator.d.ts.map +1 -0
- package/dist/lib/review-orchestrator.js +124 -0
- package/dist/lib/review-orchestrator.js.map +1 -0
- package/dist/lib/review-orchestrator.test.d.ts +2 -0
- package/dist/lib/review-orchestrator.test.d.ts.map +1 -0
- package/dist/lib/review-orchestrator.test.js +413 -0
- package/dist/lib/review-orchestrator.test.js.map +1 -0
- package/dist/lib/review-output-path.test.d.ts +2 -0
- package/dist/lib/review-output-path.test.d.ts.map +1 -0
- package/dist/lib/review-output-path.test.js +83 -0
- package/dist/lib/review-output-path.test.js.map +1 -0
- package/dist/lib/review-parser.d.ts +2 -0
- package/dist/lib/review-parser.d.ts.map +1 -0
- package/dist/lib/review-parser.js +100 -0
- package/dist/lib/review-parser.js.map +1 -0
- package/dist/lib/unified-review-executor.d.ts +49 -0
- package/dist/lib/unified-review-executor.d.ts.map +1 -0
- package/dist/lib/unified-review-executor.js +158 -0
- package/dist/lib/unified-review-executor.js.map +1 -0
- package/dist/lib/unified-review-executor.test.d.ts +5 -0
- package/dist/lib/unified-review-executor.test.d.ts.map +1 -0
- package/dist/lib/unified-review-executor.test.js +344 -0
- package/dist/lib/unified-review-executor.test.js.map +1 -0
- package/dist/lib/write-json-output.d.ts +13 -0
- package/dist/lib/write-json-output.d.ts.map +1 -0
- package/dist/lib/write-json-output.js +37 -0
- package/dist/lib/write-json-output.js.map +1 -0
- package/dist/opencode/agent-loader.d.ts +3 -4
- package/dist/opencode/agent-loader.d.ts.map +1 -1
- package/dist/opencode/agent-loader.js +51 -42
- package/dist/opencode/agent-loader.js.map +1 -1
- package/dist/opencode/agent-skill-overlay.d.ts +11 -0
- package/dist/opencode/agent-skill-overlay.d.ts.map +1 -0
- package/dist/opencode/agent-skill-overlay.js +164 -0
- package/dist/opencode/agent-skill-overlay.js.map +1 -0
- package/dist/opencode/client.d.ts +14 -5
- package/dist/opencode/client.d.ts.map +1 -1
- package/dist/opencode/client.js +311 -32
- package/dist/opencode/client.js.map +1 -1
- package/dist/opencode/client.test.d.ts +2 -0
- package/dist/opencode/client.test.d.ts.map +1 -0
- package/dist/opencode/client.test.js +317 -0
- package/dist/opencode/client.test.js.map +1 -0
- package/dist/opencode/opencode-paths.d.ts +2 -0
- package/dist/opencode/opencode-paths.d.ts.map +1 -0
- package/dist/opencode/opencode-paths.js +7 -0
- package/dist/opencode/opencode-paths.js.map +1 -0
- package/dist/opencode/skill-loader.d.ts +6 -0
- package/dist/opencode/skill-loader.d.ts.map +1 -0
- package/dist/opencode/skill-loader.js +36 -0
- package/dist/opencode/skill-loader.js.map +1 -0
- package/package.json +29 -20
- package/.opencode/agent/github-reviewer.md +0 -62
- package/.opencode/agent/gitlab-reviewer.md +0 -62
- package/.opencode/agent/local-reviewer.md +0 -71
- package/dist/gitlab/comment-formatter.d.ts.map +0 -1
- package/dist/gitlab/comment-formatter.js.map +0 -1
- package/dist/gitlab/diff-parser.d.ts.map +0 -1
- package/dist/gitlab/diff-parser.js.map +0 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment posting utilities for PR/MR reviews
|
|
3
|
+
*
|
|
4
|
+
* This module handles posting review comments to GitHub and GitLab platforms,
|
|
5
|
+
* including summary comments and inline code comments.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { formatSummaryComment, formatIssueComment } from './comment-formatter.js';
|
|
9
|
+
import { BOT_COMMENT_ID, createIssueFingerprint, findExistingSummaryComment, prepareIssuesForPosting, } from './comment-manager.js';
|
|
10
|
+
/**
|
|
11
|
+
* Post review comments to a PR/MR
|
|
12
|
+
*
|
|
13
|
+
* This function:
|
|
14
|
+
* 1. Fetches existing comments to prevent duplicates
|
|
15
|
+
* 2. Posts or updates a summary comment
|
|
16
|
+
* 3. Posts inline comments for CRITICAL/HIGH severity issues
|
|
17
|
+
* 4. Adds an "ai-reviewed" label
|
|
18
|
+
*/
|
|
19
|
+
export async function postReviewComments(platformClient, projectId, prNumber, summary, issues, changeSummary, platformData, lineValidator, createInlinePosition) {
|
|
20
|
+
console.log(chalk.gray('Fetching existing comments...\n'));
|
|
21
|
+
// Fetch existing comments to prevent duplicates
|
|
22
|
+
const [existingComments, existingInlineComments] = await Promise.all([
|
|
23
|
+
platformClient.getComments(projectId, prNumber),
|
|
24
|
+
platformClient.getInlineComments(projectId, prNumber),
|
|
25
|
+
]);
|
|
26
|
+
// Find our existing summary comment
|
|
27
|
+
const allComments = [
|
|
28
|
+
...existingComments.map((c) => ({ id: c.id, body: c.body })),
|
|
29
|
+
...existingInlineComments.map((c) => ({ id: c.id, body: c.body })),
|
|
30
|
+
];
|
|
31
|
+
const existingSummary = findExistingSummaryComment(existingComments.map((c) => ({ id: c.id, body: c.body })));
|
|
32
|
+
// Post or update summary comment
|
|
33
|
+
console.log(chalk.gray('Posting review summary...\n'));
|
|
34
|
+
const summaryComment = formatSummaryComment(summary, issues, BOT_COMMENT_ID, changeSummary);
|
|
35
|
+
if (existingSummary) {
|
|
36
|
+
await platformClient.updateComment(projectId, prNumber, existingSummary.id, summaryComment);
|
|
37
|
+
console.log(chalk.green('✓ Updated existing review summary'));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
await platformClient.createComment(projectId, prNumber, summaryComment);
|
|
41
|
+
console.log(chalk.green('✓ Posted new review summary'));
|
|
42
|
+
}
|
|
43
|
+
// Prepare issues for posting: filter to CRITICAL/HIGH, deduplicate, validate lines
|
|
44
|
+
const criticalHighCount = issues.filter((i) => i.severity === 'CRITICAL' || i.severity === 'HIGH').length;
|
|
45
|
+
const prepared = prepareIssuesForPosting(issues, allComments, (issue) => {
|
|
46
|
+
if (!issue.line || !lineValidator)
|
|
47
|
+
return false;
|
|
48
|
+
return lineValidator.isValidLine(issue.file, issue.line);
|
|
49
|
+
});
|
|
50
|
+
// Log diagnostic info about inline comment filtering
|
|
51
|
+
logInlineCommentDiagnostics(criticalHighCount, prepared.deduplicatedCount, prepared.inlineIssues.length, issues);
|
|
52
|
+
// Post inline comments for new CRITICAL/HIGH issues
|
|
53
|
+
if (!createInlinePosition) {
|
|
54
|
+
console.log(chalk.yellow(`⚠ Inline comments disabled (no position builder configured)\n`));
|
|
55
|
+
}
|
|
56
|
+
if (prepared.inlineIssues.length > 0 && createInlinePosition) {
|
|
57
|
+
const inlineComments = prepared.inlineIssues.map((issue) => ({
|
|
58
|
+
body: formatIssueComment(issue, createIssueFingerprint(issue)),
|
|
59
|
+
position: createInlinePosition(issue, platformData),
|
|
60
|
+
}));
|
|
61
|
+
await platformClient.createBulkInlineComments(projectId, prNumber, inlineComments);
|
|
62
|
+
}
|
|
63
|
+
// Add ai-reviewed label
|
|
64
|
+
await platformClient.addLabels(projectId, prNumber, ['ai-reviewed']);
|
|
65
|
+
console.log(chalk.green('✓ Review posted\n'));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Log diagnostic information about inline comment filtering
|
|
69
|
+
*/
|
|
70
|
+
function logInlineCommentDiagnostics(criticalHighCount, deduplicatedCount, inlineIssuesCount, allIssues) {
|
|
71
|
+
if (criticalHighCount > 0) {
|
|
72
|
+
console.log(chalk.gray(`Inline comments: ${criticalHighCount} CRITICAL/HIGH issue(s) found\n`));
|
|
73
|
+
if (deduplicatedCount > 0) {
|
|
74
|
+
console.log(chalk.gray(` - ${deduplicatedCount} already commented (skipped)\n`));
|
|
75
|
+
}
|
|
76
|
+
const issuesWithoutLines = allIssues.filter((i) => (i.severity === 'CRITICAL' || i.severity === 'HIGH') &&
|
|
77
|
+
(i.line === undefined || i.line === null)).length;
|
|
78
|
+
if (issuesWithoutLines > 0) {
|
|
79
|
+
console.log(chalk.gray(` - ${issuesWithoutLines} without line numbers (skipped)\n`));
|
|
80
|
+
}
|
|
81
|
+
const filteredByValidator = criticalHighCount - deduplicatedCount - issuesWithoutLines - inlineIssuesCount;
|
|
82
|
+
if (filteredByValidator > 0) {
|
|
83
|
+
console.log(chalk.gray(` - ${filteredByValidator} on lines not in diff (skipped)\n`));
|
|
84
|
+
}
|
|
85
|
+
if (inlineIssuesCount > 0) {
|
|
86
|
+
console.log(chalk.gray(` → ${inlineIssuesCount} will be posted as inline comments\n`));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.log(chalk.yellow(` → No inline comments to post (all filtered)\n`));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(chalk.gray(`No CRITICAL/HIGH issues - skipping inline comments (only summary posted)\n`));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=comment-poster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-poster.js","sourceRoot":"","sources":["../../src/lib/comment-poster.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-poster.test.d.ts","sourceRoot":"","sources":["../../src/lib/comment-poster.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for comment-poster.ts
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
5
|
+
import { postReviewComments } from './comment-poster.js';
|
|
6
|
+
// Mock dependencies
|
|
7
|
+
vi.mock('./comment-formatter.js', () => ({
|
|
8
|
+
formatSummaryComment: vi.fn((_summary, _issues, _botId, _changeSummary) => 'formatted summary'),
|
|
9
|
+
formatIssueComment: vi.fn((issue, _fingerprint) => `formatted issue: ${issue.title}`),
|
|
10
|
+
}));
|
|
11
|
+
vi.mock('./comment-manager.js', () => ({
|
|
12
|
+
BOT_COMMENT_ID: '<!-- DRS-REVIEW-BOT -->',
|
|
13
|
+
createIssueFingerprint: vi.fn((issue) => `fp-${issue.file}-${issue.line}`),
|
|
14
|
+
findExistingSummaryComment: vi.fn((comments) => {
|
|
15
|
+
return comments.find((c) => c.body.includes('<!-- DRS-REVIEW-BOT -->'));
|
|
16
|
+
}),
|
|
17
|
+
prepareIssuesForPosting: vi.fn((issues, allComments, lineValidator) => {
|
|
18
|
+
const criticalHigh = issues.filter((i) => i.severity === 'CRITICAL' || i.severity === 'HIGH');
|
|
19
|
+
const inlineIssues = criticalHigh.filter((i) => i.line && lineValidator(i));
|
|
20
|
+
return {
|
|
21
|
+
inlineIssues,
|
|
22
|
+
deduplicatedCount: 0,
|
|
23
|
+
};
|
|
24
|
+
}),
|
|
25
|
+
}));
|
|
26
|
+
describe('comment-poster', () => {
|
|
27
|
+
let mockPlatformClient;
|
|
28
|
+
let mockSummary;
|
|
29
|
+
let mockIssues;
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
mockPlatformClient = {
|
|
32
|
+
getPullRequest: vi.fn(),
|
|
33
|
+
getChangedFiles: vi.fn(),
|
|
34
|
+
getComments: vi.fn().mockResolvedValue([]),
|
|
35
|
+
getInlineComments: vi.fn().mockResolvedValue([]),
|
|
36
|
+
createComment: vi.fn().mockResolvedValue({ id: '1' }),
|
|
37
|
+
updateComment: vi.fn().mockResolvedValue({ id: '1' }),
|
|
38
|
+
createBulkInlineComments: vi.fn().mockResolvedValue([]),
|
|
39
|
+
addLabels: vi.fn().mockResolvedValue(undefined),
|
|
40
|
+
};
|
|
41
|
+
mockSummary = {
|
|
42
|
+
issuesFound: 3,
|
|
43
|
+
filesReviewed: 2,
|
|
44
|
+
bySeverity: {
|
|
45
|
+
CRITICAL: 1,
|
|
46
|
+
HIGH: 1,
|
|
47
|
+
MEDIUM: 1,
|
|
48
|
+
LOW: 0,
|
|
49
|
+
},
|
|
50
|
+
byCategory: {
|
|
51
|
+
SECURITY: 1,
|
|
52
|
+
QUALITY: 1,
|
|
53
|
+
STYLE: 1,
|
|
54
|
+
PERFORMANCE: 0,
|
|
55
|
+
DOCUMENTATION: 0,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
mockIssues = [
|
|
59
|
+
{
|
|
60
|
+
severity: 'CRITICAL',
|
|
61
|
+
category: 'SECURITY',
|
|
62
|
+
title: 'SQL injection vulnerability',
|
|
63
|
+
problem: 'SQL injection vulnerability detected',
|
|
64
|
+
solution: 'Use parameterized queries',
|
|
65
|
+
file: 'src/api.ts',
|
|
66
|
+
line: 42,
|
|
67
|
+
agent: 'security',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
severity: 'HIGH',
|
|
71
|
+
category: 'QUALITY',
|
|
72
|
+
title: 'Complex function',
|
|
73
|
+
problem: 'Function is too complex',
|
|
74
|
+
solution: 'Refactor into smaller functions',
|
|
75
|
+
file: 'src/utils.ts',
|
|
76
|
+
line: 10,
|
|
77
|
+
agent: 'quality',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
severity: 'MEDIUM',
|
|
81
|
+
category: 'STYLE',
|
|
82
|
+
title: 'Missing type annotation',
|
|
83
|
+
problem: 'Variable lacks type annotation',
|
|
84
|
+
solution: 'Add explicit type annotation',
|
|
85
|
+
file: 'src/types.ts',
|
|
86
|
+
line: 5,
|
|
87
|
+
agent: 'style',
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
});
|
|
91
|
+
describe('postReviewComments', () => {
|
|
92
|
+
it('should create a new summary comment when none exists', async () => {
|
|
93
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, mockSummary, mockIssues, undefined, {}, undefined, undefined);
|
|
94
|
+
expect(mockPlatformClient.createComment).toHaveBeenCalledWith('owner/repo', 123, 'formatted summary');
|
|
95
|
+
expect(mockPlatformClient.updateComment).not.toHaveBeenCalled();
|
|
96
|
+
});
|
|
97
|
+
it('should update existing summary comment', async () => {
|
|
98
|
+
const existingComment = {
|
|
99
|
+
id: '999',
|
|
100
|
+
body: '<!-- DRS-REVIEW-BOT --> Old summary',
|
|
101
|
+
};
|
|
102
|
+
mockPlatformClient.getComments = vi.fn().mockResolvedValue([existingComment]);
|
|
103
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, mockSummary, mockIssues, undefined, {}, undefined, undefined);
|
|
104
|
+
expect(mockPlatformClient.updateComment).toHaveBeenCalledWith('owner/repo', 123, '999', 'formatted summary');
|
|
105
|
+
expect(mockPlatformClient.createComment).not.toHaveBeenCalled();
|
|
106
|
+
});
|
|
107
|
+
it('should post inline comments for CRITICAL/HIGH issues', async () => {
|
|
108
|
+
const mockLineValidator = {
|
|
109
|
+
isValidLine: vi.fn((_file, _line) => true),
|
|
110
|
+
};
|
|
111
|
+
const mockCreateInlinePosition = vi.fn((issue) => ({
|
|
112
|
+
path: issue.file,
|
|
113
|
+
line: issue.line,
|
|
114
|
+
side: 'RIGHT',
|
|
115
|
+
}));
|
|
116
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, mockSummary, mockIssues, undefined, {}, mockLineValidator, mockCreateInlinePosition);
|
|
117
|
+
expect(mockPlatformClient.createBulkInlineComments).toHaveBeenCalledWith('owner/repo', 123, expect.arrayContaining([
|
|
118
|
+
expect.objectContaining({
|
|
119
|
+
body: expect.stringContaining('SQL injection vulnerability'),
|
|
120
|
+
position: expect.objectContaining({ path: 'src/api.ts', line: 42 }),
|
|
121
|
+
}),
|
|
122
|
+
expect.objectContaining({
|
|
123
|
+
body: expect.stringContaining('Complex function'),
|
|
124
|
+
position: expect.objectContaining({ path: 'src/utils.ts', line: 10 }),
|
|
125
|
+
}),
|
|
126
|
+
]));
|
|
127
|
+
});
|
|
128
|
+
it('should not post inline comments for MEDIUM/LOW issues', async () => {
|
|
129
|
+
const lowSeverityIssues = [
|
|
130
|
+
{
|
|
131
|
+
severity: 'MEDIUM',
|
|
132
|
+
category: 'STYLE',
|
|
133
|
+
title: 'Medium issue',
|
|
134
|
+
problem: 'Medium severity issue',
|
|
135
|
+
solution: 'Fix this issue',
|
|
136
|
+
file: 'src/test.ts',
|
|
137
|
+
line: 1,
|
|
138
|
+
agent: 'style',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
severity: 'LOW',
|
|
142
|
+
category: 'STYLE',
|
|
143
|
+
title: 'Low issue',
|
|
144
|
+
problem: 'Low severity issue',
|
|
145
|
+
solution: 'Fix this issue',
|
|
146
|
+
file: 'src/test.ts',
|
|
147
|
+
line: 2,
|
|
148
|
+
agent: 'style',
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
const mockLineValidator = {
|
|
152
|
+
isValidLine: vi.fn(() => true),
|
|
153
|
+
};
|
|
154
|
+
const mockCreateInlinePosition = vi.fn((issue) => ({
|
|
155
|
+
path: issue.file,
|
|
156
|
+
line: issue.line,
|
|
157
|
+
side: 'RIGHT',
|
|
158
|
+
}));
|
|
159
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, {
|
|
160
|
+
issuesFound: 2,
|
|
161
|
+
filesReviewed: 1,
|
|
162
|
+
bySeverity: { CRITICAL: 0, HIGH: 0, MEDIUM: 1, LOW: 1 },
|
|
163
|
+
byCategory: { SECURITY: 0, QUALITY: 0, STYLE: 2, PERFORMANCE: 0, DOCUMENTATION: 0 },
|
|
164
|
+
}, lowSeverityIssues, undefined, {}, mockLineValidator, mockCreateInlinePosition);
|
|
165
|
+
// Should not create inline comments for MEDIUM/LOW
|
|
166
|
+
expect(mockPlatformClient.createBulkInlineComments).not.toHaveBeenCalled();
|
|
167
|
+
});
|
|
168
|
+
it('should skip inline comments when no line validator provided', async () => {
|
|
169
|
+
const mockCreateInlinePosition = vi.fn((issue) => ({
|
|
170
|
+
path: issue.file,
|
|
171
|
+
line: issue.line,
|
|
172
|
+
side: 'RIGHT',
|
|
173
|
+
}));
|
|
174
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, mockSummary, mockIssues, undefined, {}, undefined, // No line validator
|
|
175
|
+
mockCreateInlinePosition);
|
|
176
|
+
// Should not create inline comments
|
|
177
|
+
expect(mockPlatformClient.createBulkInlineComments).not.toHaveBeenCalled();
|
|
178
|
+
});
|
|
179
|
+
it('should skip inline comments when no position builder provided', async () => {
|
|
180
|
+
const mockLineValidator = {
|
|
181
|
+
isValidLine: vi.fn(() => true),
|
|
182
|
+
};
|
|
183
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, mockSummary, mockIssues, undefined, {}, mockLineValidator, undefined // No position builder
|
|
184
|
+
);
|
|
185
|
+
// Should not create inline comments
|
|
186
|
+
expect(mockPlatformClient.createBulkInlineComments).not.toHaveBeenCalled();
|
|
187
|
+
});
|
|
188
|
+
it('should add ai-reviewed label', async () => {
|
|
189
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, mockSummary, mockIssues, undefined, {}, undefined, undefined);
|
|
190
|
+
expect(mockPlatformClient.addLabels).toHaveBeenCalledWith('owner/repo', 123, ['ai-reviewed']);
|
|
191
|
+
});
|
|
192
|
+
it('should fetch both regular and inline comments', async () => {
|
|
193
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, mockSummary, mockIssues, undefined, {}, undefined, undefined);
|
|
194
|
+
expect(mockPlatformClient.getComments).toHaveBeenCalledWith('owner/repo', 123);
|
|
195
|
+
expect(mockPlatformClient.getInlineComments).toHaveBeenCalledWith('owner/repo', 123);
|
|
196
|
+
});
|
|
197
|
+
it('should include change summary in formatted comment', async () => {
|
|
198
|
+
const mockChangeSummary = {
|
|
199
|
+
type: 'feature',
|
|
200
|
+
subsystems: ['api'],
|
|
201
|
+
complexity: 'medium',
|
|
202
|
+
riskLevel: 'low',
|
|
203
|
+
linesAdded: 50,
|
|
204
|
+
linesRemoved: 20,
|
|
205
|
+
filesChanged: 5,
|
|
206
|
+
description: 'Added new feature',
|
|
207
|
+
};
|
|
208
|
+
await postReviewComments(mockPlatformClient, 'owner/repo', 123, mockSummary, mockIssues, mockChangeSummary, {}, undefined, undefined);
|
|
209
|
+
// Should be called with change summary
|
|
210
|
+
const { formatSummaryComment } = await import('./comment-formatter.js');
|
|
211
|
+
expect(formatSummaryComment).toHaveBeenCalledWith(mockSummary, mockIssues, expect.any(String), mockChangeSummary);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
//# sourceMappingURL=comment-poster.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-poster.test.js","sourceRoot":"","sources":["../../src/lib/comment-poster.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive tests for model override functionality
|
|
3
|
+
*
|
|
4
|
+
* Tests the precedence order of model configuration:
|
|
5
|
+
* 1. Per-agent model in DRS config
|
|
6
|
+
* 2. Environment variable REVIEW_AGENT_<NAME>_MODEL
|
|
7
|
+
* 3. defaultModel in DRS config
|
|
8
|
+
* 4. Environment variable REVIEW_DEFAULT_MODEL
|
|
9
|
+
* 5. (Falls through to opencode.jsonc, not tested here)
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=config-model-overrides.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-model-overrides.test.d.ts","sourceRoot":"","sources":["../../src/lib/config-model-overrides.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive tests for model override functionality
|
|
3
|
+
*
|
|
4
|
+
* Tests the precedence order of model configuration:
|
|
5
|
+
* 1. Per-agent model in DRS config
|
|
6
|
+
* 2. Environment variable REVIEW_AGENT_<NAME>_MODEL
|
|
7
|
+
* 3. defaultModel in DRS config
|
|
8
|
+
* 4. Environment variable REVIEW_DEFAULT_MODEL
|
|
9
|
+
* 5. (Falls through to opencode.jsonc, not tested here)
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
12
|
+
import { getModelOverrides, getUnifiedModelOverride, normalizeAgentConfig, getAgentNames, } from './config.js';
|
|
13
|
+
describe('Model Override Precedence', () => {
|
|
14
|
+
const originalEnv = process.env;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
// Reset environment before each test
|
|
17
|
+
process.env = { ...originalEnv };
|
|
18
|
+
delete process.env.REVIEW_DEFAULT_MODEL;
|
|
19
|
+
delete process.env.REVIEW_AGENT_SECURITY_MODEL;
|
|
20
|
+
delete process.env.REVIEW_AGENT_QUALITY_MODEL;
|
|
21
|
+
delete process.env.REVIEW_AGENT_STYLE_MODEL;
|
|
22
|
+
delete process.env.REVIEW_AGENT_PERFORMANCE_MODEL;
|
|
23
|
+
delete process.env.REVIEW_UNIFIED_MODEL;
|
|
24
|
+
});
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
process.env = originalEnv;
|
|
27
|
+
});
|
|
28
|
+
const createMockConfig = (overrides) => {
|
|
29
|
+
const baseReview = {
|
|
30
|
+
agents: ['security', 'quality', 'style', 'performance'],
|
|
31
|
+
ignorePatterns: [],
|
|
32
|
+
};
|
|
33
|
+
// Only set defaultModel if no overrides provided at all (to maintain backward compatibility)
|
|
34
|
+
// If overrides are provided, only set defaultModel if explicitly included in overrides
|
|
35
|
+
if (!overrides) {
|
|
36
|
+
baseReview.defaultModel = 'anthropic/claude-sonnet-4-5-20250929';
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
opencode: {},
|
|
40
|
+
gitlab: { url: '', token: '' },
|
|
41
|
+
github: { token: '' },
|
|
42
|
+
review: {
|
|
43
|
+
...baseReview,
|
|
44
|
+
...overrides,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
describe('Test 1: Default model always set', () => {
|
|
49
|
+
it('should return overrides based on defaultModel', () => {
|
|
50
|
+
const config = createMockConfig();
|
|
51
|
+
const overrides = getModelOverrides(config);
|
|
52
|
+
// defaultModel is now required, so all agents get the default
|
|
53
|
+
// Only review/<agent> format is used (matching how agents are invoked)
|
|
54
|
+
expect(overrides['review/security']).toBe('anthropic/claude-sonnet-4-5-20250929');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('Test 2: DRS defaultModel only', () => {
|
|
58
|
+
it('should apply defaultModel to all agents', () => {
|
|
59
|
+
const config = createMockConfig({
|
|
60
|
+
defaultModel: 'zhipuai/glm-4.7',
|
|
61
|
+
agents: ['security', 'quality', 'style', 'performance'],
|
|
62
|
+
});
|
|
63
|
+
const overrides = getModelOverrides(config);
|
|
64
|
+
expect(overrides).toEqual({
|
|
65
|
+
'review/security': 'zhipuai/glm-4.7',
|
|
66
|
+
'review/quality': 'zhipuai/glm-4.7',
|
|
67
|
+
'review/style': 'zhipuai/glm-4.7',
|
|
68
|
+
'review/performance': 'zhipuai/glm-4.7',
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe('Test 3: DRS per-agent model override', () => {
|
|
73
|
+
it('should use per-agent model over defaultModel', () => {
|
|
74
|
+
const config = createMockConfig({
|
|
75
|
+
defaultModel: 'zhipuai/glm-4.7',
|
|
76
|
+
agents: [
|
|
77
|
+
{ name: 'security', model: 'anthropic/claude-opus-4-5-20251101' },
|
|
78
|
+
'quality',
|
|
79
|
+
{ name: 'style', model: 'anthropic/claude-sonnet-4-5-20250929' },
|
|
80
|
+
'performance',
|
|
81
|
+
],
|
|
82
|
+
});
|
|
83
|
+
const overrides = getModelOverrides(config);
|
|
84
|
+
expect(overrides).toEqual({
|
|
85
|
+
'review/security': 'anthropic/claude-opus-4-5-20251101',
|
|
86
|
+
'review/quality': 'zhipuai/glm-4.7',
|
|
87
|
+
'review/style': 'anthropic/claude-sonnet-4-5-20250929',
|
|
88
|
+
'review/performance': 'zhipuai/glm-4.7',
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('Test 4: Environment REVIEW_DEFAULT_MODEL', () => {
|
|
93
|
+
it('should use env default model for all agents', () => {
|
|
94
|
+
process.env.REVIEW_DEFAULT_MODEL = 'provider/model-from-env';
|
|
95
|
+
const config = createMockConfig({
|
|
96
|
+
agents: ['security', 'quality'],
|
|
97
|
+
});
|
|
98
|
+
const overrides = getModelOverrides(config);
|
|
99
|
+
expect(overrides).toEqual({
|
|
100
|
+
'review/security': 'provider/model-from-env',
|
|
101
|
+
'review/quality': 'provider/model-from-env',
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
it('should prefer config defaultModel over env REVIEW_DEFAULT_MODEL', () => {
|
|
105
|
+
process.env.REVIEW_DEFAULT_MODEL = 'provider/env-model';
|
|
106
|
+
const config = createMockConfig({
|
|
107
|
+
defaultModel: 'zhipuai/config-model',
|
|
108
|
+
agents: ['security'],
|
|
109
|
+
});
|
|
110
|
+
const overrides = getModelOverrides(config);
|
|
111
|
+
expect(overrides['review/security']).toBe('zhipuai/config-model');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('Test 5: Environment REVIEW_AGENT_<NAME>_MODEL', () => {
|
|
115
|
+
it('should use agent-specific env var', () => {
|
|
116
|
+
process.env.REVIEW_AGENT_SECURITY_MODEL = 'provider/security-from-env';
|
|
117
|
+
const config = createMockConfig({
|
|
118
|
+
defaultModel: 'zhipuai/glm-4.7',
|
|
119
|
+
agents: ['security', 'quality'],
|
|
120
|
+
});
|
|
121
|
+
const overrides = getModelOverrides(config);
|
|
122
|
+
expect(overrides).toEqual({
|
|
123
|
+
'review/security': 'provider/security-from-env',
|
|
124
|
+
'review/quality': 'zhipuai/glm-4.7',
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
it('should handle agent names with special characters', () => {
|
|
128
|
+
process.env.REVIEW_AGENT_CUSTOM_SECURITY_MODEL = 'provider/custom-model';
|
|
129
|
+
const config = createMockConfig({
|
|
130
|
+
agents: ['custom-security'],
|
|
131
|
+
defaultModel: 'zhipuai/glm-4.7',
|
|
132
|
+
});
|
|
133
|
+
const overrides = getModelOverrides(config);
|
|
134
|
+
// Env var takes precedence over defaultModel
|
|
135
|
+
expect(overrides['review/custom-security']).toBe('provider/custom-model');
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe('Test 6: Complete precedence chain', () => {
|
|
139
|
+
it('should follow full precedence order', () => {
|
|
140
|
+
// Set env vars (lowest priority among overrides)
|
|
141
|
+
process.env.REVIEW_DEFAULT_MODEL = 'provider/default-env';
|
|
142
|
+
process.env.REVIEW_AGENT_QUALITY_MODEL = 'provider/quality-env';
|
|
143
|
+
const config = createMockConfig({
|
|
144
|
+
defaultModel: 'zhipuai/default-config',
|
|
145
|
+
agents: [{ name: 'security', model: 'anthropic/security-config' }, 'quality', 'style'],
|
|
146
|
+
});
|
|
147
|
+
const overrides = getModelOverrides(config);
|
|
148
|
+
// Precedence verification:
|
|
149
|
+
// security: per-agent config wins
|
|
150
|
+
expect(overrides['review/security']).toBe('anthropic/security-config');
|
|
151
|
+
// quality: env agent var wins over config default
|
|
152
|
+
expect(overrides['review/quality']).toBe('provider/quality-env');
|
|
153
|
+
// style: config default wins over env default
|
|
154
|
+
expect(overrides['review/style']).toBe('zhipuai/default-config');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe('Test 7: Mixed agent formats', () => {
|
|
158
|
+
it('should handle mix of string and object agent configs', () => {
|
|
159
|
+
const config = createMockConfig({
|
|
160
|
+
defaultModel: 'zhipuai/glm-4.7',
|
|
161
|
+
agents: [
|
|
162
|
+
'security',
|
|
163
|
+
{ name: 'quality', model: 'anthropic/claude-opus-4-5-20251101' },
|
|
164
|
+
'style',
|
|
165
|
+
{ name: 'performance' }, // object without model
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
const overrides = getModelOverrides(config);
|
|
169
|
+
expect(overrides['review/security']).toBe('zhipuai/glm-4.7');
|
|
170
|
+
expect(overrides['review/quality']).toBe('anthropic/claude-opus-4-5-20251101');
|
|
171
|
+
expect(overrides['review/style']).toBe('zhipuai/glm-4.7');
|
|
172
|
+
expect(overrides['review/performance']).toBe('zhipuai/glm-4.7');
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('Agent name normalization', () => {
|
|
176
|
+
it('should normalize string agents', () => {
|
|
177
|
+
const agents = ['security', 'quality'];
|
|
178
|
+
const normalized = normalizeAgentConfig(agents);
|
|
179
|
+
expect(normalized).toEqual([{ name: 'security' }, { name: 'quality' }]);
|
|
180
|
+
});
|
|
181
|
+
it('should preserve object agents', () => {
|
|
182
|
+
const agents = [{ name: 'security', model: 'test/model' }, 'quality'];
|
|
183
|
+
const normalized = normalizeAgentConfig(agents);
|
|
184
|
+
expect(normalized).toEqual([{ name: 'security', model: 'test/model' }, { name: 'quality' }]);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
describe('Agent name extraction', () => {
|
|
188
|
+
it('should extract agent names from mixed config', () => {
|
|
189
|
+
const config = createMockConfig({
|
|
190
|
+
agents: ['security', { name: 'quality', model: 'test/model' }, { name: 'style' }],
|
|
191
|
+
});
|
|
192
|
+
const names = getAgentNames(config);
|
|
193
|
+
expect(names).toEqual(['security', 'quality', 'style']);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('Unified reviewer model overrides', () => {
|
|
197
|
+
it('should use unified model from config', () => {
|
|
198
|
+
const config = createMockConfig({
|
|
199
|
+
defaultModel: 'anthropic/claude-sonnet-4-5-20250929',
|
|
200
|
+
unified: {
|
|
201
|
+
model: 'provider/unified-config',
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
const overrides = getUnifiedModelOverride(config);
|
|
205
|
+
expect(overrides['review/unified-reviewer']).toBe('provider/unified-config');
|
|
206
|
+
});
|
|
207
|
+
it('should fall back to env REVIEW_UNIFIED_MODEL when config missing', () => {
|
|
208
|
+
process.env.REVIEW_UNIFIED_MODEL = 'provider/unified-env';
|
|
209
|
+
const config = createMockConfig({
|
|
210
|
+
defaultModel: 'provider/default-model',
|
|
211
|
+
});
|
|
212
|
+
const overrides = getUnifiedModelOverride(config);
|
|
213
|
+
expect(overrides['review/unified-reviewer']).toBe('provider/unified-env');
|
|
214
|
+
});
|
|
215
|
+
it('should fall back to review.defaultModel when unified model missing', () => {
|
|
216
|
+
const config = createMockConfig({
|
|
217
|
+
defaultModel: 'provider/default-model',
|
|
218
|
+
});
|
|
219
|
+
const overrides = getUnifiedModelOverride(config);
|
|
220
|
+
expect(overrides['review/unified-reviewer']).toBe('provider/default-model');
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe('Edge cases', () => {
|
|
224
|
+
it('should handle empty agents array', () => {
|
|
225
|
+
const config = createMockConfig({
|
|
226
|
+
agents: [],
|
|
227
|
+
defaultModel: 'zhipuai/glm-4.7',
|
|
228
|
+
});
|
|
229
|
+
const overrides = getModelOverrides(config);
|
|
230
|
+
expect(overrides).toEqual({});
|
|
231
|
+
});
|
|
232
|
+
it('should apply defaultModel to agents without explicit model', () => {
|
|
233
|
+
const config = createMockConfig({
|
|
234
|
+
agents: [{ name: 'security' }, { name: 'quality' }],
|
|
235
|
+
defaultModel: 'test/default-model',
|
|
236
|
+
});
|
|
237
|
+
const overrides = getModelOverrides(config);
|
|
238
|
+
// defaultModel is now always applied
|
|
239
|
+
expect(overrides['review/security']).toBe('test/default-model');
|
|
240
|
+
expect(overrides['review/quality']).toBe('test/default-model');
|
|
241
|
+
});
|
|
242
|
+
it('should only create review/ prefixed keys (matching how agents are invoked)', () => {
|
|
243
|
+
const config = createMockConfig({
|
|
244
|
+
defaultModel: 'test/model',
|
|
245
|
+
agents: ['security'],
|
|
246
|
+
});
|
|
247
|
+
const overrides = getModelOverrides(config);
|
|
248
|
+
// Only review/<agent> format is used
|
|
249
|
+
expect(overrides['review/security']).toBe('test/model');
|
|
250
|
+
expect(Object.keys(overrides)).toEqual(['review/security']);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
//# sourceMappingURL=config-model-overrides.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-model-overrides.test.js","sourceRoot":"","sources":["../../src/lib/config-model-overrides.test.ts"],"names":[],"mappings":"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"}
|