@codacy/analysis-runner 0.14.0 → 0.15.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.
Files changed (2) hide show
  1. package/dist/index.js +124 -1
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -89,6 +89,7 @@ module.exports = __toCommonJS(index_exports);
89
89
  // src/analyze.ts
90
90
  var import_os2 = __toESM(require("os"));
91
91
  var import_path4 = __toESM(require("path"));
92
+ var import_fs3 = __toESM(require("fs"));
92
93
  var import_child_process3 = require("child_process");
93
94
  var import_util = require("util");
94
95
  var import_tooling3 = require("@codacy/tooling");
@@ -586,7 +587,7 @@ function routeFilesToTool(files, adapter, toolConfig) {
586
587
  }
587
588
  function filterByTargetFiles(allFiles, targetPatterns) {
588
589
  if (targetPatterns.length === 0) return allFiles;
589
- const normalized = targetPatterns.map((p) => p.replace(/^\.\//, ""));
590
+ const normalized = targetPatterns.map((p) => p.replace(/\\/g, "/").replace(/^\.\//, ""));
590
591
  const exact = new Set(normalized);
591
592
  const globs = normalized.map((p) => new import_minimatch2.Minimatch(p, { dot: true, matchBase: false })).filter((m) => m.hasMagic());
592
593
  const dirPrefixes = normalized.filter((p) => p.endsWith("/"));
@@ -1053,6 +1054,26 @@ async function analyze(options) {
1053
1054
  []
1054
1055
  );
1055
1056
  }
1057
+ const rootStat = import_fs3.default.statSync(options.repositoryRoot, { throwIfNoEntry: false });
1058
+ if (!rootStat?.isDirectory()) {
1059
+ return buildResult(
1060
+ startedAt,
1061
+ options.repositoryRoot,
1062
+ mode,
1063
+ emptyCapability,
1064
+ [],
1065
+ [
1066
+ {
1067
+ toolId: "runner",
1068
+ phase: "requirementCheck",
1069
+ kind: "RepositoryNotFound",
1070
+ message: `${options.repositoryRoot} does not exist or is not a directory. Pass a path to an existing repository, or a quoted glob (e.g. "src/**/*.ts") to scope files.`,
1071
+ level: "error"
1072
+ }
1073
+ ],
1074
+ []
1075
+ );
1076
+ }
1056
1077
  try {
1057
1078
  await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
1058
1079
  cwd: options.repositoryRoot
@@ -2604,11 +2625,24 @@ var DEPENDENCY_CATALOG = /* @__PURE__ */ new Map([
2604
2625
  // --- Scala — Frameworks ---
2605
2626
  ["play-server", { displayName: "Play Framework", kind: "framework" }],
2606
2627
  ["akka-actor", { displayName: "Akka", kind: "framework" }],
2628
+ ["spray-can", { displayName: "Spray", kind: "framework" }],
2607
2629
  // --- Scala — Libraries ---
2608
2630
  ["scalatest", { displayName: "ScalaTest", kind: "library" }],
2609
2631
  ["specs2-core", { displayName: "Specs2", kind: "library" }],
2610
2632
  ["cats-core", { displayName: "Cats", kind: "library" }],
2611
2633
  ["circe-core", { displayName: "Circe", kind: "library" }],
2634
+ // --- Elixir — Frameworks ---
2635
+ ["phoenix", { displayName: "Phoenix", kind: "framework" }],
2636
+ ["plug", { displayName: "Plug", kind: "framework" }],
2637
+ ["plug_cowboy", { displayName: "Plug", kind: "framework" }],
2638
+ // --- Elixir — Libraries ---
2639
+ ["ecto", { displayName: "Ecto", kind: "library" }],
2640
+ ["ecto_sql", { displayName: "Ecto", kind: "library" }],
2641
+ ["phoenix_ecto", { displayName: "Ecto", kind: "library" }],
2642
+ // --- Crystal — Frameworks ---
2643
+ ["amber", { displayName: "Amber", kind: "framework" }],
2644
+ ["lucky", { displayName: "Lucky", kind: "framework" }],
2645
+ ["kemal", { displayName: "Kemal", kind: "framework" }],
2612
2646
  // --- Dart — Frameworks ---
2613
2647
  // `flutter` and `angular` appear as plain keys in pubspec.yaml. NOTE: `angular`
2614
2648
  // here is Dart's AngularDart. The npm package `angular` is AngularJS (1.x) — a
@@ -2746,6 +2780,31 @@ var FILE_SIGNAL_RULES = [
2746
2780
  name: "suitecloud.config.js",
2747
2781
  matches: (f) => pathBasename(f) === "suitecloud.config.js",
2748
2782
  classification: { displayName: "SuiteScript", kind: "platform" }
2783
+ },
2784
+ {
2785
+ name: ".github/workflows",
2786
+ matches: (f) => f.startsWith(".github/workflows/"),
2787
+ classification: { displayName: "GitHub Actions", kind: "framework" }
2788
+ },
2789
+ {
2790
+ name: ".circleci",
2791
+ matches: (f) => f.startsWith(".circleci/"),
2792
+ classification: { displayName: "CircleCI", kind: "framework" }
2793
+ },
2794
+ {
2795
+ name: ".gitlab-ci.yml",
2796
+ matches: (f) => f === ".gitlab-ci.yml" || f.startsWith(".gitlab/"),
2797
+ classification: { displayName: "GitLab CI", kind: "framework" }
2798
+ },
2799
+ {
2800
+ name: "bitbucket-pipelines.yml",
2801
+ matches: (f) => f === "bitbucket-pipelines.yml",
2802
+ classification: { displayName: "Bitbucket Pipelines", kind: "framework" }
2803
+ },
2804
+ {
2805
+ name: "azure-pipelines.yml",
2806
+ matches: (f) => f === "azure-pipelines.yml" || f === "azure-pipelines.yaml",
2807
+ classification: { displayName: "Azure Pipelines", kind: "framework" }
2749
2808
  }
2750
2809
  ];
2751
2810
  function detectFileSignals(files) {
@@ -2991,6 +3050,15 @@ function parseGemfile(content) {
2991
3050
  }
2992
3051
  return deps;
2993
3052
  }
3053
+ function parseMixExs(content) {
3054
+ const deps = [];
3055
+ const depRegex = /\{:([a-zA-Z_][a-zA-Z0-9_]*)\s*,\s*"([^"]*)"/g;
3056
+ let match;
3057
+ while ((match = depRegex.exec(content)) !== null) {
3058
+ deps.push({ name: match[1], version: match[2] || void 0 });
3059
+ }
3060
+ return deps;
3061
+ }
2994
3062
  function parseGoMod(content) {
2995
3063
  const deps = [];
2996
3064
  const singleRegex = /^require\s+(\S+)\s+(\S+)/gm;
@@ -3030,6 +3098,15 @@ function parseBuildGradle(content) {
3030
3098
  }
3031
3099
  return deps;
3032
3100
  }
3101
+ function parseBuildSbt(content) {
3102
+ const deps = [];
3103
+ const depRegex = /"([^"]+)"\s*%%?\s*"([^"]+)"\s*%\s*"([^"]+)"/g;
3104
+ let match;
3105
+ while ((match = depRegex.exec(content)) !== null) {
3106
+ deps.push({ name: match[2], version: match[3] });
3107
+ }
3108
+ return deps;
3109
+ }
3033
3110
  function parseCargoToml(content) {
3034
3111
  const deps = [];
3035
3112
  let inDepsSection = false;
@@ -3110,6 +3187,41 @@ function parsePubspecYaml(content) {
3110
3187
  }
3111
3188
  return deps;
3112
3189
  }
3190
+ function parseShardYml(content) {
3191
+ const deps = [];
3192
+ let inSection = false;
3193
+ let depIndent = -1;
3194
+ let current;
3195
+ const flush = () => {
3196
+ if (current) deps.push(current);
3197
+ current = void 0;
3198
+ };
3199
+ for (const rawLine of content.split("\n")) {
3200
+ const trimmed = rawLine.trim();
3201
+ if (trimmed === "" || trimmed.startsWith("#")) continue;
3202
+ const indent = rawLine.length - rawLine.trimStart().length;
3203
+ if (indent === 0) {
3204
+ flush();
3205
+ inSection = /^(dependencies|development_dependencies):/.test(trimmed);
3206
+ depIndent = -1;
3207
+ continue;
3208
+ }
3209
+ if (!inSection) continue;
3210
+ if (depIndent === -1) depIndent = indent;
3211
+ if (indent === depIndent) {
3212
+ flush();
3213
+ const m = trimmed.match(/^([a-zA-Z0-9_-]+)\s*:/);
3214
+ current = m ? { name: m[1] } : void 0;
3215
+ continue;
3216
+ }
3217
+ if (indent > depIndent && current) {
3218
+ const v = trimmed.match(/^version\s*:\s*["']?(?:~>|[~^])?\s*([0-9][^"'\s]*)/);
3219
+ if (v) current.version = v[1];
3220
+ }
3221
+ }
3222
+ flush();
3223
+ return deps;
3224
+ }
3113
3225
  function parseXmlDependencyElements(content, elementRegex, nameAttr) {
3114
3226
  const deps = [];
3115
3227
  const nameRegex = new RegExp(`\\b${nameAttr}\\s*=\\s*["']([^"']+)["']`, "i");
@@ -3144,11 +3256,14 @@ var MANIFEST_PARSERS = /* @__PURE__ */ new Map([
3144
3256
  ["pom.xml", parsePomXml],
3145
3257
  ["build.gradle", parseBuildGradle],
3146
3258
  ["build.gradle.kts", parseBuildGradle],
3259
+ ["build.sbt", parseBuildSbt],
3147
3260
  ["Cargo.toml", parseCargoToml],
3148
3261
  ["composer.json", parseComposerJson],
3149
3262
  ["Podfile", parsePodfile],
3150
3263
  ["Package.swift", parsePackageSwift],
3151
3264
  ["pubspec.yaml", parsePubspecYaml],
3265
+ ["mix.exs", parseMixExs],
3266
+ ["shard.yml", parseShardYml],
3152
3267
  ["packages.config", parsePackagesConfig],
3153
3268
  ["Directory.Packages.props", parseCsproj]
3154
3269
  ]);
@@ -7197,6 +7312,11 @@ async function initContainerConfig(repositoryRoot, adapters) {
7197
7312
  }
7198
7313
  return createCodacyConfig({ source: "container", tools, includeFiles });
7199
7314
  }
7315
+ function hasMatchingFiles(files, filePatterns) {
7316
+ const matcher = new CompiledMatcher(filePatterns);
7317
+ if (matcher.matchAll) return files.length > 0;
7318
+ return files.some((file) => matcher.matches(file, file.split("/").pop() ?? ""));
7319
+ }
7200
7320
  async function initAutoConfig(repositoryRoot, adapters, descriptors, filters, onDiscoveryComplete, rawFilterString, loadUnsupportedPatterns) {
7201
7321
  const discoveryResult = await discover(repositoryRoot);
7202
7322
  onDiscoveryComplete?.(discoveryResult);
@@ -7206,6 +7326,7 @@ async function initAutoConfig(repositoryRoot, adapters, descriptors, filters, on
7206
7326
  for (const lib of discoveryResult.libraries) detectedKeys.add(lib.displayName);
7207
7327
  const repoLanguages = new Set(discoveryResult.languages);
7208
7328
  const localConfigs = await detectLocalConfigFiles(repositoryRoot, adapters);
7329
+ const repoFiles = listRepoFiles(repositoryRoot);
7209
7330
  const descriptorMap = new Map(descriptors.map((d) => [d.id, d]));
7210
7331
  const candidates = [];
7211
7332
  for (const adapter of adapters) {
@@ -7213,6 +7334,7 @@ async function initAutoConfig(repositoryRoot, adapters, descriptors, filters, on
7213
7334
  const hasOverlap = adapter.languages.some((lang) => repoLanguages.has(lang));
7214
7335
  if (!hasOverlap) continue;
7215
7336
  }
7337
+ if (!hasMatchingFiles(repoFiles, adapter.filePatterns)) continue;
7216
7338
  candidates.push(adapter);
7217
7339
  }
7218
7340
  const deduped = deduplicateToolFamilies(candidates, localConfigs);
@@ -7256,6 +7378,7 @@ async function initAutoConfig(repositoryRoot, adapters, descriptors, filters, on
7256
7378
  }
7257
7379
  const family = toolFamily(desc.id);
7258
7380
  if (selectedFamilies.has(family)) continue;
7381
+ if (!hasMatchingFiles(repoFiles, desc.filePatterns)) continue;
7259
7382
  const patternsMetadata = loadUnsupportedPatterns(desc.id);
7260
7383
  if (patternsMetadata.length === 0) continue;
7261
7384
  const selectedPatterns = filterAutoPatterns(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/analysis-runner",
3
- "version": "0.14.0",
3
+ "version": "0.15.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.14.0"
15
+ "@codacy/tooling": "0.15.0"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@codacy/openapi-typescript-codegen": "0.0.9",
19
- "@codacy/tools-dummy-1": "0.14.0"
19
+ "@codacy/tools-dummy-1": "0.15.0"
20
20
  },
21
21
  "license": "MIT",
22
22
  "author": "Codacy <support@codacy.com> (https://www.codacy.com)",