karajan-code 4.28.1 → 4.29.0

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.
@@ -35,7 +35,9 @@ export class CommiterRole extends BaseRole {
35
35
  }
36
36
 
37
37
  async execute(input) {
38
- const { task, commitMessage, push = false, createPr = false } = input || {};
38
+ // KJC-TSK-0838: the caller hands the sonar stage result (pipelineSonarBlock);
39
+ // without it the stamp carries no proof and the commit gate refuses code.
40
+ const { task, commitMessage, push = false, createPr = false, sonar = null } = input || {};
39
41
 
40
42
  const isRepo = await ensureGitRepo();
41
43
  if (!isRepo) {
@@ -65,6 +67,7 @@ export class CommiterRole extends BaseRole {
65
67
  projectDir: this.config?.projectDir || process.cwd(),
66
68
  reviewer: this.config?.reviewer || "pipeline-reviewer",
67
69
  summary: "kj pipeline (commiter role): review passed",
70
+ sonar,
68
71
  }),
69
72
  });
70
73
  const commitHash = await revParse("HEAD");
@@ -37,8 +37,23 @@ export async function pickSonarScanner(scannerConfig = {}, deps = {}) {
37
37
  return { type: "docker" };
38
38
  }
39
39
 
40
+ /**
41
+ * KJC-TSK-0838: the files the scanner ITSELF reports having indexed
42
+ * (`'<path>' indexed with language '<lang>'`, emitted with sonar.verbose).
43
+ * Paths are relative to the scanned base dir. This is the proof of coverage:
44
+ * what the engine saw, not what the config claims it should see.
45
+ * @param {string} scanOutput @returns {Set<string>}
46
+ */
47
+ export function indexedFilesFrom(scanOutput) {
48
+ const files = new Set();
49
+ for (const m of String(scanOutput || "").matchAll(/'([^']+)' indexed with language '/g)) files.add(m[1]);
50
+ return files;
51
+ }
52
+
40
53
  export function buildScannerOpts(projectKey, scanner = {}) {
41
54
  const opts = [`-Dsonar.projectKey=${projectKey}`];
55
+ // KJC-TSK-0838: verbose is what makes the scanner name every indexed file.
56
+ if (scanner.verbose) opts.push("-Dsonar.verbose=true");
42
57
  if (scanner.sources) opts.push(`-Dsonar.sources=${scanner.sources}`);
43
58
  if (scanner.exclusions) opts.push(`-Dsonar.exclusions=${scanner.exclusions}`);
44
59
  if (scanner.test_inclusions) opts.push(`-Dsonar.test.inclusions=${scanner.test_inclusions}`);
@@ -225,18 +240,27 @@ export async function ensureSonarProjectProperties(cwd = process.cwd()) {
225
240
  }
226
241
  }
227
242
 
228
- export async function runSonarScan(config, projectKey = null) {
243
+ export async function runSonarScan(config, projectKey = null, { verbose = false, cwd = null } = {}) {
244
+ const scanCwd = cwd || process.cwd();
245
+ // KJC-TSK-0838 step 3 (monorepo): a nested package scans from its own
246
+ // directory under the key its properties declare — so the proof of
247
+ // coverage is about that package, not the root's `sonar.sources`.
248
+ const repoProps = await ensureSonarProjectProperties(scanCwd);
229
249
  let effectiveProjectKey;
230
- try {
231
- effectiveProjectKey = await resolveSonarProjectKey(config, { projectKey });
232
- } catch (error) {
233
- return {
234
- ok: false,
235
- projectKey: null,
236
- stdout: "",
237
- stderr: error?.message || String(error),
238
- exitCode: 1
239
- };
250
+ if (cwd && !projectKey && repoProps.declaredKey) {
251
+ effectiveProjectKey = repoProps.declaredKey;
252
+ } else {
253
+ try {
254
+ effectiveProjectKey = await resolveSonarProjectKey(config, { projectKey });
255
+ } catch (error) {
256
+ return {
257
+ ok: false,
258
+ projectKey: null,
259
+ stdout: "",
260
+ stderr: error?.message || String(error),
261
+ exitCode: 1
262
+ };
263
+ }
240
264
  }
241
265
  const sonarConfig = config?.sonarqube || {};
242
266
  const rawHost = sonarConfig.host || "http://localhost:9000";
@@ -260,7 +284,6 @@ export async function runSonarScan(config, projectKey = null) {
260
284
  }
261
285
  // KJC-BUG-0156: kj's -Dsonar.projectKey stays (scan and query must use the
262
286
  // SAME key), but the repo's properties own the LAYOUT from here on.
263
- const repoProps = await ensureSonarProjectProperties();
264
287
  const token = await resolveSonarTokenWithFallback(config, apiHost);
265
288
  if (!token) {
266
289
  return {
@@ -284,7 +307,8 @@ export async function runSonarScan(config, projectKey = null) {
284
307
  const scannerConfig = respectRepoProperties(
285
308
  normalizeScannerConfig({
286
309
  ...sonarConfig.scanner,
287
- ...coverage.scannerPatch
310
+ ...coverage.scannerPatch,
311
+ ...(verbose ? { verbose: true } : {})
288
312
  }),
289
313
  repoProps
290
314
  );
@@ -310,7 +334,7 @@ export async function runSonarScan(config, projectKey = null) {
310
334
  "run",
311
335
  "--rm",
312
336
  "-v",
313
- `${process.cwd()}:/usr/src`,
337
+ `${scanCwd}:/usr/src`,
314
338
  ...(isLocalHost ? ["--add-host", "host.docker.internal:host-gateway"] : []),
315
339
  ...(isLocalHost || isExternalSonar ? [] : ["--network", sonarNetwork]),
316
340
  "-e", "SONAR_HOST_URL",
@@ -320,10 +344,11 @@ export async function runSonarScan(config, projectKey = null) {
320
344
  ];
321
345
  }
322
346
 
323
- const result = await runCommand(cmd, args, { timeout: scannerTimeout, env });
347
+ const result = await runCommand(cmd, args, { timeout: scannerTimeout, env, cwd: scanCwd });
324
348
  return {
325
349
  ok: result.exitCode === 0,
326
350
  projectKey: effectiveProjectKey,
351
+ cwd: scanCwd,
327
352
  scanner: pick.type,
328
353
  note,
329
354
  stdout: result.stdout,
@@ -4,6 +4,7 @@
4
4
  export {
5
5
  resolveHome,
6
6
  getKarajanHome,
7
+ withKarajanHome,
7
8
  __resetKjHomeWarningForTests,
8
9
  getSessionRoot,
9
10
  getSonarComposePath,