@codacy/analysis-runner 0.11.0 → 0.13.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/README.md +96 -21
- package/dist/index.d.ts +84 -6
- package/dist/index.js +626 -241
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -39,12 +39,15 @@ __export(index_exports, {
|
|
|
39
39
|
configureApiToken: () => configureApiToken,
|
|
40
40
|
createCodacyConfig: () => createCodacyConfig,
|
|
41
41
|
createLogger: () => createLogger,
|
|
42
|
+
createNullLogger: () => createNullLogger,
|
|
43
|
+
deleteCredentials: () => deleteCredentials,
|
|
42
44
|
detectLanguages: () => detectLanguages,
|
|
43
45
|
diffConfigs: () => diffConfigs,
|
|
44
46
|
discover: () => discover,
|
|
45
47
|
formatOutput: () => formatOutput,
|
|
46
48
|
formatTextSummary: () => formatTextSummary,
|
|
47
49
|
getAdapter: () => getAdapter,
|
|
50
|
+
getKnownDisplayNames: () => getKnownDisplayNames,
|
|
48
51
|
getRegisteredAdapters: () => getRegisteredAdapters,
|
|
49
52
|
getRegisteredDescriptors: () => getRegisteredDescriptors,
|
|
50
53
|
initAutoConfig: () => initAutoConfig,
|
|
@@ -57,6 +60,7 @@ __export(index_exports, {
|
|
|
57
60
|
listIgnoredFiles: () => listIgnoredFiles,
|
|
58
61
|
listPrFiles: () => listPrFiles,
|
|
59
62
|
listStagedFiles: () => listStagedFiles,
|
|
63
|
+
loadCredentials: () => loadCredentials,
|
|
60
64
|
mergeConfigs: () => mergeConfigs,
|
|
61
65
|
parseAutoFilters: () => parseAutoFilters,
|
|
62
66
|
readCodacyConfig: () => readCodacyConfig,
|
|
@@ -64,9 +68,11 @@ __export(index_exports, {
|
|
|
64
68
|
registerAdapter: () => registerAdapter,
|
|
65
69
|
registerLazyAdapter: () => registerLazyAdapter,
|
|
66
70
|
registerUnsupportedTool: () => registerUnsupportedTool,
|
|
71
|
+
resolveApiToken: () => resolveApiToken,
|
|
67
72
|
resolveConfigPath: () => resolveConfigPath,
|
|
68
73
|
resolveEngineToAdapter: () => resolveEngineToAdapter,
|
|
69
74
|
rotateLogFiles: () => rotateLogFiles,
|
|
75
|
+
saveCredentials: () => saveCredentials,
|
|
70
76
|
validateApiToken: () => validateApiToken,
|
|
71
77
|
writeCodacyConfig: () => writeCodacyConfig,
|
|
72
78
|
writeCodacyConfigFile: () => writeCodacyConfigFile
|
|
@@ -74,9 +80,9 @@ __export(index_exports, {
|
|
|
74
80
|
module.exports = __toCommonJS(index_exports);
|
|
75
81
|
|
|
76
82
|
// src/analyze.ts
|
|
77
|
-
var
|
|
78
|
-
var
|
|
79
|
-
var
|
|
83
|
+
var import_os2 = __toESM(require("os"));
|
|
84
|
+
var import_path4 = __toESM(require("path"));
|
|
85
|
+
var import_child_process3 = require("child_process");
|
|
80
86
|
var import_util = require("util");
|
|
81
87
|
var import_tooling3 = require("@codacy/tooling");
|
|
82
88
|
|
|
@@ -238,11 +244,13 @@ function createCodacyConfig(params = {}) {
|
|
|
238
244
|
}
|
|
239
245
|
|
|
240
246
|
// src/files.ts
|
|
241
|
-
var
|
|
247
|
+
var import_child_process2 = require("child_process");
|
|
242
248
|
var import_fs = __toESM(require("fs"));
|
|
243
249
|
var import_path2 = __toESM(require("path"));
|
|
250
|
+
var import_minimatch2 = require("minimatch");
|
|
251
|
+
|
|
252
|
+
// src/glob-matcher.ts
|
|
244
253
|
var import_minimatch = require("minimatch");
|
|
245
|
-
var MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
246
254
|
var PURE_EXTENSION_PATTERN = /^\*\*\/\*(\.[^*/.]+)$/;
|
|
247
255
|
function pureExtensionOf(pattern) {
|
|
248
256
|
const m = PURE_EXTENSION_PATTERN.exec(pattern);
|
|
@@ -325,69 +333,9 @@ var CompiledMatcher = class {
|
|
|
325
333
|
return false;
|
|
326
334
|
}
|
|
327
335
|
};
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
cwd: repositoryRoot,
|
|
332
|
-
encoding: "utf-8",
|
|
333
|
-
maxBuffer: 50 * 1024 * 1024
|
|
334
|
-
}).trim();
|
|
335
|
-
const untracked = (0, import_child_process.execSync)("git ls-files --others --exclude-standard", {
|
|
336
|
-
cwd: repositoryRoot,
|
|
337
|
-
encoding: "utf-8",
|
|
338
|
-
maxBuffer: 50 * 1024 * 1024
|
|
339
|
-
}).trim();
|
|
340
|
-
const files = /* @__PURE__ */ new Set();
|
|
341
|
-
for (const f of tracked.split("\n")) {
|
|
342
|
-
if (f) files.add(f);
|
|
343
|
-
}
|
|
344
|
-
for (const f of untracked.split("\n")) {
|
|
345
|
-
if (f) files.add(f);
|
|
346
|
-
}
|
|
347
|
-
return Array.from(files).sort();
|
|
348
|
-
} catch {
|
|
349
|
-
return [];
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
function filterOversizedFiles(files, repositoryRoot, logger) {
|
|
353
|
-
const result = [];
|
|
354
|
-
let skipped = 0;
|
|
355
|
-
for (const f of files) {
|
|
356
|
-
try {
|
|
357
|
-
const stat = import_fs.default.statSync(import_path2.default.join(repositoryRoot, f));
|
|
358
|
-
if (stat.size > MAX_FILE_SIZE_BYTES) {
|
|
359
|
-
skipped++;
|
|
360
|
-
logger?.debug("Skipping oversized file", {
|
|
361
|
-
file: f,
|
|
362
|
-
sizeKB: Math.round(stat.size / 1024),
|
|
363
|
-
limitKB: MAX_FILE_SIZE_BYTES / 1024
|
|
364
|
-
});
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
} catch {
|
|
368
|
-
}
|
|
369
|
-
result.push(f);
|
|
370
|
-
}
|
|
371
|
-
if (skipped > 0) {
|
|
372
|
-
logger?.info("Filtered oversized files", { skipped, remaining: result.length });
|
|
373
|
-
}
|
|
374
|
-
return result;
|
|
375
|
-
}
|
|
376
|
-
function applyExclusions(files, globalExclude, toolExclude) {
|
|
377
|
-
if (globalExclude.length === 0 && toolExclude.length === 0) return files;
|
|
378
|
-
const matcher = new CompiledMatcher([...globalExclude, ...toolExclude]);
|
|
379
|
-
if (matcher.isEmpty) return files;
|
|
380
|
-
return files.filter((file) => !matcher.matches(file, import_path2.default.basename(file)));
|
|
381
|
-
}
|
|
382
|
-
function routeFilesToTool(files, adapter, toolConfig) {
|
|
383
|
-
const patterns = [...adapter.filePatterns];
|
|
384
|
-
if (toolConfig?.extraFilePatterns) {
|
|
385
|
-
patterns.push(...toolConfig.extraFilePatterns);
|
|
386
|
-
}
|
|
387
|
-
const matcher = new CompiledMatcher(patterns);
|
|
388
|
-
if (matcher.matchAll) return files;
|
|
389
|
-
return files.filter((file) => matcher.matches(file, import_path2.default.basename(file)));
|
|
390
|
-
}
|
|
336
|
+
|
|
337
|
+
// src/git-scope.ts
|
|
338
|
+
var import_child_process = require("child_process");
|
|
391
339
|
function listStagedFiles(repositoryRoot) {
|
|
392
340
|
try {
|
|
393
341
|
const output = (0, import_child_process.execSync)("git diff --cached --name-only --diff-filter=d", {
|
|
@@ -417,7 +365,7 @@ function listDiffFiles(repositoryRoot, base) {
|
|
|
417
365
|
}
|
|
418
366
|
function listPrFiles(repositoryRoot) {
|
|
419
367
|
try {
|
|
420
|
-
const output = (0, import_child_process.execSync)(
|
|
368
|
+
const output = (0, import_child_process.execSync)('gh pr view --json files --jq ".files[].path"', {
|
|
421
369
|
cwd: repositoryRoot,
|
|
422
370
|
encoding: "utf-8",
|
|
423
371
|
maxBuffer: 10 * 1024 * 1024,
|
|
@@ -473,11 +421,145 @@ function detectDefaultBranch(repositoryRoot) {
|
|
|
473
421
|
"Cannot auto-detect default branch: no origin/HEAD, origin/main, or origin/master found. Specify a base explicitly with --diff <base>."
|
|
474
422
|
);
|
|
475
423
|
}
|
|
424
|
+
|
|
425
|
+
// src/files.ts
|
|
426
|
+
var MAX_FILE_SIZE_BYTES = 150 * 1024;
|
|
427
|
+
var DEPENDENCY_MANIFEST_FILES = /* @__PURE__ */ new Set([
|
|
428
|
+
// JavaScript / TypeScript
|
|
429
|
+
"package.json",
|
|
430
|
+
"package-lock.json",
|
|
431
|
+
"npm-shrinkwrap.json",
|
|
432
|
+
"yarn.lock",
|
|
433
|
+
"pnpm-lock.yaml",
|
|
434
|
+
"bun.lock",
|
|
435
|
+
// Python
|
|
436
|
+
"requirements.txt",
|
|
437
|
+
"Pipfile",
|
|
438
|
+
"Pipfile.lock",
|
|
439
|
+
"poetry.lock",
|
|
440
|
+
"uv.lock",
|
|
441
|
+
// PHP
|
|
442
|
+
"composer.json",
|
|
443
|
+
"composer.lock",
|
|
444
|
+
// Ruby
|
|
445
|
+
"Gemfile.lock",
|
|
446
|
+
// Rust
|
|
447
|
+
"Cargo.toml",
|
|
448
|
+
"Cargo.lock",
|
|
449
|
+
// Go
|
|
450
|
+
"go.mod",
|
|
451
|
+
"go.sum",
|
|
452
|
+
// .NET
|
|
453
|
+
"packages.config",
|
|
454
|
+
"packages.lock.json",
|
|
455
|
+
"Directory.Packages.props",
|
|
456
|
+
"Packages.props",
|
|
457
|
+
// Java / Scala
|
|
458
|
+
"pom.xml",
|
|
459
|
+
"gradle.lockfile",
|
|
460
|
+
"build.gradle",
|
|
461
|
+
"build.gradle.kts",
|
|
462
|
+
"build.sbt.lock",
|
|
463
|
+
// Dart / Flutter
|
|
464
|
+
"pubspec.yaml",
|
|
465
|
+
"pubspec.lock",
|
|
466
|
+
// Elixir
|
|
467
|
+
"mix.lock",
|
|
468
|
+
// Swift / CocoaPods
|
|
469
|
+
"Package.resolved",
|
|
470
|
+
"Podfile.lock",
|
|
471
|
+
// C / C++ (Conan)
|
|
472
|
+
"conan.lock",
|
|
473
|
+
// Erlang
|
|
474
|
+
"rebar.lock"
|
|
475
|
+
]);
|
|
476
|
+
var DEPENDENCY_MANIFEST_SUFFIXES = [".deps.json"];
|
|
477
|
+
function isDependencyManifest(relativePath) {
|
|
478
|
+
const base = relativePath.split("/").pop() ?? "";
|
|
479
|
+
if (DEPENDENCY_MANIFEST_FILES.has(base)) return true;
|
|
480
|
+
return DEPENDENCY_MANIFEST_SUFFIXES.some((suffix) => base.endsWith(suffix));
|
|
481
|
+
}
|
|
482
|
+
function listRepoFiles(repositoryRoot) {
|
|
483
|
+
try {
|
|
484
|
+
const tracked = (0, import_child_process2.execSync)("git ls-files", {
|
|
485
|
+
cwd: repositoryRoot,
|
|
486
|
+
encoding: "utf-8",
|
|
487
|
+
maxBuffer: 50 * 1024 * 1024
|
|
488
|
+
}).trim();
|
|
489
|
+
const untracked = (0, import_child_process2.execSync)("git ls-files --others --exclude-standard", {
|
|
490
|
+
cwd: repositoryRoot,
|
|
491
|
+
encoding: "utf-8",
|
|
492
|
+
maxBuffer: 50 * 1024 * 1024
|
|
493
|
+
}).trim();
|
|
494
|
+
const files = /* @__PURE__ */ new Set();
|
|
495
|
+
for (const f of tracked.split("\n")) {
|
|
496
|
+
if (f) files.add(f);
|
|
497
|
+
}
|
|
498
|
+
for (const f of untracked.split("\n")) {
|
|
499
|
+
if (f) files.add(f);
|
|
500
|
+
}
|
|
501
|
+
return Array.from(files).sort();
|
|
502
|
+
} catch {
|
|
503
|
+
return [];
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function filterOversizedFiles(files, repositoryRoot, logger) {
|
|
507
|
+
const result = [];
|
|
508
|
+
const skipped = [];
|
|
509
|
+
for (const f of files) {
|
|
510
|
+
try {
|
|
511
|
+
const stat = import_fs.default.statSync(import_path2.default.join(repositoryRoot, f));
|
|
512
|
+
if (stat.size > MAX_FILE_SIZE_BYTES) {
|
|
513
|
+
if (isDependencyManifest(f)) {
|
|
514
|
+
logger?.debug("Keeping oversized dependency manifest", {
|
|
515
|
+
file: f,
|
|
516
|
+
sizeKB: Math.round(stat.size / 1024),
|
|
517
|
+
limitKB: MAX_FILE_SIZE_BYTES / 1024
|
|
518
|
+
});
|
|
519
|
+
result.push(f);
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
skipped.push({ filePath: f, sizeBytes: stat.size });
|
|
523
|
+
logger?.debug("Skipping oversized file", {
|
|
524
|
+
file: f,
|
|
525
|
+
sizeKB: Math.round(stat.size / 1024),
|
|
526
|
+
limitKB: MAX_FILE_SIZE_BYTES / 1024
|
|
527
|
+
});
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
} catch {
|
|
531
|
+
}
|
|
532
|
+
result.push(f);
|
|
533
|
+
}
|
|
534
|
+
if (skipped.length > 0) {
|
|
535
|
+
logger?.info("Filtered oversized files", {
|
|
536
|
+
skipped: skipped.length,
|
|
537
|
+
remaining: result.length,
|
|
538
|
+
limitKB: MAX_FILE_SIZE_BYTES / 1024
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
return { files: result, skipped };
|
|
542
|
+
}
|
|
543
|
+
function applyExclusions(files, globalExclude, toolExclude) {
|
|
544
|
+
if (globalExclude.length === 0 && toolExclude.length === 0) return files;
|
|
545
|
+
const matcher = new CompiledMatcher([...globalExclude, ...toolExclude]);
|
|
546
|
+
if (matcher.isEmpty) return files;
|
|
547
|
+
return files.filter((file) => !matcher.matches(file, import_path2.default.basename(file)));
|
|
548
|
+
}
|
|
549
|
+
function routeFilesToTool(files, adapter, toolConfig) {
|
|
550
|
+
const patterns = [...adapter.filePatterns];
|
|
551
|
+
if (toolConfig?.extraFilePatterns) {
|
|
552
|
+
patterns.push(...toolConfig.extraFilePatterns);
|
|
553
|
+
}
|
|
554
|
+
const matcher = new CompiledMatcher(patterns);
|
|
555
|
+
if (matcher.matchAll) return files;
|
|
556
|
+
return files.filter((file) => matcher.matches(file, import_path2.default.basename(file)));
|
|
557
|
+
}
|
|
476
558
|
function filterByTargetFiles(allFiles, targetPatterns) {
|
|
477
559
|
if (targetPatterns.length === 0) return allFiles;
|
|
478
560
|
const normalized = targetPatterns.map((p) => p.replace(/^\.\//, ""));
|
|
479
561
|
const exact = new Set(normalized);
|
|
480
|
-
const globs = normalized.map((p) => new
|
|
562
|
+
const globs = normalized.map((p) => new import_minimatch2.Minimatch(p, { dot: true, matchBase: false })).filter((m) => m.hasMagic());
|
|
481
563
|
const dirPrefixes = normalized.filter((p) => p.endsWith("/"));
|
|
482
564
|
return allFiles.filter(
|
|
483
565
|
(f) => (
|
|
@@ -491,19 +573,62 @@ function filterByTargetFiles(allFiles, targetPatterns) {
|
|
|
491
573
|
|
|
492
574
|
// src/executor.ts
|
|
493
575
|
var import_tooling2 = require("@codacy/tooling");
|
|
494
|
-
|
|
576
|
+
var HARD_TIMEOUT_GRACE_MS = 2e3;
|
|
577
|
+
function anySignal(a, b) {
|
|
578
|
+
if (typeof AbortSignal.any === "function") return AbortSignal.any([a, b]);
|
|
579
|
+
const composite = new AbortController();
|
|
580
|
+
if (a.aborted || b.aborted) {
|
|
581
|
+
composite.abort();
|
|
582
|
+
} else {
|
|
583
|
+
const onAbort = () => composite.abort();
|
|
584
|
+
a.addEventListener("abort", onAbort, { once: true });
|
|
585
|
+
b.addEventListener("abort", onAbort, { once: true });
|
|
586
|
+
}
|
|
587
|
+
return composite.signal;
|
|
588
|
+
}
|
|
589
|
+
function cancelledResult(adapter) {
|
|
590
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
591
|
+
return {
|
|
592
|
+
metadata: { startedAt: now, completedAt: now, durationMs: 0 },
|
|
593
|
+
issues: [],
|
|
594
|
+
errors: [
|
|
595
|
+
{
|
|
596
|
+
toolId: adapter.id,
|
|
597
|
+
phase: "toolInvoke",
|
|
598
|
+
kind: "Cancelled",
|
|
599
|
+
message: `Analysis cancelled by caller; ${adapter.id} was not run`,
|
|
600
|
+
level: "error"
|
|
601
|
+
}
|
|
602
|
+
],
|
|
603
|
+
summary: {
|
|
604
|
+
toolId: adapter.id,
|
|
605
|
+
status: "skipped",
|
|
606
|
+
issueCount: 0,
|
|
607
|
+
errorCount: 1,
|
|
608
|
+
durationMs: 0,
|
|
609
|
+
filesAnalyzed: 0
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
async function runTool(adapter, ctx, codacyToolConfig, timeoutMs, callerSignal) {
|
|
495
614
|
const startTime = Date.now();
|
|
496
615
|
ctx.logger.debug("runTool started", {
|
|
497
616
|
toolId: adapter.id,
|
|
498
617
|
fileCount: ctx.targetFiles.length,
|
|
499
618
|
timeoutMs
|
|
500
619
|
});
|
|
620
|
+
const abortController = new AbortController();
|
|
621
|
+
ctx.signal = callerSignal ? anySignal(callerSignal, abortController.signal) : abortController.signal;
|
|
622
|
+
const abortTimer = setTimeout(() => abortController.abort(), timeoutMs);
|
|
623
|
+
abortTimer.unref?.();
|
|
624
|
+
let hardTimer;
|
|
501
625
|
try {
|
|
502
626
|
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
503
|
-
setTimeout(
|
|
627
|
+
hardTimer = setTimeout(
|
|
504
628
|
() => reject(new Error(`TIMEOUT: Tool ${adapter.id} exceeded ${(0, import_tooling2.formatDuration)(timeoutMs)}`)),
|
|
505
|
-
timeoutMs
|
|
629
|
+
timeoutMs + HARD_TIMEOUT_GRACE_MS
|
|
506
630
|
);
|
|
631
|
+
hardTimer.unref?.();
|
|
507
632
|
});
|
|
508
633
|
const result = await Promise.race([adapter.analyze(ctx, codacyToolConfig), timeoutPromise]);
|
|
509
634
|
ctx.logger.debug("runTool completed", {
|
|
@@ -514,8 +639,14 @@ async function runTool(adapter, ctx, codacyToolConfig, timeoutMs) {
|
|
|
514
639
|
return result;
|
|
515
640
|
} catch (err) {
|
|
516
641
|
const durationMs = Date.now() - startTime;
|
|
517
|
-
const
|
|
518
|
-
|
|
642
|
+
const isCancelled = callerSignal?.aborted === true;
|
|
643
|
+
const isTimeout = !isCancelled && err instanceof Error && err.message.includes("TIMEOUT");
|
|
644
|
+
if (isCancelled) {
|
|
645
|
+
ctx.logger.error("Tool cancelled by caller", {
|
|
646
|
+
toolId: adapter.id,
|
|
647
|
+
elapsedMs: durationMs
|
|
648
|
+
});
|
|
649
|
+
} else if (isTimeout) {
|
|
519
650
|
ctx.logger.error("Tool timed out", { toolId: adapter.id, timeoutMs, elapsedMs: durationMs });
|
|
520
651
|
} else {
|
|
521
652
|
ctx.logger.error("Tool execution failed", {
|
|
@@ -525,6 +656,8 @@ async function runTool(adapter, ctx, codacyToolConfig, timeoutMs) {
|
|
|
525
656
|
});
|
|
526
657
|
}
|
|
527
658
|
const now = /* @__PURE__ */ new Date();
|
|
659
|
+
const kind = isCancelled ? "Cancelled" : isTimeout ? "Timeout" : "InvocationError";
|
|
660
|
+
const message = isCancelled ? `Tool ${adapter.id} cancelled by caller` : isTimeout ? `Tool ${adapter.id} exceeded timeout of ${(0, import_tooling2.formatDuration)(timeoutMs)}` : `Tool ${adapter.id} failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
528
661
|
return {
|
|
529
662
|
metadata: {
|
|
530
663
|
startedAt: new Date(now.getTime() - durationMs).toISOString(),
|
|
@@ -536,8 +669,8 @@ async function runTool(adapter, ctx, codacyToolConfig, timeoutMs) {
|
|
|
536
669
|
{
|
|
537
670
|
toolId: adapter.id,
|
|
538
671
|
phase: "toolInvoke",
|
|
539
|
-
kind
|
|
540
|
-
message
|
|
672
|
+
kind,
|
|
673
|
+
message,
|
|
541
674
|
level: "error"
|
|
542
675
|
}
|
|
543
676
|
],
|
|
@@ -550,17 +683,24 @@ async function runTool(adapter, ctx, codacyToolConfig, timeoutMs) {
|
|
|
550
683
|
filesAnalyzed: ctx.targetFiles.length
|
|
551
684
|
}
|
|
552
685
|
};
|
|
686
|
+
} finally {
|
|
687
|
+
clearTimeout(abortTimer);
|
|
688
|
+
if (hardTimer) clearTimeout(hardTimer);
|
|
553
689
|
}
|
|
554
690
|
}
|
|
555
|
-
async function runToolsSequential(tools, timeoutMs, callbacks) {
|
|
691
|
+
async function runToolsSequential(tools, timeoutMs, callbacks, callerSignal) {
|
|
556
692
|
const results = [];
|
|
557
693
|
for (const { adapter, ctx, codacyToolConfig } of tools) {
|
|
694
|
+
if (callerSignal?.aborted) {
|
|
695
|
+
results.push(cancelledResult(adapter));
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
558
698
|
if (callbacks?.onToolProgress) {
|
|
559
699
|
const cb = callbacks.onToolProgress;
|
|
560
700
|
ctx.onProgress = (message) => cb(adapter.id, adapter.displayName, message);
|
|
561
701
|
}
|
|
562
702
|
callbacks?.onToolStart?.(adapter.id, adapter.displayName);
|
|
563
|
-
const result = await runTool(adapter, ctx, codacyToolConfig, timeoutMs);
|
|
703
|
+
const result = await runTool(adapter, ctx, codacyToolConfig, timeoutMs, callerSignal);
|
|
564
704
|
callbacks?.onToolComplete?.(
|
|
565
705
|
adapter.id,
|
|
566
706
|
adapter.displayName,
|
|
@@ -571,19 +711,23 @@ async function runToolsSequential(tools, timeoutMs, callbacks) {
|
|
|
571
711
|
}
|
|
572
712
|
return results;
|
|
573
713
|
}
|
|
574
|
-
async function runToolsParallel(tools, timeoutMs, concurrency, callbacks) {
|
|
714
|
+
async function runToolsParallel(tools, timeoutMs, concurrency, callbacks, callerSignal) {
|
|
575
715
|
const results = new Array(tools.length);
|
|
576
716
|
let nextIndex = 0;
|
|
577
717
|
async function worker() {
|
|
578
718
|
while (nextIndex < tools.length) {
|
|
579
719
|
const index = nextIndex++;
|
|
580
720
|
const { adapter, ctx, codacyToolConfig } = tools[index];
|
|
721
|
+
if (callerSignal?.aborted) {
|
|
722
|
+
results[index] = cancelledResult(adapter);
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
581
725
|
if (callbacks?.onToolProgress) {
|
|
582
726
|
const cb = callbacks.onToolProgress;
|
|
583
727
|
ctx.onProgress = (message) => cb(adapter.id, adapter.displayName, message);
|
|
584
728
|
}
|
|
585
729
|
callbacks?.onToolStart?.(adapter.id, adapter.displayName);
|
|
586
|
-
results[index] = await runTool(adapter, ctx, codacyToolConfig, timeoutMs);
|
|
730
|
+
results[index] = await runTool(adapter, ctx, codacyToolConfig, timeoutMs, callerSignal);
|
|
587
731
|
callbacks?.onToolComplete?.(
|
|
588
732
|
adapter.id,
|
|
589
733
|
adapter.displayName,
|
|
@@ -597,6 +741,124 @@ async function runToolsParallel(tools, timeoutMs, concurrency, callbacks) {
|
|
|
597
741
|
return results;
|
|
598
742
|
}
|
|
599
743
|
|
|
744
|
+
// src/logger.ts
|
|
745
|
+
var import_fs2 = __toESM(require("fs"));
|
|
746
|
+
var import_path3 = __toESM(require("path"));
|
|
747
|
+
var import_os = __toESM(require("os"));
|
|
748
|
+
var LEVEL_ORDER = {
|
|
749
|
+
debug: 0,
|
|
750
|
+
info: 1,
|
|
751
|
+
warning: 2,
|
|
752
|
+
error: 3
|
|
753
|
+
};
|
|
754
|
+
function createNullLogger() {
|
|
755
|
+
return {
|
|
756
|
+
debug: () => {
|
|
757
|
+
},
|
|
758
|
+
info: () => {
|
|
759
|
+
},
|
|
760
|
+
warn: () => {
|
|
761
|
+
},
|
|
762
|
+
error: () => {
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
function rotateLogFiles(logsDir, maxFiles) {
|
|
767
|
+
let entries2;
|
|
768
|
+
try {
|
|
769
|
+
entries2 = import_fs2.default.readdirSync(logsDir).filter((f) => f.startsWith("analysis-") && f.endsWith(".log"));
|
|
770
|
+
} catch {
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
if (entries2.length <= maxFiles) return;
|
|
774
|
+
entries2.sort();
|
|
775
|
+
const toRemove = entries2.slice(0, entries2.length - maxFiles);
|
|
776
|
+
for (const f of toRemove) {
|
|
777
|
+
try {
|
|
778
|
+
import_fs2.default.unlinkSync(import_path3.default.join(logsDir, f));
|
|
779
|
+
} catch {
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
var fileSeq = 0;
|
|
784
|
+
function fileTimestamp() {
|
|
785
|
+
return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${fileSeq++}`;
|
|
786
|
+
}
|
|
787
|
+
function enrichMessage(message, fields) {
|
|
788
|
+
if (!fields) return message;
|
|
789
|
+
const parts = [];
|
|
790
|
+
if (fields.toolId) parts.push(String(fields.toolId));
|
|
791
|
+
if (fields.version) parts.push(`v${fields.version}`);
|
|
792
|
+
if (fields.installation) parts.push(String(fields.installation));
|
|
793
|
+
if (fields.configSource) parts.push(String(fields.configSource));
|
|
794
|
+
if (typeof fields.fileCount === "number") parts.push(`${fields.fileCount} files`);
|
|
795
|
+
if (typeof fields.issueCount === "number") parts.push(`${fields.issueCount} issues`);
|
|
796
|
+
if (typeof fields.errorCount === "number" && fields.errorCount > 0)
|
|
797
|
+
parts.push(`${fields.errorCount} errors`);
|
|
798
|
+
if (typeof fields.totalIssues === "number") parts.push(`${fields.totalIssues} issues`);
|
|
799
|
+
if (typeof fields.totalErrors === "number" && fields.totalErrors > 0)
|
|
800
|
+
parts.push(`${fields.totalErrors} errors`);
|
|
801
|
+
if (typeof fields.durationMs === "number")
|
|
802
|
+
parts.push(`${(fields.durationMs / 1e3).toFixed(1)}s`);
|
|
803
|
+
if (fields.reason) parts.push(String(fields.reason));
|
|
804
|
+
if (fields.error) parts.push(String(fields.error));
|
|
805
|
+
if (typeof fields.found === "boolean") parts.push(fields.found ? "found" : "not found");
|
|
806
|
+
if (fields.path && !fields.version) parts.push(String(fields.path));
|
|
807
|
+
if (parts.length === 0) return message;
|
|
808
|
+
return `${message} (${parts.join(", ")})`;
|
|
809
|
+
}
|
|
810
|
+
function createLogger(options = {}) {
|
|
811
|
+
const minLevel = LEVEL_ORDER[options.level ?? "info"];
|
|
812
|
+
const fileEnabled = options.fileEnabled ?? true;
|
|
813
|
+
const logsDir = options.logsDir ?? import_path3.default.join(import_os.default.homedir(), ".codacy", "logs");
|
|
814
|
+
const maxFileSize = options.maxFileSize ?? 10 * 1024 * 1024;
|
|
815
|
+
const maxFiles = options.maxFiles ?? 5;
|
|
816
|
+
const onStderrMessage = options.onStderrMessage;
|
|
817
|
+
let logFd = null;
|
|
818
|
+
let bytesWritten = 0;
|
|
819
|
+
if (fileEnabled) {
|
|
820
|
+
import_fs2.default.mkdirSync(logsDir, { recursive: true });
|
|
821
|
+
rotateLogFiles(logsDir, maxFiles);
|
|
822
|
+
const logFilePath = import_path3.default.join(logsDir, `analysis-${fileTimestamp()}.log`);
|
|
823
|
+
logFd = import_fs2.default.openSync(logFilePath, "a");
|
|
824
|
+
}
|
|
825
|
+
function log(level, message, fields) {
|
|
826
|
+
const numLevel = LEVEL_ORDER[level];
|
|
827
|
+
if (numLevel < minLevel) return;
|
|
828
|
+
if (fileEnabled && logFd !== null) {
|
|
829
|
+
const entry = JSON.stringify({
|
|
830
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
831
|
+
level,
|
|
832
|
+
message,
|
|
833
|
+
...fields
|
|
834
|
+
});
|
|
835
|
+
const buf = Buffer.from(entry + "\n", "utf-8");
|
|
836
|
+
import_fs2.default.writeSync(logFd, buf);
|
|
837
|
+
bytesWritten += buf.length;
|
|
838
|
+
if (bytesWritten >= maxFileSize) {
|
|
839
|
+
import_fs2.default.closeSync(logFd);
|
|
840
|
+
rotateLogFiles(logsDir, maxFiles);
|
|
841
|
+
const newPath = import_path3.default.join(logsDir, `analysis-${fileTimestamp()}.log`);
|
|
842
|
+
logFd = import_fs2.default.openSync(newPath, "a");
|
|
843
|
+
bytesWritten = 0;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
const enriched = enrichMessage(message, fields);
|
|
847
|
+
if (onStderrMessage) {
|
|
848
|
+
onStderrMessage(enriched, level);
|
|
849
|
+
} else {
|
|
850
|
+
process.stderr.write(` ${enriched}
|
|
851
|
+
`);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
return {
|
|
855
|
+
debug: (msg, fields) => log("debug", msg, fields),
|
|
856
|
+
info: (msg, fields) => log("info", msg, fields),
|
|
857
|
+
warn: (msg, fields) => log("warning", msg, fields),
|
|
858
|
+
error: (msg, fields) => log("error", msg, fields)
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
|
|
600
862
|
// src/summary.ts
|
|
601
863
|
var NOISY_THRESHOLD = 500;
|
|
602
864
|
var SEVERITY_ORDER = ["Error", "High", "Warning", "Info"];
|
|
@@ -708,17 +970,7 @@ function computePatternSummary(issues, lookup) {
|
|
|
708
970
|
}
|
|
709
971
|
|
|
710
972
|
// src/analyze.ts
|
|
711
|
-
var execFileAsync = (0, import_util.promisify)(
|
|
712
|
-
var nullLogger = {
|
|
713
|
-
debug: () => {
|
|
714
|
-
},
|
|
715
|
-
info: () => {
|
|
716
|
-
},
|
|
717
|
-
warn: () => {
|
|
718
|
-
},
|
|
719
|
-
error: () => {
|
|
720
|
-
}
|
|
721
|
-
};
|
|
973
|
+
var execFileAsync = (0, import_util.promisify)(import_child_process3.execFile);
|
|
722
974
|
var CHECK_CONCURRENCY = 12;
|
|
723
975
|
async function mapWithConcurrency(items, concurrency, task) {
|
|
724
976
|
const results = new Array(items.length);
|
|
@@ -736,9 +988,9 @@ async function mapWithConcurrency(items, concurrency, task) {
|
|
|
736
988
|
async function analyze(options) {
|
|
737
989
|
const startedAt = /* @__PURE__ */ new Date();
|
|
738
990
|
const mode = options.mode || "standard";
|
|
739
|
-
const toolTimeout = options.toolTimeout ||
|
|
991
|
+
const toolTimeout = options.toolTimeout || 9e5;
|
|
740
992
|
const parallelTools = options.parallelTools || 1;
|
|
741
|
-
const logger = options.logger ??
|
|
993
|
+
const logger = options.logger ?? createNullLogger();
|
|
742
994
|
const phaseTimings = {
|
|
743
995
|
availabilityMs: 0,
|
|
744
996
|
fileDiscoveryMs: 0,
|
|
@@ -751,6 +1003,26 @@ async function analyze(options) {
|
|
|
751
1003
|
unavailable: [],
|
|
752
1004
|
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
753
1005
|
};
|
|
1006
|
+
if (options.signal?.aborted) {
|
|
1007
|
+
logger.info("Analysis cancelled by caller before it started");
|
|
1008
|
+
return buildResult(
|
|
1009
|
+
startedAt,
|
|
1010
|
+
options.repositoryRoot,
|
|
1011
|
+
mode,
|
|
1012
|
+
emptyCapability,
|
|
1013
|
+
[],
|
|
1014
|
+
[
|
|
1015
|
+
{
|
|
1016
|
+
toolId: "",
|
|
1017
|
+
phase: "toolInvoke",
|
|
1018
|
+
kind: "Cancelled",
|
|
1019
|
+
message: "Analysis cancelled by caller before it started",
|
|
1020
|
+
level: "error"
|
|
1021
|
+
}
|
|
1022
|
+
],
|
|
1023
|
+
[]
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
754
1026
|
try {
|
|
755
1027
|
await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
756
1028
|
cwd: options.repositoryRoot
|
|
@@ -814,11 +1086,11 @@ async function analyze(options) {
|
|
|
814
1086
|
const requestedTools = options.tools ?? codacyConfig.tools.map((t) => t.toolId);
|
|
815
1087
|
const adapters = await getRegisteredAdapters(requestedTools);
|
|
816
1088
|
logger.info("Pipeline started", { mode, toolCount: adapters.length, parallelTools, toolTimeout });
|
|
817
|
-
const globalDir =
|
|
1089
|
+
const globalDir = import_path4.default.join(import_os2.default.homedir(), ".codacy");
|
|
818
1090
|
const baseCtx = {
|
|
819
1091
|
repositoryRoot: options.repositoryRoot,
|
|
820
1092
|
globalDir,
|
|
821
|
-
platform: { os:
|
|
1093
|
+
platform: { os: import_os2.default.platform(), arch: import_os2.default.arch() },
|
|
822
1094
|
logger,
|
|
823
1095
|
runner: "local"
|
|
824
1096
|
};
|
|
@@ -1096,7 +1368,9 @@ async function analyze(options) {
|
|
|
1096
1368
|
allFiles = filterByTargetFiles(allFiles, options.files);
|
|
1097
1369
|
logger.debug("Filtered by target files", { afterFilter: allFiles.length });
|
|
1098
1370
|
}
|
|
1099
|
-
|
|
1371
|
+
const oversize = filterOversizedFiles(allFiles, options.repositoryRoot, logger);
|
|
1372
|
+
allFiles = oversize.files;
|
|
1373
|
+
const skippedFiles = oversize.skipped;
|
|
1100
1374
|
phaseTimings.fileDiscoveryMs = Date.now() - fileDiscoveryStartMs;
|
|
1101
1375
|
const fileRoutingStartMs = Date.now();
|
|
1102
1376
|
const readyById = new Map(capability.ready.map((r) => [r.toolId, r]));
|
|
@@ -1178,9 +1452,15 @@ async function analyze(options) {
|
|
|
1178
1452
|
};
|
|
1179
1453
|
let results;
|
|
1180
1454
|
if (parallelTools > 1 && toolRuns.length > 1) {
|
|
1181
|
-
results = await runToolsParallel(
|
|
1455
|
+
results = await runToolsParallel(
|
|
1456
|
+
toolRuns,
|
|
1457
|
+
toolTimeout,
|
|
1458
|
+
parallelTools,
|
|
1459
|
+
callbacks,
|
|
1460
|
+
options.signal
|
|
1461
|
+
);
|
|
1182
1462
|
} else {
|
|
1183
|
-
results = await runToolsSequential(toolRuns, toolTimeout, callbacks);
|
|
1463
|
+
results = await runToolsSequential(toolRuns, toolTimeout, callbacks, options.signal);
|
|
1184
1464
|
}
|
|
1185
1465
|
phaseTimings.toolExecutionMs = Date.now() - toolExecStartMs;
|
|
1186
1466
|
const allIssues = normalizeIssues(results.flatMap((r) => r.issues));
|
|
@@ -1213,15 +1493,16 @@ async function analyze(options) {
|
|
|
1213
1493
|
allErrors,
|
|
1214
1494
|
allSummaries,
|
|
1215
1495
|
patternSummary,
|
|
1216
|
-
phaseTimings
|
|
1496
|
+
phaseTimings,
|
|
1497
|
+
skippedFiles
|
|
1217
1498
|
);
|
|
1218
1499
|
}
|
|
1219
1500
|
function makeToolContext(base, adapter, targetFiles) {
|
|
1220
1501
|
return {
|
|
1221
1502
|
...base,
|
|
1222
1503
|
targetFiles,
|
|
1223
|
-
toolInstallDir:
|
|
1224
|
-
generatedConfigDir:
|
|
1504
|
+
toolInstallDir: import_path4.default.join(base.globalDir, "tools", adapter.id),
|
|
1505
|
+
generatedConfigDir: import_path4.default.join(base.repositoryRoot, ".codacy", "generated", adapter.id)
|
|
1225
1506
|
};
|
|
1226
1507
|
}
|
|
1227
1508
|
function normalizeIssues(issues) {
|
|
@@ -1239,7 +1520,7 @@ function resolveGitScope(repositoryRoot, scope) {
|
|
|
1239
1520
|
const base = scope.diff === true ? void 0 : scope.diff;
|
|
1240
1521
|
return listDiffFiles(repositoryRoot, base);
|
|
1241
1522
|
}
|
|
1242
|
-
function buildResult(startedAt, repositoryRoot, mode, capability, issues, errors, toolResults, patternSummary, phaseTimings) {
|
|
1523
|
+
function buildResult(startedAt, repositoryRoot, mode, capability, issues, errors, toolResults, patternSummary, phaseTimings, skippedFiles) {
|
|
1243
1524
|
const completedAt = /* @__PURE__ */ new Date();
|
|
1244
1525
|
return {
|
|
1245
1526
|
metadata: {
|
|
@@ -1254,15 +1535,17 @@ function buildResult(startedAt, repositoryRoot, mode, capability, issues, errors
|
|
|
1254
1535
|
issues,
|
|
1255
1536
|
errors,
|
|
1256
1537
|
toolResults,
|
|
1257
|
-
...patternSummary ? { patternSummary } : {}
|
|
1538
|
+
...patternSummary ? { patternSummary } : {},
|
|
1539
|
+
...skippedFiles && skippedFiles.length > 0 ? { skippedFiles } : {}
|
|
1258
1540
|
};
|
|
1259
1541
|
}
|
|
1260
1542
|
|
|
1261
1543
|
// src/format.ts
|
|
1262
|
-
var
|
|
1544
|
+
var import_path5 = __toESM(require("path"));
|
|
1263
1545
|
var import_tooling4 = require("@codacy/tooling");
|
|
1264
1546
|
var import_ansis = __toESM(require("ansis"));
|
|
1265
1547
|
var import_cli_table3 = __toESM(require("cli-table3"));
|
|
1548
|
+
var MAX_SKIPPED_FILES_SHOWN = 5;
|
|
1266
1549
|
function formatOutput(result, format) {
|
|
1267
1550
|
switch (format) {
|
|
1268
1551
|
case "json":
|
|
@@ -1420,9 +1703,30 @@ function formatText(result) {
|
|
|
1420
1703
|
lines.push(...formatErrorSection(result));
|
|
1421
1704
|
lines.push("");
|
|
1422
1705
|
}
|
|
1706
|
+
if (result.skippedFiles && result.skippedFiles.length > 0) {
|
|
1707
|
+
lines.push(...formatSkippedFilesSection(result.skippedFiles));
|
|
1708
|
+
lines.push("");
|
|
1709
|
+
}
|
|
1423
1710
|
lines.push(formatTextSummary(result, isInspect));
|
|
1424
1711
|
return lines.join("\n");
|
|
1425
1712
|
}
|
|
1713
|
+
function formatSkippedFilesSection(skipped) {
|
|
1714
|
+
const limitKB = Math.round(MAX_FILE_SIZE_BYTES / 1024);
|
|
1715
|
+
const out = [""];
|
|
1716
|
+
out.push(
|
|
1717
|
+
import_ansis.default.yellow(
|
|
1718
|
+
`\u26A0 ${skipped.length} file${skipped.length !== 1 ? "s" : ""} skipped (exceeding the ${limitKB} KB size limit):`
|
|
1719
|
+
)
|
|
1720
|
+
);
|
|
1721
|
+
for (const f of skipped.slice(0, MAX_SKIPPED_FILES_SHOWN)) {
|
|
1722
|
+
out.push(import_ansis.default.dim(` - ${f.filePath} (${Math.round(f.sizeBytes / 1024)} KB)`));
|
|
1723
|
+
}
|
|
1724
|
+
const remaining = skipped.length - MAX_SKIPPED_FILES_SHOWN;
|
|
1725
|
+
if (remaining > 0) {
|
|
1726
|
+
out.push(import_ansis.default.dim(` \u2026 and ${remaining} more`));
|
|
1727
|
+
}
|
|
1728
|
+
return out;
|
|
1729
|
+
}
|
|
1426
1730
|
function formatTextSummary(result, isInspect) {
|
|
1427
1731
|
const lines = [];
|
|
1428
1732
|
const inspect = isInspect ?? result.metadata.executionMode === "inspect";
|
|
@@ -1564,6 +1868,13 @@ function formatTextSummary(result, isInspect) {
|
|
|
1564
1868
|
return lines.join("\n");
|
|
1565
1869
|
}
|
|
1566
1870
|
var MAX_ERRORS_PER_GROUP = 5;
|
|
1871
|
+
var MAX_ERROR_MESSAGE_LENGTH = 240;
|
|
1872
|
+
function flattenErrorMessage(message) {
|
|
1873
|
+
return message.replace(/\s+/g, " ").trim();
|
|
1874
|
+
}
|
|
1875
|
+
function truncateErrorMessage(message) {
|
|
1876
|
+
return message.length > MAX_ERROR_MESSAGE_LENGTH ? `${message.slice(0, MAX_ERROR_MESSAGE_LENGTH)}\u2026` : message;
|
|
1877
|
+
}
|
|
1567
1878
|
function formatErrorSection(result) {
|
|
1568
1879
|
const lines = [];
|
|
1569
1880
|
const displayNameMap = /* @__PURE__ */ new Map();
|
|
@@ -1585,13 +1896,14 @@ function formatErrorSection(result) {
|
|
|
1585
1896
|
const deduped = [];
|
|
1586
1897
|
const seen = /* @__PURE__ */ new Map();
|
|
1587
1898
|
for (const err of groupErrors) {
|
|
1588
|
-
const
|
|
1899
|
+
const flat = flattenErrorMessage(err.message);
|
|
1900
|
+
const dedupKey = `${err.filePath ?? ""}|||${flat}`;
|
|
1589
1901
|
const idx = seen.get(dedupKey);
|
|
1590
1902
|
if (idx !== void 0) {
|
|
1591
1903
|
deduped[idx].count++;
|
|
1592
1904
|
} else {
|
|
1593
1905
|
seen.set(dedupKey, deduped.length);
|
|
1594
|
-
deduped.push({ filePath: err.filePath, message:
|
|
1906
|
+
deduped.push({ filePath: err.filePath, message: truncateErrorMessage(flat), count: 1 });
|
|
1595
1907
|
}
|
|
1596
1908
|
}
|
|
1597
1909
|
const shown = deduped.slice(0, MAX_ERRORS_PER_GROUP);
|
|
@@ -1655,7 +1967,7 @@ function formatFilesCell(filesRouted) {
|
|
|
1655
1967
|
}
|
|
1656
1968
|
function formatConfigCell(tool, repositoryRoot) {
|
|
1657
1969
|
if (tool.configSource === "local" && tool.configPath) {
|
|
1658
|
-
const rawPath =
|
|
1970
|
+
const rawPath = import_path5.default.isAbsolute(tool.configPath) ? import_path5.default.relative(repositoryRoot, tool.configPath) : tool.configPath;
|
|
1659
1971
|
return rawPath.startsWith("./") ? rawPath : `./${rawPath}`;
|
|
1660
1972
|
}
|
|
1661
1973
|
if (tool.configSource === "codacy") return "Codacy";
|
|
@@ -1917,13 +2229,13 @@ function applyConfigOperation(op, source, dest) {
|
|
|
1917
2229
|
|
|
1918
2230
|
// src/init.ts
|
|
1919
2231
|
var import_promises4 = __toESM(require("fs/promises"));
|
|
1920
|
-
var
|
|
1921
|
-
var
|
|
2232
|
+
var import_path8 = __toESM(require("path"));
|
|
2233
|
+
var import_child_process4 = require("child_process");
|
|
1922
2234
|
var import_tooling5 = require("@codacy/tooling");
|
|
1923
2235
|
|
|
1924
2236
|
// src/discover.ts
|
|
1925
2237
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
1926
|
-
var
|
|
2238
|
+
var import_path6 = __toESM(require("path"));
|
|
1927
2239
|
|
|
1928
2240
|
// src/discover-catalog.ts
|
|
1929
2241
|
var DEPENDENCY_CATALOG = /* @__PURE__ */ new Map([
|
|
@@ -1953,6 +2265,10 @@ var DEPENDENCY_CATALOG = /* @__PURE__ */ new Map([
|
|
|
1953
2265
|
["@hapi/hapi", { displayName: "Hapi", kind: "framework" }],
|
|
1954
2266
|
["hono", { displayName: "Hono", kind: "framework" }],
|
|
1955
2267
|
["electron", { displayName: "Electron", kind: "framework" }],
|
|
2268
|
+
// AWS CDK — the v2 umbrella package `aws-cdk-lib`, the CLI package `aws-cdk`,
|
|
2269
|
+
// and the v1 `@aws-cdk/*` construct packages (prefix rule below).
|
|
2270
|
+
["aws-cdk-lib", { displayName: "AWS CDK", kind: "framework" }],
|
|
2271
|
+
["aws-cdk", { displayName: "AWS CDK", kind: "framework" }],
|
|
1956
2272
|
// --- JavaScript / TypeScript — Libraries ---
|
|
1957
2273
|
["lodash", { displayName: "Lodash", kind: "library" }],
|
|
1958
2274
|
["underscore", { displayName: "Underscore.js", kind: "library" }],
|
|
@@ -2005,9 +2321,20 @@ var DEPENDENCY_CATALOG = /* @__PURE__ */ new Map([
|
|
|
2005
2321
|
["pino", { displayName: "Pino", kind: "library" }],
|
|
2006
2322
|
["winston", { displayName: "Winston", kind: "library" }],
|
|
2007
2323
|
["i18next", { displayName: "i18next", kind: "library" }],
|
|
2008
|
-
|
|
2324
|
+
// react-intl is the React binding of the FormatJS ecosystem; eslint-plugin-formatjs
|
|
2325
|
+
// lints both, so we report the umbrella name "formatjs" (matches the mapping key).
|
|
2326
|
+
["react-intl", { displayName: "formatjs", kind: "library" }],
|
|
2009
2327
|
["vue-i18n", { displayName: "vue-i18n", kind: "library" }],
|
|
2010
2328
|
["next-intl", { displayName: "next-intl", kind: "library" }],
|
|
2329
|
+
// Type checker (eslint-plugin-flowtype). Also detected via a `.flowconfig` file.
|
|
2330
|
+
["flow-bin", { displayName: "Flow", kind: "library" }],
|
|
2331
|
+
// Legacy JS libraries with dedicated ESLint plugins.
|
|
2332
|
+
["backbone", { displayName: "Backbone.js", kind: "library" }],
|
|
2333
|
+
["chai", { displayName: "Chai", kind: "library" }],
|
|
2334
|
+
["codeceptjs", { displayName: "CodeceptJS", kind: "library" }],
|
|
2335
|
+
["webdriverio", { displayName: "WebdriverIO", kind: "library" }],
|
|
2336
|
+
["react-relay", { displayName: "Relay", kind: "library" }],
|
|
2337
|
+
["relay-runtime", { displayName: "Relay", kind: "library" }],
|
|
2011
2338
|
// --- JavaScript / TypeScript — Tools ---
|
|
2012
2339
|
["typescript", { displayName: "TypeScript", kind: "tool" }],
|
|
2013
2340
|
["eslint", { displayName: "ESLint", kind: "tool" }],
|
|
@@ -2219,7 +2546,9 @@ var DEPENDENCY_CATALOG = /* @__PURE__ */ new Map([
|
|
|
2219
2546
|
["cats-core", { displayName: "Cats", kind: "library" }],
|
|
2220
2547
|
["circe-core", { displayName: "Circe", kind: "library" }],
|
|
2221
2548
|
// --- Dart — Frameworks ---
|
|
2222
|
-
// `flutter` and `angular` appear as plain keys in pubspec.yaml.
|
|
2549
|
+
// `flutter` and `angular` appear as plain keys in pubspec.yaml. NOTE: `angular`
|
|
2550
|
+
// here is Dart's AngularDart. The npm package `angular` is AngularJS (1.x) — a
|
|
2551
|
+
// different framework — so package.json overrides this via MANIFEST_SCOPED_CATALOG.
|
|
2223
2552
|
["flutter", { displayName: "Flutter", kind: "framework" }],
|
|
2224
2553
|
["flutter_test", { displayName: "Flutter", kind: "framework" }],
|
|
2225
2554
|
["angular", { displayName: "Angular", kind: "framework" }],
|
|
@@ -2256,10 +2585,13 @@ var DEPENDENCY_PREFIX_RULES = [
|
|
|
2256
2585
|
classification: { displayName: "Testing Library", kind: "library" }
|
|
2257
2586
|
},
|
|
2258
2587
|
{ prefix: "@tanstack/", classification: { displayName: "TanStack", kind: "library" } },
|
|
2588
|
+
{ prefix: "@wdio/", classification: { displayName: "WebdriverIO", kind: "library" } },
|
|
2589
|
+
// AWS CDK v1 construct libraries are published under the @aws-cdk/ scope.
|
|
2590
|
+
{ prefix: "@aws-cdk/", classification: { displayName: "AWS CDK", kind: "framework" } },
|
|
2259
2591
|
{ prefix: "@reduxjs/", classification: { displayName: "Redux", kind: "library" } },
|
|
2260
2592
|
{ prefix: "@prisma/", classification: { displayName: "Prisma", kind: "library" } },
|
|
2261
2593
|
{ prefix: "@apollo/", classification: { displayName: "Apollo", kind: "library" } },
|
|
2262
|
-
{ prefix: "@formatjs/", classification: { displayName: "
|
|
2594
|
+
{ prefix: "@formatjs/", classification: { displayName: "formatjs", kind: "library" } },
|
|
2263
2595
|
{ prefix: "@lingui/", classification: { displayName: "Lingui", kind: "library" } },
|
|
2264
2596
|
{ prefix: "@emotion/", classification: { displayName: "Emotion", kind: "library" } },
|
|
2265
2597
|
{ prefix: "@mui/", classification: { displayName: "Material UI", kind: "library" } },
|
|
@@ -2302,7 +2634,14 @@ var DEPENDENCY_PREFIX_RULES = [
|
|
|
2302
2634
|
{ prefix: "MSTest.", classification: { displayName: "MSTest", kind: "library" } },
|
|
2303
2635
|
{ prefix: "Serilog", classification: { displayName: "Serilog", kind: "library" } }
|
|
2304
2636
|
];
|
|
2305
|
-
|
|
2637
|
+
var MANIFEST_SCOPED_CATALOG = /* @__PURE__ */ new Map([
|
|
2638
|
+
["package.json", /* @__PURE__ */ new Map([["angular", { displayName: "AngularJS", kind: "framework" }]])]
|
|
2639
|
+
]);
|
|
2640
|
+
function classifyDependency(name, manifestBasename) {
|
|
2641
|
+
if (manifestBasename) {
|
|
2642
|
+
const scoped = MANIFEST_SCOPED_CATALOG.get(manifestBasename)?.get(name);
|
|
2643
|
+
if (scoped) return scoped;
|
|
2644
|
+
}
|
|
2306
2645
|
const exact = DEPENDENCY_CATALOG.get(name);
|
|
2307
2646
|
if (exact) return exact;
|
|
2308
2647
|
for (const rule of DEPENDENCY_PREFIX_RULES) {
|
|
@@ -2310,6 +2649,91 @@ function classifyDependency(name) {
|
|
|
2310
2649
|
}
|
|
2311
2650
|
return void 0;
|
|
2312
2651
|
}
|
|
2652
|
+
function pathBasename(filePath) {
|
|
2653
|
+
return filePath.split("/").pop() ?? filePath;
|
|
2654
|
+
}
|
|
2655
|
+
var FILE_SIGNAL_RULES = [
|
|
2656
|
+
{
|
|
2657
|
+
name: ".flowconfig",
|
|
2658
|
+
matches: (f) => pathBasename(f) === ".flowconfig",
|
|
2659
|
+
classification: { displayName: "Flow", kind: "library" }
|
|
2660
|
+
},
|
|
2661
|
+
{
|
|
2662
|
+
name: "cdk.json",
|
|
2663
|
+
matches: (f) => pathBasename(f) === "cdk.json",
|
|
2664
|
+
classification: { displayName: "AWS CDK", kind: "framework" }
|
|
2665
|
+
},
|
|
2666
|
+
{
|
|
2667
|
+
name: ".meteor/release",
|
|
2668
|
+
matches: (f) => f === ".meteor/release" || f.endsWith("/.meteor/release"),
|
|
2669
|
+
classification: { displayName: "Meteor", kind: "framework" }
|
|
2670
|
+
},
|
|
2671
|
+
{
|
|
2672
|
+
name: "sfdx-project.json",
|
|
2673
|
+
matches: (f) => pathBasename(f) === "sfdx-project.json",
|
|
2674
|
+
classification: { displayName: "Salesforce", kind: "platform" }
|
|
2675
|
+
},
|
|
2676
|
+
{
|
|
2677
|
+
name: "lwc.config.json",
|
|
2678
|
+
matches: (f) => pathBasename(f) === "lwc.config.json",
|
|
2679
|
+
classification: { displayName: "Lightning Web Components", kind: "platform" }
|
|
2680
|
+
},
|
|
2681
|
+
{
|
|
2682
|
+
name: "suitecloud.config.js",
|
|
2683
|
+
matches: (f) => pathBasename(f) === "suitecloud.config.js",
|
|
2684
|
+
classification: { displayName: "SuiteScript", kind: "platform" }
|
|
2685
|
+
}
|
|
2686
|
+
];
|
|
2687
|
+
function detectFileSignals(files) {
|
|
2688
|
+
const result = [];
|
|
2689
|
+
for (const rule of FILE_SIGNAL_RULES) {
|
|
2690
|
+
const hit = files.find((f) => rule.matches(f));
|
|
2691
|
+
if (!hit) continue;
|
|
2692
|
+
result.push({
|
|
2693
|
+
name: rule.name,
|
|
2694
|
+
displayName: rule.classification.displayName,
|
|
2695
|
+
kind: rule.classification.kind,
|
|
2696
|
+
source: "file",
|
|
2697
|
+
manifestFile: hit
|
|
2698
|
+
});
|
|
2699
|
+
}
|
|
2700
|
+
return result;
|
|
2701
|
+
}
|
|
2702
|
+
var PACKAGE_JSON_SIGNAL_DISPLAY_NAMES = ["ESLint Plugin"];
|
|
2703
|
+
function isEslintPluginName(name) {
|
|
2704
|
+
return /^eslint-plugin-/.test(name) || /^@[^/]+\/eslint-plugin(-.*)?$/.test(name);
|
|
2705
|
+
}
|
|
2706
|
+
function detectPackageJsonSignals(content) {
|
|
2707
|
+
let pkg;
|
|
2708
|
+
try {
|
|
2709
|
+
pkg = JSON.parse(content);
|
|
2710
|
+
} catch {
|
|
2711
|
+
return [];
|
|
2712
|
+
}
|
|
2713
|
+
const name = pkg && typeof pkg.name === "string" ? pkg.name : "";
|
|
2714
|
+
if (name && isEslintPluginName(name)) {
|
|
2715
|
+
return [
|
|
2716
|
+
{
|
|
2717
|
+
name,
|
|
2718
|
+
displayName: "ESLint Plugin",
|
|
2719
|
+
kind: "tool",
|
|
2720
|
+
source: "manifest",
|
|
2721
|
+
manifestFile: "package.json"
|
|
2722
|
+
}
|
|
2723
|
+
];
|
|
2724
|
+
}
|
|
2725
|
+
return [];
|
|
2726
|
+
}
|
|
2727
|
+
function getKnownDisplayNames() {
|
|
2728
|
+
const names = /* @__PURE__ */ new Set();
|
|
2729
|
+
for (const { displayName } of DEPENDENCY_CATALOG.values()) names.add(displayName);
|
|
2730
|
+
for (const scoped of MANIFEST_SCOPED_CATALOG.values())
|
|
2731
|
+
for (const { displayName } of scoped.values()) names.add(displayName);
|
|
2732
|
+
for (const rule of DEPENDENCY_PREFIX_RULES) names.add(rule.classification.displayName);
|
|
2733
|
+
for (const rule of FILE_SIGNAL_RULES) names.add(rule.classification.displayName);
|
|
2734
|
+
for (const name of PACKAGE_JSON_SIGNAL_DISPLAY_NAMES) names.add(name);
|
|
2735
|
+
return names;
|
|
2736
|
+
}
|
|
2313
2737
|
var NOTABLE_ANY_DEPTH = /* @__PURE__ */ new Set([
|
|
2314
2738
|
"Dockerfile",
|
|
2315
2739
|
"docker-compose.yml",
|
|
@@ -2679,7 +3103,8 @@ async function discover(repositoryRoot, options) {
|
|
|
2679
3103
|
let frameworks = [];
|
|
2680
3104
|
let libraries = [];
|
|
2681
3105
|
if (!options?.skipDependencies) {
|
|
2682
|
-
const
|
|
3106
|
+
const manifestDeps = await extractDependencies(repositoryRoot, files);
|
|
3107
|
+
const allDeps = [...manifestDeps, ...detectFileSignals(files)];
|
|
2683
3108
|
frameworks = deduplicateDeps(allDeps.filter((d) => d.kind === "framework"));
|
|
2684
3109
|
libraries = deduplicateDeps(
|
|
2685
3110
|
allDeps.filter((d) => d.kind === "library" || d.kind === "platform" || d.kind === "tool")
|
|
@@ -2692,7 +3117,7 @@ async function discover(repositoryRoot, options) {
|
|
|
2692
3117
|
frameworks,
|
|
2693
3118
|
libraries,
|
|
2694
3119
|
metadata: {
|
|
2695
|
-
repositoryRoot:
|
|
3120
|
+
repositoryRoot: import_path6.default.resolve(repositoryRoot),
|
|
2696
3121
|
totalFiles: files.length,
|
|
2697
3122
|
scannedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2698
3123
|
}
|
|
@@ -2701,7 +3126,7 @@ async function discover(repositoryRoot, options) {
|
|
|
2701
3126
|
function extractFilePatterns(files) {
|
|
2702
3127
|
const extensions = /* @__PURE__ */ new Set();
|
|
2703
3128
|
for (const file of files) {
|
|
2704
|
-
const ext =
|
|
3129
|
+
const ext = import_path6.default.extname(file).toLowerCase();
|
|
2705
3130
|
if (ext) {
|
|
2706
3131
|
extensions.add(`*${ext}`);
|
|
2707
3132
|
}
|
|
@@ -2734,13 +3159,14 @@ async function extractDependencies(repositoryRoot, files) {
|
|
|
2734
3159
|
if (!parser) continue;
|
|
2735
3160
|
let content;
|
|
2736
3161
|
try {
|
|
2737
|
-
content = await import_promises2.default.readFile(
|
|
3162
|
+
content = await import_promises2.default.readFile(import_path6.default.join(repositoryRoot, filePath), "utf-8");
|
|
2738
3163
|
} catch {
|
|
2739
3164
|
continue;
|
|
2740
3165
|
}
|
|
3166
|
+
const basename = filePath.split("/").pop() ?? filePath;
|
|
2741
3167
|
const rawDeps = parser(content);
|
|
2742
3168
|
for (const raw of rawDeps) {
|
|
2743
|
-
const classification = classifyDependency(raw.name);
|
|
3169
|
+
const classification = classifyDependency(raw.name, basename);
|
|
2744
3170
|
if (classification) {
|
|
2745
3171
|
allDeps.push({
|
|
2746
3172
|
name: raw.name,
|
|
@@ -2752,6 +3178,11 @@ async function extractDependencies(repositoryRoot, files) {
|
|
|
2752
3178
|
});
|
|
2753
3179
|
}
|
|
2754
3180
|
}
|
|
3181
|
+
if (basename === "package.json") {
|
|
3182
|
+
for (const signal of detectPackageJsonSignals(content)) {
|
|
3183
|
+
allDeps.push({ ...signal, manifestFile: filePath });
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
2755
3186
|
}
|
|
2756
3187
|
return allDeps;
|
|
2757
3188
|
}
|
|
@@ -2769,14 +3200,14 @@ function deduplicateDeps(deps) {
|
|
|
2769
3200
|
|
|
2770
3201
|
// src/codacy-yaml.ts
|
|
2771
3202
|
var import_promises3 = __toESM(require("fs/promises"));
|
|
2772
|
-
var
|
|
3203
|
+
var import_path7 = __toESM(require("path"));
|
|
2773
3204
|
var import_yaml = require("yaml");
|
|
2774
3205
|
async function readCodacyYaml(repositoryRoot) {
|
|
2775
3206
|
const candidates = [".codacy.yaml", ".codacy.yml"];
|
|
2776
3207
|
let raw = null;
|
|
2777
3208
|
for (const filename of candidates) {
|
|
2778
3209
|
try {
|
|
2779
|
-
raw = await import_promises3.default.readFile(
|
|
3210
|
+
raw = await import_promises3.default.readFile(import_path7.default.join(repositoryRoot, filename), "utf-8");
|
|
2780
3211
|
break;
|
|
2781
3212
|
} catch {
|
|
2782
3213
|
}
|
|
@@ -3034,13 +3465,13 @@ var getQueryString = (params) => {
|
|
|
3034
3465
|
};
|
|
3035
3466
|
var getUrl = (config, options) => {
|
|
3036
3467
|
const encoder = config.ENCODE_PATH || encodeURI;
|
|
3037
|
-
const
|
|
3468
|
+
const path10 = options.url.replace("{api-version}", config.VERSION).replace(/{(.*?)}/g, (substring, group) => {
|
|
3038
3469
|
if (options.path?.hasOwnProperty(group)) {
|
|
3039
3470
|
return encoder(String(options.path[group]));
|
|
3040
3471
|
}
|
|
3041
3472
|
return substring;
|
|
3042
3473
|
});
|
|
3043
|
-
const url = `${config.BASE}${
|
|
3474
|
+
const url = `${config.BASE}${path10}`;
|
|
3044
3475
|
if (options.query) {
|
|
3045
3476
|
return `${url}${getQueryString(options.query)}`;
|
|
3046
3477
|
}
|
|
@@ -6422,7 +6853,7 @@ async function detectLanguages(repositoryRoot, precomputedFiles) {
|
|
|
6422
6853
|
files = precomputedFiles;
|
|
6423
6854
|
} else {
|
|
6424
6855
|
try {
|
|
6425
|
-
const output = (0,
|
|
6856
|
+
const output = (0, import_child_process4.execSync)("git ls-files", {
|
|
6426
6857
|
cwd: repositoryRoot,
|
|
6427
6858
|
encoding: "utf-8",
|
|
6428
6859
|
maxBuffer: 50 * 1024 * 1024
|
|
@@ -6434,8 +6865,8 @@ async function detectLanguages(repositoryRoot, precomputedFiles) {
|
|
|
6434
6865
|
}
|
|
6435
6866
|
const detected = /* @__PURE__ */ new Set();
|
|
6436
6867
|
for (const file of files) {
|
|
6437
|
-
const basename =
|
|
6438
|
-
const ext =
|
|
6868
|
+
const basename = import_path8.default.basename(file);
|
|
6869
|
+
const ext = import_path8.default.extname(file).toLowerCase();
|
|
6439
6870
|
for (const [lang, config] of Object.entries(import_tooling5.LANGUAGE_CONFIG)) {
|
|
6440
6871
|
if (config.extensions.includes(ext)) {
|
|
6441
6872
|
detected.add(lang);
|
|
@@ -6452,12 +6883,12 @@ async function detectLocalConfigFiles(repositoryRoot, adapters) {
|
|
|
6452
6883
|
adapters.map(async (adapter) => {
|
|
6453
6884
|
const result = await adapter.checkLocalConfigurationFile({
|
|
6454
6885
|
repositoryRoot,
|
|
6455
|
-
generatedConfigDir:
|
|
6456
|
-
globalDir:
|
|
6457
|
-
toolInstallDir:
|
|
6886
|
+
generatedConfigDir: import_path8.default.join(repositoryRoot, ".codacy", "generated"),
|
|
6887
|
+
globalDir: import_path8.default.join(process.env.HOME ?? "~", ".codacy"),
|
|
6888
|
+
toolInstallDir: import_path8.default.join(process.env.HOME ?? "~", ".codacy", "tools", adapter.id),
|
|
6458
6889
|
targetFiles: [],
|
|
6459
6890
|
platform: { os: process.platform, arch: process.arch },
|
|
6460
|
-
logger:
|
|
6891
|
+
logger: createNullLogger(),
|
|
6461
6892
|
runner: "local"
|
|
6462
6893
|
});
|
|
6463
6894
|
return { toolId: adapter.id, result };
|
|
@@ -6470,16 +6901,6 @@ async function detectLocalConfigFiles(repositoryRoot, adapters) {
|
|
|
6470
6901
|
}
|
|
6471
6902
|
return found;
|
|
6472
6903
|
}
|
|
6473
|
-
var silentLogger = {
|
|
6474
|
-
debug: () => {
|
|
6475
|
-
},
|
|
6476
|
-
info: () => {
|
|
6477
|
-
},
|
|
6478
|
-
warn: () => {
|
|
6479
|
-
},
|
|
6480
|
-
error: () => {
|
|
6481
|
-
}
|
|
6482
|
-
};
|
|
6483
6904
|
async function enrichWithCodacyYaml(config, repositoryRoot, adapters) {
|
|
6484
6905
|
const yamlConfig = await readCodacyYaml(repositoryRoot);
|
|
6485
6906
|
if (!yamlConfig) return { config, codacyYamlApplied: false };
|
|
@@ -6658,7 +7079,7 @@ async function initRemoteConfig(repositoryRoot, provider, organization, reposito
|
|
|
6658
7079
|
};
|
|
6659
7080
|
}
|
|
6660
7081
|
async function initContainerConfig(repositoryRoot, adapters) {
|
|
6661
|
-
const codacyrcPath =
|
|
7082
|
+
const codacyrcPath = import_path8.default.join(repositoryRoot, ".codacyrc");
|
|
6662
7083
|
let raw;
|
|
6663
7084
|
try {
|
|
6664
7085
|
raw = await import_promises4.default.readFile(codacyrcPath, "utf-8");
|
|
@@ -6989,110 +7410,68 @@ function parseAutoFilters(raw) {
|
|
|
6989
7410
|
return { filters: { severities, categories }, unknown };
|
|
6990
7411
|
}
|
|
6991
7412
|
|
|
6992
|
-
// src/
|
|
6993
|
-
var
|
|
6994
|
-
var
|
|
6995
|
-
var
|
|
6996
|
-
var
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7413
|
+
// src/credentials.ts
|
|
7414
|
+
var import_crypto = __toESM(require("crypto"));
|
|
7415
|
+
var import_promises5 = __toESM(require("fs/promises"));
|
|
7416
|
+
var import_os3 = __toESM(require("os"));
|
|
7417
|
+
var import_path9 = __toESM(require("path"));
|
|
7418
|
+
function credentialsPath() {
|
|
7419
|
+
return import_path9.default.join(import_os3.default.homedir(), ".codacy", "credentials");
|
|
7420
|
+
}
|
|
7421
|
+
function deriveKey(salt) {
|
|
7422
|
+
const info = import_os3.default.userInfo();
|
|
7423
|
+
const machineKey = [import_os3.default.hostname(), info.username, import_os3.default.homedir(), import_os3.default.platform()].join("|");
|
|
7424
|
+
return import_crypto.default.pbkdf2Sync(machineKey, salt, 1e5, 32, "sha512");
|
|
7425
|
+
}
|
|
7426
|
+
async function saveCredentials(token) {
|
|
7427
|
+
const credentialsFile = credentialsPath();
|
|
7428
|
+
const salt = import_crypto.default.randomBytes(32);
|
|
7429
|
+
const iv = import_crypto.default.randomBytes(16);
|
|
7430
|
+
const key = deriveKey(salt);
|
|
7431
|
+
const cipher = import_crypto.default.createCipheriv("aes-256-gcm", key, iv);
|
|
7432
|
+
const encrypted = Buffer.concat([cipher.update(token, "utf-8"), cipher.final()]);
|
|
7433
|
+
const authTag = cipher.getAuthTag();
|
|
7434
|
+
const payload = JSON.stringify({
|
|
7435
|
+
salt: salt.toString("hex"),
|
|
7436
|
+
iv: iv.toString("hex"),
|
|
7437
|
+
authTag: authTag.toString("hex"),
|
|
7438
|
+
encrypted: encrypted.toString("hex")
|
|
7439
|
+
});
|
|
7440
|
+
await import_promises5.default.mkdir(import_path9.default.dirname(credentialsFile), { recursive: true });
|
|
7441
|
+
await import_promises5.default.writeFile(credentialsFile, payload, { encoding: "utf-8", mode: 384 });
|
|
7442
|
+
}
|
|
7443
|
+
async function loadCredentials() {
|
|
7004
7444
|
try {
|
|
7005
|
-
|
|
7445
|
+
const raw = await import_promises5.default.readFile(credentialsPath(), "utf-8");
|
|
7446
|
+
const data = JSON.parse(raw);
|
|
7447
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return null;
|
|
7448
|
+
const salt = Buffer.from(data.salt, "hex");
|
|
7449
|
+
const iv = Buffer.from(data.iv, "hex");
|
|
7450
|
+
const authTag = Buffer.from(data.authTag, "hex");
|
|
7451
|
+
const encrypted = Buffer.from(data.encrypted, "hex");
|
|
7452
|
+
const key = deriveKey(salt);
|
|
7453
|
+
const decipher = import_crypto.default.createDecipheriv("aes-256-gcm", key, iv);
|
|
7454
|
+
decipher.setAuthTag(authTag);
|
|
7455
|
+
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
7456
|
+
return decrypted.toString("utf-8");
|
|
7006
7457
|
} catch {
|
|
7007
|
-
return;
|
|
7008
|
-
}
|
|
7009
|
-
if (entries2.length <= maxFiles) return;
|
|
7010
|
-
entries2.sort();
|
|
7011
|
-
const toRemove = entries2.slice(0, entries2.length - maxFiles);
|
|
7012
|
-
for (const f of toRemove) {
|
|
7013
|
-
try {
|
|
7014
|
-
import_fs2.default.unlinkSync(import_path8.default.join(logsDir, f));
|
|
7015
|
-
} catch {
|
|
7016
|
-
}
|
|
7458
|
+
return null;
|
|
7017
7459
|
}
|
|
7018
7460
|
}
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
const parts = [];
|
|
7026
|
-
if (fields.toolId) parts.push(String(fields.toolId));
|
|
7027
|
-
if (fields.version) parts.push(`v${fields.version}`);
|
|
7028
|
-
if (fields.installation) parts.push(String(fields.installation));
|
|
7029
|
-
if (fields.configSource) parts.push(String(fields.configSource));
|
|
7030
|
-
if (typeof fields.fileCount === "number") parts.push(`${fields.fileCount} files`);
|
|
7031
|
-
if (typeof fields.issueCount === "number") parts.push(`${fields.issueCount} issues`);
|
|
7032
|
-
if (typeof fields.errorCount === "number" && fields.errorCount > 0)
|
|
7033
|
-
parts.push(`${fields.errorCount} errors`);
|
|
7034
|
-
if (typeof fields.totalIssues === "number") parts.push(`${fields.totalIssues} issues`);
|
|
7035
|
-
if (typeof fields.totalErrors === "number" && fields.totalErrors > 0)
|
|
7036
|
-
parts.push(`${fields.totalErrors} errors`);
|
|
7037
|
-
if (typeof fields.durationMs === "number")
|
|
7038
|
-
parts.push(`${(fields.durationMs / 1e3).toFixed(1)}s`);
|
|
7039
|
-
if (fields.reason) parts.push(String(fields.reason));
|
|
7040
|
-
if (fields.error) parts.push(String(fields.error));
|
|
7041
|
-
if (typeof fields.found === "boolean") parts.push(fields.found ? "found" : "not found");
|
|
7042
|
-
if (fields.path && !fields.version) parts.push(String(fields.path));
|
|
7043
|
-
if (parts.length === 0) return message;
|
|
7044
|
-
return `${message} (${parts.join(", ")})`;
|
|
7045
|
-
}
|
|
7046
|
-
function createLogger(options = {}) {
|
|
7047
|
-
const minLevel = LEVEL_ORDER[options.level ?? "info"];
|
|
7048
|
-
const fileEnabled = options.fileEnabled ?? true;
|
|
7049
|
-
const logsDir = options.logsDir ?? import_path8.default.join(import_os2.default.homedir(), ".codacy", "logs");
|
|
7050
|
-
const maxFileSize = options.maxFileSize ?? 10 * 1024 * 1024;
|
|
7051
|
-
const maxFiles = options.maxFiles ?? 5;
|
|
7052
|
-
const onStderrMessage = options.onStderrMessage;
|
|
7053
|
-
let logFd = null;
|
|
7054
|
-
let bytesWritten = 0;
|
|
7055
|
-
if (fileEnabled) {
|
|
7056
|
-
import_fs2.default.mkdirSync(logsDir, { recursive: true });
|
|
7057
|
-
rotateLogFiles(logsDir, maxFiles);
|
|
7058
|
-
const logFilePath = import_path8.default.join(logsDir, `analysis-${fileTimestamp()}.log`);
|
|
7059
|
-
logFd = import_fs2.default.openSync(logFilePath, "a");
|
|
7060
|
-
}
|
|
7061
|
-
function log(level, message, fields) {
|
|
7062
|
-
const numLevel = LEVEL_ORDER[level];
|
|
7063
|
-
if (numLevel < minLevel) return;
|
|
7064
|
-
if (fileEnabled && logFd !== null) {
|
|
7065
|
-
const entry = JSON.stringify({
|
|
7066
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7067
|
-
level,
|
|
7068
|
-
message,
|
|
7069
|
-
...fields
|
|
7070
|
-
});
|
|
7071
|
-
const buf = Buffer.from(entry + "\n", "utf-8");
|
|
7072
|
-
import_fs2.default.writeSync(logFd, buf);
|
|
7073
|
-
bytesWritten += buf.length;
|
|
7074
|
-
if (bytesWritten >= maxFileSize) {
|
|
7075
|
-
import_fs2.default.closeSync(logFd);
|
|
7076
|
-
rotateLogFiles(logsDir, maxFiles);
|
|
7077
|
-
const newPath = import_path8.default.join(logsDir, `analysis-${fileTimestamp()}.log`);
|
|
7078
|
-
logFd = import_fs2.default.openSync(newPath, "a");
|
|
7079
|
-
bytesWritten = 0;
|
|
7080
|
-
}
|
|
7081
|
-
}
|
|
7082
|
-
const enriched = enrichMessage(message, fields);
|
|
7083
|
-
if (onStderrMessage) {
|
|
7084
|
-
onStderrMessage(enriched, level);
|
|
7085
|
-
} else {
|
|
7086
|
-
process.stderr.write(` ${enriched}
|
|
7087
|
-
`);
|
|
7088
|
-
}
|
|
7461
|
+
async function deleteCredentials() {
|
|
7462
|
+
try {
|
|
7463
|
+
await import_promises5.default.unlink(credentialsPath());
|
|
7464
|
+
return true;
|
|
7465
|
+
} catch {
|
|
7466
|
+
return false;
|
|
7089
7467
|
}
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7468
|
+
}
|
|
7469
|
+
async function resolveApiToken() {
|
|
7470
|
+
const envToken = process.env.CODACY_API_TOKEN;
|
|
7471
|
+
if (envToken) return envToken;
|
|
7472
|
+
const stored = await loadCredentials();
|
|
7473
|
+
if (stored) return stored;
|
|
7474
|
+
throw new Error("No API token found. Set CODACY_API_TOKEN or run 'codacy-analysis login'.");
|
|
7096
7475
|
}
|
|
7097
7476
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7098
7477
|
0 && (module.exports = {
|
|
@@ -7105,12 +7484,15 @@ function createLogger(options = {}) {
|
|
|
7105
7484
|
configureApiToken,
|
|
7106
7485
|
createCodacyConfig,
|
|
7107
7486
|
createLogger,
|
|
7487
|
+
createNullLogger,
|
|
7488
|
+
deleteCredentials,
|
|
7108
7489
|
detectLanguages,
|
|
7109
7490
|
diffConfigs,
|
|
7110
7491
|
discover,
|
|
7111
7492
|
formatOutput,
|
|
7112
7493
|
formatTextSummary,
|
|
7113
7494
|
getAdapter,
|
|
7495
|
+
getKnownDisplayNames,
|
|
7114
7496
|
getRegisteredAdapters,
|
|
7115
7497
|
getRegisteredDescriptors,
|
|
7116
7498
|
initAutoConfig,
|
|
@@ -7123,6 +7505,7 @@ function createLogger(options = {}) {
|
|
|
7123
7505
|
listIgnoredFiles,
|
|
7124
7506
|
listPrFiles,
|
|
7125
7507
|
listStagedFiles,
|
|
7508
|
+
loadCredentials,
|
|
7126
7509
|
mergeConfigs,
|
|
7127
7510
|
parseAutoFilters,
|
|
7128
7511
|
readCodacyConfig,
|
|
@@ -7130,9 +7513,11 @@ function createLogger(options = {}) {
|
|
|
7130
7513
|
registerAdapter,
|
|
7131
7514
|
registerLazyAdapter,
|
|
7132
7515
|
registerUnsupportedTool,
|
|
7516
|
+
resolveApiToken,
|
|
7133
7517
|
resolveConfigPath,
|
|
7134
7518
|
resolveEngineToAdapter,
|
|
7135
7519
|
rotateLogFiles,
|
|
7520
|
+
saveCredentials,
|
|
7136
7521
|
validateApiToken,
|
|
7137
7522
|
writeCodacyConfig,
|
|
7138
7523
|
writeCodacyConfigFile
|