@codacy/analysis-runner 0.4.0 → 0.5.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 CHANGED
@@ -1,4 +1,4 @@
1
- import { OutputFormat, Logger, AnalysisResult, ToolAdapter, CodacyConfig, ConfigurationFileCheckResult, CodacyToolConfig, Language, LogLevel } from '@codacy/tooling';
1
+ import { OutputFormat, Logger, AnalysisResult, ToolAdapter, AdapterDescriptor, CodacyConfig, ConfigurationFileCheckResult, CodacyToolConfig, Language, LogLevel } from '@codacy/tooling';
2
2
  export { AnalysisResult, OutputFormat } from '@codacy/tooling';
3
3
 
4
4
  /**
@@ -60,16 +60,55 @@ interface AnalyzeOptions {
60
60
  declare function analyze(options: AnalyzeOptions): Promise<AnalysisResult>;
61
61
 
62
62
  /**
63
- * Tool adapter registry — stores registered adapters for discovery by the runner.
63
+ * Tool adapter registry — stores adapters for discovery by the runner.
64
64
  *
65
- * Adapters must be registered before calling analyze(). The registry is a simple
66
- * in-memory map keyed by adapter ID. clearAdapters() is provided for testing.
65
+ * Supports two registration modes:
66
+ * - **Eager** (`registerAdapter`): stores a fully resolved adapter. Used by tests
67
+ * and programmatic consumers that already have the adapter object.
68
+ * - **Lazy** (`registerLazyAdapter`): stores lightweight metadata plus a factory
69
+ * function that dynamically imports the full adapter module on first use. Used
70
+ * by the CLI to avoid loading all 30+ adapter modules at startup.
71
+ *
72
+ * `clearAdapters()` is provided for testing.
67
73
  */
68
74
 
69
- /** Register a tool adapter so the runner can discover and invoke it. */
75
+ /** Async factory that loads and returns a full ToolAdapter. */
76
+ type AdapterFactory = () => Promise<Readonly<ToolAdapter>>;
77
+ /**
78
+ * Register a fully resolved tool adapter (eager mode).
79
+ *
80
+ * The adapter is available immediately — no dynamic import needed. This is the
81
+ * path used by tests and by consumers that import adapters directly.
82
+ */
70
83
  declare function registerAdapter(adapter: Readonly<ToolAdapter>): void;
71
- /** Returns all registered adapters, optionally filtered by tool ID list. */
72
- declare function getRegisteredAdapters(toolIds?: string[]): Readonly<ToolAdapter>[];
84
+ /**
85
+ * Register an adapter lazily via its descriptor and a factory function.
86
+ *
87
+ * The factory is only called when the adapter is first needed for analysis.
88
+ * The descriptor provides enough information for fuzzy matching, file routing,
89
+ * and inspect-mode metadata display without loading the full module.
90
+ */
91
+ declare function registerLazyAdapter(descriptor: AdapterDescriptor, factory: AdapterFactory): void;
92
+ /**
93
+ * Returns all registered adapters, optionally filtered by tool ID list.
94
+ *
95
+ * This is async because lazy entries may need to import their module on first
96
+ * access. For callers that only need metadata, use `getRegisteredDescriptors`.
97
+ */
98
+ declare function getRegisteredAdapters(toolIds?: string[]): Promise<Readonly<ToolAdapter>[]>;
99
+ /**
100
+ * Returns descriptors for all registered adapters (sync, no module loading).
101
+ *
102
+ * Useful when only metadata is needed — e.g. file routing, fuzzy matching,
103
+ * or init-mode tool discovery.
104
+ */
105
+ declare function getRegisteredDescriptors(toolIds?: string[]): AdapterDescriptor[];
106
+ /**
107
+ * Loads and returns a single adapter by its ID (exact match).
108
+ *
109
+ * Returns undefined if no adapter with that ID is registered.
110
+ */
111
+ declare function getAdapter(toolId: string): Promise<Readonly<ToolAdapter> | undefined>;
73
112
  /** Remove all registered adapters. Used in tests to reset state between runs. */
74
113
  declare function clearAdapters(): void;
75
114
 
