opencode-sonarqube 1.2.40 → 1.2.41
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/index.js +1 -259
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20600,152 +20600,6 @@ Issues: ${issues.blocker} blockers, ${issues.critical} critical, ${issues.major}
|
|
|
20600
20600
|
|
|
20601
20601
|
${statusNote}`;
|
|
20602
20602
|
};
|
|
20603
|
-
const sendAutoFixPrompt = async (analysisResult) => {
|
|
20604
|
-
await client.session.prompt({
|
|
20605
|
-
path: { id: currentSessionId },
|
|
20606
|
-
body: {
|
|
20607
|
-
parts: [{
|
|
20608
|
-
type: "text",
|
|
20609
|
-
text: `## SonarQube: Auto-Fix Required
|
|
20610
|
-
|
|
20611
|
-
Found blocking issues before commit. Attempting automatic fix...
|
|
20612
|
-
|
|
20613
|
-
${formatAnalysisResult(analysisResult)}
|
|
20614
|
-
|
|
20615
|
-
Please fix these issues and then try committing again.`
|
|
20616
|
-
}]
|
|
20617
|
-
}
|
|
20618
|
-
});
|
|
20619
|
-
await showToast("SonarQube: Fixing issues before commit...", "info");
|
|
20620
|
-
};
|
|
20621
|
-
const sendBlockingMessage = async (issues, shouldBlock, autoFixAvailable) => {
|
|
20622
|
-
const statusText = shouldBlock ? "Commit Blocked" : "Pre-Commit Warning";
|
|
20623
|
-
const labelText = shouldBlock ? "BLOCKED" : "WARNING";
|
|
20624
|
-
const actionText = shouldBlock ? "Commit is blocked until these issues are fixed." : "Consider fixing these before committing.";
|
|
20625
|
-
const autoFixHint = autoFixAvailable ? '\nOr run `sonarqube({ action: "analyze", fix: true })` to auto-fix.' : "";
|
|
20626
|
-
const warningMessage = `## SonarQube: ${statusText}
|
|
20627
|
-
|
|
20628
|
-
**${labelText}:** Found ${issues.blocker} BLOCKER and ${issues.critical} CRITICAL issues.
|
|
20629
|
-
|
|
20630
|
-
${actionText}
|
|
20631
|
-
|
|
20632
|
-
Run \`sonarqube({ action: "issues", severity: "critical" })\` to see details.${autoFixHint}`;
|
|
20633
|
-
await client.session.prompt({
|
|
20634
|
-
path: { id: currentSessionId },
|
|
20635
|
-
body: { noReply: !shouldBlock, parts: [{ type: "text", text: warningMessage }] }
|
|
20636
|
-
});
|
|
20637
|
-
const toastMessage = shouldBlock ? "SonarQube: Commit BLOCKED - fix issues first" : "SonarQube: Issues found";
|
|
20638
|
-
await showToast(toastMessage, "error");
|
|
20639
|
-
return warningMessage;
|
|
20640
|
-
};
|
|
20641
|
-
const checkExistingIssuesAndBlock = async (api2, projectKey, operationType, blockingSeverity, shouldBlock) => {
|
|
20642
|
-
const counts = await api2.issues.getCounts(projectKey);
|
|
20643
|
-
const hasBlockingIssues = checkBlockingIssues(counts, blockingSeverity);
|
|
20644
|
-
if (!hasBlockingIssues || !shouldBlock) {
|
|
20645
|
-
return { block: false };
|
|
20646
|
-
}
|
|
20647
|
-
const opName = operationType === "commit" ? "Commit" : "Push";
|
|
20648
|
-
const message = `## SonarQube: ${opName} Blocked
|
|
20649
|
-
|
|
20650
|
-
**BLOCKED:** There are ${counts.blocker} BLOCKER, ${counts.critical} CRITICAL, and ${counts.major} MAJOR issues.
|
|
20651
|
-
|
|
20652
|
-
Fix these issues before ${operationType === "commit" ? "committing" : "pushing"}.`;
|
|
20653
|
-
await client.session.prompt({
|
|
20654
|
-
path: { id: currentSessionId },
|
|
20655
|
-
body: { noReply: true, parts: [{ type: "text", text: message }] }
|
|
20656
|
-
});
|
|
20657
|
-
await showToast(`SonarQube: ${operationType} BLOCKED`, "error");
|
|
20658
|
-
return { block: true, message };
|
|
20659
|
-
};
|
|
20660
|
-
const isGitCommit = (cmd) => /git\s+commit\b/.test(cmd) && !/--amend/.test(cmd);
|
|
20661
|
-
const isGitPush = (cmd) => /git\s+push\b/.test(cmd);
|
|
20662
|
-
const processAnalysisResult = async (analysisResult, blockingSeverity, shouldBlock, fixBeforeCommit, autoFix) => {
|
|
20663
|
-
const issues = analysisResult.issues;
|
|
20664
|
-
safeLog(`[processAnalysisResult] issues=${JSON.stringify(issues)}, blockingSeverity=${blockingSeverity}`);
|
|
20665
|
-
const hasBlockingIssues = checkBlockingIssues(issues, blockingSeverity);
|
|
20666
|
-
safeLog(`[processAnalysisResult] hasBlockingIssues=${hasBlockingIssues}, qualityGate=${analysisResult.qualityGateStatus}`);
|
|
20667
|
-
const qgExplicitlyPassed = analysisResult.qualityGateStatus === "OK";
|
|
20668
|
-
const passedCheck = qgExplicitlyPassed && !hasBlockingIssues;
|
|
20669
|
-
safeLog(`[processAnalysisResult] qgStatus=${analysisResult.qualityGateStatus}, qgExplicitlyPassed=${qgExplicitlyPassed}, hasBlockingIssues=${hasBlockingIssues}, passedCheck=${passedCheck}`);
|
|
20670
|
-
if (passedCheck) {
|
|
20671
|
-
await showToast("SonarQube: Quality check passed!", "success");
|
|
20672
|
-
return { block: false };
|
|
20673
|
-
}
|
|
20674
|
-
if (fixBeforeCommit && autoFix) {
|
|
20675
|
-
await sendAutoFixPrompt(analysisResult);
|
|
20676
|
-
return { block: shouldBlock, message: "Quality gate FAILED. Run sonarqube({ action: 'issues' }) to see problems, then fix them before committing." };
|
|
20677
|
-
}
|
|
20678
|
-
const warningMessage = await sendBlockingMessage(analysisResult.issues, shouldBlock, autoFix);
|
|
20679
|
-
return { block: shouldBlock, message: warningMessage };
|
|
20680
|
-
};
|
|
20681
|
-
const handleGitOperationCheck = async (output, operationType) => {
|
|
20682
|
-
const args = output.args;
|
|
20683
|
-
const command = args?.command ?? "";
|
|
20684
|
-
const workdir = args?.workdir;
|
|
20685
|
-
const isMatch = operationType === "commit" ? isGitCommit(command) : isGitPush(command);
|
|
20686
|
-
if (!isMatch)
|
|
20687
|
-
return { block: false };
|
|
20688
|
-
const dir = workdir || getDirectory();
|
|
20689
|
-
safeLog(`[handleGitOperationCheck] workdir=${workdir}, resolved dir=${dir}`);
|
|
20690
|
-
const targetConfigPath = `${dir}/.sonarqube/config.json`;
|
|
20691
|
-
let targetConfig;
|
|
20692
|
-
try {
|
|
20693
|
-
const configFile = Bun.file(targetConfigPath);
|
|
20694
|
-
if (await configFile.exists()) {
|
|
20695
|
-
targetConfig = await configFile.json();
|
|
20696
|
-
safeLog(`[handleGitOperationCheck] Loaded config from ${targetConfigPath}`);
|
|
20697
|
-
}
|
|
20698
|
-
} catch {}
|
|
20699
|
-
if (!targetConfig) {
|
|
20700
|
-
await loadPluginConfig();
|
|
20701
|
-
targetConfig = pluginConfig?.["sonarqube"];
|
|
20702
|
-
safeLog(`[handleGitOperationCheck] Using plugin config (no target config found)`);
|
|
20703
|
-
}
|
|
20704
|
-
safeLog(`[handleGitOperationCheck] targetConfig=${JSON.stringify(targetConfig)}`);
|
|
20705
|
-
const config2 = loadConfig(targetConfig);
|
|
20706
|
-
safeLog(`[handleGitOperationCheck] ${operationType}: level=${config2?.level}, blockCommit=${config2?.blockCommit}, blockPush=${config2?.blockPush}`);
|
|
20707
|
-
if (!config2 || config2.level === "off")
|
|
20708
|
-
return { block: false };
|
|
20709
|
-
const { analyzeBeforeCommit = true, blockCommit = false, blockPush = false } = config2;
|
|
20710
|
-
const { fixBeforeCommit = false, blockingSeverity = "CRITICAL", autoFix = false } = config2;
|
|
20711
|
-
const shouldBlock = operationType === "commit" ? blockCommit : blockPush;
|
|
20712
|
-
safeLog(`[handleGitOperationCheck] shouldBlock=${shouldBlock}, blockCommit=${blockCommit}, blockPush=${blockPush}, blockingSeverity=${blockingSeverity}`);
|
|
20713
|
-
try {
|
|
20714
|
-
const state = await getProjectState(dir);
|
|
20715
|
-
safeLog(`[handleGitOperationCheck] dir=${dir}, projectKey=${state?.projectKey ?? "NONE"}`);
|
|
20716
|
-
if (!state?.projectKey)
|
|
20717
|
-
return { block: false };
|
|
20718
|
-
const api2 = createSonarQubeAPI(config2, state);
|
|
20719
|
-
if (operationType === "push" || !analyzeBeforeCommit) {
|
|
20720
|
-
return checkExistingIssuesAndBlock(api2, state.projectKey, operationType, blockingSeverity, shouldBlock);
|
|
20721
|
-
}
|
|
20722
|
-
await showToast("SonarQube: Running pre-commit analysis...", "info");
|
|
20723
|
-
const analysisResult = await runAnalysis(config2, state, { projectKey: state.projectKey }, dir);
|
|
20724
|
-
safeLog(`[handleGitOperationCheck] qualityGate=${analysisResult.qualityGateStatus}`);
|
|
20725
|
-
const result = await processAnalysisResult(analysisResult, blockingSeverity, shouldBlock, fixBeforeCommit, autoFix);
|
|
20726
|
-
safeLog(`[handleGitOperationCheck] processResult block=${result.block}, message=${result.message}`);
|
|
20727
|
-
return result;
|
|
20728
|
-
} catch (err) {
|
|
20729
|
-
safeLog(`[handleGitOperationCheck] ERROR: ${err instanceof Error ? err.message : String(err)}`);
|
|
20730
|
-
return { block: false };
|
|
20731
|
-
}
|
|
20732
|
-
};
|
|
20733
|
-
const checkBlockingIssues = (issues, threshold) => {
|
|
20734
|
-
switch (threshold) {
|
|
20735
|
-
case "BLOCKER":
|
|
20736
|
-
return issues.blocker > 0;
|
|
20737
|
-
case "CRITICAL":
|
|
20738
|
-
return issues.blocker > 0 || issues.critical > 0;
|
|
20739
|
-
case "MAJOR":
|
|
20740
|
-
return issues.blocker > 0 || issues.critical > 0 || issues.major > 0;
|
|
20741
|
-
case "MINOR":
|
|
20742
|
-
return issues.blocker > 0 || issues.critical > 0 || issues.major > 0 || issues.minor > 0;
|
|
20743
|
-
case "INFO":
|
|
20744
|
-
return issues.blocker > 0 || issues.critical > 0 || issues.major > 0 || issues.minor > 0 || issues.info > 0;
|
|
20745
|
-
default:
|
|
20746
|
-
return issues.blocker > 0 || issues.critical > 0;
|
|
20747
|
-
}
|
|
20748
|
-
};
|
|
20749
20603
|
const logSonarQubeResult = async (input, output) => {
|
|
20750
20604
|
if (input.tool !== "sonarqube")
|
|
20751
20605
|
return;
|
|
@@ -20857,122 +20711,10 @@ Git operation completed with changes. Consider running:
|
|
|
20857
20711
|
await showToast("SonarQube: Analysis error occurred", "error");
|
|
20858
20712
|
}
|
|
20859
20713
|
}, "event"),
|
|
20860
|
-
"tool.execute.before": safeAsync(async (input,
|
|
20861
|
-
safeLog(`=== TOOL.EXECUTE.BEFORE HOOK CALLED === tool=${input.tool}`);
|
|
20714
|
+
"tool.execute.before": safeAsync(async (input, _output) => {
|
|
20862
20715
|
if (input.tool === "sonarqube") {
|
|
20863
20716
|
await loadPluginConfig();
|
|
20864
20717
|
}
|
|
20865
|
-
const isBashTool = input.tool === "bash" || input.tool === "mcp_bash";
|
|
20866
|
-
safeLog(`[pre-check] tool=${input.tool}, isBash=${isBashTool}, sessionId=${currentSessionId}`);
|
|
20867
|
-
if (isBashTool) {
|
|
20868
|
-
const args = output.args;
|
|
20869
|
-
const command = args?.command ?? "";
|
|
20870
|
-
safeLog(`[pre-check] command: ${command.substring(0, 50)}...`);
|
|
20871
|
-
if (/git\s+commit\b/.test(command) && !/--amend/.test(command)) {
|
|
20872
|
-
safeLog(`[pre-check] Detected git commit, running quality check...`);
|
|
20873
|
-
const result = await handleGitOperationCheck(output, "commit");
|
|
20874
|
-
safeLog(`[pre-check] commit check result: block=${result.block}, message=${result.message}`);
|
|
20875
|
-
if (result.block && args) {
|
|
20876
|
-
const aiMessage = `echo "
|
|
20877
|
-
================================================================================
|
|
20878
|
-
\uD83D\uDEAB COMMIT BLOCKED - SonarQube Quality Gate Failed
|
|
20879
|
-
================================================================================
|
|
20880
|
-
|
|
20881
|
-
STOP! Your commit was blocked. DO NOT:
|
|
20882
|
-
❌ Delete opencode.json
|
|
20883
|
-
❌ Remove plugins
|
|
20884
|
-
❌ Retry without fixing issues
|
|
20885
|
-
|
|
20886
|
-
================================================================================
|
|
20887
|
-
\uD83D\uDCCB YOU HAVE A SONARQUBE TOOL - USE IT!
|
|
20888
|
-
================================================================================
|
|
20889
|
-
|
|
20890
|
-
You have access to the 'sonarqube' MCP tool (same as mcp_sonarqube).
|
|
20891
|
-
Call it NOW to see exactly what issues are blocking you:
|
|
20892
|
-
|
|
20893
|
-
sonarqube({ action: 'issues' }) ← CALL THIS TOOL NOW!
|
|
20894
|
-
|
|
20895
|
-
This tool will show you:
|
|
20896
|
-
- Every issue found in the code
|
|
20897
|
-
- The file and line number
|
|
20898
|
-
- The severity (BLOCKER/CRITICAL/MAJOR/MINOR/INFO)
|
|
20899
|
-
- Description of what's wrong
|
|
20900
|
-
- How to fix it
|
|
20901
|
-
|
|
20902
|
-
Other useful tool calls:
|
|
20903
|
-
sonarqube({ action: 'status' }) ← See why quality gate failed
|
|
20904
|
-
sonarqube({ action: 'analyze' }) ← Re-run analysis after fixes
|
|
20905
|
-
|
|
20906
|
-
================================================================================
|
|
20907
|
-
⚡ WHAT TO DO NOW:
|
|
20908
|
-
================================================================================
|
|
20909
|
-
|
|
20910
|
-
1. CALL THE TOOL: sonarqube({ action: 'issues' })
|
|
20911
|
-
2. READ the issues it returns
|
|
20912
|
-
3. FIX the code problems
|
|
20913
|
-
4. THEN try to commit again
|
|
20914
|
-
|
|
20915
|
-
The quality gate may fail due to issues in existing code, not just your changes.
|
|
20916
|
-
Use sonarqube({ action: 'status' }) to see what conditions failed.
|
|
20917
|
-
|
|
20918
|
-
================================================================================
|
|
20919
|
-
" && exit 1`;
|
|
20920
|
-
args.command = aiMessage;
|
|
20921
|
-
safeLog(`[pre-check] Commit BLOCKED - command replaced with AI-friendly message`);
|
|
20922
|
-
await showToast("Commit blocked by SonarQube quality gate!", "error");
|
|
20923
|
-
}
|
|
20924
|
-
}
|
|
20925
|
-
if (/git\s+push\b/.test(command)) {
|
|
20926
|
-
safeLog(`[pre-check] Detected git push, running quality check...`);
|
|
20927
|
-
const result = await handleGitOperationCheck(output, "push");
|
|
20928
|
-
if (result.block && args) {
|
|
20929
|
-
const aiMessage = `echo "
|
|
20930
|
-
================================================================================
|
|
20931
|
-
\uD83D\uDEAB PUSH BLOCKED - SonarQube Quality Gate Failed
|
|
20932
|
-
================================================================================
|
|
20933
|
-
|
|
20934
|
-
STOP! Your push was blocked. DO NOT:
|
|
20935
|
-
❌ Delete opencode.json
|
|
20936
|
-
❌ Remove plugins
|
|
20937
|
-
❌ Retry without fixing issues
|
|
20938
|
-
|
|
20939
|
-
================================================================================
|
|
20940
|
-
\uD83D\uDCCB YOU HAVE A SONARQUBE TOOL - USE IT!
|
|
20941
|
-
================================================================================
|
|
20942
|
-
|
|
20943
|
-
You have access to the 'sonarqube' MCP tool (same as mcp_sonarqube).
|
|
20944
|
-
Call it NOW to see exactly what issues are blocking you:
|
|
20945
|
-
|
|
20946
|
-
sonarqube({ action: 'issues' }) ← CALL THIS TOOL NOW!
|
|
20947
|
-
|
|
20948
|
-
This tool will show you:
|
|
20949
|
-
- Every issue found in the code
|
|
20950
|
-
- The file and line number
|
|
20951
|
-
- The severity (BLOCKER/CRITICAL/MAJOR/MINOR/INFO)
|
|
20952
|
-
- Description of what's wrong
|
|
20953
|
-
|
|
20954
|
-
Other useful tool calls:
|
|
20955
|
-
sonarqube({ action: 'status' }) ← See why quality gate failed
|
|
20956
|
-
sonarqube({ action: 'analyze' }) ← Re-run analysis after fixes
|
|
20957
|
-
|
|
20958
|
-
================================================================================
|
|
20959
|
-
⚡ WHAT TO DO NOW:
|
|
20960
|
-
================================================================================
|
|
20961
|
-
|
|
20962
|
-
1. CALL THE TOOL: sonarqube({ action: 'issues' })
|
|
20963
|
-
2. READ the issues it returns
|
|
20964
|
-
3. FIX the code problems
|
|
20965
|
-
4. Commit your fixes
|
|
20966
|
-
5. THEN try to push again
|
|
20967
|
-
|
|
20968
|
-
================================================================================
|
|
20969
|
-
" && exit 1`;
|
|
20970
|
-
args.command = aiMessage;
|
|
20971
|
-
safeLog(`[pre-check] Push BLOCKED - command replaced with AI-friendly message`);
|
|
20972
|
-
await showToast("Push blocked by SonarQube quality gate!", "error");
|
|
20973
|
-
}
|
|
20974
|
-
}
|
|
20975
|
-
}
|
|
20976
20718
|
}, "tool.execute.before"),
|
|
20977
20719
|
"tool.execute.after": safeAsync(async (input, output) => {
|
|
20978
20720
|
await logSonarQubeResult(input, output);
|