@codacy/analysis-runner 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +39 -1
- package/dist/index.js +137 -2
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,18 @@ interface AnalyzeOptions {
|
|
|
34
34
|
/** Target execution environment. "local" = developer machine, "container" = Codacy Docker runner.
|
|
35
35
|
* Phase 9 implements the actual container path; this field is accepted but currently ignored. */
|
|
36
36
|
runner?: "local" | "container";
|
|
37
|
+
/**
|
|
38
|
+
* Git-aware file scope. Mutually exclusive options:
|
|
39
|
+
* - `"staged"` — analyze only files in the git staging area
|
|
40
|
+
* - `{ diff: string | true }` — analyze files changed vs a base ref (true = auto-detect)
|
|
41
|
+
* - `"pr"` — analyze files in the current pull request
|
|
42
|
+
*
|
|
43
|
+
* Resolved files are intersected with `files` if both are provided.
|
|
44
|
+
* If the resolved set is empty, analysis returns immediately with zero issues.
|
|
45
|
+
*/
|
|
46
|
+
gitScope?: "staged" | {
|
|
47
|
+
diff: string | true;
|
|
48
|
+
} | "pr";
|
|
37
49
|
/** Logger for pipeline progress messages (install status, etc.). Defaults to no-op. */
|
|
38
50
|
logger?: Logger;
|
|
39
51
|
/** Called when a tool starts executing. */
|
|
@@ -278,6 +290,32 @@ declare function resolveEngineToAdapter(engineName: string, adapters: Readonly<T
|
|
|
278
290
|
*/
|
|
279
291
|
declare function applyCodacyYamlExcludes(config: CodacyConfig, yamlConfig: CodacyYamlConfig, adapters: Readonly<ToolAdapter>[], logger?: Logger): CodacyConfig;
|
|
280
292
|
|
|
293
|
+
/**
|
|
294
|
+
* File discovery and routing — finds files in a repository, applies exclusion
|
|
295
|
+
* layers (.gitignore, global exclude, per-tool exclude), and routes files to
|
|
296
|
+
* the appropriate tool adapters based on file patterns.
|
|
297
|
+
*/
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Returns files changed in the git staging area (index), excluding deleted files.
|
|
301
|
+
* Used by `--staged` to analyze only what's about to be committed.
|
|
302
|
+
*/
|
|
303
|
+
declare function listStagedFiles(repositoryRoot: string): string[];
|
|
304
|
+
/**
|
|
305
|
+
* Returns files changed between a base ref and HEAD, excluding deleted files.
|
|
306
|
+
* Uses the three-dot diff (`base...HEAD`) to show only changes since divergence.
|
|
307
|
+
*
|
|
308
|
+
* If `base` is omitted, auto-detects the default branch via `detectDefaultBranch()`.
|
|
309
|
+
*/
|
|
310
|
+
declare function listDiffFiles(repositoryRoot: string, base?: string): string[];
|
|
311
|
+
/**
|
|
312
|
+
* Returns files changed in the current pull request.
|
|
313
|
+
*
|
|
314
|
+
* Tries `gh pr view` first for accuracy (handles renames, squash merges).
|
|
315
|
+
* Falls back to git merge-base diff when gh is unavailable or not in a PR context.
|
|
316
|
+
*/
|
|
317
|
+
declare function listPrFiles(repositoryRoot: string): string[];
|
|
318
|
+
|
|
281
319
|
/**
|
|
282
320
|
* Codacy API client — thin wrappers around the generated OpenAPI client.
|
|
283
321
|
*
|
|
@@ -361,4 +399,4 @@ declare function rotateLogFiles(logsDir: string, maxFiles: number): void;
|
|
|
361
399
|
*/
|
|
362
400
|
declare function createLogger(options?: LoggerOptions): Logger;
|
|
363
401
|
|
|
364
|
-
export { type AnalyzeOptions, type CodacyYamlConfig, type CodacyYamlEngineConfig, type ExecutionMode, type InitDefaultStats, type InitLocalStats, type InitRemoteStats, type LoggerOptions, analyze, applyCodacyYamlExcludes, buildToolConfig, clearAdapters, configureApiToken, createCodacyConfig, createLogger, detectLanguages, formatOutput, formatTextSummary, getRegisteredAdapters, initContainerConfig, initDefaultConfig, initLocalConfig, initRemoteConfig, readCodacyConfig, readCodacyYaml, registerAdapter, resolveEngineToAdapter, rotateLogFiles, validateApiToken, writeCodacyConfig };
|
|
402
|
+
export { type AnalyzeOptions, type CodacyYamlConfig, type CodacyYamlEngineConfig, type ExecutionMode, type InitDefaultStats, type InitLocalStats, type InitRemoteStats, type LoggerOptions, analyze, applyCodacyYamlExcludes, buildToolConfig, clearAdapters, configureApiToken, createCodacyConfig, createLogger, detectLanguages, formatOutput, formatTextSummary, getRegisteredAdapters, initContainerConfig, initDefaultConfig, initLocalConfig, initRemoteConfig, listDiffFiles, listPrFiles, listStagedFiles, readCodacyConfig, readCodacyYaml, registerAdapter, resolveEngineToAdapter, rotateLogFiles, validateApiToken, writeCodacyConfig };
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,9 @@ __export(index_exports, {
|
|
|
45
45
|
initDefaultConfig: () => initDefaultConfig,
|
|
46
46
|
initLocalConfig: () => initLocalConfig,
|
|
47
47
|
initRemoteConfig: () => initRemoteConfig,
|
|
48
|
+
listDiffFiles: () => listDiffFiles,
|
|
49
|
+
listPrFiles: () => listPrFiles,
|
|
50
|
+
listStagedFiles: () => listStagedFiles,
|
|
48
51
|
readCodacyConfig: () => readCodacyConfig,
|
|
49
52
|
readCodacyYaml: () => readCodacyYaml,
|
|
50
53
|
registerAdapter: () => registerAdapter,
|
|
@@ -92,11 +95,25 @@ async function readCodacyConfig(repositoryRoot) {
|
|
|
92
95
|
const configPath = import_path.default.join(repositoryRoot, CODACY_DIR, CONFIG_FILE);
|
|
93
96
|
try {
|
|
94
97
|
const raw = await import_promises.default.readFile(configPath, "utf-8");
|
|
95
|
-
|
|
98
|
+
const config = JSON.parse(raw);
|
|
99
|
+
coerceParameterValues(config);
|
|
100
|
+
return config;
|
|
96
101
|
} catch {
|
|
97
102
|
return null;
|
|
98
103
|
}
|
|
99
104
|
}
|
|
105
|
+
function coerceParameterValues(config) {
|
|
106
|
+
for (const tool of config.tools) {
|
|
107
|
+
for (const pattern of tool.patterns) {
|
|
108
|
+
if (!pattern.parameters) continue;
|
|
109
|
+
for (const [key, value] of Object.entries(pattern.parameters)) {
|
|
110
|
+
if (typeof value !== "string") {
|
|
111
|
+
pattern.parameters[key] = String(value);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
100
117
|
async function writeCodacyConfig(repositoryRoot, config) {
|
|
101
118
|
const codacyDir = import_path.default.join(repositoryRoot, CODACY_DIR);
|
|
102
119
|
await import_promises.default.mkdir(codacyDir, { recursive: true });
|
|
@@ -207,6 +224,91 @@ function routeFilesToTool(files, adapter, toolConfig) {
|
|
|
207
224
|
);
|
|
208
225
|
});
|
|
209
226
|
}
|
|
227
|
+
function listStagedFiles(repositoryRoot) {
|
|
228
|
+
try {
|
|
229
|
+
const output = (0, import_child_process.execSync)("git diff --cached --name-only --diff-filter=d", {
|
|
230
|
+
cwd: repositoryRoot,
|
|
231
|
+
encoding: "utf-8",
|
|
232
|
+
maxBuffer: 10 * 1024 * 1024
|
|
233
|
+
}).trim();
|
|
234
|
+
return output ? output.split("\n").filter(Boolean).sort() : [];
|
|
235
|
+
} catch {
|
|
236
|
+
throw new Error("Cannot list staged files: not inside a git repository");
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function listDiffFiles(repositoryRoot, base) {
|
|
240
|
+
const baseBranch = base ?? detectDefaultBranch(repositoryRoot);
|
|
241
|
+
try {
|
|
242
|
+
const output = (0, import_child_process.execFileSync)(
|
|
243
|
+
"git",
|
|
244
|
+
["diff", "--name-only", "--diff-filter=d", `${baseBranch}...HEAD`],
|
|
245
|
+
{ cwd: repositoryRoot, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
246
|
+
).trim();
|
|
247
|
+
return output ? output.split("\n").filter(Boolean).sort() : [];
|
|
248
|
+
} catch {
|
|
249
|
+
throw new Error(
|
|
250
|
+
`Cannot diff against "${baseBranch}": ref not found or not inside a git repository. Specify a base explicitly with --diff <base>.`
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function listPrFiles(repositoryRoot) {
|
|
255
|
+
try {
|
|
256
|
+
const output = (0, import_child_process.execSync)("gh pr view --json files --jq '.files[].path'", {
|
|
257
|
+
cwd: repositoryRoot,
|
|
258
|
+
encoding: "utf-8",
|
|
259
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
260
|
+
timeout: 15e3
|
|
261
|
+
}).trim();
|
|
262
|
+
if (output) {
|
|
263
|
+
return output.split("\n").filter(Boolean).sort();
|
|
264
|
+
}
|
|
265
|
+
} catch {
|
|
266
|
+
}
|
|
267
|
+
const baseBranch = detectDefaultBranch(repositoryRoot);
|
|
268
|
+
try {
|
|
269
|
+
const mergeBase = (0, import_child_process.execFileSync)("git", ["merge-base", "HEAD", baseBranch], {
|
|
270
|
+
cwd: repositoryRoot,
|
|
271
|
+
encoding: "utf-8"
|
|
272
|
+
}).trim();
|
|
273
|
+
const output = (0, import_child_process.execFileSync)(
|
|
274
|
+
"git",
|
|
275
|
+
["diff", "--name-only", "--diff-filter=d", `${mergeBase}...HEAD`],
|
|
276
|
+
{ cwd: repositoryRoot, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
277
|
+
).trim();
|
|
278
|
+
return output ? output.split("\n").filter(Boolean).sort() : [];
|
|
279
|
+
} catch {
|
|
280
|
+
throw new Error(
|
|
281
|
+
`Cannot determine PR files: gh CLI unavailable and git merge-base with "${baseBranch}" failed. Use --diff <base> instead.`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function detectDefaultBranch(repositoryRoot) {
|
|
286
|
+
try {
|
|
287
|
+
const ref = (0, import_child_process.execSync)("git rev-parse --abbrev-ref origin/HEAD", {
|
|
288
|
+
cwd: repositoryRoot,
|
|
289
|
+
encoding: "utf-8",
|
|
290
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
291
|
+
}).trim();
|
|
292
|
+
if (ref && ref !== "origin/HEAD") {
|
|
293
|
+
return ref;
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
}
|
|
297
|
+
for (const branch of ["origin/main", "origin/master"]) {
|
|
298
|
+
try {
|
|
299
|
+
(0, import_child_process.execFileSync)("git", ["rev-parse", "--verify", branch], {
|
|
300
|
+
cwd: repositoryRoot,
|
|
301
|
+
encoding: "utf-8",
|
|
302
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
303
|
+
});
|
|
304
|
+
return branch;
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
throw new Error(
|
|
309
|
+
"Cannot auto-detect default branch: no origin/HEAD, origin/main, or origin/master found. Specify a base explicitly with --diff <base>."
|
|
310
|
+
);
|
|
311
|
+
}
|
|
210
312
|
function filterByTargetFiles(allFiles, targetPatterns) {
|
|
211
313
|
if (targetPatterns.length === 0) return allFiles;
|
|
212
314
|
const normalized = targetPatterns.map((p) => p.replace(/^\.\//, ""));
|
|
@@ -551,6 +653,20 @@ async function analyze(options) {
|
|
|
551
653
|
const globalExclude = codacyConfig?.exclude || [];
|
|
552
654
|
let allFiles = listRepoFiles(options.repositoryRoot);
|
|
553
655
|
logger.debug("File discovery", { totalFiles: allFiles.length });
|
|
656
|
+
if (options.gitScope) {
|
|
657
|
+
const scopeFiles = resolveGitScope(options.repositoryRoot, options.gitScope);
|
|
658
|
+
logger.debug("Git scope resolved", {
|
|
659
|
+
scope: typeof options.gitScope === "string" ? options.gitScope : "diff",
|
|
660
|
+
fileCount: scopeFiles.length
|
|
661
|
+
});
|
|
662
|
+
if (scopeFiles.length === 0) {
|
|
663
|
+
logger.info("Git scope resolved to zero files, skipping analysis");
|
|
664
|
+
return buildResult(startedAt, options.repositoryRoot, mode, capability, [], [], []);
|
|
665
|
+
}
|
|
666
|
+
const scopeSet = new Set(scopeFiles);
|
|
667
|
+
allFiles = allFiles.filter((f) => scopeSet.has(f));
|
|
668
|
+
logger.debug("After git scope intersection", { fileCount: allFiles.length });
|
|
669
|
+
}
|
|
554
670
|
if (options.files && options.files.length > 0) {
|
|
555
671
|
allFiles = filterByTargetFiles(allFiles, options.files);
|
|
556
672
|
logger.debug("Filtered by target files", { afterFilter: allFiles.length });
|
|
@@ -641,6 +757,12 @@ function normalizeIssues(issues) {
|
|
|
641
757
|
return issue;
|
|
642
758
|
});
|
|
643
759
|
}
|
|
760
|
+
function resolveGitScope(repositoryRoot, scope) {
|
|
761
|
+
if (scope === "staged") return listStagedFiles(repositoryRoot);
|
|
762
|
+
if (scope === "pr") return listPrFiles(repositoryRoot);
|
|
763
|
+
const base = scope.diff === true ? void 0 : scope.diff;
|
|
764
|
+
return listDiffFiles(repositoryRoot, base);
|
|
765
|
+
}
|
|
644
766
|
function buildResult(startedAt, repositoryRoot, mode, capability, issues, errors, toolResults) {
|
|
645
767
|
const completedAt = /* @__PURE__ */ new Date();
|
|
646
768
|
return {
|
|
@@ -4853,9 +4975,19 @@ async function initContainerConfig(repositoryRoot, adapters2) {
|
|
|
4853
4975
|
for (const p of entry["patterns"]) {
|
|
4854
4976
|
if (typeof p === "object" && p !== null && typeof p["patternId"] === "string") {
|
|
4855
4977
|
const pe = p;
|
|
4978
|
+
const rawParams = pe["parameters"];
|
|
4979
|
+
let params;
|
|
4980
|
+
if (rawParams && typeof rawParams === "object" && !Array.isArray(rawParams)) {
|
|
4981
|
+
params = Object.fromEntries(
|
|
4982
|
+
Object.entries(rawParams).map(([k, v]) => [
|
|
4983
|
+
k,
|
|
4984
|
+
String(v)
|
|
4985
|
+
])
|
|
4986
|
+
);
|
|
4987
|
+
}
|
|
4856
4988
|
patterns.push({
|
|
4857
4989
|
patternId: pe["patternId"],
|
|
4858
|
-
...
|
|
4990
|
+
...params ? { parameters: params } : {}
|
|
4859
4991
|
});
|
|
4860
4992
|
}
|
|
4861
4993
|
}
|
|
@@ -4988,6 +5120,9 @@ function createLogger(options = {}) {
|
|
|
4988
5120
|
initDefaultConfig,
|
|
4989
5121
|
initLocalConfig,
|
|
4990
5122
|
initRemoteConfig,
|
|
5123
|
+
listDiffFiles,
|
|
5124
|
+
listPrFiles,
|
|
5125
|
+
listStagedFiles,
|
|
4991
5126
|
readCodacyConfig,
|
|
4992
5127
|
readCodacyYaml,
|
|
4993
5128
|
registerAdapter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codacy/analysis-runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Core orchestration engine for Codacy analysis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"cli-table3": "^0.6",
|
|
13
13
|
"minimatch": "10.2.4",
|
|
14
14
|
"yaml": "^2.6.0",
|
|
15
|
-
"@codacy/tooling": "0.
|
|
15
|
+
"@codacy/tooling": "0.2.1"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@codacy/openapi-typescript-codegen": "0.0.9",
|
|
19
|
-
"@codacy/tools-dummy-1": "0.
|
|
19
|
+
"@codacy/tools-dummy-1": "0.2.1"
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "Codacy <support@codacy.com> (https://www.codacy.com)",
|