opencode-sonarqube 1.2.40 → 1.2.42

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.
Files changed (2) hide show
  1. package/dist/index.js +1 -259
  2. 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, output) => {
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-sonarqube",
3
- "version": "1.2.40",
3
+ "version": "1.2.42",
4
4
  "description": "OpenCode Plugin for SonarQube integration - Enterprise-level code quality from the start",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",