@codacy/analysis-runner 0.1.0 → 0.2.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.
- package/dist/index.d.ts +39 -1
- package/dist/index.js +262 -41
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,18 @@ interface AnalyzeOptions {
|
|
|
34
34
|
/** Target execution environment. "local" = developer machine, "container" = Codacy Docker runner.
|
|
35
35
|
* Phase 9 implements the actual container path; this field is accepted but currently ignored. */
|
|
36
36
|
runner?: "local" | "container";
|
|
37
|
+
/**
|
|
38
|
+
* Git-aware file scope. Mutually exclusive options:
|
|
39
|
+
* - `"staged"` — analyze only files in the git staging area
|
|
40
|
+
* - `{ diff: string | true }` — analyze files changed vs a base ref (true = auto-detect)
|
|
41
|
+
* - `"pr"` — analyze files in the current pull request
|
|
42
|
+
*
|
|
43
|
+
* Resolved files are intersected with `files` if both are provided.
|
|
44
|
+
* If the resolved set is empty, analysis returns immediately with zero issues.
|
|
45
|
+
*/
|
|
46
|
+
gitScope?: "staged" | {
|
|
47
|
+
diff: string | true;
|
|
48
|
+
} | "pr";
|
|
37
49
|
/** Logger for pipeline progress messages (install status, etc.). Defaults to no-op. */
|
|
38
50
|
logger?: Logger;
|
|
39
51
|
/** Called when a tool starts executing. */
|
|
@@ -278,6 +290,32 @@ declare function resolveEngineToAdapter(engineName: string, adapters: Readonly<T
|
|
|
278
290
|
*/
|
|
279
291
|
declare function applyCodacyYamlExcludes(config: CodacyConfig, yamlConfig: CodacyYamlConfig, adapters: Readonly<ToolAdapter>[], logger?: Logger): CodacyConfig;
|
|
280
292
|
|
|
293
|
+
/**
|
|
294
|
+
* File discovery and routing — finds files in a repository, applies exclusion
|
|
295
|
+
* layers (.gitignore, global exclude, per-tool exclude), and routes files to
|
|
296
|
+
* the appropriate tool adapters based on file patterns.
|
|
297
|
+
*/
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Returns files changed in the git staging area (index), excluding deleted files.
|
|
301
|
+
* Used by `--staged` to analyze only what's about to be committed.
|
|
302
|
+
*/
|
|
303
|
+
declare function listStagedFiles(repositoryRoot: string): string[];
|
|
304
|
+
/**
|
|
305
|
+
* Returns files changed between a base ref and HEAD, excluding deleted files.
|
|
306
|
+
* Uses the three-dot diff (`base...HEAD`) to show only changes since divergence.
|
|
307
|
+
*
|
|
308
|
+
* If `base` is omitted, auto-detects the default branch via `detectDefaultBranch()`.
|
|
309
|
+
*/
|
|
310
|
+
declare function listDiffFiles(repositoryRoot: string, base?: string): string[];
|
|
311
|
+
/**
|
|
312
|
+
* Returns files changed in the current pull request.
|
|
313
|
+
*
|
|
314
|
+
* Tries `gh pr view` first for accuracy (handles renames, squash merges).
|
|
315
|
+
* Falls back to git merge-base diff when gh is unavailable or not in a PR context.
|
|
316
|
+
*/
|
|
317
|
+
declare function listPrFiles(repositoryRoot: string): string[];
|
|
318
|
+
|
|
281
319
|
/**
|
|
282
320
|
* Codacy API client — thin wrappers around the generated OpenAPI client.
|
|
283
321
|
*
|
|
@@ -361,4 +399,4 @@ declare function rotateLogFiles(logsDir: string, maxFiles: number): void;
|
|
|
361
399
|
*/
|
|
362
400
|
declare function createLogger(options?: LoggerOptions): Logger;
|
|
363
401
|
|
|
364
|
-
export { type AnalyzeOptions, type CodacyYamlConfig, type CodacyYamlEngineConfig, type ExecutionMode, type InitDefaultStats, type InitLocalStats, type InitRemoteStats, type LoggerOptions, analyze, applyCodacyYamlExcludes, buildToolConfig, clearAdapters, configureApiToken, createCodacyConfig, createLogger, detectLanguages, formatOutput, formatTextSummary, getRegisteredAdapters, initContainerConfig, initDefaultConfig, initLocalConfig, initRemoteConfig, readCodacyConfig, readCodacyYaml, registerAdapter, resolveEngineToAdapter, rotateLogFiles, validateApiToken, writeCodacyConfig };
|
|
402
|
+
export { type AnalyzeOptions, type CodacyYamlConfig, type CodacyYamlEngineConfig, type ExecutionMode, type InitDefaultStats, type InitLocalStats, type InitRemoteStats, type LoggerOptions, analyze, applyCodacyYamlExcludes, buildToolConfig, clearAdapters, configureApiToken, createCodacyConfig, createLogger, detectLanguages, formatOutput, formatTextSummary, getRegisteredAdapters, initContainerConfig, initDefaultConfig, initLocalConfig, initRemoteConfig, listDiffFiles, listPrFiles, listStagedFiles, readCodacyConfig, readCodacyYaml, registerAdapter, resolveEngineToAdapter, rotateLogFiles, validateApiToken, writeCodacyConfig };
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,9 @@ __export(index_exports, {
|
|
|
45
45
|
initDefaultConfig: () => initDefaultConfig,
|
|
46
46
|
initLocalConfig: () => initLocalConfig,
|
|
47
47
|
initRemoteConfig: () => initRemoteConfig,
|
|
48
|
+
listDiffFiles: () => listDiffFiles,
|
|
49
|
+
listPrFiles: () => listPrFiles,
|
|
50
|
+
listStagedFiles: () => listStagedFiles,
|
|
48
51
|
readCodacyConfig: () => readCodacyConfig,
|
|
49
52
|
readCodacyYaml: () => readCodacyYaml,
|
|
50
53
|
registerAdapter: () => registerAdapter,
|
|
@@ -207,6 +210,91 @@ function routeFilesToTool(files, adapter, toolConfig) {
|
|
|
207
210
|
);
|
|
208
211
|
});
|
|
209
212
|
}
|
|
213
|
+
function listStagedFiles(repositoryRoot) {
|
|
214
|
+
try {
|
|
215
|
+
const output = (0, import_child_process.execSync)("git diff --cached --name-only --diff-filter=d", {
|
|
216
|
+
cwd: repositoryRoot,
|
|
217
|
+
encoding: "utf-8",
|
|
218
|
+
maxBuffer: 10 * 1024 * 1024
|
|
219
|
+
}).trim();
|
|
220
|
+
return output ? output.split("\n").filter(Boolean).sort() : [];
|
|
221
|
+
} catch {
|
|
222
|
+
throw new Error("Cannot list staged files: not inside a git repository");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function listDiffFiles(repositoryRoot, base) {
|
|
226
|
+
const baseBranch = base ?? detectDefaultBranch(repositoryRoot);
|
|
227
|
+
try {
|
|
228
|
+
const output = (0, import_child_process.execFileSync)(
|
|
229
|
+
"git",
|
|
230
|
+
["diff", "--name-only", "--diff-filter=d", `${baseBranch}...HEAD`],
|
|
231
|
+
{ cwd: repositoryRoot, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
232
|
+
).trim();
|
|
233
|
+
return output ? output.split("\n").filter(Boolean).sort() : [];
|
|
234
|
+
} catch {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`Cannot diff against "${baseBranch}": ref not found or not inside a git repository. Specify a base explicitly with --diff <base>.`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function listPrFiles(repositoryRoot) {
|
|
241
|
+
try {
|
|
242
|
+
const output = (0, import_child_process.execSync)("gh pr view --json files --jq '.files[].path'", {
|
|
243
|
+
cwd: repositoryRoot,
|
|
244
|
+
encoding: "utf-8",
|
|
245
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
246
|
+
timeout: 15e3
|
|
247
|
+
}).trim();
|
|
248
|
+
if (output) {
|
|
249
|
+
return output.split("\n").filter(Boolean).sort();
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
}
|
|
253
|
+
const baseBranch = detectDefaultBranch(repositoryRoot);
|
|
254
|
+
try {
|
|
255
|
+
const mergeBase = (0, import_child_process.execFileSync)("git", ["merge-base", "HEAD", baseBranch], {
|
|
256
|
+
cwd: repositoryRoot,
|
|
257
|
+
encoding: "utf-8"
|
|
258
|
+
}).trim();
|
|
259
|
+
const output = (0, import_child_process.execFileSync)(
|
|
260
|
+
"git",
|
|
261
|
+
["diff", "--name-only", "--diff-filter=d", `${mergeBase}...HEAD`],
|
|
262
|
+
{ cwd: repositoryRoot, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
263
|
+
).trim();
|
|
264
|
+
return output ? output.split("\n").filter(Boolean).sort() : [];
|
|
265
|
+
} catch {
|
|
266
|
+
throw new Error(
|
|
267
|
+
`Cannot determine PR files: gh CLI unavailable and git merge-base with "${baseBranch}" failed. Use --diff <base> instead.`
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function detectDefaultBranch(repositoryRoot) {
|
|
272
|
+
try {
|
|
273
|
+
const ref = (0, import_child_process.execSync)("git rev-parse --abbrev-ref origin/HEAD", {
|
|
274
|
+
cwd: repositoryRoot,
|
|
275
|
+
encoding: "utf-8",
|
|
276
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
277
|
+
}).trim();
|
|
278
|
+
if (ref && ref !== "origin/HEAD") {
|
|
279
|
+
return ref;
|
|
280
|
+
}
|
|
281
|
+
} catch {
|
|
282
|
+
}
|
|
283
|
+
for (const branch of ["origin/main", "origin/master"]) {
|
|
284
|
+
try {
|
|
285
|
+
(0, import_child_process.execFileSync)("git", ["rev-parse", "--verify", branch], {
|
|
286
|
+
cwd: repositoryRoot,
|
|
287
|
+
encoding: "utf-8",
|
|
288
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
289
|
+
});
|
|
290
|
+
return branch;
|
|
291
|
+
} catch {
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
throw new Error(
|
|
295
|
+
"Cannot auto-detect default branch: no origin/HEAD, origin/main, or origin/master found. Specify a base explicitly with --diff <base>."
|
|
296
|
+
);
|
|
297
|
+
}
|
|
210
298
|
function filterByTargetFiles(allFiles, targetPatterns) {
|
|
211
299
|
if (targetPatterns.length === 0) return allFiles;
|
|
212
300
|
const normalized = targetPatterns.map((p) => p.replace(/^\.\//, ""));
|
|
@@ -225,16 +313,24 @@ function filterByTargetFiles(allFiles, targetPatterns) {
|
|
|
225
313
|
// src/executor.ts
|
|
226
314
|
async function runTool(adapter, ctx, codacyToolConfig, timeoutMs) {
|
|
227
315
|
const startTime = Date.now();
|
|
228
|
-
ctx.logger.debug("runTool started", {
|
|
316
|
+
ctx.logger.debug("runTool started", {
|
|
317
|
+
toolId: adapter.id,
|
|
318
|
+
fileCount: ctx.targetFiles.length,
|
|
319
|
+
timeoutMs
|
|
320
|
+
});
|
|
229
321
|
try {
|
|
230
322
|
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
231
|
-
setTimeout(
|
|
323
|
+
setTimeout(
|
|
324
|
+
() => reject(new Error(`TIMEOUT: Tool ${adapter.id} exceeded ${timeoutMs}ms`)),
|
|
325
|
+
timeoutMs
|
|
326
|
+
);
|
|
327
|
+
});
|
|
328
|
+
const result = await Promise.race([adapter.analyze(ctx, codacyToolConfig), timeoutPromise]);
|
|
329
|
+
ctx.logger.debug("runTool completed", {
|
|
330
|
+
toolId: adapter.id,
|
|
331
|
+
issueCount: result.summary.issueCount,
|
|
332
|
+
durationMs: result.summary.durationMs
|
|
232
333
|
});
|
|
233
|
-
const result = await Promise.race([
|
|
234
|
-
adapter.analyze(ctx, codacyToolConfig),
|
|
235
|
-
timeoutPromise
|
|
236
|
-
]);
|
|
237
|
-
ctx.logger.debug("runTool completed", { toolId: adapter.id, issueCount: result.summary.issueCount, durationMs: result.summary.durationMs });
|
|
238
334
|
return result;
|
|
239
335
|
} catch (err) {
|
|
240
336
|
const durationMs = Date.now() - startTime;
|
|
@@ -242,7 +338,11 @@ async function runTool(adapter, ctx, codacyToolConfig, timeoutMs) {
|
|
|
242
338
|
if (isTimeout) {
|
|
243
339
|
ctx.logger.error("Tool timed out", { toolId: adapter.id, timeoutMs, elapsedMs: durationMs });
|
|
244
340
|
} else {
|
|
245
|
-
ctx.logger.error("Tool execution failed", {
|
|
341
|
+
ctx.logger.error("Tool execution failed", {
|
|
342
|
+
toolId: adapter.id,
|
|
343
|
+
error: err instanceof Error ? err.message : String(err),
|
|
344
|
+
durationMs
|
|
345
|
+
});
|
|
246
346
|
}
|
|
247
347
|
const now = /* @__PURE__ */ new Date();
|
|
248
348
|
return {
|
|
@@ -277,7 +377,12 @@ async function runToolsSequential(tools, timeoutMs, callbacks) {
|
|
|
277
377
|
for (const { adapter, ctx, codacyToolConfig } of tools) {
|
|
278
378
|
callbacks?.onToolStart?.(adapter.id, adapter.displayName);
|
|
279
379
|
const result = await runTool(adapter, ctx, codacyToolConfig, timeoutMs);
|
|
280
|
-
callbacks?.onToolComplete?.(
|
|
380
|
+
callbacks?.onToolComplete?.(
|
|
381
|
+
adapter.id,
|
|
382
|
+
adapter.displayName,
|
|
383
|
+
result.summary.issueCount,
|
|
384
|
+
result.summary.durationMs
|
|
385
|
+
);
|
|
281
386
|
results.push(result);
|
|
282
387
|
}
|
|
283
388
|
return results;
|
|
@@ -291,7 +396,12 @@ async function runToolsParallel(tools, timeoutMs, concurrency, callbacks) {
|
|
|
291
396
|
const { adapter, ctx, codacyToolConfig } = tools[index];
|
|
292
397
|
callbacks?.onToolStart?.(adapter.id, adapter.displayName);
|
|
293
398
|
results[index] = await runTool(adapter, ctx, codacyToolConfig, timeoutMs);
|
|
294
|
-
callbacks?.onToolComplete?.(
|
|
399
|
+
callbacks?.onToolComplete?.(
|
|
400
|
+
adapter.id,
|
|
401
|
+
adapter.displayName,
|
|
402
|
+
results[index].summary.issueCount,
|
|
403
|
+
results[index].summary.durationMs
|
|
404
|
+
);
|
|
295
405
|
}
|
|
296
406
|
}
|
|
297
407
|
const workers = Array.from({ length: Math.min(concurrency, tools.length) }, () => worker());
|
|
@@ -337,11 +447,19 @@ async function analyze(options) {
|
|
|
337
447
|
const availability = await Promise.race([
|
|
338
448
|
adapter.checkAvailability(ctx),
|
|
339
449
|
new Promise(
|
|
340
|
-
(_, reject) => setTimeout(
|
|
450
|
+
(_, reject) => setTimeout(
|
|
451
|
+
() => reject(new Error(`checkAvailability timed out after ${availabilityTimeout}ms`)),
|
|
452
|
+
availabilityTimeout
|
|
453
|
+
)
|
|
341
454
|
)
|
|
342
455
|
]);
|
|
343
456
|
if (availability.available) {
|
|
344
|
-
logger.debug("Tool available", {
|
|
457
|
+
logger.debug("Tool available", {
|
|
458
|
+
toolId: adapter.id,
|
|
459
|
+
version: availability.version,
|
|
460
|
+
installation: availability.installation,
|
|
461
|
+
durationMs: Date.now() - checkStart
|
|
462
|
+
});
|
|
345
463
|
ready.push({
|
|
346
464
|
toolId: adapter.id,
|
|
347
465
|
displayName: adapter.displayName,
|
|
@@ -350,7 +468,11 @@ async function analyze(options) {
|
|
|
350
468
|
runner: "local"
|
|
351
469
|
});
|
|
352
470
|
} else {
|
|
353
|
-
logger.warn("Tool unavailable", {
|
|
471
|
+
logger.warn("Tool unavailable", {
|
|
472
|
+
toolId: adapter.id,
|
|
473
|
+
reason: availability.reason,
|
|
474
|
+
durationMs: Date.now() - checkStart
|
|
475
|
+
});
|
|
354
476
|
unavailable.push({
|
|
355
477
|
toolId: adapter.id,
|
|
356
478
|
displayName: adapter.displayName,
|
|
@@ -359,7 +481,11 @@ async function analyze(options) {
|
|
|
359
481
|
});
|
|
360
482
|
}
|
|
361
483
|
} catch (err) {
|
|
362
|
-
logger.warn("Availability check failed", {
|
|
484
|
+
logger.warn("Availability check failed", {
|
|
485
|
+
toolId: adapter.id,
|
|
486
|
+
error: err instanceof Error ? err.message : String(err),
|
|
487
|
+
durationMs: Date.now() - checkStart
|
|
488
|
+
});
|
|
363
489
|
unavailable.push({
|
|
364
490
|
toolId: adapter.id,
|
|
365
491
|
displayName: adapter.displayName,
|
|
@@ -378,7 +504,11 @@ async function analyze(options) {
|
|
|
378
504
|
const configuredIds = new Set(codacyConfig.tools.map((t) => t.toolId));
|
|
379
505
|
capability.ready = capability.ready.filter((t) => configuredIds.has(t.toolId));
|
|
380
506
|
capability.unavailable = capability.unavailable.filter((t) => configuredIds.has(t.toolId));
|
|
381
|
-
logger.debug("Filtered by config", {
|
|
507
|
+
logger.debug("Filtered by config", {
|
|
508
|
+
readyBefore,
|
|
509
|
+
readyAfter: capability.ready.length,
|
|
510
|
+
configuredToolCount: configuredIds.size
|
|
511
|
+
});
|
|
382
512
|
} else {
|
|
383
513
|
logger.debug("No codacy config found, running all available tools");
|
|
384
514
|
}
|
|
@@ -407,7 +537,9 @@ async function analyze(options) {
|
|
|
407
537
|
});
|
|
408
538
|
capability.unavailable.splice(i, 1);
|
|
409
539
|
} else {
|
|
410
|
-
logger.error(
|
|
540
|
+
logger.error(
|
|
541
|
+
`${adapter.displayName} post-install check failed: ${recheck.reason ?? "unknown"}`
|
|
542
|
+
);
|
|
411
543
|
installErrors.push({
|
|
412
544
|
toolId: adapter.id,
|
|
413
545
|
phase: "toolInstall",
|
|
@@ -445,7 +577,15 @@ async function analyze(options) {
|
|
|
445
577
|
}
|
|
446
578
|
}
|
|
447
579
|
if (installErrors.length > 0) {
|
|
448
|
-
return buildResult(
|
|
580
|
+
return buildResult(
|
|
581
|
+
startedAt,
|
|
582
|
+
options.repositoryRoot,
|
|
583
|
+
mode,
|
|
584
|
+
capability,
|
|
585
|
+
[],
|
|
586
|
+
installErrors,
|
|
587
|
+
[]
|
|
588
|
+
);
|
|
449
589
|
}
|
|
450
590
|
}
|
|
451
591
|
if (mode === "inspect") {
|
|
@@ -478,19 +618,41 @@ async function analyze(options) {
|
|
|
478
618
|
}
|
|
479
619
|
if (mode === "strict" && capability.unavailable.length > 0) {
|
|
480
620
|
const missingTools = capability.unavailable.map((u) => u.toolId).join(", ");
|
|
481
|
-
return buildResult(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
621
|
+
return buildResult(
|
|
622
|
+
startedAt,
|
|
623
|
+
options.repositoryRoot,
|
|
624
|
+
mode,
|
|
625
|
+
capability,
|
|
626
|
+
[],
|
|
627
|
+
[
|
|
628
|
+
{
|
|
629
|
+
toolId: "runner",
|
|
630
|
+
phase: "requirementCheck",
|
|
631
|
+
kind: "UnavailableTools",
|
|
632
|
+
message: `Strict mode: the following tools are unavailable: ${missingTools}`,
|
|
633
|
+
level: "error"
|
|
634
|
+
}
|
|
635
|
+
],
|
|
636
|
+
[]
|
|
637
|
+
);
|
|
490
638
|
}
|
|
491
639
|
const globalExclude = codacyConfig?.exclude || [];
|
|
492
640
|
let allFiles = listRepoFiles(options.repositoryRoot);
|
|
493
641
|
logger.debug("File discovery", { totalFiles: allFiles.length });
|
|
642
|
+
if (options.gitScope) {
|
|
643
|
+
const scopeFiles = resolveGitScope(options.repositoryRoot, options.gitScope);
|
|
644
|
+
logger.debug("Git scope resolved", {
|
|
645
|
+
scope: typeof options.gitScope === "string" ? options.gitScope : "diff",
|
|
646
|
+
fileCount: scopeFiles.length
|
|
647
|
+
});
|
|
648
|
+
if (scopeFiles.length === 0) {
|
|
649
|
+
logger.info("Git scope resolved to zero files, skipping analysis");
|
|
650
|
+
return buildResult(startedAt, options.repositoryRoot, mode, capability, [], [], []);
|
|
651
|
+
}
|
|
652
|
+
const scopeSet = new Set(scopeFiles);
|
|
653
|
+
allFiles = allFiles.filter((f) => scopeSet.has(f));
|
|
654
|
+
logger.debug("After git scope intersection", { fileCount: allFiles.length });
|
|
655
|
+
}
|
|
494
656
|
if (options.files && options.files.length > 0) {
|
|
495
657
|
allFiles = filterByTargetFiles(allFiles, options.files);
|
|
496
658
|
logger.debug("Filtered by target files", { afterFilter: allFiles.length });
|
|
@@ -515,7 +677,11 @@ async function analyze(options) {
|
|
|
515
677
|
const ctx = makeToolContext(baseCtx, adapter, toolFiles);
|
|
516
678
|
const configCheck = await adapter.checkLocalConfigurationFile(ctx);
|
|
517
679
|
const codacyToolConfig = buildToolConfig(codacyConfig, adapter, configCheck);
|
|
518
|
-
logger.debug("Tool config resolved", {
|
|
680
|
+
logger.debug("Tool config resolved", {
|
|
681
|
+
toolId: adapter.id,
|
|
682
|
+
configSource: codacyToolConfig.useLocalConfigurationFile ? "local" : "codacy",
|
|
683
|
+
patternCount: codacyToolConfig.patterns?.length ?? 0
|
|
684
|
+
});
|
|
519
685
|
const readyEntry = capability.ready.find((r) => r.toolId === adapter.id);
|
|
520
686
|
if (readyEntry) {
|
|
521
687
|
if (configCheck.found && codacyToolConfig.useLocalConfigurationFile) {
|
|
@@ -527,7 +693,11 @@ async function analyze(options) {
|
|
|
527
693
|
}
|
|
528
694
|
toolRuns.push({ adapter, ctx, codacyToolConfig });
|
|
529
695
|
}
|
|
530
|
-
logger.info("Starting tool execution", {
|
|
696
|
+
logger.info("Starting tool execution", {
|
|
697
|
+
toolCount: toolRuns.length,
|
|
698
|
+
parallel: parallelTools > 1,
|
|
699
|
+
parallelTools
|
|
700
|
+
});
|
|
531
701
|
const callbacks = {
|
|
532
702
|
onToolStart: options.onToolStart,
|
|
533
703
|
onToolComplete: options.onToolComplete
|
|
@@ -541,8 +711,20 @@ async function analyze(options) {
|
|
|
541
711
|
const allIssues = normalizeIssues(results.flatMap((r) => r.issues));
|
|
542
712
|
const allErrors = results.flatMap((r) => r.errors);
|
|
543
713
|
const allSummaries = results.map((r) => r.summary);
|
|
544
|
-
logger.info("Pipeline complete", {
|
|
545
|
-
|
|
714
|
+
logger.info("Pipeline complete", {
|
|
715
|
+
totalIssues: allIssues.length,
|
|
716
|
+
totalErrors: allErrors.length,
|
|
717
|
+
durationMs: Date.now() - startedAt.getTime()
|
|
718
|
+
});
|
|
719
|
+
return buildResult(
|
|
720
|
+
startedAt,
|
|
721
|
+
options.repositoryRoot,
|
|
722
|
+
mode,
|
|
723
|
+
capability,
|
|
724
|
+
allIssues,
|
|
725
|
+
allErrors,
|
|
726
|
+
allSummaries
|
|
727
|
+
);
|
|
546
728
|
}
|
|
547
729
|
function makeToolContext(base, adapter, targetFiles) {
|
|
548
730
|
return {
|
|
@@ -561,6 +743,12 @@ function normalizeIssues(issues) {
|
|
|
561
743
|
return issue;
|
|
562
744
|
});
|
|
563
745
|
}
|
|
746
|
+
function resolveGitScope(repositoryRoot, scope) {
|
|
747
|
+
if (scope === "staged") return listStagedFiles(repositoryRoot);
|
|
748
|
+
if (scope === "pr") return listPrFiles(repositoryRoot);
|
|
749
|
+
const base = scope.diff === true ? void 0 : scope.diff;
|
|
750
|
+
return listDiffFiles(repositoryRoot, base);
|
|
751
|
+
}
|
|
564
752
|
function buildResult(startedAt, repositoryRoot, mode, capability, issues, errors, toolResults) {
|
|
565
753
|
const completedAt = /* @__PURE__ */ new Date();
|
|
566
754
|
return {
|
|
@@ -792,7 +980,14 @@ function formatTextSummary(result, isInspect) {
|
|
|
792
980
|
]);
|
|
793
981
|
}
|
|
794
982
|
for (const tool of unavailableTools) {
|
|
795
|
-
table.push([
|
|
983
|
+
table.push([
|
|
984
|
+
import_ansis.default.dim.red(tool.displayName ?? tool.toolId),
|
|
985
|
+
"-",
|
|
986
|
+
"-",
|
|
987
|
+
"-",
|
|
988
|
+
"-",
|
|
989
|
+
tool.reason
|
|
990
|
+
]);
|
|
796
991
|
}
|
|
797
992
|
lines.push(table.toString());
|
|
798
993
|
} else {
|
|
@@ -4602,7 +4797,11 @@ async function initLocalConfigBase(repositoryRoot, adapters2) {
|
|
|
4602
4797
|
}
|
|
4603
4798
|
async function initLocalConfig(repositoryRoot, adapters2) {
|
|
4604
4799
|
const baseConfig = await initLocalConfigBase(repositoryRoot, adapters2);
|
|
4605
|
-
const { config, codacyYamlApplied } = await enrichWithCodacyYaml(
|
|
4800
|
+
const { config, codacyYamlApplied } = await enrichWithCodacyYaml(
|
|
4801
|
+
baseConfig,
|
|
4802
|
+
repositoryRoot,
|
|
4803
|
+
adapters2
|
|
4804
|
+
);
|
|
4606
4805
|
return { config, stats: { codacyYamlApplied } };
|
|
4607
4806
|
}
|
|
4608
4807
|
async function initDefaultConfig(repositoryRoot, adapters2) {
|
|
@@ -4618,7 +4817,7 @@ async function initDefaultConfig(repositoryRoot, adapters2) {
|
|
|
4618
4817
|
for (const adapter of adapters2) {
|
|
4619
4818
|
if (toolsWithLocalConfig.has(adapter.id)) continue;
|
|
4620
4819
|
const apiTool = apiTools.find(
|
|
4621
|
-
(t) => t.prefix ? t.prefix.replace(/_$/, "") === adapter.id : t.
|
|
4820
|
+
(t) => t.prefix ? t.prefix.replace(/_$/, "") === adapter.id : t.shortName === adapter.id
|
|
4622
4821
|
);
|
|
4623
4822
|
if (!apiTool) continue;
|
|
4624
4823
|
if (!apiTool.enabledByDefault) continue;
|
|
@@ -4641,8 +4840,16 @@ async function initDefaultConfig(repositoryRoot, adapters2) {
|
|
|
4641
4840
|
addedTools++;
|
|
4642
4841
|
}
|
|
4643
4842
|
}
|
|
4644
|
-
const baseConfig = createCodacyConfig({
|
|
4645
|
-
|
|
4843
|
+
const baseConfig = createCodacyConfig({
|
|
4844
|
+
source: "default",
|
|
4845
|
+
languages: base.metadata.languages,
|
|
4846
|
+
tools: updatedTools
|
|
4847
|
+
});
|
|
4848
|
+
const { config, codacyYamlApplied } = await enrichWithCodacyYaml(
|
|
4849
|
+
baseConfig,
|
|
4850
|
+
repositoryRoot,
|
|
4851
|
+
adapters2
|
|
4852
|
+
);
|
|
4646
4853
|
return { config, stats: { totalApiTools: apiTools.length, addedTools, codacyYamlApplied } };
|
|
4647
4854
|
}
|
|
4648
4855
|
async function initRemoteConfig(repositoryRoot, provider, organization, repositoryName, adapters2, apiToken, onRemoteToolsFound, onToolProcessed) {
|
|
@@ -4711,8 +4918,15 @@ async function initRemoteConfig(repositoryRoot, provider, organization, reposito
|
|
|
4711
4918
|
repositoryId: repoInfo.repositoryId != null ? String(repoInfo.repositoryId) : void 0,
|
|
4712
4919
|
repositoryName
|
|
4713
4920
|
});
|
|
4714
|
-
const { config, codacyYamlApplied } = await enrichWithCodacyYaml(
|
|
4715
|
-
|
|
4921
|
+
const { config, codacyYamlApplied } = await enrichWithCodacyYaml(
|
|
4922
|
+
baseConfig,
|
|
4923
|
+
repositoryRoot,
|
|
4924
|
+
adapters2
|
|
4925
|
+
);
|
|
4926
|
+
return {
|
|
4927
|
+
config,
|
|
4928
|
+
stats: { totalRemoteTools: remoteTools.length, matchedAdapters, codacyYamlApplied }
|
|
4929
|
+
};
|
|
4716
4930
|
}
|
|
4717
4931
|
async function initContainerConfig(repositoryRoot, adapters2) {
|
|
4718
4932
|
const codacyrcPath = import_path6.default.join(repositoryRoot, ".codacyrc");
|
|
@@ -4787,8 +5001,9 @@ function rotateLogFiles(logsDir, maxFiles) {
|
|
|
4787
5001
|
}
|
|
4788
5002
|
}
|
|
4789
5003
|
}
|
|
5004
|
+
var fileSeq = 0;
|
|
4790
5005
|
function fileTimestamp() {
|
|
4791
|
-
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")
|
|
5006
|
+
return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${fileSeq++}`;
|
|
4792
5007
|
}
|
|
4793
5008
|
function enrichMessage(message, fields) {
|
|
4794
5009
|
if (!fields) return message;
|
|
@@ -4799,10 +5014,13 @@ function enrichMessage(message, fields) {
|
|
|
4799
5014
|
if (fields.configSource) parts.push(String(fields.configSource));
|
|
4800
5015
|
if (typeof fields.fileCount === "number") parts.push(`${fields.fileCount} files`);
|
|
4801
5016
|
if (typeof fields.issueCount === "number") parts.push(`${fields.issueCount} issues`);
|
|
4802
|
-
if (typeof fields.errorCount === "number" && fields.errorCount > 0)
|
|
5017
|
+
if (typeof fields.errorCount === "number" && fields.errorCount > 0)
|
|
5018
|
+
parts.push(`${fields.errorCount} errors`);
|
|
4803
5019
|
if (typeof fields.totalIssues === "number") parts.push(`${fields.totalIssues} issues`);
|
|
4804
|
-
if (typeof fields.totalErrors === "number" && fields.totalErrors > 0)
|
|
4805
|
-
|
|
5020
|
+
if (typeof fields.totalErrors === "number" && fields.totalErrors > 0)
|
|
5021
|
+
parts.push(`${fields.totalErrors} errors`);
|
|
5022
|
+
if (typeof fields.durationMs === "number")
|
|
5023
|
+
parts.push(`${(fields.durationMs / 1e3).toFixed(1)}s`);
|
|
4806
5024
|
if (fields.reason) parts.push(String(fields.reason));
|
|
4807
5025
|
if (fields.error) parts.push(String(fields.error));
|
|
4808
5026
|
if (typeof fields.found === "boolean") parts.push(fields.found ? "found" : "not found");
|
|
@@ -4878,6 +5096,9 @@ function createLogger(options = {}) {
|
|
|
4878
5096
|
initDefaultConfig,
|
|
4879
5097
|
initLocalConfig,
|
|
4880
5098
|
initRemoteConfig,
|
|
5099
|
+
listDiffFiles,
|
|
5100
|
+
listPrFiles,
|
|
5101
|
+
listStagedFiles,
|
|
4881
5102
|
readCodacyConfig,
|
|
4882
5103
|
readCodacyYaml,
|
|
4883
5104
|
registerAdapter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codacy/analysis-runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Core orchestration engine for Codacy analysis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"cli-table3": "^0.6",
|
|
13
13
|
"minimatch": "10.2.4",
|
|
14
14
|
"yaml": "^2.6.0",
|
|
15
|
-
"@codacy/tooling": "0.
|
|
15
|
+
"@codacy/tooling": "0.2.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@codacy/openapi-typescript-codegen": "0.0.9",
|
|
19
|
-
"@codacy/tools-dummy-1": "0.
|
|
19
|
+
"@codacy/tools-dummy-1": "0.2.0"
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "Codacy <support@codacy.com> (https://www.codacy.com)",
|