Skip to content

Commit 32aba24

Browse files
authored
feat(codereview): add JetBrains integration for code review functionality (#593)
1 parent d7d8866 commit 32aba24

File tree

6 files changed

+147
-7
lines changed

6 files changed

+147
-7
lines changed

packages/types/src/vscode.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ export const costrictCommandIds = [
7474
// code review
7575
"codeReviewButtonClicked",
7676
"codeReview",
77+
"codeReviewJetbrains",
78+
"reviewFilesAndFoldersJetbrains",
79+
"askReviewSuggestionWithAIJetbrains",
80+
"acceptIssueJetbrains",
81+
"rejectIssueJetbrains",
7782
"reviewFilesAndFolders",
7883
"reviewRepo",
7984
"askReviewSuggestionWithAI",

src/core/costrict/code-review/codeReviewService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ import type { ClineProvider } from "../../webview/ClineProvider"
4848
import { TelemetryService } from "@roo-code/telemetry"
4949
import { CodeReviewErrorType, type TelemetryErrorType } from "../telemetry"
5050
import { COSTRICT_DEFAULT_HEADERS } from "../../../shared/headers"
51-
import { zgsmCodebaseIndexManager } from "../codebase-index"
5251
import { fileExistsAtPath } from "../../../utils/fs"
52+
import { isJetbrainsPlatform } from "../../../utils/platform"
5353
/**
5454
* Code Review Service - Singleton
5555
*
@@ -793,7 +793,7 @@ export class CodeReviewService {
793793
vscode.CommentMode.Preview,
794794
{ name: "CoStrict", iconPath },
795795
undefined,
796-
"Intial",
796+
isJetbrainsPlatform() ? issue.id : "Intial",
797797
),
798798
}
799799
}

src/core/costrict/code-review/index.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,115 @@ export function initCodeReview(
120120
reviewInstance.askWithAI(comment.id)
121121
}
122122
},
123+
codeReviewJetbrains: async (args: any) => {
124+
const visibleProvider = await ClineProvider.getInstance()
125+
if (!visibleProvider) {
126+
return
127+
}
128+
visibleProvider.log(`[CodeReview] start review ${args}`)
129+
130+
const data = args?.[0]?.[0]
131+
if (!data) {
132+
visibleProvider.log("[CodeReview] Invalid args structure")
133+
return
134+
}
135+
136+
const { startLine, endLine, filePath, selectedText } = data
137+
visibleProvider.log(
138+
`[CodeReview] extracted data: filePath=${filePath}, startLine=${startLine}, endLine=${endLine}`,
139+
)
140+
141+
const cwd = visibleProvider.cwd.toPosix()
142+
reviewInstance.setProvider(visibleProvider)
143+
const params = {
144+
filePath,
145+
endLine: endLine + "",
146+
startLine: startLine + "",
147+
selectedText: selectedText,
148+
}
149+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", params)
150+
reviewInstance.createReviewTask(prompt, [
151+
{
152+
type: ReviewTargetType.CODE,
153+
file_path: toRelativePath(filePath.toPosix(), cwd),
154+
line_range: [startLine, endLine],
155+
},
156+
])
157+
},
158+
reviewFilesAndFoldersJetbrains: async (args: any) => {
159+
const visibleProvider = await ClineProvider.getInstance()
160+
if (!visibleProvider) {
161+
return
162+
}
163+
visibleProvider.log(`[CodeReview] start review ${JSON.stringify(args)}`)
164+
const data = args?.[0]?.[0]
165+
if (!data) {
166+
visibleProvider.log("[CodeReview] Invalid args structure")
167+
return
168+
}
169+
const cwd = visibleProvider.cwd.toPosix()
170+
const { filePaths } = data
171+
const targets: ReviewTarget[] = await Promise.all(
172+
filePaths.map(async (filePath: string) => {
173+
return {
174+
type: ReviewTargetType.FILE,
175+
file_path: toRelativePath(filePath.toPosix(), cwd),
176+
}
177+
}),
178+
)
179+
reviewInstance.setProvider(visibleProvider)
180+
reviewInstance.startReview(targets)
181+
},
182+
acceptIssueJetbrains: async (args: any) => {
183+
const visibleProvider = await ClineProvider.getInstance()
184+
if (!visibleProvider) {
185+
return
186+
}
187+
reviewInstance.setProvider(visibleProvider)
188+
visibleProvider.log(`[CodeReview] accept issue ${JSON.stringify(args)}`)
189+
const data = args?.[0]?.[0]
190+
if (!data) {
191+
visibleProvider.log("[CodeReview] Invalid args structure")
192+
return
193+
}
194+
195+
const { id } = data
196+
reviewInstance.updateIssueStatus(id, IssueStatus.ACCEPT)
197+
},
198+
rejectIssueJetbrains: async (args: any) => {
199+
const visibleProvider = await ClineProvider.getInstance()
200+
if (!visibleProvider) {
201+
return
202+
}
203+
reviewInstance.setProvider(visibleProvider)
204+
visibleProvider.log(`[CodeReview] reject issue ${JSON.stringify(args)}`)
205+
const data = args?.[0]?.[0]
206+
if (!data) {
207+
visibleProvider.log("[CodeReview] Invalid args structure")
208+
return
209+
}
210+
211+
const { id } = data
212+
reviewInstance.updateIssueStatus(id, IssueStatus.REJECT)
213+
},
214+
askReviewSuggestionWithAIJetbrains: async (args: any) => {
215+
const visibleProvider = await ClineProvider.getInstance()
216+
if (!visibleProvider) {
217+
return
218+
}
219+
visibleProvider.log(`[CodeReview] ask review suggestion with AI ${JSON.stringify(args)}`)
220+
reviewInstance.setProvider(visibleProvider)
221+
const data = args?.[0]?.[0]
222+
if (!data) {
223+
visibleProvider.log("[CodeReview] Invalid args structure")
224+
return
225+
}
226+
227+
const { id } = data
228+
if (id) {
229+
reviewInstance.askWithAI(id)
230+
}
231+
},
123232
}
124233
for (const [id, callback] of Object.entries(commandMap)) {
125234
const command = getCommand(id as CostrictCommandId)

src/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,26 @@
195195
"command": "zgsm.reviewRepo",
196196
"title": "%command.reviewRepo.title%"
197197
},
198+
{
199+
"command": "zgsm.codeReviewJetbrains",
200+
"title": "%command.codeReview.title%"
201+
},
202+
{
203+
"command": "zgsm.reviewFilesAndFoldersJetbrains",
204+
"title": "%command.codeReview.title%"
205+
},
206+
{
207+
"command": "zgsm.askReviewSuggestionWithAIJetbrains",
208+
"title": "%command.codeReview.title%"
209+
},
210+
{
211+
"command": "zgsm.acceptIssueJetbrains",
212+
"title": "%command.codeReview.title%"
213+
},
214+
{
215+
"command": "zgsm.rejectIssueJetbrains",
216+
"title": "%command.codeReview.title%"
217+
},
198218
{
199219
"command": "zgsm.acceptIssue",
200220
"title": "Accept",

src/utils/platform.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import * as vscode from "vscode"
2+
export function isJetbrainsPlatform(): boolean {
3+
return ["intellij-machine", "development-machine"].includes(vscode?.env?.machineId)
4+
}

webview-ui/src/components/code-review/FileIssueList.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ const FileIssueList: React.FC<FileIssueListProps> = ({ fileName, issues, onIssue
2929
return (
3030
<div className="w-full" style={{ opacity: allIssuesProcessed ? 0.4 : 1 }}>
3131
<div className="flex justify-between pr-5">
32-
<div className="flex items-center gap-2">
33-
<SetiFileIcon fileName={fileName} size={16} />
34-
<span>{fileName}</span>
35-
<div onClick={() => setIsExpanded(!isExpanded)} className="cursor-pointer">
32+
<div className="flex items-center gap-2 min-w-0 flex-1 overflow-hidden">
33+
<SetiFileIcon fileName={fileName} size={16} className="flex-shrink-0" />
34+
<span className="truncate" title={fileName}>
35+
{fileName}
36+
</span>
37+
<div onClick={() => setIsExpanded(!isExpanded)} className="cursor-pointer flex-shrink-0">
3638
{isExpanded ? <ChevronUpIcon /> : <ChevronDownIcon />}
3739
</div>
3840
</div>
39-
<div className="flex items-center gap-1">
41+
<div className="flex items-center gap-1 flex-shrink-0">
4042
<span className="codicon codicon-bug"></span>
4143
<span>{issues.length}</span>
4244
</div>

0 commit comments

Comments
 (0)