Skip to content

Commit 1815946

Browse files
inesgomasalerizzo
andauthored
feat: Integrate with CLI v2 CY-7445 (#43)
* feature: Add problems from codacy CLI CY-7445 * chore: Add decounce CY-7445 * chore: Sanitize file path CY-7445 * merge local analysis into CLI branch * added temp file analysis and sarif processing, still in progress * refactor diagnostics to support both API and CLI * add analysis of unsaved files * local analysis working with latest version of cli v2 * fix typos * move dep to devdep --------- Co-authored-by: Alejandro Rizzo <alejandro.rizzo@codacy.com> Co-authored-by: Alejandro Rizzo <alerizzo@gmail.com>
1 parent 9e2de19 commit 1815946

File tree

4 files changed

+295
-46
lines changed

4 files changed

+295
-46
lines changed

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,13 @@
203203
},
204204
{
205205
"command": "codacy.configureMCP",
206+
"title": "Configure Codacy MCP Server",
206207
"when": "Codacy:RepositoryManagerStateContext != NeedsAuthentication && codacy:supportsMCP && !codacy:mcpConfigured"
207208
},
208209
{
209210
"command": "codacy.configureMCP.reset",
210-
"when": "Codacy:RepositoryManagerStateContext != NeedsAuthentication && codacy:supportsMCP && codacy:mcpConfigured"
211+
"title": "Reset Codacy MCP Server configuration",
212+
"when": "Codacy:RepositoryManagerStateContext != NeedsAuthentication && codacy:supportsMCP && !codacy:mcpConfigured"
211213
}
212214
],
213215
"menus": {
@@ -310,6 +312,7 @@
310312
"@types/lodash": "^4.14.196",
311313
"@types/mocha": "^10.0.1",
312314
"@types/node": "20.4.7",
315+
"@types/sarif": "2.1.7",
313316
"@types/sinon": "^10.0.16",
314317
"@types/temp": "^0.9.1",
315318
"@types/vscode": "^1.81.0",

src/commands/runCodacyAnalyze.ts

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import * as vscode from 'vscode'
2+
import { exec } from 'child_process'
3+
import Logger from '../common/logger'
4+
import * as path from 'path'
5+
import { Run } from 'sarif'
6+
7+
// Set a larger buffer size (10MB)
8+
const MAX_BUFFER_SIZE = 1024 * 1024 * 10
9+
10+
const sanitizeFilePath = (workspaceRoot: string, filePath?: string): string => {
11+
// Remove any shell metacharacters
12+
const safePath = filePath?.replace(/[;&|`$]/g, '') || ''
13+
14+
return path.relative(workspaceRoot, safePath) || ''
15+
}
16+
17+
export async function runCodacyAnalyze(filePath?: string) {
18+
try {
19+
// Get workspace folder (to solve: mkdir error)
20+
const workspaceFolders = vscode.workspace.workspaceFolders
21+
if (!workspaceFolders || workspaceFolders.length === 0) {
22+
throw new Error('No workspace folder found')
23+
}
24+
const workspaceRoot = workspaceFolders[0].uri.fsPath
25+
26+
// If filePath is provided, make it relative to workspace root
27+
const relativeFilePath = sanitizeFilePath(workspaceRoot, filePath)
28+
29+
// Construct the command
30+
const command = `codacy-cli analyze --format sarif ${relativeFilePath || ''}`
31+
32+
Logger.appendLine(`Running Codacy CLI V2 analyze command for ${relativeFilePath || 'entire workspace'}...`)
33+
34+
return new Promise<ProcessedSarifResult[]>((resolve, reject) => {
35+
// Execute in workspace directory with increased maxBuffer
36+
exec(
37+
command,
38+
{
39+
cwd: workspaceRoot,
40+
maxBuffer: MAX_BUFFER_SIZE, // To solve: stdout maxBuffer exceeded
41+
},
42+
(error, stdout, stderr) => {
43+
if (error) {
44+
Logger.error(`Error executing Codacy CLI V2: ${error.message}`)
45+
vscode.window.showErrorMessage(`Failed to run Codacy analysis: ${error.message}`)
46+
reject(error)
47+
return
48+
}
49+
50+
if (stderr && (!stdout || /error|fail|exception/i.test(stderr))) {
51+
Logger.warn(`Codacy CLI V2 warnings: ${stderr}`)
52+
}
53+
54+
const jsonMatch = /(\{[\s\S]*\}|\[[\s\S]*\])/.exec(stdout)
55+
const sarifResult = jsonMatch ? JSON.parse(jsonMatch[0]) : null
56+
57+
const results: ProcessedSarifResult[] =
58+
sarifResult && 'runs' in sarifResult ? processSarifResults(sarifResult.runs) : []
59+
60+
Logger.appendLine(
61+
`Codacy CLI V2 analysis completed for ${filePath || 'entire workspace'} with ${results.length} results.`
62+
)
63+
64+
resolve(results)
65+
}
66+
)
67+
})
68+
} catch (error: unknown) {
69+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'
70+
Logger.error(`Failed to run Codacy analysis: ${errorMessage}`)
71+
vscode.window.showErrorMessage(`Failed to run Codacy analysis: ${errorMessage}`)
72+
throw error
73+
}
74+
}
75+
76+
const processSarifResults = (runs: Run[]) => {
77+
return (
78+
runs.flatMap((run) => {
79+
const tool = run.tool.driver.name
80+
const rules = Object.fromEntries(run.tool.driver.rules?.map((rule) => [rule.id, rule]) || [])
81+
82+
return (
83+
run.results?.flatMap((result) => {
84+
const rule = result.ruleId ? rules[result.ruleId] : null
85+
const level = result.level || 'error'
86+
const message = result.message?.text || 'No message provided.'
87+
88+
return (
89+
result.locations?.map((location) => {
90+
const filePath = location.physicalLocation?.artifactLocation?.uri
91+
92+
return {
93+
tool,
94+
rule: rule
95+
? {
96+
id: rule.id,
97+
name: rule.name,
98+
helpUri: rule.helpUri,
99+
shortDescription: rule.shortDescription?.text,
100+
}
101+
: undefined,
102+
level,
103+
message,
104+
filePath,
105+
region: location.physicalLocation?.region,
106+
}
107+
}) || []
108+
)
109+
}) || []
110+
)
111+
}) || []
112+
)
113+
}
114+
115+
export type ProcessedSarifResult = ReturnType<typeof processSarifResults>[number]

0 commit comments

Comments
 (0)