codeant-cli 0.4.7 → 0.4.8
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/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import { runHistory } from './history.js';
|
|
|
4
4
|
import { runGet } from './get.js';
|
|
5
5
|
import { runResults } from './results.js';
|
|
6
6
|
import { runDismissed } from './dismissed.js';
|
|
7
|
+
import { runStartScan } from './start-scan.js';
|
|
7
8
|
import { setQuiet, setNoColor } from './lib/log.js';
|
|
8
9
|
import { setNoColor as tableSetNoColor } from './formatters/table.js';
|
|
9
10
|
|
|
@@ -118,4 +119,28 @@ export default function registerScansCommands(program, { runCmd }) {
|
|
|
118
119
|
.action((opts) =>
|
|
119
120
|
runCmd(() => runDismissed({ repo: opts.repo, analysisType: opts.analysisType }))
|
|
120
121
|
);
|
|
122
|
+
|
|
123
|
+
// ── start-scan ─────────────────────────────────────────────────────────────
|
|
124
|
+
scans
|
|
125
|
+
.command('start-scan')
|
|
126
|
+
.description('Trigger a new analysis run for a repository')
|
|
127
|
+
.option('--repo <repo>', 'Repository (owner/repo, auto-detected from git remote)')
|
|
128
|
+
.option('--branch <name>', 'Branch to scan (auto-detected from current checkout)')
|
|
129
|
+
.option('--commit <sha>', 'Commit SHA to scan (resolved from remote if omitted)')
|
|
130
|
+
.option('--include <paths>', 'Comma-separated file path glob patterns to include')
|
|
131
|
+
.option('--exclude <paths>', 'Comma-separated file path glob patterns to exclude')
|
|
132
|
+
.action(async (opts) => {
|
|
133
|
+
try {
|
|
134
|
+
await runStartScan({
|
|
135
|
+
repo: opts.repo,
|
|
136
|
+
branch: opts.branch,
|
|
137
|
+
commit: opts.commit,
|
|
138
|
+
include: opts.include,
|
|
139
|
+
exclude: opts.exclude,
|
|
140
|
+
});
|
|
141
|
+
} catch (err) {
|
|
142
|
+
process.stderr.write(JSON.stringify({ error: err.message }) + '\n');
|
|
143
|
+
process.exit(err.exitCode ?? 1);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
121
146
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { exec, execFile } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { detectRepoName } from '../../scm/index.js';
|
|
4
|
+
import { startScan } from '../../scans/startScan.js';
|
|
5
|
+
|
|
6
|
+
const execAsync = promisify(exec);
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
|
|
9
|
+
// Mirrors splitGlobs in src/index.js (not exported) — preserves commas inside {} brace expansions
|
|
10
|
+
function splitGlobs(input) {
|
|
11
|
+
const parts = [];
|
|
12
|
+
let current = '';
|
|
13
|
+
let depth = 0;
|
|
14
|
+
for (const ch of String(input)) {
|
|
15
|
+
if (ch === '{') depth++;
|
|
16
|
+
else if (ch === '}') depth--;
|
|
17
|
+
if (ch === ',' && depth === 0) {
|
|
18
|
+
parts.push(current.trim());
|
|
19
|
+
current = '';
|
|
20
|
+
} else {
|
|
21
|
+
current += ch;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (current.trim()) parts.push(current.trim());
|
|
25
|
+
return parts.filter(Boolean);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function resolveCurrentBranch() {
|
|
29
|
+
try {
|
|
30
|
+
const { stdout } = await execAsync('git rev-parse --abbrev-ref HEAD');
|
|
31
|
+
return stdout.trim();
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function resolveRemoteCommit(branch) {
|
|
38
|
+
try {
|
|
39
|
+
const { stdout } = await execFileAsync('git', ['ls-remote', 'origin', `refs/heads/${branch}`]);
|
|
40
|
+
const sha = stdout.trim().split(/\s+/)[0];
|
|
41
|
+
if (!sha) {
|
|
42
|
+
const err = new Error(`Branch "${branch}" not found on remote origin. Pass --commit <sha> explicitly.`);
|
|
43
|
+
err.exitCode = 1;
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
return sha;
|
|
47
|
+
} catch (err) {
|
|
48
|
+
if (err.exitCode) throw err;
|
|
49
|
+
const wrapped = new Error(`Could not resolve commit for branch "${branch}": ${err.message}. Pass --commit <sha> explicitly.`);
|
|
50
|
+
wrapped.exitCode = 1;
|
|
51
|
+
throw wrapped;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function runStartScan({ repo, branch, commit, include, exclude } = {}) {
|
|
56
|
+
const resolvedRepo = repo || detectRepoName();
|
|
57
|
+
if (!resolvedRepo) {
|
|
58
|
+
const err = new Error('Could not detect repo name. Use --repo owner/repo');
|
|
59
|
+
err.exitCode = 1;
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const resolvedBranch = branch || await resolveCurrentBranch();
|
|
64
|
+
if (!resolvedBranch) {
|
|
65
|
+
const err = new Error('Could not detect current branch. Use --branch <name>');
|
|
66
|
+
err.exitCode = 1;
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const commitId = commit || await resolveRemoteCommit(resolvedBranch);
|
|
71
|
+
|
|
72
|
+
const includeFiles = include ? splitGlobs(include) : [];
|
|
73
|
+
const excludeFiles = exclude ? splitGlobs(exclude) : [];
|
|
74
|
+
|
|
75
|
+
const result = await startScan({
|
|
76
|
+
repo: resolvedRepo,
|
|
77
|
+
branch: resolvedBranch,
|
|
78
|
+
commitId,
|
|
79
|
+
includeFiles: includeFiles.length ? includeFiles : undefined,
|
|
80
|
+
excludeFiles: excludeFiles.length ? excludeFiles : undefined,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (!result.success) {
|
|
84
|
+
const err = new Error(result.error || 'Failed to start scan');
|
|
85
|
+
err.exitCode = 1;
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log(result.message || 'Analysis started');
|
|
90
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { fetchApi } from '../utils/fetchApi.js';
|
|
2
|
+
|
|
3
|
+
export async function startScan({ repo, branch, commitId, includeFiles, excludeFiles }) {
|
|
4
|
+
try {
|
|
5
|
+
const body = { repo, branch, commit_id: commitId };
|
|
6
|
+
if (includeFiles && includeFiles.length > 0) body.include_files = includeFiles;
|
|
7
|
+
if (excludeFiles && excludeFiles.length > 0) body.exclude_files = excludeFiles;
|
|
8
|
+
|
|
9
|
+
const response = await fetchApi('/extension/analysis/run', 'POST', body);
|
|
10
|
+
|
|
11
|
+
if (!response) {
|
|
12
|
+
return { success: false, error: 'Failed to connect to CodeAnt server' };
|
|
13
|
+
}
|
|
14
|
+
if (response.status === 'error') {
|
|
15
|
+
return { success: false, error: response.message || 'Failed to start scan' };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return { success: true, ...response };
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return { success: false, error: error.message || 'Failed to start scan' };
|
|
21
|
+
}
|
|
22
|
+
}
|