@@ -206,6 +245,10 @@ interface InitRemoteStats {
206
245
  matchedAdapters: number;
207
246
  /** Whether a .codacy.yaml file was found and its exclude paths were applied. */
208
247
  codacyYamlApplied: boolean;
248
+ /** Number of cloud-ignored files fetched from the Codacy API. */
249
+ ignoredFilesCount: number;
250
+ /** Whether the fetch was stopped because it hit the 1000-file cap. */
251
+ ignoredFilesCapped: boolean;
209
252
  }
210
253
  /**
211
254
  * `--remote <provider> <org> <repo>` mode.
@@ -219,8 +262,10 @@ interface InitRemoteStats {
219
262
  * @param onToolProcessed - Optional callback invoked after each tool's patterns are
220
263
  * fetched. Receives the adapter's display name, the number of patterns configured, and
221
264
  * whether the tool uses a local configuration file. Useful for real-time CLI progress.
265
+ * @param onIgnoredFilesFetched - Optional callback invoked after cloud-ignored files are
266
+ * fetched. Receives the count and whether the 1000-file cap was reached.
222
267
  */
223
- declare function initRemoteConfig(repositoryRoot: string, provider: string, organization: string, repositoryName: string, adapters: Readonly<ToolAdapter>[], apiToken: string, onRemoteToolsFound?: (totalEnabledTools: number, matchedAdapters: number) => void, onToolProcessed?: (displayName: string, patternCount: number, usesConfigFile: boolean) => void): Promise<{
268
+ declare function initRemoteConfig(repositoryRoot: string, provider: string, organization: string, repositoryName: string, adapters: Readonly<ToolAdapter>[], apiToken: string, onRemoteToolsFound?: (totalEnabledTools: number, matchedAdapters: number) => void, onToolProcessed?: (displayName: string, patternCount: number, usesConfigFile: boolean) => void, onIgnoredFilesFetched?: (count: number, capped: boolean) => void): Promise<{
224
269
  config: CodacyConfig;
225
270
  stats: InitRemoteStats;
226
271
  }>;
@@ -334,6 +379,15 @@ declare function listPrFiles(repositoryRoot: string): string[];
334
379
  * follows cursors until the response contains no next cursor.
335
380
  */
336
381
 
382
+ /** Result of fetching cloud-ignored files, with pagination cap. */
383
+ interface IgnoredFilesResult {
384
+ /** File paths ignored in Codacy Cloud. */
385
+ files: string[];
386
+ /** Total number of files fetched (same as files.length). */
387
+ totalFetched: number;
388
+ /** Whether the fetch was stopped because it hit the 1000-file cap. */
389
+ capped: boolean;
390
+ }
337
391
  /**
338
392
  * Configures the API token used for authenticated requests.
339
393
  * Must be called before `getRepository`, `listRepositoryTools`, or
@@ -350,6 +404,13 @@ declare function validateApiToken(token: string): Promise<{
350
404
  name?: string;
351
405
  email?: string;
352
406
  }>;
407
+ /**
408
+ * Fetches files individually ignored in Codacy Cloud for a repository.
409
+ * Uses cursor-based pagination capped at 10 pages (1000 files max) to avoid
410
+ * unbounded fetching for repositories with very large ignore lists.
411
+ * Requires `configureApiToken()` to have been called.
412
+ */
413
+ declare function listIgnoredFiles(provider: string, org: string, repo: string): Promise<IgnoredFilesResult>;
353
414
 
354
415
  /**
355
416
  * Structured file + stderr logger for the analysis pipeline.
@@ -403,4 +464,4 @@ declare function rotateLogFiles(logsDir: string, maxFiles: number): void;
403
464
  */
404
465
  declare function createLogger(options?: LoggerOptions): Logger;
405
466
 
406
- 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 };
467
+ export { type AdapterFactory, type AnalyzeOptions, type CodacyYamlConfig, type CodacyYamlEngineConfig, type ExecutionMode, type IgnoredFilesResult, type InitDefaultStats, type InitLocalStats, type InitRemoteStats, type LoggerOptions, analyze, applyCodacyYamlExcludes, buildToolConfig, clearAdapters, configureApiToken, createCodacyConfig, createLogger, detectLanguages, formatOutput, formatTextSummary, getAdapter, getRegisteredAdapters, getRegisteredDescriptors, initContainerConfig, initDefaultConfig, initLocalConfig, initRemoteConfig, listDiffFiles, listIgnoredFiles, listPrFiles, listStagedFiles, readCodacyConfig, readCodacyYaml, registerAdapter, registerLazyAdapter, resolveEngineToAdapter, rotateLogFiles, validateApiToken, writeCodacyConfig };
package/dist/index.js CHANGED
@@ -40,17 +40,21 @@ __export(index_exports, {
40
40
  detectLanguages: () => detectLanguages,
41
41
  formatOutput: () => formatOutput,
42
42
  formatTextSummary: () => formatTextSummary,
43
+ getAdapter: () => getAdapter,
43
44
  getRegisteredAdapters: () => getRegisteredAdapters,
45
+ getRegisteredDescriptors: () => getRegisteredDescriptors,
44
46
  initContainerConfig: () => initContainerConfig,
45
47
  initDefaultConfig: () => initDefaultConfig,
46
48
  initLocalConfig: () => initLocalConfig,
47
49
  initRemoteConfig: () => initRemoteConfig,
48
50
  listDiffFiles: () => listDiffFiles,
51
+ listIgnoredFiles: () => listIgnoredFiles,
49
52
  listPrFiles: () => listPrFiles,
50
53
  listStagedFiles: () => listStagedFiles,
51
54
  readCodacyConfig: () => readCodacyConfig,
52
55
  readCodacyYaml: () => readCodacyYaml,
53
56
  registerAdapter: () => registerAdapter,
57
+ registerLazyAdapter: () => registerLazyAdapter,
54
58
  resolveEngineToAdapter: () => resolveEngineToAdapter,
55
59
  rotateLogFiles: () => rotateLogFiles,
56
60
  validateApiToken: () => validateApiToken,
@@ -62,29 +66,55 @@ module.exports = __toCommonJS(index_exports);
62
66
  var import_os = __toESM(require("os"));
63
67
  var import_path3 = __toESM(require("path"));
64
68
  var import_child_process2 = require("child_process");
69
+ var import_util = require("util");
65
70
 
66
71
  // src/registry.ts
67
- var adapters = /* @__PURE__ */ new Map();
72
+ var import_tooling = require("@codacy/tooling");
73
+ var entries = /* @__PURE__ */ new Map();
68
74
  function registerAdapter(adapter) {
69
- adapters.set(adapter.id, adapter);
75
+ entries.set(adapter.id, {
76
+ descriptor: (0, import_tooling.extractDescriptor)(adapter),
77
+ factory: async () => adapter,
78
+ resolved: adapter
79
+ });
80
+ }
81
+ function registerLazyAdapter(descriptor, factory) {
82
+ entries.set(descriptor.id, { descriptor, factory });
70
83
  }
71
- function resolveAdapter(input) {
72
- const exact = adapters.get(input);
84
+ function resolveEntry(input) {
85
+ const exact = entries.get(input);
73
86
  if (exact) return exact;
74
87
  const needle = input.toLowerCase();
75
- const matches = Array.from(adapters.values()).filter((a) => {
76
- return a.id.toLowerCase().includes(needle) || a.displayName.toLowerCase().includes(needle);
88
+ const matches = Array.from(entries.values()).filter((e) => {
89
+ return e.descriptor.id.toLowerCase().includes(needle) || e.descriptor.displayName.toLowerCase().includes(needle);
77
90
  });
78
91
  return matches.length === 1 ? matches[0] : void 0;
79
92
  }
80
- function getRegisteredAdapters(toolIds) {
93
+ async function loadAdapter(entry) {
94
+ if (entry.resolved) return entry.resolved;
95
+ entry.resolved = await entry.factory();
96
+ return entry.resolved;
97
+ }
98
+ async function getRegisteredAdapters(toolIds) {
81
99
  if (toolIds && toolIds.length > 0) {
82
- return toolIds.map((id) => resolveAdapter(id)).filter((a) => a !== void 0);
100
+ const matched = toolIds.map((id) => resolveEntry(id)).filter((e) => e !== void 0);
101
+ return Promise.all(matched.map(loadAdapter));
83
102
  }
84
- return Array.from(adapters.values());
103
+ return Promise.all(Array.from(entries.values()).map(loadAdapter));
104
+ }
105
+ function getRegisteredDescriptors(toolIds) {
106
+ if (toolIds && toolIds.length > 0) {
107
+ return toolIds.map((id) => resolveEntry(id)).filter((e) => e !== void 0).map((e) => e.descriptor);
108
+ }
109
+ return Array.from(entries.values()).map((e) => e.descriptor);
110
+ }
111
+ async function getAdapter(toolId) {
112
+ const entry = entries.get(toolId);
113
+ if (!entry) return void 0;
114
+ return loadAdapter(entry);
85
115
  }
86
116
  function clearAdapters() {
87
- adapters.clear();
117
+ entries.clear();
88
118
  }
89
119
 
90
120
  // src/config.ts
@@ -429,6 +459,7 @@ async function runToolsParallel(tools, timeoutMs, concurrency, callbacks) {
429
459
  }
430
460
 
431
461
  // src/analyze.ts
462
+ var execFileAsync = (0, import_util.promisify)(import_child_process2.execFile);
432
463
  var nullLogger = {
433
464
  debug: () => {
434
465
  },
@@ -451,26 +482,20 @@ async function analyze(options) {
451
482
  checkedAt: (/* @__PURE__ */ new Date()).toISOString()
452
483
  };
453
484
  try {
454
- (0, import_child_process2.execSync)("git rev-parse --is-inside-work-tree", {
455
- cwd: options.repositoryRoot,
456
- stdio: "pipe"
485
+ await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
486
+ cwd: options.repositoryRoot
457
487
  });
458
- } catch {
488
+ } catch (err) {
489
+ const isGitMissing = err instanceof Error && "code" in err && err.code === "ENOENT";
490
+ const message = isGitMissing ? "git is not installed. Codacy analysis requires git for file discovery." : `${options.repositoryRoot} is not a git repository. Codacy analysis requires a git repository for file discovery. Run \`git init\` to initialize one.`;
491
+ const kind = isGitMissing ? "GitNotInstalled" : "NotAGitRepository";
459
492
  return buildResult(
460
493
  startedAt,
461
494
  options.repositoryRoot,
462
495
  mode,
463
496
  emptyCapability,
464
497
  [],
465
- [
466
- {
467
- toolId: "runner",
468
- phase: "requirementCheck",
469
- kind: "NotAGitRepository",
470
- message: `${options.repositoryRoot} is not a git repository. Codacy analysis requires a git repository for file discovery. Run \`git init\` to initialize one.`,
471
- level: "error"
472
- }
473
- ],
498
+ [{ toolId: "runner", phase: "requirementCheck", kind, message, level: "error" }],
474
499
  []
475
500
  );
476
501
  }
@@ -515,8 +540,9 @@ async function analyze(options) {
515
540
  []
516
541
  );
517
542
  }
518
- const adapters2 = getRegisteredAdapters(options.tools);
519
- logger.info("Pipeline started", { mode, toolCount: adapters2.length, parallelTools, toolTimeout });
543
+ const requestedTools = options.tools ?? codacyConfig.tools.map((t) => t.toolId);
544
+ const adapters = await getRegisteredAdapters(requestedTools);
545
+ logger.info("Pipeline started", { mode, toolCount: adapters.length, parallelTools, toolTimeout });
520
546
  const globalDir = import_path3.default.join(import_os.default.homedir(), ".codacy");
521
547
  const baseCtx = {
522
548
  repositoryRoot: options.repositoryRoot,
@@ -528,7 +554,7 @@ async function analyze(options) {
528
554
  const ready = [];
529
555
  const unavailable = [];
530
556
  const availabilityTimeout = 6e4;
531
- for (const adapter of adapters2) {
557
+ for (const adapter of adapters) {
532
558
  const ctx = makeToolContext(baseCtx, adapter, []);
533
559
  const checkStart = Date.now();
534
560
  logger.debug("Checking availability", { toolId: adapter.id });
@@ -600,7 +626,7 @@ async function analyze(options) {
600
626
  const installErrors = [];
601
627
  for (let i = capability.unavailable.length - 1; i >= 0; i--) {
602
628
  const status = capability.unavailable[i];
603
- const adapter = adapters2.find((a) => a.id === status.toolId);
629
+ const adapter = adapters.find((a) => a.id === status.toolId);
604
630
  if (!adapter) continue;
605
631
  const ctx = makeToolContext(baseCtx, adapter, []);
606
632
  logger.info(`${adapter.displayName} is missing, attempting install...`);
@@ -674,7 +700,7 @@ async function analyze(options) {
674
700
  }
675
701
  if (mode === "inspect") {
676
702
  for (const tool of capability.ready) {
677
- const adapter = adapters2.find((a) => a.id === tool.toolId);
703
+ const adapter = adapters.find((a) => a.id === tool.toolId);
678
704
  if (!adapter) continue;
679
705
  const ctx = makeToolContext(baseCtx, adapter, []);
680
706
  const availability = await adapter.checkAvailability(ctx).catch(() => null);
@@ -741,7 +767,7 @@ async function analyze(options) {
741
767
  allFiles = filterByTargetFiles(allFiles, options.files);
742
768
  logger.debug("Filtered by target files", { afterFilter: allFiles.length });
743
769
  }
744
- const readyAdapters = adapters2.filter((a) => capability.ready.some((r) => r.toolId === a.id));
770
+ const readyAdapters = adapters.filter((a) => capability.ready.some((r) => r.toolId === a.id));
745
771
  const toolRuns = [];
746
772
  for (const adapter of readyAdapters) {
747
773
  const toolConfig = getToolConfig(codacyConfig, adapter.id);
@@ -769,6 +795,10 @@ async function analyze(options) {
769
795
  logger.debug("No files routed, skipping", { toolId: adapter.id });
770
796
  continue;
771
797
  }
798
+ if (!codacyToolConfig.useLocalConfigurationFile && codacyToolConfig.patterns.length === 0) {
799
+ logger.debug("No patterns and no local config, skipping", { toolId: adapter.id });
800
+ continue;
801
+ }
772
802
  logger.debug("Files routed to tool", { toolId: adapter.id, fileCount: toolFiles.length });
773
803
  logger.debug("Tool config resolved", {
774
804
  toolId: adapter.id,
@@ -1209,7 +1239,7 @@ function colorSeverity(severity) {
1209
1239
  var import_promises3 = __toESM(require("fs/promises"));
1210
1240
  var import_path6 = __toESM(require("path"));
1211
1241
  var import_child_process3 = require("child_process");
1212
- var import_tooling = require("@codacy/tooling");
1242
+ var import_tooling2 = require("@codacy/tooling");
1213
1243
 
1214
1244
  // src/codacy-yaml.ts
1215
1245
  var import_promises2 = __toESM(require("fs/promises"));
@@ -1252,16 +1282,16 @@ function extractStringArray(value) {
1252
1282
  if (!Array.isArray(value)) return [];
1253
1283
  return value.filter((v) => typeof v === "string");
1254
1284
  }
1255
- function resolveEngineToAdapter(engineName, adapters2) {
1256
- const exact = adapters2.find((a) => a.id === engineName);
1285
+ function resolveEngineToAdapter(engineName, adapters) {
1286
+ const exact = adapters.find((a) => a.id === engineName);
1257
1287
  if (exact) return exact.id;
1258
1288
  const needle = engineName.toLowerCase();
1259
- const matches = adapters2.filter((a) => {
1289
+ const matches = adapters.filter((a) => {
1260
1290
  return a.id.toLowerCase().includes(needle) || a.displayName.toLowerCase().includes(needle);
1261
1291
  });
1262
1292
  return matches.length === 1 ? matches[0].id : void 0;
1263
1293
  }
1264
- function applyCodacyYamlExcludes(config, yamlConfig, adapters2, logger) {
1294
+ function applyCodacyYamlExcludes(config, yamlConfig, adapters, logger) {
1265
1295
  const hasGlobalIncludes = yamlConfig.includePaths.length > 0;
1266
1296
  const hasEngineIncludes = Array.from(yamlConfig.engines.values()).some(
1267
1297
  (e) => e.includePaths.length > 0
@@ -1273,7 +1303,7 @@ function applyCodacyYamlExcludes(config, yamlConfig, adapters2, logger) {
1273
1303
  const tools = config.tools.map((tool) => ({ ...tool }));
1274
1304
  for (const [engineName, engineConfig] of yamlConfig.engines) {
1275
1305
  if (engineConfig.excludePaths.length === 0) continue;
1276
- const adapterId = resolveEngineToAdapter(engineName, adapters2);
1306
+ const adapterId = resolveEngineToAdapter(engineName, adapters);
1277
1307
  if (!adapterId) {
1278
1308
  logger?.warn(`Could not resolve .codacy.yaml engine "${engineName}" to a registered adapter`);
1279
1309
  continue;
@@ -4798,6 +4828,34 @@ async function listRepositoryToolPatterns(provider, org, repo, toolUuid) {
4798
4828
  );
4799
4829
  return all;
4800
4830
  }
4831
+ async function listIgnoredFiles(provider, org, repo) {
4832
+ const MAX_PAGES = 10;
4833
+ const files = [];
4834
+ let cursor;
4835
+ let pages = 0;
4836
+ while (pages < MAX_PAGES) {
4837
+ const page = await RepositoryService.listIgnoredFiles(
4838
+ provider,
4839
+ org,
4840
+ repo,
4841
+ void 0,
4842
+ // branch — use default branch
4843
+ void 0,
4844
+ // search
4845
+ cursor,
4846
+ 100
4847
+ );
4848
+ files.push(...page.data.map((f) => f.filepath));
4849
+ cursor = page.pagination?.cursor;
4850
+ pages++;
4851
+ if (!cursor || page.data.length === 0) break;
4852
+ }
4853
+ return {
4854
+ files,
4855
+ totalFetched: files.length,
4856
+ capped: pages >= MAX_PAGES && cursor !== void 0
4857
+ };
4858
+ }
4801
4859
 
4802
4860
  // src/init.ts
4803
4861
  async function detectLanguages(repositoryRoot) {
@@ -4816,7 +4874,7 @@ async function detectLanguages(repositoryRoot) {
4816
4874
  for (const file of files) {
4817
4875
  const basename = import_path6.default.basename(file);
4818
4876
  const ext = import_path6.default.extname(file).toLowerCase();
4819
- for (const [lang, config] of Object.entries(import_tooling.LANGUAGE_CONFIG)) {
4877
+ for (const [lang, config] of Object.entries(import_tooling2.LANGUAGE_CONFIG)) {
4820
4878
  if (config.extensions.includes(ext)) {
4821
4879
  detected.add(lang);
4822
4880
  } else if (config.files.includes(basename)) {
@@ -4826,10 +4884,10 @@ async function detectLanguages(repositoryRoot) {
4826
4884
  }
4827
4885
  return Array.from(detected).sort();
4828
4886
  }
4829
- async function detectLocalConfigFiles(repositoryRoot, adapters2) {
4887
+ async function detectLocalConfigFiles(repositoryRoot, adapters) {
4830
4888
  const found = /* @__PURE__ */ new Map();
4831
4889
  const checks = await Promise.allSettled(
4832
- adapters2.map(async (adapter) => {
4890
+ adapters.map(async (adapter) => {
4833
4891
  const result = await adapter.checkLocalConfigurationFile({
4834
4892
  repositoryRoot,
4835
4893
  generatedConfigDir: import_path6.default.join(repositoryRoot, ".codacy", "generated"),
@@ -4860,17 +4918,17 @@ var silentLogger = {
4860
4918
  error: () => {
4861
4919
  }
4862
4920
  };
4863
- async function enrichWithCodacyYaml(config, repositoryRoot, adapters2) {
4921
+ async function enrichWithCodacyYaml(config, repositoryRoot, adapters) {
4864
4922
  const yamlConfig = await readCodacyYaml(repositoryRoot);
4865
4923
  if (!yamlConfig) return { config, codacyYamlApplied: false };
4866
4924
  return {
4867
- config: applyCodacyYamlExcludes(config, yamlConfig, adapters2),
4925
+ config: applyCodacyYamlExcludes(config, yamlConfig, adapters),
4868
4926
  codacyYamlApplied: true
4869
4927
  };
4870
4928
  }
4871
- async function initLocalConfigBase(repositoryRoot, adapters2) {
4929
+ async function initLocalConfigBase(repositoryRoot, adapters) {
4872
4930
  const languages = await detectLanguages(repositoryRoot);
4873
- const localConfigs = await detectLocalConfigFiles(repositoryRoot, adapters2);
4931
+ const localConfigs = await detectLocalConfigFiles(repositoryRoot, adapters);
4874
4932
  const tools = [];
4875
4933
  for (const [toolId, configPath] of localConfigs.entries()) {
4876
4934
  tools.push({
@@ -4882,17 +4940,17 @@ async function initLocalConfigBase(repositoryRoot, adapters2) {
4882
4940
  }
4883
4941
  return createCodacyConfig({ source: "local", languages, tools });
4884
4942
  }
4885
- async function initLocalConfig(repositoryRoot, adapters2) {
4886
- const baseConfig = await initLocalConfigBase(repositoryRoot, adapters2);
4943
+ async function initLocalConfig(repositoryRoot, adapters) {
4944
+ const baseConfig = await initLocalConfigBase(repositoryRoot, adapters);
4887
4945
  const { config, codacyYamlApplied } = await enrichWithCodacyYaml(
4888
4946
  baseConfig,
4889
4947
  repositoryRoot,
4890
- adapters2
4948
+ adapters
4891
4949
  );
4892
4950
  return { config, stats: { codacyYamlApplied } };
4893
4951
  }
4894
- async function initDefaultConfig(repositoryRoot, adapters2) {
4895
- const base = await initLocalConfigBase(repositoryRoot, adapters2);
4952
+ async function initDefaultConfig(repositoryRoot, adapters) {
4953
+ const base = await initLocalConfigBase(repositoryRoot, adapters);
4896
4954
  const toolsWithLocalConfig = new Set(
4897
4955
  base.tools.filter((t) => t.useLocalConfigurationFile).map((t) => t.toolId)
4898
4956
  );
@@ -4901,7 +4959,7 @@ async function initDefaultConfig(repositoryRoot, adapters2) {
4901
4959
  const updatedTools = [...base.tools];
4902
4960
  const coveredToolIds = new Set(updatedTools.map((t) => t.toolId));
4903
4961
  let addedTools = 0;
4904
- for (const adapter of adapters2) {
4962
+ for (const adapter of adapters) {
4905
4963
  if (toolsWithLocalConfig.has(adapter.id)) continue;
4906
4964
  const apiTool = apiTools.find(
4907
4965
  (t) => t.prefix ? t.prefix.replace(/_$/, "") === adapter.id : t.shortName === adapter.id
@@ -4935,20 +4993,26 @@ async function initDefaultConfig(repositoryRoot, adapters2) {
4935
4993
  const { config, codacyYamlApplied } = await enrichWithCodacyYaml(
4936
4994
  baseConfig,
4937
4995
  repositoryRoot,
4938
- adapters2
4996
+ adapters
4939
4997
  );
4940
4998
  return { config, stats: { totalApiTools: apiTools.length, addedTools, codacyYamlApplied } };
4941
4999
  }
4942
- async function initRemoteConfig(repositoryRoot, provider, organization, repositoryName, adapters2, apiToken, onRemoteToolsFound, onToolProcessed) {
5000
+ async function initRemoteConfig(repositoryRoot, provider, organization, repositoryName, adapters, apiToken, onRemoteToolsFound, onToolProcessed, onIgnoredFilesFetched) {
4943
5001
  configureApiToken(apiToken);
4944
5002
  const repoInfo = await getRepository(provider, organization, repositoryName);
4945
5003
  const remoteTools = await listRepositoryTools(provider, organization, repositoryName);
5004
+ let ignoredFilesResult = { files: [], totalFetched: 0, capped: false };
5005
+ try {
5006
+ ignoredFilesResult = await listIgnoredFiles(provider, organization, repositoryName);
5007
+ } catch {
5008
+ }
5009
+ onIgnoredFilesFetched?.(ignoredFilesResult.totalFetched, ignoredFilesResult.capped);
4946
5010
  const adapterByName = /* @__PURE__ */ new Map();
4947
- for (const adapter of adapters2) {
5011
+ for (const adapter of adapters) {
4948
5012
  adapterByName.set(adapter.id, adapter);
4949
5013
  adapterByName.set(adapter.displayName.toLowerCase(), adapter);
4950
5014
  }
4951
- const localConfigs = await detectLocalConfigFiles(repositoryRoot, adapters2);
5015
+ const localConfigs = await detectLocalConfigFiles(repositoryRoot, adapters);
4952
5016
  const allApiTools = await listTools();
4953
5017
  const adapterByUuid = /* @__PURE__ */ new Map();
4954
5018
  for (const apiTool of allApiTools) {
@@ -5005,17 +5069,26 @@ async function initRemoteConfig(repositoryRoot, provider, organization, reposito
5005
5069
  repositoryId: repoInfo.repositoryId != null ? String(repoInfo.repositoryId) : void 0,
5006
5070
  repositoryName
5007
5071
  });
5072
+ if (ignoredFilesResult.files.length > 0) {
5073
+ baseConfig.exclude = [.../* @__PURE__ */ new Set([...baseConfig.exclude ?? [], ...ignoredFilesResult.files])];
5074
+ }
5008
5075
  const { config, codacyYamlApplied } = await enrichWithCodacyYaml(
5009
5076
  baseConfig,
5010
5077
  repositoryRoot,
5011
- adapters2
5078
+ adapters
5012
5079
  );
5013
5080
  return {
5014
5081
  config,
5015
- stats: { totalRemoteTools: remoteTools.length, matchedAdapters, codacyYamlApplied }
5082
+ stats: {
5083
+ totalRemoteTools: remoteTools.length,
5084
+ matchedAdapters,
5085
+ codacyYamlApplied,
5086
+ ignoredFilesCount: ignoredFilesResult.totalFetched,
5087
+ ignoredFilesCapped: ignoredFilesResult.capped
5088
+ }
5016
5089
  };
5017
5090
  }
5018
- async function initContainerConfig(repositoryRoot, adapters2) {
5091
+ async function initContainerConfig(repositoryRoot, adapters) {
5019
5092
  const codacyrcPath = import_path6.default.join(repositoryRoot, ".codacyrc");
5020
5093
  let raw;
5021
5094
  try {
@@ -5035,7 +5108,7 @@ async function initContainerConfig(repositoryRoot, adapters2) {
5035
5108
  }
5036
5109
  }
5037
5110
  const includeFiles = Array.isArray(parsed.files) ? parsed.files.filter((f) => typeof f === "string") : [];
5038
- const adapterById = new Map(adapters2.map((a) => [a.id, a]));
5111
+ const adapterById = new Map(adapters.map((a) => [a.id, a]));
5039
5112
  const tools = [];
5040
5113
  if (Array.isArray(parsed.tools)) {
5041
5114
  for (const toolEntry of parsed.tools) {
@@ -5082,15 +5155,15 @@ var LEVEL_ORDER = {
5082
5155
  error: 3
5083
5156
  };
5084
5157
  function rotateLogFiles(logsDir, maxFiles) {
5085
- let entries;
5158
+ let entries2;
5086
5159
  try {
5087
- entries = import_fs.default.readdirSync(logsDir).filter((f) => f.startsWith("analysis-") && f.endsWith(".log"));
5160
+ entries2 = import_fs.default.readdirSync(logsDir).filter((f) => f.startsWith("analysis-") && f.endsWith(".log"));
5088
5161
  } catch {
5089
5162
  return;
5090
5163
  }
5091
- if (entries.length <= maxFiles) return;
5092
- entries.sort();
5093
- const toRemove = entries.slice(0, entries.length - maxFiles);
5164
+ if (entries2.length <= maxFiles) return;
5165
+ entries2.sort();
5166
+ const toRemove = entries2.slice(0, entries2.length - maxFiles);
5094
5167
  for (const f of toRemove) {
5095
5168
  try {
5096
5169
  import_fs.default.unlinkSync(import_path7.default.join(logsDir, f));
@@ -5188,17 +5261,21 @@ function createLogger(options = {}) {
5188
5261
  detectLanguages,
5189
5262
  formatOutput,
5190
5263
  formatTextSummary,
5264
+ getAdapter,
5191
5265
  getRegisteredAdapters,
5266
+ getRegisteredDescriptors,
5192
5267
  initContainerConfig,
5193
5268
  initDefaultConfig,
5194
5269
  initLocalConfig,
5195
5270
  initRemoteConfig,
5196
5271
  listDiffFiles,
5272
+ listIgnoredFiles,
5197
5273
  listPrFiles,
5198
5274
  listStagedFiles,
5199
5275
  readCodacyConfig,
5200
5276
  readCodacyYaml,
5201
5277
  registerAdapter,
5278
+ registerLazyAdapter,
5202
5279
  resolveEngineToAdapter,
5203
5280
  rotateLogFiles,
5204
5281
  validateApiToken,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/analysis-runner",
3
- "version": "0.4.0",
3
+ "version": "0.5.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.4.0"
15
+ "@codacy/tooling": "0.5.0"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@codacy/openapi-typescript-codegen": "0.0.9",
19
- "@codacy/tools-dummy-1": "0.4.0"
19
+ "@codacy/tools-dummy-1": "0.5.0"
20
20
  },
21
21
  "license": "MIT",
22
22
  "author": "Codacy <support@codacy.com> (https://www.codacy.com)",