opencode-sonarqube 0.1.2 → 0.1.4
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 +288 -147
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4104,94 +4104,6 @@ var init_types2 = __esm(() => {
|
|
|
4104
4104
|
};
|
|
4105
4105
|
});
|
|
4106
4106
|
|
|
4107
|
-
// src/utils/logger.ts
|
|
4108
|
-
class Logger {
|
|
4109
|
-
service;
|
|
4110
|
-
minLevel;
|
|
4111
|
-
client;
|
|
4112
|
-
constructor(service, options) {
|
|
4113
|
-
this.service = service;
|
|
4114
|
-
this.minLevel = options?.minLevel ?? "info";
|
|
4115
|
-
this.client = options?.client;
|
|
4116
|
-
}
|
|
4117
|
-
shouldLog(level) {
|
|
4118
|
-
const levels = ["debug", "info", "warn", "error"];
|
|
4119
|
-
return levels.indexOf(level) >= levels.indexOf(this.minLevel);
|
|
4120
|
-
}
|
|
4121
|
-
formatMessage(level, message, extra) {
|
|
4122
|
-
const timestamp = new Date().toISOString();
|
|
4123
|
-
const color = LOG_COLORS[level];
|
|
4124
|
-
const prefix = `${color}[${this.service}]${RESET}`;
|
|
4125
|
-
const levelStr = `${color}${level.toUpperCase()}${RESET}`;
|
|
4126
|
-
let formatted = `${prefix} ${timestamp} ${levelStr}: ${message}`;
|
|
4127
|
-
if (extra && Object.keys(extra).length > 0) {
|
|
4128
|
-
formatted += ` ${JSON.stringify(extra)}`;
|
|
4129
|
-
}
|
|
4130
|
-
return formatted;
|
|
4131
|
-
}
|
|
4132
|
-
async log(level, message, extra) {
|
|
4133
|
-
if (!this.shouldLog(level))
|
|
4134
|
-
return;
|
|
4135
|
-
if (this.client) {
|
|
4136
|
-
try {
|
|
4137
|
-
await this.client.app.log({
|
|
4138
|
-
service: this.service,
|
|
4139
|
-
level,
|
|
4140
|
-
message,
|
|
4141
|
-
extra
|
|
4142
|
-
});
|
|
4143
|
-
return;
|
|
4144
|
-
} catch {}
|
|
4145
|
-
}
|
|
4146
|
-
const formatted = this.formatMessage(level, message, extra);
|
|
4147
|
-
switch (level) {
|
|
4148
|
-
case "debug":
|
|
4149
|
-
console.debug(formatted);
|
|
4150
|
-
break;
|
|
4151
|
-
case "info":
|
|
4152
|
-
console.info(formatted);
|
|
4153
|
-
break;
|
|
4154
|
-
case "warn":
|
|
4155
|
-
console.warn(formatted);
|
|
4156
|
-
break;
|
|
4157
|
-
case "error":
|
|
4158
|
-
console.error(formatted);
|
|
4159
|
-
break;
|
|
4160
|
-
}
|
|
4161
|
-
}
|
|
4162
|
-
debug(message, extra) {
|
|
4163
|
-
this.log("debug", message, extra);
|
|
4164
|
-
}
|
|
4165
|
-
info(message, extra) {
|
|
4166
|
-
this.log("info", message, extra);
|
|
4167
|
-
}
|
|
4168
|
-
warn(message, extra) {
|
|
4169
|
-
this.log("warn", message, extra);
|
|
4170
|
-
}
|
|
4171
|
-
error(message, extra) {
|
|
4172
|
-
this.log("error", message, extra);
|
|
4173
|
-
}
|
|
4174
|
-
child(subService) {
|
|
4175
|
-
return new Logger(`${this.service}:${subService}`, {
|
|
4176
|
-
minLevel: this.minLevel,
|
|
4177
|
-
client: this.client
|
|
4178
|
-
});
|
|
4179
|
-
}
|
|
4180
|
-
}
|
|
4181
|
-
function createLogger(service, client) {
|
|
4182
|
-
return new Logger(service, { client });
|
|
4183
|
-
}
|
|
4184
|
-
var LOG_COLORS, RESET = "\x1B[0m", logger;
|
|
4185
|
-
var init_logger = __esm(() => {
|
|
4186
|
-
LOG_COLORS = {
|
|
4187
|
-
debug: "\x1B[90m",
|
|
4188
|
-
info: "\x1B[36m",
|
|
4189
|
-
warn: "\x1B[33m",
|
|
4190
|
-
error: "\x1B[31m"
|
|
4191
|
-
};
|
|
4192
|
-
logger = new Logger("opencode-sonarqube");
|
|
4193
|
-
});
|
|
4194
|
-
|
|
4195
4107
|
// src/utils/state.ts
|
|
4196
4108
|
function getStatePath(directory) {
|
|
4197
4109
|
return `${directory}/${STATE_DIR}/${STATE_FILE}`;
|
|
@@ -4205,20 +4117,30 @@ async function hasProjectState(directory) {
|
|
|
4205
4117
|
}
|
|
4206
4118
|
async function loadProjectState(directory) {
|
|
4207
4119
|
const statePath = getStatePath(directory);
|
|
4120
|
+
logger4.info(">>> loadProjectState called", { directory, statePath });
|
|
4208
4121
|
const exists = await Bun.file(statePath).exists();
|
|
4122
|
+
logger4.info("State file exists check", { exists, statePath });
|
|
4209
4123
|
if (!exists) {
|
|
4210
|
-
logger4.
|
|
4124
|
+
logger4.info("No project state file found", { directory, statePath });
|
|
4211
4125
|
return null;
|
|
4212
4126
|
}
|
|
4213
4127
|
try {
|
|
4214
4128
|
const content = await Bun.file(statePath).text();
|
|
4129
|
+
logger4.info("State file content loaded", { contentLength: content.length });
|
|
4215
4130
|
const data = JSON.parse(content);
|
|
4131
|
+
logger4.info("State file parsed", { keys: Object.keys(data) });
|
|
4216
4132
|
const state = ProjectStateSchema.parse(data);
|
|
4217
|
-
logger4.
|
|
4133
|
+
logger4.info("<<< loadProjectState success", {
|
|
4134
|
+
projectKey: state.projectKey,
|
|
4135
|
+
projectKeyLength: state.projectKey?.length,
|
|
4136
|
+
hasToken: !!state.projectToken,
|
|
4137
|
+
tokenLength: state.projectToken?.length
|
|
4138
|
+
});
|
|
4218
4139
|
return state;
|
|
4219
4140
|
} catch (error45) {
|
|
4220
|
-
logger4.
|
|
4221
|
-
error: error45 instanceof Error ? error45.message : String(error45)
|
|
4141
|
+
logger4.error("Failed to load project state", {
|
|
4142
|
+
error: error45 instanceof Error ? error45.message : String(error45),
|
|
4143
|
+
statePath
|
|
4222
4144
|
});
|
|
4223
4145
|
return null;
|
|
4224
4146
|
}
|
|
@@ -4275,8 +4197,20 @@ ${entry}
|
|
|
4275
4197
|
var logger4, STATE_DIR = ".sonarqube", STATE_FILE = "project.json";
|
|
4276
4198
|
var init_state = __esm(() => {
|
|
4277
4199
|
init_types2();
|
|
4278
|
-
|
|
4279
|
-
|
|
4200
|
+
logger4 = {
|
|
4201
|
+
info: (msg, extra) => {
|
|
4202
|
+
console.log(`[SONARQUBE-STATE] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
4203
|
+
},
|
|
4204
|
+
warn: (msg, extra) => {
|
|
4205
|
+
console.warn(`[SONARQUBE-STATE] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
4206
|
+
},
|
|
4207
|
+
error: (msg, extra) => {
|
|
4208
|
+
console.error(`[SONARQUBE-STATE] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
4209
|
+
},
|
|
4210
|
+
debug: (msg, extra) => {
|
|
4211
|
+
console.log(`[SONARQUBE-STATE] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
4212
|
+
}
|
|
4213
|
+
};
|
|
4280
4214
|
});
|
|
4281
4215
|
|
|
4282
4216
|
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
|
|
@@ -16601,6 +16535,17 @@ function tool(input) {
|
|
|
16601
16535
|
tool.schema = exports_external;
|
|
16602
16536
|
// src/utils/config.ts
|
|
16603
16537
|
init_types2();
|
|
16538
|
+
var configLogger = {
|
|
16539
|
+
info: (msg, extra) => {
|
|
16540
|
+
console.log(`[SONARQUBE-CONFIG] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
16541
|
+
},
|
|
16542
|
+
warn: (msg, extra) => {
|
|
16543
|
+
console.warn(`[SONARQUBE-CONFIG] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
16544
|
+
},
|
|
16545
|
+
error: (msg, extra) => {
|
|
16546
|
+
console.error(`[SONARQUBE-CONFIG] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
16547
|
+
}
|
|
16548
|
+
};
|
|
16604
16549
|
var DEFAULT_CONFIG = {
|
|
16605
16550
|
level: "enterprise",
|
|
16606
16551
|
autoAnalyze: true,
|
|
@@ -16609,9 +16554,16 @@ var DEFAULT_CONFIG = {
|
|
|
16609
16554
|
sources: "src"
|
|
16610
16555
|
};
|
|
16611
16556
|
function loadConfig(rawConfig) {
|
|
16557
|
+
configLogger.info(">>> loadConfig called", { hasRawConfig: !!rawConfig });
|
|
16612
16558
|
const envUrl = process.env["SONAR_HOST_URL"];
|
|
16613
16559
|
const envUser = process.env["SONAR_USER"];
|
|
16614
16560
|
const envPassword = process.env["SONAR_PASSWORD"];
|
|
16561
|
+
configLogger.info("Environment variables", {
|
|
16562
|
+
hasEnvUrl: !!envUrl,
|
|
16563
|
+
hasEnvUser: !!envUser,
|
|
16564
|
+
hasEnvPassword: !!envPassword,
|
|
16565
|
+
envUrl: envUrl ? `${envUrl.substring(0, 20)}...` : undefined
|
|
16566
|
+
});
|
|
16615
16567
|
const configToValidate = {
|
|
16616
16568
|
...DEFAULT_CONFIG,
|
|
16617
16569
|
...rawConfig,
|
|
@@ -16620,13 +16572,19 @@ function loadConfig(rawConfig) {
|
|
|
16620
16572
|
...envPassword && { password: envPassword }
|
|
16621
16573
|
};
|
|
16622
16574
|
if (!configToValidate.url || !configToValidate.user || !configToValidate.password) {
|
|
16575
|
+
configLogger.warn("Missing required config", {
|
|
16576
|
+
hasUrl: !!configToValidate.url,
|
|
16577
|
+
hasUser: !!configToValidate.user,
|
|
16578
|
+
hasPassword: !!configToValidate.password
|
|
16579
|
+
});
|
|
16623
16580
|
return null;
|
|
16624
16581
|
}
|
|
16625
16582
|
const result = SonarQubeConfigSchema.safeParse(configToValidate);
|
|
16626
16583
|
if (!result.success) {
|
|
16627
|
-
|
|
16584
|
+
configLogger.error("Config validation failed", { errors: result.error.format() });
|
|
16628
16585
|
return null;
|
|
16629
16586
|
}
|
|
16587
|
+
configLogger.info("<<< loadConfig success", { url: result.data.url, level: result.data.level });
|
|
16630
16588
|
return result.data;
|
|
16631
16589
|
}
|
|
16632
16590
|
async function deriveProjectKey(directory) {
|
|
@@ -16676,8 +16634,94 @@ function sanitizeProjectKey(input) {
|
|
|
16676
16634
|
return input.toLowerCase().replaceAll(/[^a-z0-9-_]/g, "-").replaceAll(/-+/g, "-").replaceAll(/(?:^-)|(?:-$)/g, "").slice(0, 400);
|
|
16677
16635
|
}
|
|
16678
16636
|
|
|
16637
|
+
// src/utils/logger.ts
|
|
16638
|
+
var LOG_COLORS = {
|
|
16639
|
+
debug: "\x1B[90m",
|
|
16640
|
+
info: "\x1B[36m",
|
|
16641
|
+
warn: "\x1B[33m",
|
|
16642
|
+
error: "\x1B[31m"
|
|
16643
|
+
};
|
|
16644
|
+
var RESET = "\x1B[0m";
|
|
16645
|
+
|
|
16646
|
+
class Logger {
|
|
16647
|
+
service;
|
|
16648
|
+
minLevel;
|
|
16649
|
+
client;
|
|
16650
|
+
constructor(service, options) {
|
|
16651
|
+
this.service = service;
|
|
16652
|
+
this.minLevel = options?.minLevel ?? "info";
|
|
16653
|
+
this.client = options?.client;
|
|
16654
|
+
}
|
|
16655
|
+
shouldLog(level) {
|
|
16656
|
+
const levels = ["debug", "info", "warn", "error"];
|
|
16657
|
+
return levels.indexOf(level) >= levels.indexOf(this.minLevel);
|
|
16658
|
+
}
|
|
16659
|
+
formatMessage(level, message, extra) {
|
|
16660
|
+
const timestamp = new Date().toISOString();
|
|
16661
|
+
const color = LOG_COLORS[level];
|
|
16662
|
+
const prefix = `${color}[${this.service}]${RESET}`;
|
|
16663
|
+
const levelStr = `${color}${level.toUpperCase()}${RESET}`;
|
|
16664
|
+
let formatted = `${prefix} ${timestamp} ${levelStr}: ${message}`;
|
|
16665
|
+
if (extra && Object.keys(extra).length > 0) {
|
|
16666
|
+
formatted += ` ${JSON.stringify(extra)}`;
|
|
16667
|
+
}
|
|
16668
|
+
return formatted;
|
|
16669
|
+
}
|
|
16670
|
+
async log(level, message, extra) {
|
|
16671
|
+
if (!this.shouldLog(level))
|
|
16672
|
+
return;
|
|
16673
|
+
if (this.client) {
|
|
16674
|
+
try {
|
|
16675
|
+
await this.client.app.log({
|
|
16676
|
+
service: this.service,
|
|
16677
|
+
level,
|
|
16678
|
+
message,
|
|
16679
|
+
extra
|
|
16680
|
+
});
|
|
16681
|
+
return;
|
|
16682
|
+
} catch {}
|
|
16683
|
+
}
|
|
16684
|
+
const formatted = this.formatMessage(level, message, extra);
|
|
16685
|
+
switch (level) {
|
|
16686
|
+
case "debug":
|
|
16687
|
+
console.debug(formatted);
|
|
16688
|
+
break;
|
|
16689
|
+
case "info":
|
|
16690
|
+
console.info(formatted);
|
|
16691
|
+
break;
|
|
16692
|
+
case "warn":
|
|
16693
|
+
console.warn(formatted);
|
|
16694
|
+
break;
|
|
16695
|
+
case "error":
|
|
16696
|
+
console.error(formatted);
|
|
16697
|
+
break;
|
|
16698
|
+
}
|
|
16699
|
+
}
|
|
16700
|
+
debug(message, extra) {
|
|
16701
|
+
this.log("debug", message, extra);
|
|
16702
|
+
}
|
|
16703
|
+
info(message, extra) {
|
|
16704
|
+
this.log("info", message, extra);
|
|
16705
|
+
}
|
|
16706
|
+
warn(message, extra) {
|
|
16707
|
+
this.log("warn", message, extra);
|
|
16708
|
+
}
|
|
16709
|
+
error(message, extra) {
|
|
16710
|
+
this.log("error", message, extra);
|
|
16711
|
+
}
|
|
16712
|
+
child(subService) {
|
|
16713
|
+
return new Logger(`${this.service}:${subService}`, {
|
|
16714
|
+
minLevel: this.minLevel,
|
|
16715
|
+
client: this.client
|
|
16716
|
+
});
|
|
16717
|
+
}
|
|
16718
|
+
}
|
|
16719
|
+
var logger = new Logger("opencode-sonarqube");
|
|
16720
|
+
function createLogger(service, client) {
|
|
16721
|
+
return new Logger(service, { client });
|
|
16722
|
+
}
|
|
16723
|
+
|
|
16679
16724
|
// src/scanner/config.ts
|
|
16680
|
-
init_logger();
|
|
16681
16725
|
var logger2 = new Logger("scanner-config");
|
|
16682
16726
|
async function checkProjectFiles(directory) {
|
|
16683
16727
|
const checks3 = await Promise.all([
|
|
@@ -16945,7 +16989,6 @@ async function writePropertiesFile(options, config2, directory) {
|
|
|
16945
16989
|
}
|
|
16946
16990
|
// src/api/client.ts
|
|
16947
16991
|
init_types2();
|
|
16948
|
-
init_logger();
|
|
16949
16992
|
function buildUrl(baseUrl, endpoint, params) {
|
|
16950
16993
|
let url2 = `${baseUrl}${endpoint}`;
|
|
16951
16994
|
if (!params) {
|
|
@@ -17032,11 +17075,10 @@ function buildAuthHeader(auth) {
|
|
|
17032
17075
|
class SonarQubeClient {
|
|
17033
17076
|
baseUrl;
|
|
17034
17077
|
auth;
|
|
17035
|
-
|
|
17036
|
-
constructor(config2, logger3) {
|
|
17078
|
+
constructor(config2, _logger) {
|
|
17037
17079
|
this.baseUrl = normalizeUrl(config2.url);
|
|
17038
17080
|
this.auth = config2.auth;
|
|
17039
|
-
|
|
17081
|
+
console.log(`[SONARQUBE-CLIENT] Created client for ${this.baseUrl}`);
|
|
17040
17082
|
}
|
|
17041
17083
|
async request(endpoint, options = {}) {
|
|
17042
17084
|
const { method = "GET", params, body } = options;
|
|
@@ -17049,19 +17091,36 @@ class SonarQubeClient {
|
|
|
17049
17091
|
if (requestBody) {
|
|
17050
17092
|
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
17051
17093
|
}
|
|
17052
|
-
|
|
17094
|
+
console.log(`[SONARQUBE-API] >>> ${method} ${endpoint}`, JSON.stringify({
|
|
17095
|
+
url: url2,
|
|
17096
|
+
params,
|
|
17097
|
+
hasBody: !!body,
|
|
17098
|
+
bodyKeys: body ? Object.keys(body) : []
|
|
17099
|
+
}));
|
|
17053
17100
|
try {
|
|
17054
17101
|
const response = await fetch(url2, {
|
|
17055
17102
|
method,
|
|
17056
17103
|
headers,
|
|
17057
17104
|
body: requestBody
|
|
17058
17105
|
});
|
|
17106
|
+
console.log(`[SONARQUBE-API] <<< ${method} ${endpoint}`, JSON.stringify({
|
|
17107
|
+
status: response.status,
|
|
17108
|
+
ok: response.ok
|
|
17109
|
+
}));
|
|
17059
17110
|
if (!response.ok) {
|
|
17111
|
+
console.error(`[SONARQUBE-API] ERROR: ${method} ${endpoint}`, JSON.stringify({
|
|
17112
|
+
status: response.status,
|
|
17113
|
+
url: url2
|
|
17114
|
+
}));
|
|
17060
17115
|
await handleResponseError(response);
|
|
17061
17116
|
}
|
|
17062
17117
|
const text = await response.text();
|
|
17063
17118
|
return parseResponseBody(text);
|
|
17064
17119
|
} catch (error45) {
|
|
17120
|
+
console.error(`[SONARQUBE-API] EXCEPTION: ${method} ${endpoint}`, JSON.stringify({
|
|
17121
|
+
error: String(error45),
|
|
17122
|
+
url: url2
|
|
17123
|
+
}));
|
|
17065
17124
|
handleFetchError(error45, this.baseUrl);
|
|
17066
17125
|
}
|
|
17067
17126
|
}
|
|
@@ -17127,8 +17186,6 @@ function createClientWithCredentials(url2, user, password, logger3) {
|
|
|
17127
17186
|
}
|
|
17128
17187
|
// src/api/projects.ts
|
|
17129
17188
|
init_types2();
|
|
17130
|
-
init_logger();
|
|
17131
|
-
|
|
17132
17189
|
class ProjectsAPI {
|
|
17133
17190
|
client;
|
|
17134
17191
|
logger;
|
|
@@ -17229,8 +17286,6 @@ class ProjectsAPI {
|
|
|
17229
17286
|
}
|
|
17230
17287
|
}
|
|
17231
17288
|
// src/api/issues.ts
|
|
17232
|
-
init_logger();
|
|
17233
|
-
|
|
17234
17289
|
class IssuesAPI {
|
|
17235
17290
|
client;
|
|
17236
17291
|
logger;
|
|
@@ -17380,7 +17435,6 @@ class IssuesAPI {
|
|
|
17380
17435
|
}
|
|
17381
17436
|
// src/api/quality-gate.ts
|
|
17382
17437
|
init_types2();
|
|
17383
|
-
init_logger();
|
|
17384
17438
|
var METRIC_KEYS = {
|
|
17385
17439
|
coverage: "coverage",
|
|
17386
17440
|
newCoverage: "new_coverage",
|
|
@@ -17717,8 +17771,6 @@ class QualityGateAPI {
|
|
|
17717
17771
|
}
|
|
17718
17772
|
}
|
|
17719
17773
|
// src/api/rules.ts
|
|
17720
|
-
init_logger();
|
|
17721
|
-
|
|
17722
17774
|
class RulesAPI {
|
|
17723
17775
|
client;
|
|
17724
17776
|
logger;
|
|
@@ -17822,8 +17874,6 @@ class RulesAPI {
|
|
|
17822
17874
|
}
|
|
17823
17875
|
}
|
|
17824
17876
|
// src/api/sources.ts
|
|
17825
|
-
init_logger();
|
|
17826
|
-
|
|
17827
17877
|
class SourcesAPI {
|
|
17828
17878
|
client;
|
|
17829
17879
|
logger;
|
|
@@ -17962,8 +18012,6 @@ class SourcesAPI {
|
|
|
17962
18012
|
}
|
|
17963
18013
|
}
|
|
17964
18014
|
// src/api/duplications.ts
|
|
17965
|
-
init_logger();
|
|
17966
|
-
|
|
17967
18015
|
class DuplicationsAPI {
|
|
17968
18016
|
client;
|
|
17969
18017
|
logger;
|
|
@@ -18072,8 +18120,6 @@ class DuplicationsAPI {
|
|
|
18072
18120
|
}
|
|
18073
18121
|
}
|
|
18074
18122
|
// src/api/ce.ts
|
|
18075
|
-
init_logger();
|
|
18076
|
-
|
|
18077
18123
|
class ComputeEngineAPI {
|
|
18078
18124
|
client;
|
|
18079
18125
|
logger;
|
|
@@ -18189,8 +18235,6 @@ class ComputeEngineAPI {
|
|
|
18189
18235
|
}
|
|
18190
18236
|
}
|
|
18191
18237
|
// src/api/analyses.ts
|
|
18192
|
-
init_logger();
|
|
18193
|
-
|
|
18194
18238
|
class ProjectAnalysesAPI {
|
|
18195
18239
|
client;
|
|
18196
18240
|
logger;
|
|
@@ -18199,7 +18243,14 @@ class ProjectAnalysesAPI {
|
|
|
18199
18243
|
this.logger = logger3 ?? new Logger("sonarqube-analyses");
|
|
18200
18244
|
}
|
|
18201
18245
|
async getAnalyses(options) {
|
|
18202
|
-
this.logger.
|
|
18246
|
+
this.logger.info(`>>> getAnalyses called`, {
|
|
18247
|
+
projectKey: options.projectKey,
|
|
18248
|
+
projectKeyLength: options.projectKey?.length
|
|
18249
|
+
});
|
|
18250
|
+
if (!options.projectKey) {
|
|
18251
|
+
this.logger.error(`getAnalyses: projectKey is empty/undefined!`);
|
|
18252
|
+
return [];
|
|
18253
|
+
}
|
|
18203
18254
|
try {
|
|
18204
18255
|
const response = await this.client.get("/api/project_analyses/search", {
|
|
18205
18256
|
project: options.projectKey,
|
|
@@ -18209,9 +18260,10 @@ class ProjectAnalysesAPI {
|
|
|
18209
18260
|
to: options.to,
|
|
18210
18261
|
ps: options.pageSize ?? 10
|
|
18211
18262
|
});
|
|
18263
|
+
this.logger.info(`<<< getAnalyses success`, { analysesCount: response.analyses.length });
|
|
18212
18264
|
return response.analyses;
|
|
18213
18265
|
} catch (error45) {
|
|
18214
|
-
this.logger.
|
|
18266
|
+
this.logger.error(`getAnalyses failed`, { error: String(error45), projectKey: options.projectKey });
|
|
18215
18267
|
return [];
|
|
18216
18268
|
}
|
|
18217
18269
|
}
|
|
@@ -18251,8 +18303,6 @@ class ProjectAnalysesAPI {
|
|
|
18251
18303
|
}
|
|
18252
18304
|
}
|
|
18253
18305
|
// src/api/profiles.ts
|
|
18254
|
-
init_logger();
|
|
18255
|
-
|
|
18256
18306
|
class QualityProfilesAPI {
|
|
18257
18307
|
client;
|
|
18258
18308
|
logger;
|
|
@@ -18261,12 +18311,17 @@ class QualityProfilesAPI {
|
|
|
18261
18311
|
this.logger = logger3 ?? new Logger("sonarqube-profiles");
|
|
18262
18312
|
}
|
|
18263
18313
|
async getProjectProfiles(projectKey) {
|
|
18264
|
-
this.logger.
|
|
18314
|
+
this.logger.info(`>>> getProjectProfiles called`, { projectKey, projectKeyLength: projectKey?.length });
|
|
18315
|
+
if (!projectKey) {
|
|
18316
|
+
this.logger.error(`getProjectProfiles: projectKey is empty/undefined!`);
|
|
18317
|
+
return [];
|
|
18318
|
+
}
|
|
18265
18319
|
try {
|
|
18266
18320
|
const response = await this.client.get("/api/qualityprofiles/search", { project: projectKey });
|
|
18321
|
+
this.logger.info(`<<< getProjectProfiles success`, { profileCount: response.profiles.length });
|
|
18267
18322
|
return response.profiles;
|
|
18268
18323
|
} catch (error45) {
|
|
18269
|
-
this.logger.
|
|
18324
|
+
this.logger.error(`getProjectProfiles failed`, { error: String(error45), projectKey });
|
|
18270
18325
|
return [];
|
|
18271
18326
|
}
|
|
18272
18327
|
}
|
|
@@ -18340,8 +18395,6 @@ class QualityProfilesAPI {
|
|
|
18340
18395
|
}
|
|
18341
18396
|
}
|
|
18342
18397
|
// src/api/branches.ts
|
|
18343
|
-
init_logger();
|
|
18344
|
-
|
|
18345
18398
|
class BranchesAPI {
|
|
18346
18399
|
client;
|
|
18347
18400
|
logger;
|
|
@@ -18350,12 +18403,17 @@ class BranchesAPI {
|
|
|
18350
18403
|
this.logger = logger3 ?? new Logger("sonarqube-branches");
|
|
18351
18404
|
}
|
|
18352
18405
|
async getBranches(projectKey) {
|
|
18353
|
-
this.logger.
|
|
18406
|
+
this.logger.info(`>>> getBranches called`, { projectKey, projectKeyLength: projectKey?.length });
|
|
18407
|
+
if (!projectKey) {
|
|
18408
|
+
this.logger.error(`getBranches: projectKey is empty/undefined!`);
|
|
18409
|
+
return [];
|
|
18410
|
+
}
|
|
18354
18411
|
try {
|
|
18355
18412
|
const response = await this.client.get("/api/project_branches/list", { project: projectKey });
|
|
18413
|
+
this.logger.info(`<<< getBranches success`, { branchCount: response.branches.length });
|
|
18356
18414
|
return response.branches;
|
|
18357
18415
|
} catch (error45) {
|
|
18358
|
-
this.logger.
|
|
18416
|
+
this.logger.error(`getBranches failed`, { error: String(error45), projectKey });
|
|
18359
18417
|
return [];
|
|
18360
18418
|
}
|
|
18361
18419
|
}
|
|
@@ -18459,7 +18517,6 @@ class BranchesAPI {
|
|
|
18459
18517
|
}
|
|
18460
18518
|
}
|
|
18461
18519
|
// src/api/metrics.ts
|
|
18462
|
-
init_logger();
|
|
18463
18520
|
var COMMON_METRICS = [
|
|
18464
18521
|
"ncloc",
|
|
18465
18522
|
"lines",
|
|
@@ -18619,8 +18676,6 @@ class MetricsAPI {
|
|
|
18619
18676
|
}
|
|
18620
18677
|
}
|
|
18621
18678
|
// src/api/components.ts
|
|
18622
|
-
init_logger();
|
|
18623
|
-
|
|
18624
18679
|
class ComponentsAPI {
|
|
18625
18680
|
client;
|
|
18626
18681
|
logger;
|
|
@@ -18734,8 +18789,6 @@ class ComponentsAPI {
|
|
|
18734
18789
|
}
|
|
18735
18790
|
}
|
|
18736
18791
|
// src/api/index.ts
|
|
18737
|
-
init_logger();
|
|
18738
|
-
|
|
18739
18792
|
class SonarQubeAPI {
|
|
18740
18793
|
client;
|
|
18741
18794
|
projects;
|
|
@@ -18797,6 +18850,16 @@ function createSonarQubeAPIWithToken(url2, token, logger3) {
|
|
|
18797
18850
|
return new SonarQubeAPI(client, logger3);
|
|
18798
18851
|
}
|
|
18799
18852
|
function createSonarQubeAPI(config2, state, logger3) {
|
|
18853
|
+
console.log(`[SONARQUBE-API] >>> createSonarQubeAPI called`, JSON.stringify({
|
|
18854
|
+
url: config2.url,
|
|
18855
|
+
projectKey: state.projectKey,
|
|
18856
|
+
projectKeyLength: state.projectKey?.length,
|
|
18857
|
+
hasToken: !!state.projectToken,
|
|
18858
|
+
tokenLength: state.projectToken?.length
|
|
18859
|
+
}));
|
|
18860
|
+
if (!state.projectToken) {
|
|
18861
|
+
console.error(`[SONARQUBE-API] createSonarQubeAPI: projectToken is missing!`);
|
|
18862
|
+
}
|
|
18800
18863
|
return createSonarQubeAPIWithToken(config2.url, state.projectToken, logger3);
|
|
18801
18864
|
}
|
|
18802
18865
|
|
|
@@ -18901,7 +18964,6 @@ function formatIssueBlock(issue2, _number2) {
|
|
|
18901
18964
|
}
|
|
18902
18965
|
|
|
18903
18966
|
// src/scanner/runner.ts
|
|
18904
|
-
init_logger();
|
|
18905
18967
|
var logger3 = new Logger("scanner-runner");
|
|
18906
18968
|
async function runScanner(config2, state, options, directory) {
|
|
18907
18969
|
const dir = directory ?? process.cwd();
|
|
@@ -19076,8 +19138,17 @@ function shouldBlockOnResult(result, level) {
|
|
|
19076
19138
|
// src/bootstrap/index.ts
|
|
19077
19139
|
init_types2();
|
|
19078
19140
|
init_state();
|
|
19079
|
-
|
|
19080
|
-
|
|
19141
|
+
var logger5 = {
|
|
19142
|
+
info: (msg, extra) => {
|
|
19143
|
+
console.log(`[SONARQUBE-BOOTSTRAP] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
19144
|
+
},
|
|
19145
|
+
warn: (msg, extra) => {
|
|
19146
|
+
console.warn(`[SONARQUBE-BOOTSTRAP] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
19147
|
+
},
|
|
19148
|
+
error: (msg, extra) => {
|
|
19149
|
+
console.error(`[SONARQUBE-BOOTSTRAP] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
19150
|
+
}
|
|
19151
|
+
};
|
|
19081
19152
|
var QUALITY_GATE_MAPPING = {
|
|
19082
19153
|
enterprise: "Sonar way",
|
|
19083
19154
|
standard: "Sonar way",
|
|
@@ -19085,12 +19156,22 @@ var QUALITY_GATE_MAPPING = {
|
|
|
19085
19156
|
off: "Sonar way"
|
|
19086
19157
|
};
|
|
19087
19158
|
async function needsBootstrap(directory) {
|
|
19159
|
+
logger5.info(">>> needsBootstrap called", { directory });
|
|
19088
19160
|
const hasState = await hasProjectState(directory);
|
|
19161
|
+
logger5.info("hasProjectState result", { hasState, directory });
|
|
19089
19162
|
if (!hasState) {
|
|
19163
|
+
logger5.info("<<< needsBootstrap: true (no state file)");
|
|
19090
19164
|
return true;
|
|
19091
19165
|
}
|
|
19092
19166
|
const state = await loadProjectState(directory);
|
|
19093
|
-
|
|
19167
|
+
const needsBoot = !state?.setupComplete;
|
|
19168
|
+
logger5.info("<<< needsBootstrap result", {
|
|
19169
|
+
needsBoot,
|
|
19170
|
+
hasState: !!state,
|
|
19171
|
+
setupComplete: state?.setupComplete,
|
|
19172
|
+
projectKey: state?.projectKey
|
|
19173
|
+
});
|
|
19174
|
+
return needsBoot;
|
|
19094
19175
|
}
|
|
19095
19176
|
async function getProjectState(directory) {
|
|
19096
19177
|
return loadProjectState(directory);
|
|
@@ -19227,7 +19308,6 @@ async function configureProjectSettings(client, projectKey, languages, config2)
|
|
|
19227
19308
|
}
|
|
19228
19309
|
|
|
19229
19310
|
// src/hooks/index.ts
|
|
19230
|
-
init_logger();
|
|
19231
19311
|
var logger6 = new Logger("sonarqube-hooks");
|
|
19232
19312
|
var editedFiles = new Set;
|
|
19233
19313
|
var lastAnalysisTime = 0;
|
|
@@ -19388,7 +19468,6 @@ function createHooks(getConfig, getDirectory) {
|
|
|
19388
19468
|
|
|
19389
19469
|
// src/tools/sonarqube.ts
|
|
19390
19470
|
init_zod();
|
|
19391
|
-
init_logger();
|
|
19392
19471
|
var logger7 = new Logger("sonarqube-tool");
|
|
19393
19472
|
var SonarQubeToolArgsSchema = exports_external2.object({
|
|
19394
19473
|
action: exports_external2.enum(["analyze", "issues", "newissues", "status", "init", "setup", "validate", "hotspots", "duplications", "rule", "history", "profile", "branches", "metrics", "worstfiles"]).describe("Action to perform: analyze (run scanner), issues (all issues), newissues (only new code issues), status (quality gate), init/setup (initialize), validate (enterprise check), hotspots (security review), duplications (code duplicates), rule (explain rule), history (past analyses), profile (quality profile), branches (branch status), metrics (detailed metrics), worstfiles (files with most issues)"),
|
|
@@ -19989,8 +20068,18 @@ function getSeveritiesFromLevel(level) {
|
|
|
19989
20068
|
}
|
|
19990
20069
|
|
|
19991
20070
|
// src/index.ts
|
|
19992
|
-
init_logger();
|
|
19993
20071
|
init_types2();
|
|
20072
|
+
var debugLog = {
|
|
20073
|
+
info: (msg, extra) => {
|
|
20074
|
+
console.log(`[SONARQUBE-DEBUG] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
20075
|
+
},
|
|
20076
|
+
warn: (msg, extra) => {
|
|
20077
|
+
console.warn(`[SONARQUBE-DEBUG] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
20078
|
+
},
|
|
20079
|
+
error: (msg, extra) => {
|
|
20080
|
+
console.error(`[SONARQUBE-DEBUG] ${msg}`, extra ? JSON.stringify(extra) : "");
|
|
20081
|
+
}
|
|
20082
|
+
};
|
|
19994
20083
|
var IGNORED_FILE_PATTERNS2 = [
|
|
19995
20084
|
/node_modules/,
|
|
19996
20085
|
/\.git/,
|
|
@@ -20007,6 +20096,7 @@ function shouldIgnoreFile2(filePath) {
|
|
|
20007
20096
|
return IGNORED_FILE_PATTERNS2.some((pattern) => pattern.test(filePath));
|
|
20008
20097
|
}
|
|
20009
20098
|
var SonarQubePlugin = async ({ client, directory, worktree }) => {
|
|
20099
|
+
debugLog.info("=== PLUGIN START ===", { directory, worktree });
|
|
20010
20100
|
await client.app.log({
|
|
20011
20101
|
body: {
|
|
20012
20102
|
service: "opencode-sonarqube",
|
|
@@ -20020,38 +20110,71 @@ var SonarQubePlugin = async ({ client, directory, worktree }) => {
|
|
|
20020
20110
|
const getConfig = () => pluginConfig;
|
|
20021
20111
|
const getDirectory = () => worktree ?? directory;
|
|
20022
20112
|
const loadPluginConfig = async () => {
|
|
20023
|
-
|
|
20113
|
+
debugLog.info("loadPluginConfig called", { hasExistingConfig: !!pluginConfig });
|
|
20114
|
+
if (pluginConfig) {
|
|
20115
|
+
debugLog.info("Config already loaded, skipping");
|
|
20024
20116
|
return;
|
|
20117
|
+
}
|
|
20025
20118
|
try {
|
|
20026
|
-
const
|
|
20119
|
+
const configPath = `${getDirectory()}/opencode.json`;
|
|
20120
|
+
debugLog.info("Loading config from", { configPath });
|
|
20121
|
+
const configFile = Bun.file(configPath);
|
|
20027
20122
|
if (await configFile.exists()) {
|
|
20028
20123
|
pluginConfig = await configFile.json();
|
|
20124
|
+
debugLog.info("Config loaded", { keys: Object.keys(pluginConfig ?? {}) });
|
|
20125
|
+
} else {
|
|
20126
|
+
debugLog.info("No opencode.json found");
|
|
20029
20127
|
}
|
|
20030
|
-
} catch {
|
|
20128
|
+
} catch (error45) {
|
|
20129
|
+
debugLog.warn("Config load error", { error: String(error45) });
|
|
20130
|
+
}
|
|
20031
20131
|
};
|
|
20032
20132
|
const hooks = createHooks(getConfig, getDirectory);
|
|
20033
20133
|
let currentSessionId;
|
|
20034
20134
|
let initialCheckDone = false;
|
|
20035
20135
|
const performInitialQualityCheck = async (sessionId) => {
|
|
20036
|
-
|
|
20136
|
+
debugLog.info("=== performInitialQualityCheck START ===", { sessionId, initialCheckDone });
|
|
20137
|
+
if (initialCheckDone) {
|
|
20138
|
+
debugLog.info("Initial check already done, skipping");
|
|
20037
20139
|
return;
|
|
20140
|
+
}
|
|
20038
20141
|
initialCheckDone = true;
|
|
20039
20142
|
try {
|
|
20040
20143
|
await loadPluginConfig();
|
|
20041
20144
|
const sonarConfig = pluginConfig?.["sonarqube"];
|
|
20145
|
+
debugLog.info("Loading SonarQube config", { hasSonarConfig: !!sonarConfig });
|
|
20042
20146
|
const config2 = loadConfig(sonarConfig);
|
|
20043
|
-
|
|
20147
|
+
debugLog.info("Config loaded", { hasConfig: !!config2, level: config2?.level });
|
|
20148
|
+
if (!config2 || config2.level === "off") {
|
|
20149
|
+
debugLog.info("Config missing or level=off, skipping");
|
|
20044
20150
|
return;
|
|
20045
|
-
|
|
20151
|
+
}
|
|
20152
|
+
const dir = getDirectory();
|
|
20153
|
+
debugLog.info("Checking needsBootstrap", { directory: dir });
|
|
20154
|
+
const needsBoot = await needsBootstrap(dir);
|
|
20155
|
+
debugLog.info("needsBootstrap result", { needsBoot });
|
|
20156
|
+
if (needsBoot) {
|
|
20157
|
+
debugLog.info("Bootstrap needed, skipping initial check");
|
|
20046
20158
|
return;
|
|
20047
|
-
|
|
20048
|
-
|
|
20159
|
+
}
|
|
20160
|
+
debugLog.info("Loading project state");
|
|
20161
|
+
const state = await getProjectState(dir);
|
|
20162
|
+
debugLog.info("Project state loaded", {
|
|
20163
|
+
hasState: !!state,
|
|
20164
|
+
projectKey: state?.projectKey,
|
|
20165
|
+
hasToken: !!state?.projectToken
|
|
20166
|
+
});
|
|
20167
|
+
if (!state || !state.projectKey) {
|
|
20168
|
+
debugLog.info("No state or projectKey, skipping");
|
|
20049
20169
|
return;
|
|
20170
|
+
}
|
|
20171
|
+
debugLog.info("Creating API and fetching quality status", { projectKey: state.projectKey });
|
|
20050
20172
|
const api2 = createSonarQubeAPI(config2, state);
|
|
20051
20173
|
const [qgStatus, counts] = await Promise.all([
|
|
20052
20174
|
api2.qualityGate.getStatus(state.projectKey),
|
|
20053
20175
|
api2.issues.getCounts(state.projectKey)
|
|
20054
20176
|
]);
|
|
20177
|
+
debugLog.info("Quality status fetched", { qgStatus: qgStatus.projectStatus.status, counts });
|
|
20055
20178
|
const hasIssues = counts.blocker > 0 || counts.critical > 0 || counts.major > 0;
|
|
20056
20179
|
const qgFailed = qgStatus.projectStatus.status !== "OK";
|
|
20057
20180
|
if (hasIssues || qgFailed) {
|
|
@@ -20383,18 +20506,36 @@ Git operation completed with changes. Consider running:
|
|
|
20383
20506
|
}
|
|
20384
20507
|
},
|
|
20385
20508
|
"experimental.chat.system.transform": async (_input, output) => {
|
|
20509
|
+
debugLog.info("=== experimental.chat.system.transform START ===");
|
|
20386
20510
|
await loadPluginConfig();
|
|
20387
20511
|
const sonarConfig = pluginConfig?.["sonarqube"];
|
|
20512
|
+
debugLog.info("system.transform: Loading config", { hasSonarConfig: !!sonarConfig });
|
|
20388
20513
|
const config2 = loadConfig(sonarConfig);
|
|
20514
|
+
debugLog.info("system.transform: Config result", { hasConfig: !!config2, level: config2?.level });
|
|
20389
20515
|
if (!config2 || config2.level === "off") {
|
|
20516
|
+
debugLog.info("system.transform: No config or level=off, skipping");
|
|
20390
20517
|
return;
|
|
20391
20518
|
}
|
|
20392
20519
|
try {
|
|
20393
|
-
const
|
|
20520
|
+
const dir = getDirectory();
|
|
20521
|
+
debugLog.info("system.transform: Loading project state", { directory: dir });
|
|
20522
|
+
const state = await getProjectState(dir);
|
|
20523
|
+
debugLog.info("system.transform: State loaded", {
|
|
20524
|
+
hasState: !!state,
|
|
20525
|
+
projectKey: state?.projectKey,
|
|
20526
|
+
hasToken: !!state?.projectToken
|
|
20527
|
+
});
|
|
20394
20528
|
if (!state || !state.projectKey) {
|
|
20529
|
+
debugLog.info("system.transform: No state or projectKey, skipping");
|
|
20395
20530
|
return;
|
|
20396
20531
|
}
|
|
20532
|
+
debugLog.info("system.transform: Creating API", {
|
|
20533
|
+
url: config2.url,
|
|
20534
|
+
projectKey: state.projectKey,
|
|
20535
|
+
tokenLength: state.projectToken?.length
|
|
20536
|
+
});
|
|
20397
20537
|
const api2 = createSonarQubeAPI(config2, state);
|
|
20538
|
+
debugLog.info("system.transform: Fetching quality data", { projectKey: state.projectKey });
|
|
20398
20539
|
const [qgStatus, counts, newCodeResponse] = await Promise.all([
|
|
20399
20540
|
api2.qualityGate.getStatus(state.projectKey),
|
|
20400
20541
|
api2.issues.getCounts(state.projectKey),
|