feat(qa): sonar triage --no-webhook (file issues now, deliver them with --drain)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mARTin-B78 2026-10-06 11:58:53 +02:00
parent 69c33526f4
commit bab9b50643

View File

@ -147,7 +147,7 @@ export function postWebhook(url, payload) {
return { ok: code >= 200 && code < 300, code }; return { ok: code >= 200 && code < 300, code };
} }
function ghIssues(groups, apply, cap, log, lane = 'fix') { function ghIssues(groups, apply, cap, log, lane = 'fix', noHook = false) {
const agentLabel = lane === 'refactor' ? 'agent-refactor' : 'agent-fix'; const agentLabel = lane === 'refactor' ? 'agent-refactor' : 'agent-fix';
if (run('gh', ['auth', 'status']).status !== 0) { log('gh unauthenticated: skipping GitHub issues (run `gh auth login`).'); return []; } if (run('gh', ['auth', 'status']).status !== 0) { log('gh unauthenticated: skipping GitHub issues (run `gh auth login`).'); return []; }
const list = run('gh', ['issue', 'list', '--state', 'open', '--label', 'sonar', '--limit', '300', '--json', 'number,body']); const list = run('gh', ['issue', 'list', '--state', 'open', '--label', 'sonar', '--limit', '300', '--json', 'number,body']);
@ -167,7 +167,8 @@ function ghIssues(groups, apply, cap, log, lane = 'fix') {
// Mechanism 1: a multica autopilot webhook (URL is a secret: env MULTICA_WEBHOOK_URL or ~/.config/multica-webhook). // Mechanism 1: a multica autopilot webhook (URL is a secret: env MULTICA_WEBHOOK_URL or ~/.config/multica-webhook).
// Mechanism 2 (fallback): the multica CLI, which refuses to run in an agent context. // Mechanism 2 (fallback): the multica CLI, which refuses to run in an agent context.
const hook = webhookUrl(process.env, undefined, lane); const hook = webhookUrl(process.env, undefined, lane);
if (hook) { if (noHook) { log(' webhook skipped (--no-webhook): use --drain to deliver it'); }
else if (hook) {
const w = postWebhook(hook, { source: 'sonar-triage', rule: g.rule, title: g.title, github_issue_url: url, files: g.files, sonar_keys: g.keys, effort_min: g.effort, body: issueBody(g) }); const w = postWebhook(hook, { source: 'sonar-triage', rule: g.rule, title: g.title, github_issue_url: url, files: g.files, sonar_keys: g.keys, effort_min: g.effort, body: issueBody(g) });
log(w.ok ? ` multica autopilot fired (HTTP ${w.code})` : ` multica webhook failed (HTTP ${w.code || 'none'}): assign the issue manually`); log(w.ok ? ` multica autopilot fired (HTTP ${w.code})` : ` multica webhook failed (HTTP ${w.code || 'none'}): assign the issue manually`);
} else { } else {
@ -243,6 +244,7 @@ export async function main(argv, deps = {}) {
else if (f === '--cap') { a.cap = +argv[++i]; a.capSet = true; } else if (f === '--cap') { a.cap = +argv[++i]; a.capSet = true; }
else if (f === '--lane') { a.lane = argv[++i]; if (!['fix', 'refactor'].includes(a.lane)) throw new Error('--lane must be fix or refactor'); } else if (f === '--lane') { a.lane = argv[++i]; if (!['fix', 'refactor'].includes(a.lane)) throw new Error('--lane must be fix or refactor'); }
else if (f === '--drain') a.drain = true; else if (f === '--drain') a.drain = true;
else if (f === '--no-webhook') a.noHook = true;
else if (f === '--timeout') a.timeout = +argv[++i]; else if (f === '--timeout') a.timeout = +argv[++i];
else if (f === '--resends') a.resends = +argv[++i]; else if (f === '--resends') a.resends = +argv[++i];
else if (f === '--exclude-rules') a.exclude = (argv[++i] || '').split(',').filter(Boolean); else if (f === '--exclude-rules') a.exclude = (argv[++i] || '').split(',').filter(Boolean);
@ -274,7 +276,7 @@ export async function main(argv, deps = {}) {
: groupIssues(all)).filter((g) => !(a.exclude || []).includes(g.rule)); : groupIssues(all)).filter((g) => !(a.exclude || []).includes(g.rule));
const cap = lane === 'refactor' && !a.capSet ? 3 : a.cap; const cap = lane === 'refactor' && !a.capSet ? 3 : a.cap;
log(`\n${lane === 'refactor' ? 'Refactor' : 'Medium+'} groups (${lane === 'refactor' ? 'one per function' : 'per rule, max 40 locations'}): ${groups.length}`); log(`\n${lane === 'refactor' ? 'Refactor' : 'Medium+'} groups (${lane === 'refactor' ? 'one per function' : 'per rule, max 40 locations'}): ${groups.length}`);
ghIssues(groups, a.apply, cap, log, lane); ghIssues(groups, a.apply, cap, log, lane, !!a.noHook);
if (a.fixSmall) { if (a.apply) fixSmall(res.small, log); else log('fix-small needs --apply (dry-run).'); } if (a.fixSmall) { if (a.apply) fixSmall(res.small, log); else log('fix-small needs --apply (dry-run).'); }
return res; return res;
} }