opencode-sonarqube 1.2.18 → 1.2.20
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 +156 -166
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3999,10 +3999,10 @@ function numberToRating(num) {
|
|
|
3999
3999
|
const ratings = ["A", "B", "C", "D", "E"];
|
|
4000
4000
|
return ratings[num - 1] ?? "?";
|
|
4001
4001
|
}
|
|
4002
|
-
function SonarQubeError(message,
|
|
4002
|
+
function SonarQubeError(message, code, statusCode) {
|
|
4003
4003
|
const error45 = new Error(message);
|
|
4004
4004
|
error45.name = "SonarQubeError";
|
|
4005
|
-
error45.code =
|
|
4005
|
+
error45.code = code;
|
|
4006
4006
|
error45.statusCode = statusCode;
|
|
4007
4007
|
return error45;
|
|
4008
4008
|
}
|
|
@@ -4110,18 +4110,18 @@ var init_types2 = __esm(() => {
|
|
|
4110
4110
|
});
|
|
4111
4111
|
|
|
4112
4112
|
// src/utils/state.ts
|
|
4113
|
-
function getStatePath(
|
|
4114
|
-
return `${
|
|
4113
|
+
function getStatePath(directory) {
|
|
4114
|
+
return `${directory}/${STATE_DIR}/${STATE_FILE}`;
|
|
4115
4115
|
}
|
|
4116
|
-
function getStateDir(
|
|
4117
|
-
return `${
|
|
4116
|
+
function getStateDir(directory) {
|
|
4117
|
+
return `${directory}/${STATE_DIR}`;
|
|
4118
4118
|
}
|
|
4119
|
-
async function hasProjectState(
|
|
4120
|
-
const statePath = getStatePath(
|
|
4119
|
+
async function hasProjectState(directory) {
|
|
4120
|
+
const statePath = getStatePath(directory);
|
|
4121
4121
|
return Bun.file(statePath).exists();
|
|
4122
4122
|
}
|
|
4123
|
-
async function loadProjectState(
|
|
4124
|
-
const statePath = getStatePath(
|
|
4123
|
+
async function loadProjectState(directory) {
|
|
4124
|
+
const statePath = getStatePath(directory);
|
|
4125
4125
|
const exists = await Bun.file(statePath).exists();
|
|
4126
4126
|
if (!exists) {
|
|
4127
4127
|
return null;
|
|
@@ -4139,9 +4139,9 @@ async function loadProjectState(directory2) {
|
|
|
4139
4139
|
return null;
|
|
4140
4140
|
}
|
|
4141
4141
|
}
|
|
4142
|
-
async function saveProjectState(
|
|
4143
|
-
const stateDir = getStateDir(
|
|
4144
|
-
const statePath = getStatePath(
|
|
4142
|
+
async function saveProjectState(directory, state) {
|
|
4143
|
+
const stateDir = getStateDir(directory);
|
|
4144
|
+
const statePath = getStatePath(directory);
|
|
4145
4145
|
const dirExists = await Bun.file(stateDir).exists();
|
|
4146
4146
|
if (!dirExists) {
|
|
4147
4147
|
await Bun.write(`${stateDir}/.gitkeep`, "");
|
|
@@ -4161,8 +4161,8 @@ function createInitialState(options) {
|
|
|
4161
4161
|
setupComplete: true
|
|
4162
4162
|
};
|
|
4163
4163
|
}
|
|
4164
|
-
async function ensureGitignore(
|
|
4165
|
-
const gitignorePath = `${
|
|
4164
|
+
async function ensureGitignore(directory) {
|
|
4165
|
+
const gitignorePath = `${directory}/.gitignore`;
|
|
4166
4166
|
const entry = ".sonarqube/";
|
|
4167
4167
|
const exists = await Bun.file(gitignorePath).exists();
|
|
4168
4168
|
if (!exists) {
|
|
@@ -16567,15 +16567,15 @@ function loadConfig(rawConfig) {
|
|
|
16567
16567
|
configLogger.info("<<< loadConfig success", { url: result.data.url, level: result.data.level });
|
|
16568
16568
|
return result.data;
|
|
16569
16569
|
}
|
|
16570
|
-
async function deriveProjectKey(
|
|
16570
|
+
async function deriveProjectKey(directory) {
|
|
16571
16571
|
try {
|
|
16572
|
-
const packageJsonPath = `${
|
|
16572
|
+
const packageJsonPath = `${directory}/package.json`;
|
|
16573
16573
|
const packageJson = await Bun.file(packageJsonPath).json();
|
|
16574
16574
|
if (packageJson.name) {
|
|
16575
16575
|
return packageJson.name;
|
|
16576
16576
|
}
|
|
16577
16577
|
} catch {}
|
|
16578
|
-
const dirName =
|
|
16578
|
+
const dirName = directory.split("/").pop();
|
|
16579
16579
|
if (dirName && dirName.length > 0) {
|
|
16580
16580
|
return dirName;
|
|
16581
16581
|
}
|
|
@@ -16678,22 +16678,22 @@ var logger = new Logger("opencode-sonarqube");
|
|
|
16678
16678
|
|
|
16679
16679
|
// src/scanner/config.ts
|
|
16680
16680
|
var logger2 = new Logger("scanner-config");
|
|
16681
|
-
async function checkProjectFiles(
|
|
16681
|
+
async function checkProjectFiles(directory) {
|
|
16682
16682
|
const checks3 = await Promise.all([
|
|
16683
|
-
Bun.file(`${
|
|
16684
|
-
Bun.file(`${
|
|
16685
|
-
Bun.file(`${
|
|
16686
|
-
Bun.file(`${
|
|
16687
|
-
Bun.file(`${
|
|
16688
|
-
Bun.file(`${
|
|
16689
|
-
Bun.file(`${
|
|
16690
|
-
Bun.file(`${
|
|
16691
|
-
Bun.file(`${
|
|
16692
|
-
Bun.file(`${
|
|
16693
|
-
Bun.file(`${
|
|
16694
|
-
Bun.file(`${
|
|
16695
|
-
Bun.file(`${
|
|
16696
|
-
Bun.file(`${
|
|
16683
|
+
Bun.file(`${directory}/package.json`).exists(),
|
|
16684
|
+
Bun.file(`${directory}/tsconfig.json`).exists(),
|
|
16685
|
+
Bun.file(`${directory}/requirements.txt`).exists(),
|
|
16686
|
+
Bun.file(`${directory}/pyproject.toml`).exists(),
|
|
16687
|
+
Bun.file(`${directory}/pom.xml`).exists(),
|
|
16688
|
+
Bun.file(`${directory}/build.gradle`).exists(),
|
|
16689
|
+
Bun.file(`${directory}/go.mod`).exists(),
|
|
16690
|
+
Bun.file(`${directory}/Cargo.toml`).exists(),
|
|
16691
|
+
Bun.file(`${directory}/composer.json`).exists(),
|
|
16692
|
+
Bun.file(`${directory}/Gemfile`).exists(),
|
|
16693
|
+
Bun.file(`${directory}/package-lock.json`).exists(),
|
|
16694
|
+
Bun.file(`${directory}/yarn.lock`).exists(),
|
|
16695
|
+
Bun.file(`${directory}/pnpm-lock.yaml`).exists(),
|
|
16696
|
+
Bun.file(`${directory}/bun.lockb`).exists()
|
|
16697
16697
|
]);
|
|
16698
16698
|
return {
|
|
16699
16699
|
hasPackageJson: checks3[0],
|
|
@@ -16748,9 +16748,9 @@ function detectTestFramework(deps) {
|
|
|
16748
16748
|
}
|
|
16749
16749
|
return {};
|
|
16750
16750
|
}
|
|
16751
|
-
async function parsePackageJson(
|
|
16751
|
+
async function parsePackageJson(directory) {
|
|
16752
16752
|
try {
|
|
16753
|
-
const packageJson = await Bun.file(`${
|
|
16753
|
+
const packageJson = await Bun.file(`${directory}/package.json`).json();
|
|
16754
16754
|
const deps = {
|
|
16755
16755
|
...packageJson.dependencies,
|
|
16756
16756
|
...packageJson.devDependencies
|
|
@@ -16794,13 +16794,13 @@ function detectLanguages(checks3) {
|
|
|
16794
16794
|
}
|
|
16795
16795
|
return languages.length > 0 ? languages : ["generic"];
|
|
16796
16796
|
}
|
|
16797
|
-
async function detectProjectType(
|
|
16798
|
-
const checks3 = await checkProjectFiles(
|
|
16797
|
+
async function detectProjectType(directory) {
|
|
16798
|
+
const checks3 = await checkProjectFiles(directory);
|
|
16799
16799
|
const languages = detectLanguages(checks3);
|
|
16800
16800
|
const result = { languages };
|
|
16801
16801
|
if (checks3.hasPackageJson) {
|
|
16802
16802
|
result.packageManager = detectPackageManager(checks3);
|
|
16803
|
-
const packageInfo = await parsePackageJson(
|
|
16803
|
+
const packageInfo = await parsePackageJson(directory);
|
|
16804
16804
|
result.framework = packageInfo.framework;
|
|
16805
16805
|
result.testFramework = packageInfo.testFramework;
|
|
16806
16806
|
result.coverageReportPath = packageInfo.coverageReportPath;
|
|
@@ -16811,8 +16811,8 @@ async function detectProjectType(directory2) {
|
|
|
16811
16811
|
});
|
|
16812
16812
|
return result;
|
|
16813
16813
|
}
|
|
16814
|
-
async function generatePropertiesContent(options, config2,
|
|
16815
|
-
const dir =
|
|
16814
|
+
async function generatePropertiesContent(options, config2, directory) {
|
|
16815
|
+
const dir = directory ?? process.cwd();
|
|
16816
16816
|
const detection = await detectProjectType(dir);
|
|
16817
16817
|
const lines = [
|
|
16818
16818
|
"# =============================================================================",
|
|
@@ -16934,8 +16934,8 @@ function getTestPatterns(languages) {
|
|
|
16934
16934
|
}
|
|
16935
16935
|
return patterns.join(",");
|
|
16936
16936
|
}
|
|
16937
|
-
async function writePropertiesFile(options, config2,
|
|
16938
|
-
const dir =
|
|
16937
|
+
async function writePropertiesFile(options, config2, directory) {
|
|
16938
|
+
const dir = directory ?? process.cwd();
|
|
16939
16939
|
const content = await generatePropertiesContent(options, config2, dir);
|
|
16940
16940
|
const filePath = `${dir}/sonar-project.properties`;
|
|
16941
16941
|
await Bun.write(filePath, content);
|
|
@@ -17125,8 +17125,8 @@ init_types2();
|
|
|
17125
17125
|
class ProjectsAPI {
|
|
17126
17126
|
client;
|
|
17127
17127
|
logger;
|
|
17128
|
-
constructor(
|
|
17129
|
-
this.client =
|
|
17128
|
+
constructor(client, logger3) {
|
|
17129
|
+
this.client = client;
|
|
17130
17130
|
this.logger = logger3 ?? new Logger("sonarqube-projects");
|
|
17131
17131
|
}
|
|
17132
17132
|
async create(options) {
|
|
@@ -17225,8 +17225,8 @@ class ProjectsAPI {
|
|
|
17225
17225
|
class IssuesAPI {
|
|
17226
17226
|
client;
|
|
17227
17227
|
logger;
|
|
17228
|
-
constructor(
|
|
17229
|
-
this.client =
|
|
17228
|
+
constructor(client, logger3) {
|
|
17229
|
+
this.client = client;
|
|
17230
17230
|
this.logger = logger3 ?? new Logger("sonarqube-issues");
|
|
17231
17231
|
}
|
|
17232
17232
|
async search(options) {
|
|
@@ -17403,8 +17403,8 @@ var METRIC_KEYS = {
|
|
|
17403
17403
|
class QualityGateAPI {
|
|
17404
17404
|
client;
|
|
17405
17405
|
logger;
|
|
17406
|
-
constructor(
|
|
17407
|
-
this.client =
|
|
17406
|
+
constructor(client, logger3) {
|
|
17407
|
+
this.client = client;
|
|
17408
17408
|
this.logger = logger3 ?? new Logger("sonarqube-quality-gate");
|
|
17409
17409
|
}
|
|
17410
17410
|
async getStatus(projectKey, branch) {
|
|
@@ -17711,8 +17711,8 @@ class RulesAPI {
|
|
|
17711
17711
|
client;
|
|
17712
17712
|
logger;
|
|
17713
17713
|
cache = new Map;
|
|
17714
|
-
constructor(
|
|
17715
|
-
this.client =
|
|
17714
|
+
constructor(client, logger3) {
|
|
17715
|
+
this.client = client;
|
|
17716
17716
|
this.logger = logger3 ?? new Logger("sonarqube-rules");
|
|
17717
17717
|
}
|
|
17718
17718
|
parseRuleResponse(rule) {
|
|
@@ -17813,8 +17813,8 @@ class RulesAPI {
|
|
|
17813
17813
|
class SourcesAPI {
|
|
17814
17814
|
client;
|
|
17815
17815
|
logger;
|
|
17816
|
-
constructor(
|
|
17817
|
-
this.client =
|
|
17816
|
+
constructor(client, logger3) {
|
|
17817
|
+
this.client = client;
|
|
17818
17818
|
this.logger = logger3 ?? new Logger("sonarqube-sources");
|
|
17819
17819
|
}
|
|
17820
17820
|
async getSourceLines(componentKey, from, to) {
|
|
@@ -17825,9 +17825,9 @@ class SourcesAPI {
|
|
|
17825
17825
|
from: from ?? 1,
|
|
17826
17826
|
to
|
|
17827
17827
|
});
|
|
17828
|
-
return response.sources.map(([line,
|
|
17828
|
+
return response.sources.map(([line, code]) => ({
|
|
17829
17829
|
line,
|
|
17830
|
-
code: this.stripHtmlTags(
|
|
17830
|
+
code: this.stripHtmlTags(code)
|
|
17831
17831
|
}));
|
|
17832
17832
|
} catch (error45) {
|
|
17833
17833
|
this.logger.warn(`Failed to fetch source lines: ${error45}`);
|
|
@@ -17951,8 +17951,8 @@ class SourcesAPI {
|
|
|
17951
17951
|
class DuplicationsAPI {
|
|
17952
17952
|
client;
|
|
17953
17953
|
logger;
|
|
17954
|
-
constructor(
|
|
17955
|
-
this.client =
|
|
17954
|
+
constructor(client, logger3) {
|
|
17955
|
+
this.client = client;
|
|
17956
17956
|
this.logger = logger3 ?? new Logger("sonarqube-duplications");
|
|
17957
17957
|
}
|
|
17958
17958
|
async getDuplications(componentKey) {
|
|
@@ -18056,19 +18056,13 @@ class DuplicationsAPI {
|
|
|
18056
18056
|
}
|
|
18057
18057
|
}
|
|
18058
18058
|
// src/api/ce.ts
|
|
18059
|
-
|
|
18060
|
-
var debugLog = (msg) => {
|
|
18061
|
-
try {
|
|
18062
|
-
appendFileSync("/tmp/sonarqube-plugin-debug.log", `${new Date().toISOString()} [ce] ${msg}
|
|
18063
|
-
`);
|
|
18064
|
-
} catch {}
|
|
18065
|
-
};
|
|
18059
|
+
var debugLog = (_msg) => {};
|
|
18066
18060
|
|
|
18067
18061
|
class ComputeEngineAPI {
|
|
18068
18062
|
client;
|
|
18069
18063
|
logger;
|
|
18070
|
-
constructor(
|
|
18071
|
-
this.client =
|
|
18064
|
+
constructor(client, logger3) {
|
|
18065
|
+
this.client = client;
|
|
18072
18066
|
this.logger = logger3 ?? new Logger("sonarqube-ce");
|
|
18073
18067
|
}
|
|
18074
18068
|
async getTask(taskId) {
|
|
@@ -18216,8 +18210,8 @@ class ComputeEngineAPI {
|
|
|
18216
18210
|
class ProjectAnalysesAPI {
|
|
18217
18211
|
client;
|
|
18218
18212
|
logger;
|
|
18219
|
-
constructor(
|
|
18220
|
-
this.client =
|
|
18213
|
+
constructor(client, logger3) {
|
|
18214
|
+
this.client = client;
|
|
18221
18215
|
this.logger = logger3 ?? new Logger("sonarqube-analyses");
|
|
18222
18216
|
}
|
|
18223
18217
|
async getAnalyses(options) {
|
|
@@ -18284,8 +18278,8 @@ class ProjectAnalysesAPI {
|
|
|
18284
18278
|
class QualityProfilesAPI {
|
|
18285
18279
|
client;
|
|
18286
18280
|
logger;
|
|
18287
|
-
constructor(
|
|
18288
|
-
this.client =
|
|
18281
|
+
constructor(client, logger3) {
|
|
18282
|
+
this.client = client;
|
|
18289
18283
|
this.logger = logger3 ?? new Logger("sonarqube-profiles");
|
|
18290
18284
|
}
|
|
18291
18285
|
async getProjectProfiles(projectKey) {
|
|
@@ -18376,8 +18370,8 @@ class QualityProfilesAPI {
|
|
|
18376
18370
|
class BranchesAPI {
|
|
18377
18371
|
client;
|
|
18378
18372
|
logger;
|
|
18379
|
-
constructor(
|
|
18380
|
-
this.client =
|
|
18373
|
+
constructor(client, logger3) {
|
|
18374
|
+
this.client = client;
|
|
18381
18375
|
this.logger = logger3 ?? new Logger("sonarqube-branches");
|
|
18382
18376
|
}
|
|
18383
18377
|
async getBranches(projectKey) {
|
|
@@ -18527,8 +18521,8 @@ var COMMON_METRICS = [
|
|
|
18527
18521
|
class MetricsAPI {
|
|
18528
18522
|
client;
|
|
18529
18523
|
logger;
|
|
18530
|
-
constructor(
|
|
18531
|
-
this.client =
|
|
18524
|
+
constructor(client, logger3) {
|
|
18525
|
+
this.client = client;
|
|
18532
18526
|
this.logger = logger3 ?? new Logger("sonarqube-metrics");
|
|
18533
18527
|
}
|
|
18534
18528
|
async getMetricDefinitions() {
|
|
@@ -18657,8 +18651,8 @@ class MetricsAPI {
|
|
|
18657
18651
|
class ComponentsAPI {
|
|
18658
18652
|
client;
|
|
18659
18653
|
logger;
|
|
18660
|
-
constructor(
|
|
18661
|
-
this.client =
|
|
18654
|
+
constructor(client, logger3) {
|
|
18655
|
+
this.client = client;
|
|
18662
18656
|
this.logger = logger3 ?? new Logger("sonarqube-components");
|
|
18663
18657
|
}
|
|
18664
18658
|
componentToSummary(comp, includeLanguage) {
|
|
@@ -18782,21 +18776,21 @@ class SonarQubeAPI {
|
|
|
18782
18776
|
metrics;
|
|
18783
18777
|
components;
|
|
18784
18778
|
logger;
|
|
18785
|
-
constructor(
|
|
18779
|
+
constructor(client, logger3) {
|
|
18786
18780
|
this.logger = logger3 ?? new Logger("sonarqube-api");
|
|
18787
|
-
this.client =
|
|
18788
|
-
this.projects = new ProjectsAPI(
|
|
18789
|
-
this.issues = new IssuesAPI(
|
|
18790
|
-
this.qualityGate = new QualityGateAPI(
|
|
18791
|
-
this.rules = new RulesAPI(
|
|
18792
|
-
this.sources = new SourcesAPI(
|
|
18793
|
-
this.duplications = new DuplicationsAPI(
|
|
18794
|
-
this.ce = new ComputeEngineAPI(
|
|
18795
|
-
this.analyses = new ProjectAnalysesAPI(
|
|
18796
|
-
this.profiles = new QualityProfilesAPI(
|
|
18797
|
-
this.branches = new BranchesAPI(
|
|
18798
|
-
this.metrics = new MetricsAPI(
|
|
18799
|
-
this.components = new ComponentsAPI(
|
|
18781
|
+
this.client = client;
|
|
18782
|
+
this.projects = new ProjectsAPI(client, this.logger.child("projects"));
|
|
18783
|
+
this.issues = new IssuesAPI(client, this.logger.child("issues"));
|
|
18784
|
+
this.qualityGate = new QualityGateAPI(client, this.logger.child("quality-gate"));
|
|
18785
|
+
this.rules = new RulesAPI(client, this.logger.child("rules"));
|
|
18786
|
+
this.sources = new SourcesAPI(client, this.logger.child("sources"));
|
|
18787
|
+
this.duplications = new DuplicationsAPI(client, this.logger.child("duplications"));
|
|
18788
|
+
this.ce = new ComputeEngineAPI(client, this.logger.child("ce"));
|
|
18789
|
+
this.analyses = new ProjectAnalysesAPI(client, this.logger.child("analyses"));
|
|
18790
|
+
this.profiles = new QualityProfilesAPI(client, this.logger.child("profiles"));
|
|
18791
|
+
this.branches = new BranchesAPI(client, this.logger.child("branches"));
|
|
18792
|
+
this.metrics = new MetricsAPI(client, this.logger.child("metrics"));
|
|
18793
|
+
this.components = new ComponentsAPI(client, this.logger.child("components"));
|
|
18800
18794
|
}
|
|
18801
18795
|
async healthCheck() {
|
|
18802
18796
|
return this.client.healthCheck();
|
|
@@ -18820,8 +18814,8 @@ class SonarQubeAPI {
|
|
|
18820
18814
|
}
|
|
18821
18815
|
}
|
|
18822
18816
|
function createSonarQubeAPIWithToken(url2, token, logger3) {
|
|
18823
|
-
const
|
|
18824
|
-
return new SonarQubeAPI(
|
|
18817
|
+
const client = createClientWithToken(url2, token, logger3?.child("client"));
|
|
18818
|
+
return new SonarQubeAPI(client, logger3);
|
|
18825
18819
|
}
|
|
18826
18820
|
function createSonarQubeAPI(config2, state, logger3) {
|
|
18827
18821
|
return createSonarQubeAPIWithToken(config2.url, state.projectToken, logger3);
|
|
@@ -18939,8 +18933,8 @@ function extractTaskId(output) {
|
|
|
18939
18933
|
const altMatch = altRegex.exec(output);
|
|
18940
18934
|
return altMatch?.[1];
|
|
18941
18935
|
}
|
|
18942
|
-
async function runScanner(config2, state, options,
|
|
18943
|
-
const dir =
|
|
18936
|
+
async function runScanner(config2, state, options, directory) {
|
|
18937
|
+
const dir = directory ?? process.cwd();
|
|
18944
18938
|
logger3.info(`Starting SonarQube analysis for ${options.projectKey}`);
|
|
18945
18939
|
const args = [
|
|
18946
18940
|
`-Dsonar.host.url=${config2.url}`,
|
|
@@ -19014,8 +19008,8 @@ ${stderr}` : "");
|
|
|
19014
19008
|
};
|
|
19015
19009
|
}
|
|
19016
19010
|
}
|
|
19017
|
-
async function runAnalysis(config2, state, options,
|
|
19018
|
-
const dir =
|
|
19011
|
+
async function runAnalysis(config2, state, options, directory) {
|
|
19012
|
+
const dir = directory ?? process.cwd();
|
|
19019
19013
|
const api2 = createSonarQubeAPI(config2, state);
|
|
19020
19014
|
const projectName = options.projectName ?? options.projectKey;
|
|
19021
19015
|
const propsFile = Bun.file(`${dir}/sonar-project.properties`);
|
|
@@ -19140,15 +19134,15 @@ var QUALITY_GATE_MAPPING = {
|
|
|
19140
19134
|
relaxed: "Sonar way",
|
|
19141
19135
|
off: "Sonar way"
|
|
19142
19136
|
};
|
|
19143
|
-
async function needsBootstrap(
|
|
19144
|
-
logger5.info(">>> needsBootstrap called", { directory
|
|
19145
|
-
const hasState = await hasProjectState(
|
|
19146
|
-
logger5.info("hasProjectState result", { hasState, directory
|
|
19137
|
+
async function needsBootstrap(directory) {
|
|
19138
|
+
logger5.info(">>> needsBootstrap called", { directory });
|
|
19139
|
+
const hasState = await hasProjectState(directory);
|
|
19140
|
+
logger5.info("hasProjectState result", { hasState, directory });
|
|
19147
19141
|
if (!hasState) {
|
|
19148
19142
|
logger5.info("<<< needsBootstrap: true (no state file)");
|
|
19149
19143
|
return true;
|
|
19150
19144
|
}
|
|
19151
|
-
const state = await loadProjectState(
|
|
19145
|
+
const state = await loadProjectState(directory);
|
|
19152
19146
|
const needsBoot = !state?.setupComplete;
|
|
19153
19147
|
logger5.info("<<< needsBootstrap result", {
|
|
19154
19148
|
needsBoot,
|
|
@@ -19158,8 +19152,8 @@ async function needsBootstrap(directory2) {
|
|
|
19158
19152
|
});
|
|
19159
19153
|
return needsBoot;
|
|
19160
19154
|
}
|
|
19161
|
-
async function getProjectState(
|
|
19162
|
-
return loadProjectState(
|
|
19155
|
+
async function getProjectState(directory) {
|
|
19156
|
+
return loadProjectState(directory);
|
|
19163
19157
|
}
|
|
19164
19158
|
function generateTokenName(projectKey) {
|
|
19165
19159
|
const timestamp = Date.now();
|
|
@@ -19184,36 +19178,36 @@ function resolveDirectoryFromImportMeta() {
|
|
|
19184
19178
|
} catch {}
|
|
19185
19179
|
return null;
|
|
19186
19180
|
}
|
|
19187
|
-
async function generateAnalysisToken(
|
|
19181
|
+
async function generateAnalysisToken(client, tokenName, projectKey) {
|
|
19188
19182
|
try {
|
|
19189
|
-
return await
|
|
19183
|
+
return await client.post("/api/user_tokens/generate", { name: tokenName, type: "PROJECT_ANALYSIS_TOKEN", projectKey });
|
|
19190
19184
|
} catch {
|
|
19191
19185
|
logger5.warn("PROJECT_ANALYSIS_TOKEN not available, using GLOBAL_ANALYSIS_TOKEN");
|
|
19192
|
-
return await
|
|
19186
|
+
return await client.post("/api/user_tokens/generate", { name: tokenName, type: "GLOBAL_ANALYSIS_TOKEN" });
|
|
19193
19187
|
}
|
|
19194
19188
|
}
|
|
19195
19189
|
async function bootstrap(options) {
|
|
19196
|
-
let { config: config2, directory
|
|
19197
|
-
logger5.info("Starting bootstrap", { directory
|
|
19198
|
-
if (!isValidDirectory(
|
|
19190
|
+
let { config: config2, directory, force = false } = options;
|
|
19191
|
+
logger5.info("Starting bootstrap", { directory, projectKey: config2.projectKey || "(auto)" });
|
|
19192
|
+
if (!isValidDirectory(directory)) {
|
|
19199
19193
|
const resolved = resolveDirectoryFromImportMeta();
|
|
19200
19194
|
if (resolved) {
|
|
19201
|
-
|
|
19195
|
+
directory = resolved;
|
|
19202
19196
|
}
|
|
19203
19197
|
}
|
|
19204
|
-
if (!isValidDirectory(
|
|
19198
|
+
if (!isValidDirectory(directory)) {
|
|
19205
19199
|
return {
|
|
19206
19200
|
success: false,
|
|
19207
19201
|
projectKey: "",
|
|
19208
19202
|
projectToken: "",
|
|
19209
19203
|
qualityGate: "",
|
|
19210
19204
|
languages: [],
|
|
19211
|
-
message: `Invalid directory: ${
|
|
19205
|
+
message: `Invalid directory: ${directory}`,
|
|
19212
19206
|
isNewProject: false
|
|
19213
19207
|
};
|
|
19214
19208
|
}
|
|
19215
19209
|
if (!force) {
|
|
19216
|
-
const existingState = await loadProjectState(
|
|
19210
|
+
const existingState = await loadProjectState(directory);
|
|
19217
19211
|
if (existingState?.setupComplete) {
|
|
19218
19212
|
logger5.info("Project already bootstrapped", { projectKey: existingState.projectKey });
|
|
19219
19213
|
return {
|
|
@@ -19233,8 +19227,8 @@ async function bootstrap(options) {
|
|
|
19233
19227
|
throw SetupError(`Cannot connect to SonarQube: ${health.error}`);
|
|
19234
19228
|
}
|
|
19235
19229
|
logger5.info("Connected to SonarQube", { version: health.version });
|
|
19236
|
-
const detection = await detectProjectType(
|
|
19237
|
-
const projectKey = config2.projectKey || sanitizeProjectKey(await deriveProjectKey(
|
|
19230
|
+
const detection = await detectProjectType(directory);
|
|
19231
|
+
const projectKey = config2.projectKey || sanitizeProjectKey(await deriveProjectKey(directory));
|
|
19238
19232
|
const projectName = config2.projectName || projectKey;
|
|
19239
19233
|
const projectsApi = new ProjectsAPI(adminClient);
|
|
19240
19234
|
const exists = await projectsApi.exists(projectKey);
|
|
@@ -19259,8 +19253,8 @@ async function bootstrap(options) {
|
|
|
19259
19253
|
languages: detection.languages,
|
|
19260
19254
|
qualityGate: qualityGateName
|
|
19261
19255
|
});
|
|
19262
|
-
await saveProjectState(
|
|
19263
|
-
await ensureGitignore(
|
|
19256
|
+
await saveProjectState(directory, state);
|
|
19257
|
+
await ensureGitignore(directory);
|
|
19264
19258
|
logger5.info("Bootstrap complete", { projectKey, isNewProject });
|
|
19265
19259
|
return {
|
|
19266
19260
|
success: true,
|
|
@@ -19272,19 +19266,19 @@ async function bootstrap(options) {
|
|
|
19272
19266
|
isNewProject
|
|
19273
19267
|
};
|
|
19274
19268
|
}
|
|
19275
|
-
async function setProjectQualityGate(
|
|
19276
|
-
const gatesResponse = await
|
|
19269
|
+
async function setProjectQualityGate(client, projectKey, qualityGateName) {
|
|
19270
|
+
const gatesResponse = await client.get("/api/qualitygates/list");
|
|
19277
19271
|
const gate = gatesResponse.qualitygates.find((g) => g.name === qualityGateName);
|
|
19278
19272
|
if (!gate) {
|
|
19279
19273
|
logger5.warn(`Quality gate '${qualityGateName}' not found, using default`);
|
|
19280
19274
|
return;
|
|
19281
19275
|
}
|
|
19282
|
-
await
|
|
19276
|
+
await client.post("/api/qualitygates/select", {
|
|
19283
19277
|
projectKey,
|
|
19284
19278
|
gateId: gate.id
|
|
19285
19279
|
});
|
|
19286
19280
|
}
|
|
19287
|
-
async function configureProjectSettings(
|
|
19281
|
+
async function configureProjectSettings(client, projectKey, languages, config2) {
|
|
19288
19282
|
const settings = [];
|
|
19289
19283
|
settings.push({ key: "sonar.sourceEncoding", value: "UTF-8" });
|
|
19290
19284
|
if (languages.includes("typescript") || languages.includes("javascript")) {
|
|
@@ -19301,7 +19295,7 @@ async function configureProjectSettings(client2, projectKey, languages, config2)
|
|
|
19301
19295
|
}
|
|
19302
19296
|
for (const setting of settings) {
|
|
19303
19297
|
try {
|
|
19304
|
-
await
|
|
19298
|
+
await client.post("/api/settings/set", {
|
|
19305
19299
|
key: setting.key,
|
|
19306
19300
|
value: setting.value,
|
|
19307
19301
|
component: projectKey
|
|
@@ -19323,7 +19317,7 @@ function isInCooldown() {
|
|
|
19323
19317
|
const now = Date.now();
|
|
19324
19318
|
return now - lastAnalysisTime < ANALYSIS_COOLDOWN_MS;
|
|
19325
19319
|
}
|
|
19326
|
-
async function handleBootstrap(config2,
|
|
19320
|
+
async function handleBootstrap(config2, directory) {
|
|
19327
19321
|
if (bootstrapInProgress) {
|
|
19328
19322
|
logger6.debug("Bootstrap already in progress");
|
|
19329
19323
|
return;
|
|
@@ -19331,7 +19325,7 @@ async function handleBootstrap(config2, directory2) {
|
|
|
19331
19325
|
logger6.info("First run detected - initializing SonarQube integration");
|
|
19332
19326
|
bootstrapInProgress = true;
|
|
19333
19327
|
try {
|
|
19334
|
-
const result = await bootstrap({ config: config2, directory
|
|
19328
|
+
const result = await bootstrap({ config: config2, directory });
|
|
19335
19329
|
bootstrapInProgress = false;
|
|
19336
19330
|
return result.success ? formatBootstrapMessage(result) : `**SonarQube Setup Failed**
|
|
19337
19331
|
|
|
@@ -19345,7 +19339,7 @@ ${result.message}`;
|
|
|
19345
19339
|
${errorMsg}`;
|
|
19346
19340
|
}
|
|
19347
19341
|
}
|
|
19348
|
-
async function performAnalysis(config2, state,
|
|
19342
|
+
async function performAnalysis(config2, state, directory) {
|
|
19349
19343
|
const projectKey = state.projectKey;
|
|
19350
19344
|
const projectName = config2.projectName ?? projectKey;
|
|
19351
19345
|
const result = await runAnalysis(config2, state, {
|
|
@@ -19353,7 +19347,7 @@ async function performAnalysis(config2, state, directory2) {
|
|
|
19353
19347
|
projectName,
|
|
19354
19348
|
sources: config2.sources,
|
|
19355
19349
|
tests: config2.tests
|
|
19356
|
-
},
|
|
19350
|
+
}, directory);
|
|
19357
19351
|
editedFiles.clear();
|
|
19358
19352
|
return formatAnalysisOutput(result, config2);
|
|
19359
19353
|
}
|
|
@@ -19385,16 +19379,16 @@ function formatActionPrompt(result, config2) {
|
|
|
19385
19379
|
}
|
|
19386
19380
|
return prompt;
|
|
19387
19381
|
}
|
|
19388
|
-
function createIdleHook(
|
|
19382
|
+
function createIdleHook(getConfig, getDirectory) {
|
|
19389
19383
|
return async function handleSessionIdle() {
|
|
19390
|
-
const rawConfig =
|
|
19384
|
+
const rawConfig = getConfig()?.["sonarqube"];
|
|
19391
19385
|
const config2 = loadConfig(rawConfig);
|
|
19392
19386
|
if (!isAnalysisEnabled(config2)) {
|
|
19393
19387
|
return;
|
|
19394
19388
|
}
|
|
19395
|
-
const
|
|
19396
|
-
if (await needsBootstrap(
|
|
19397
|
-
return handleBootstrap(config2,
|
|
19389
|
+
const directory = getDirectory();
|
|
19390
|
+
if (await needsBootstrap(directory)) {
|
|
19391
|
+
return handleBootstrap(config2, directory);
|
|
19398
19392
|
}
|
|
19399
19393
|
if (isInCooldown()) {
|
|
19400
19394
|
logger6.debug("Skipping auto-analysis (cooldown)");
|
|
@@ -19407,12 +19401,12 @@ function createIdleHook(getConfig2, getDirectory2) {
|
|
|
19407
19401
|
logger6.info("Session idle - triggering auto-analysis");
|
|
19408
19402
|
lastAnalysisTime = Date.now();
|
|
19409
19403
|
try {
|
|
19410
|
-
const state = await getProjectState(
|
|
19404
|
+
const state = await getProjectState(directory);
|
|
19411
19405
|
if (!state) {
|
|
19412
19406
|
logger6.warn("No project state found, cannot run analysis");
|
|
19413
19407
|
return;
|
|
19414
19408
|
}
|
|
19415
|
-
return await performAnalysis(config2, state,
|
|
19409
|
+
return await performAnalysis(config2, state, directory);
|
|
19416
19410
|
} catch (error45) {
|
|
19417
19411
|
logger6.error(`Auto-analysis failed: ${error45}`);
|
|
19418
19412
|
return;
|
|
@@ -19462,9 +19456,9 @@ function createFileEditedHook() {
|
|
|
19462
19456
|
function getEditedFiles() {
|
|
19463
19457
|
return Array.from(editedFiles);
|
|
19464
19458
|
}
|
|
19465
|
-
function createHooks(
|
|
19459
|
+
function createHooks(getConfig, getDirectory) {
|
|
19466
19460
|
return {
|
|
19467
|
-
sessionIdle: createIdleHook(
|
|
19461
|
+
sessionIdle: createIdleHook(getConfig, getDirectory),
|
|
19468
19462
|
fileEdited: createFileEditedHook()
|
|
19469
19463
|
};
|
|
19470
19464
|
}
|
|
@@ -19483,7 +19477,7 @@ var SonarQubeToolArgsSchema = exports_external2.object({
|
|
|
19483
19477
|
branch: exports_external2.string().optional().describe("Branch name for multi-branch analysis (default: main branch)")
|
|
19484
19478
|
});
|
|
19485
19479
|
async function executeSonarQubeTool(args, context) {
|
|
19486
|
-
const
|
|
19480
|
+
const directory = context.directory ?? process.cwd();
|
|
19487
19481
|
const sonarConfig = context.config?.["sonarqube"];
|
|
19488
19482
|
const config2 = loadConfig(sonarConfig);
|
|
19489
19483
|
if (!config2) {
|
|
@@ -19506,14 +19500,14 @@ Or set environment variables:
|
|
|
19506
19500
|
- SONAR_USER
|
|
19507
19501
|
- SONAR_PASSWORD`;
|
|
19508
19502
|
}
|
|
19509
|
-
logger7.info(`Executing SonarQube tool: ${args.action}`, { directory
|
|
19503
|
+
logger7.info(`Executing SonarQube tool: ${args.action}`, { directory });
|
|
19510
19504
|
try {
|
|
19511
19505
|
if (args.action === "init" || args.action === "setup") {
|
|
19512
|
-
return await handleSetup(config2,
|
|
19506
|
+
return await handleSetup(config2, directory, args.force);
|
|
19513
19507
|
}
|
|
19514
|
-
if (await needsBootstrap(
|
|
19508
|
+
if (await needsBootstrap(directory)) {
|
|
19515
19509
|
logger7.info("First run detected, running bootstrap");
|
|
19516
|
-
const setupResult = await bootstrap({ config: config2, directory
|
|
19510
|
+
const setupResult = await bootstrap({ config: config2, directory });
|
|
19517
19511
|
if (!setupResult.success) {
|
|
19518
19512
|
return `## SonarQube Setup Failed
|
|
19519
19513
|
|
|
@@ -19521,7 +19515,7 @@ ${setupResult.message}`;
|
|
|
19521
19515
|
}
|
|
19522
19516
|
logger7.info("Bootstrap completed", { projectKey: setupResult.projectKey });
|
|
19523
19517
|
}
|
|
19524
|
-
const state = await getProjectState(
|
|
19518
|
+
const state = await getProjectState(directory);
|
|
19525
19519
|
if (!state) {
|
|
19526
19520
|
return `## SonarQube Error
|
|
19527
19521
|
|
|
@@ -19530,7 +19524,7 @@ Project not initialized. Run with action: "setup" first.`;
|
|
|
19530
19524
|
const projectKey = args.projectKey ?? state.projectKey;
|
|
19531
19525
|
switch (args.action) {
|
|
19532
19526
|
case "analyze":
|
|
19533
|
-
return await handleAnalyze(config2, state, projectKey, args,
|
|
19527
|
+
return await handleAnalyze(config2, state, projectKey, args, directory);
|
|
19534
19528
|
case "issues":
|
|
19535
19529
|
return await handleIssues(config2, state, projectKey, args);
|
|
19536
19530
|
case "newissues":
|
|
@@ -19571,8 +19565,8 @@ Please check:
|
|
|
19571
19565
|
3. Run with action: "setup" to initialize`;
|
|
19572
19566
|
}
|
|
19573
19567
|
}
|
|
19574
|
-
async function handleSetup(config2,
|
|
19575
|
-
const result = await bootstrap({ config: config2, directory
|
|
19568
|
+
async function handleSetup(config2, directory, force = false) {
|
|
19569
|
+
const result = await bootstrap({ config: config2, directory, force });
|
|
19576
19570
|
if (!result.success) {
|
|
19577
19571
|
return `## SonarQube Setup Failed
|
|
19578
19572
|
|
|
@@ -19596,7 +19590,7 @@ ${result.message}`;
|
|
|
19596
19590
|
return lines.join(`
|
|
19597
19591
|
`);
|
|
19598
19592
|
}
|
|
19599
|
-
async function handleAnalyze(config2, state, projectKey, args,
|
|
19593
|
+
async function handleAnalyze(config2, state, projectKey, args, directory) {
|
|
19600
19594
|
const projectName = config2.projectName ?? projectKey;
|
|
19601
19595
|
const result = await runAnalysis(config2, state, {
|
|
19602
19596
|
projectKey,
|
|
@@ -19604,7 +19598,7 @@ async function handleAnalyze(config2, state, projectKey, args, directory2) {
|
|
|
19604
19598
|
sources: config2.sources,
|
|
19605
19599
|
tests: config2.tests,
|
|
19606
19600
|
exclusions: config2.exclusions
|
|
19607
|
-
},
|
|
19601
|
+
}, directory);
|
|
19608
19602
|
let output = formatAnalysisResult(result);
|
|
19609
19603
|
if (args.fix && result.formattedIssues.length > 0) {
|
|
19610
19604
|
output += `
|
|
@@ -20071,7 +20065,7 @@ function getSeveritiesFromLevel(level) {
|
|
|
20071
20065
|
}
|
|
20072
20066
|
|
|
20073
20067
|
// src/index.ts
|
|
20074
|
-
import { readFileSync, writeFileSync
|
|
20068
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
20075
20069
|
|
|
20076
20070
|
// src/cli.ts
|
|
20077
20071
|
var CLI_HELP = `
|
|
@@ -20094,8 +20088,8 @@ Environment Variables:
|
|
|
20094
20088
|
SONAR_USER SonarQube username
|
|
20095
20089
|
SONAR_PASSWORD SonarQube password
|
|
20096
20090
|
`;
|
|
20097
|
-
async function handleSetup2(config2,
|
|
20098
|
-
const result = await bootstrap({ config: config2, directory
|
|
20091
|
+
async function handleSetup2(config2, directory, force) {
|
|
20092
|
+
const result = await bootstrap({ config: config2, directory, force });
|
|
20099
20093
|
return {
|
|
20100
20094
|
success: result.success,
|
|
20101
20095
|
output: result.success ? `Initializing SonarQube project...
|
|
@@ -20103,8 +20097,8 @@ ${result.message}` : result.message,
|
|
|
20103
20097
|
exitCode: result.success ? 0 : 1
|
|
20104
20098
|
};
|
|
20105
20099
|
}
|
|
20106
|
-
async function handleAnalyze2(config2, state, projectKey,
|
|
20107
|
-
const result = await runAnalysis(config2, state, { projectKey },
|
|
20100
|
+
async function handleAnalyze2(config2, state, projectKey, directory) {
|
|
20101
|
+
const result = await runAnalysis(config2, state, { projectKey }, directory);
|
|
20108
20102
|
return {
|
|
20109
20103
|
success: true,
|
|
20110
20104
|
output: `Running analysis for ${projectKey}...
|
|
@@ -20172,7 +20166,7 @@ function getProjectKeyFromArgs(args, state) {
|
|
|
20172
20166
|
const projectKeyArg = args.find((a) => a.startsWith("--project-key="));
|
|
20173
20167
|
return projectKeyArg ? projectKeyArg.split("=")[1] : state.projectKey;
|
|
20174
20168
|
}
|
|
20175
|
-
async function runCLI(args,
|
|
20169
|
+
async function runCLI(args, directory = process.cwd()) {
|
|
20176
20170
|
if (args.includes("--help") || args.includes("-h")) {
|
|
20177
20171
|
return { success: true, output: CLI_HELP, exitCode: 0 };
|
|
20178
20172
|
}
|
|
@@ -20186,10 +20180,10 @@ Set SONAR_HOST_URL, SONAR_USER, and SONAR_PASSWORD environment variables`,
|
|
|
20186
20180
|
};
|
|
20187
20181
|
}
|
|
20188
20182
|
if (args.includes("--setup")) {
|
|
20189
|
-
return handleSetup2(config2,
|
|
20183
|
+
return handleSetup2(config2, directory, args.includes("--force"));
|
|
20190
20184
|
}
|
|
20191
|
-
if (await needsBootstrap(
|
|
20192
|
-
const result = await bootstrap({ config: config2, directory
|
|
20185
|
+
if (await needsBootstrap(directory)) {
|
|
20186
|
+
const result = await bootstrap({ config: config2, directory });
|
|
20193
20187
|
if (!result.success) {
|
|
20194
20188
|
return {
|
|
20195
20189
|
success: false,
|
|
@@ -20199,7 +20193,7 @@ Setup failed: ${result.message}`,
|
|
|
20199
20193
|
};
|
|
20200
20194
|
}
|
|
20201
20195
|
}
|
|
20202
|
-
const state = await getProjectState(
|
|
20196
|
+
const state = await getProjectState(directory);
|
|
20203
20197
|
if (!state) {
|
|
20204
20198
|
return {
|
|
20205
20199
|
success: false,
|
|
@@ -20216,7 +20210,7 @@ Setup failed: ${result.message}`,
|
|
|
20216
20210
|
};
|
|
20217
20211
|
}
|
|
20218
20212
|
if (args.includes("--analyze")) {
|
|
20219
|
-
return handleAnalyze2(config2, state, projectKey,
|
|
20213
|
+
return handleAnalyze2(config2, state, projectKey, directory);
|
|
20220
20214
|
}
|
|
20221
20215
|
if (args.includes("--status")) {
|
|
20222
20216
|
return handleStatus2(config2, state, projectKey);
|
|
@@ -20259,19 +20253,19 @@ var writeSharedState = (state) => {
|
|
|
20259
20253
|
writeFileSync(SHARED_STATE_FILE, JSON.stringify(state, null, 2));
|
|
20260
20254
|
} catch {}
|
|
20261
20255
|
};
|
|
20262
|
-
var mapSessionToDirectory = (sessionId,
|
|
20256
|
+
var mapSessionToDirectory = (sessionId, directory) => {
|
|
20263
20257
|
const state = readSharedState();
|
|
20264
|
-
state.sessionToDirectory[sessionId] =
|
|
20258
|
+
state.sessionToDirectory[sessionId] = directory;
|
|
20265
20259
|
writeSharedState(state);
|
|
20266
20260
|
};
|
|
20267
20261
|
var getDirectoryForSession = (sessionId) => {
|
|
20268
20262
|
const state = readSharedState();
|
|
20269
20263
|
return state.sessionToDirectory[sessionId];
|
|
20270
20264
|
};
|
|
20271
|
-
var registerDirectory = (
|
|
20265
|
+
var registerDirectory = (directory) => {
|
|
20272
20266
|
const state = readSharedState();
|
|
20273
|
-
if (!state.registeredDirectories.includes(
|
|
20274
|
-
state.registeredDirectories.push(
|
|
20267
|
+
if (!state.registeredDirectories.includes(directory)) {
|
|
20268
|
+
state.registeredDirectories.push(directory);
|
|
20275
20269
|
writeSharedState(state);
|
|
20276
20270
|
}
|
|
20277
20271
|
};
|
|
@@ -20291,11 +20285,7 @@ function shouldIgnoreFile2(filePath) {
|
|
|
20291
20285
|
return IGNORED_FILE_PATTERNS2.some((pattern) => pattern.test(filePath));
|
|
20292
20286
|
}
|
|
20293
20287
|
var SonarQubePlugin = async ({ client, directory, worktree }) => {
|
|
20294
|
-
const safeLog = (
|
|
20295
|
-
appendFileSync2("/tmp/sonarqube-plugin-debug.log", `${new Date().toISOString()} ${msg}
|
|
20296
|
-
`);
|
|
20297
|
-
};
|
|
20298
|
-
const dangerousEval = (code) => eval(code);
|
|
20288
|
+
const safeLog = (_msg) => {};
|
|
20299
20289
|
const pluginImportUrl = import.meta.url;
|
|
20300
20290
|
const resolveDirectoryFromImportUrl = () => {
|
|
20301
20291
|
try {
|