@yasserkhanorg/e2e-agents 0.3.3 → 0.3.4
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/README.md +7 -2
- package/dist/agent/config.d.ts +2 -0
- package/dist/agent/config.d.ts.map +1 -1
- package/dist/agent/config.js +28 -0
- package/dist/agent/operational_insights.d.ts +1 -1
- package/dist/agent/operational_insights.d.ts.map +1 -1
- package/dist/agent/operational_insights.js +2 -1
- package/dist/agent/pipeline.d.ts +2 -0
- package/dist/agent/pipeline.d.ts.map +1 -1
- package/dist/agent/pipeline.js +240 -29
- package/dist/agent/plan.d.ts +39 -0
- package/dist/agent/plan.d.ts.map +1 -1
- package/dist/agent/plan.js +146 -0
- package/dist/agent/report.d.ts +11 -0
- package/dist/agent/report.d.ts.map +1 -1
- package/dist/agent/report.js +9 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +41 -5
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +1 -0
- package/dist/cli.js +38 -2
- package/dist/esm/agent/config.js +28 -0
- package/dist/esm/agent/operational_insights.js +2 -1
- package/dist/esm/agent/pipeline.js +240 -29
- package/dist/esm/agent/plan.js +145 -1
- package/dist/esm/agent/report.js +9 -0
- package/dist/esm/agent/runner.js +41 -5
- package/dist/esm/api.js +2 -1
- package/dist/esm/cli.js +39 -3
- package/package.json +1 -1
- package/schemas/impact.schema.json +37 -0
- package/schemas/plan.schema.json +48 -0
package/dist/agent/plan.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface DecisionSummary {
|
|
|
14
14
|
}
|
|
15
15
|
export interface PlanReport {
|
|
16
16
|
schemaVersion: '1.0.0';
|
|
17
|
+
runId: string;
|
|
18
|
+
sourceRunId?: string;
|
|
17
19
|
generatedAt: string;
|
|
18
20
|
source: 'impact';
|
|
19
21
|
runSet: RecommendedRunSet;
|
|
@@ -23,6 +25,13 @@ export interface PlanReport {
|
|
|
23
25
|
requiredNewTests: string[];
|
|
24
26
|
policy: PolicyEvaluation;
|
|
25
27
|
decision: DecisionSummary;
|
|
28
|
+
enforcement: {
|
|
29
|
+
mode: PolicyConfig['enforcementMode'];
|
|
30
|
+
blockOnActions: CiAction[];
|
|
31
|
+
matchedAction: boolean;
|
|
32
|
+
shouldFail: boolean;
|
|
33
|
+
summary: string;
|
|
34
|
+
};
|
|
26
35
|
insights?: {
|
|
27
36
|
flaky?: {
|
|
28
37
|
highRiskRecommendedTests: Array<{
|
|
@@ -79,6 +88,7 @@ export interface PlanReport {
|
|
|
79
88
|
warnings: number;
|
|
80
89
|
};
|
|
81
90
|
}
|
|
91
|
+
export declare function refreshPlanEnforcement(plan: PlanReport): PlanReport;
|
|
82
92
|
export declare function buildPlanFromImpactReport(impact: ReportData, policyOverride?: Partial<PolicyConfig>): PlanReport;
|
|
83
93
|
export declare function attachDeveloperActions(plan: PlanReport, context: {
|
|
84
94
|
appPath: string;
|
|
@@ -87,5 +97,34 @@ export declare function attachDeveloperActions(plan: PlanReport, context: {
|
|
|
87
97
|
}): PlanReport;
|
|
88
98
|
export declare function writePlanReport(appRoot: string, plan: PlanReport): string;
|
|
89
99
|
export declare function renderCiSummaryMarkdown(plan: PlanReport): string;
|
|
100
|
+
export interface PlanMetricEvent {
|
|
101
|
+
schemaVersion: '1.0.0';
|
|
102
|
+
timestamp: string;
|
|
103
|
+
runId: string;
|
|
104
|
+
sourceRunId?: string;
|
|
105
|
+
action: CiAction;
|
|
106
|
+
runSet: RecommendedRunSet;
|
|
107
|
+
confidence: number;
|
|
108
|
+
changedFiles: number;
|
|
109
|
+
impactedFlows: number;
|
|
110
|
+
uncoveredP0P1Flows: number;
|
|
111
|
+
warnings: number;
|
|
112
|
+
enforcementMode: PolicyConfig['enforcementMode'];
|
|
113
|
+
enforcementShouldFail: boolean;
|
|
114
|
+
}
|
|
115
|
+
export interface PlanMetricsSummary {
|
|
116
|
+
schemaVersion: '1.0.0';
|
|
117
|
+
generatedAt: string;
|
|
118
|
+
totalRuns: number;
|
|
119
|
+
averageConfidence: number;
|
|
120
|
+
byAction: Record<CiAction, number>;
|
|
121
|
+
byRunSet: Record<RecommendedRunSet, number>;
|
|
122
|
+
blockingRecommendations: number;
|
|
123
|
+
blockingRate: number;
|
|
124
|
+
}
|
|
125
|
+
export declare function appendPlanMetrics(appRoot: string, plan: PlanReport): {
|
|
126
|
+
eventsPath: string;
|
|
127
|
+
summaryPath: string;
|
|
128
|
+
};
|
|
90
129
|
export declare function writeCiSummary(appRoot: string, markdown: string, relativePath?: string): string;
|
|
91
130
|
//# sourceMappingURL=plan.d.ts.map
|
package/dist/agent/plan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/agent/plan.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/agent/plan.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/plan.js
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
3
|
// See LICENSE.txt for license information.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.refreshPlanEnforcement = refreshPlanEnforcement;
|
|
5
6
|
exports.buildPlanFromImpactReport = buildPlanFromImpactReport;
|
|
6
7
|
exports.attachDeveloperActions = attachDeveloperActions;
|
|
7
8
|
exports.writePlanReport = writePlanReport;
|
|
8
9
|
exports.renderCiSummaryMarkdown = renderCiSummaryMarkdown;
|
|
10
|
+
exports.appendPlanMetrics = appendPlanMetrics;
|
|
9
11
|
exports.writeCiSummary = writeCiSummary;
|
|
10
12
|
const fs_1 = require("fs");
|
|
11
13
|
const path_1 = require("path");
|
|
@@ -27,6 +29,8 @@ const DEFAULT_POLICY = {
|
|
|
27
29
|
'**/*.sql',
|
|
28
30
|
'**/webhook/**',
|
|
29
31
|
],
|
|
32
|
+
enforcementMode: 'advisory',
|
|
33
|
+
blockOnActions: ['must-add-tests'],
|
|
30
34
|
};
|
|
31
35
|
function countPriority(flows) {
|
|
32
36
|
const counts = { p0: 0, p1: 0, p2: 0 };
|
|
@@ -172,6 +176,61 @@ function buildDecision(runSet, confidence, impact, policy) {
|
|
|
172
176
|
summary: `Execute the ${runSet} suite for this change set.`,
|
|
173
177
|
};
|
|
174
178
|
}
|
|
179
|
+
function evaluateEnforcement(decision, policy) {
|
|
180
|
+
const blockOnActions = (policy.blockOnActions && policy.blockOnActions.length > 0)
|
|
181
|
+
? [...policy.blockOnActions]
|
|
182
|
+
: ['must-add-tests'];
|
|
183
|
+
const matchedAction = blockOnActions.includes(decision.action);
|
|
184
|
+
if (policy.enforcementMode === 'block' && matchedAction) {
|
|
185
|
+
return {
|
|
186
|
+
mode: policy.enforcementMode,
|
|
187
|
+
blockOnActions,
|
|
188
|
+
matchedAction,
|
|
189
|
+
shouldFail: true,
|
|
190
|
+
summary: `Blocking mode active: decision "${decision.action}" is configured to fail CI.`,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (policy.enforcementMode === 'warn' && matchedAction) {
|
|
194
|
+
return {
|
|
195
|
+
mode: policy.enforcementMode,
|
|
196
|
+
blockOnActions,
|
|
197
|
+
matchedAction,
|
|
198
|
+
shouldFail: false,
|
|
199
|
+
summary: `Warning mode active: decision "${decision.action}" is advisory-only for CI.`,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (policy.enforcementMode === 'block') {
|
|
203
|
+
return {
|
|
204
|
+
mode: policy.enforcementMode,
|
|
205
|
+
blockOnActions,
|
|
206
|
+
matchedAction,
|
|
207
|
+
shouldFail: false,
|
|
208
|
+
summary: `Blocking mode active, but decision "${decision.action}" is not configured for CI failure.`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (policy.enforcementMode === 'warn') {
|
|
212
|
+
return {
|
|
213
|
+
mode: policy.enforcementMode,
|
|
214
|
+
blockOnActions,
|
|
215
|
+
matchedAction,
|
|
216
|
+
shouldFail: false,
|
|
217
|
+
summary: `Warning mode active, but decision "${decision.action}" is not configured for warning.`,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
mode: policy.enforcementMode,
|
|
222
|
+
blockOnActions,
|
|
223
|
+
matchedAction,
|
|
224
|
+
shouldFail: false,
|
|
225
|
+
summary: 'Advisory mode active: recommendations do not fail CI by default.',
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function refreshPlanEnforcement(plan) {
|
|
229
|
+
return {
|
|
230
|
+
...plan,
|
|
231
|
+
enforcement: evaluateEnforcement(plan.decision, plan.policy.applied),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
175
234
|
function buildPlanFromImpactReport(impact, policyOverride) {
|
|
176
235
|
if (impact.mode !== 'impact') {
|
|
177
236
|
throw new Error(`Plan generation requires impact report data, received mode=${impact.mode}`);
|
|
@@ -181,9 +240,14 @@ function buildPlanFromImpactReport(impact, policyOverride) {
|
|
|
181
240
|
const confidence = computeConfidence(impact, p0, p1);
|
|
182
241
|
const runSet = pickRunSet(impact, p0, confidence, policy);
|
|
183
242
|
const decision = buildDecision(runSet.runSet, confidence, impact, policy);
|
|
243
|
+
const enforcement = evaluateEnforcement(decision, policy);
|
|
184
244
|
const requiredNewTests = impact.gaps.map((flow) => `${flow.id}: ${flow.name}`);
|
|
245
|
+
const sourceRunId = impact.runMetadata?.runId;
|
|
246
|
+
const runId = `plan-${sourceRunId || Date.now().toString(36)}`;
|
|
185
247
|
return {
|
|
186
248
|
schemaVersion: '1.0.0',
|
|
249
|
+
runId,
|
|
250
|
+
sourceRunId,
|
|
187
251
|
generatedAt: new Date().toISOString(),
|
|
188
252
|
source: 'impact',
|
|
189
253
|
runSet: runSet.runSet,
|
|
@@ -197,6 +261,7 @@ function buildPlanFromImpactReport(impact, policyOverride) {
|
|
|
197
261
|
applied: policy,
|
|
198
262
|
},
|
|
199
263
|
decision,
|
|
264
|
+
enforcement,
|
|
200
265
|
metrics: {
|
|
201
266
|
changedFiles: impact.changedFiles.length,
|
|
202
267
|
impactedFlows: impact.flows.length,
|
|
@@ -243,6 +308,8 @@ function renderCiSummaryMarkdown(plan) {
|
|
|
243
308
|
lines.push(`- Run set: \`${plan.runSet}\``);
|
|
244
309
|
lines.push(`- Confidence: \`${plan.confidence}\``);
|
|
245
310
|
lines.push(`- Summary: ${plan.decision.summary}`);
|
|
311
|
+
lines.push(`- Enforcement: mode=\`${plan.enforcement.mode}\`, shouldFail=\`${plan.enforcement.shouldFail}\``);
|
|
312
|
+
lines.push(`- Enforcement detail: ${plan.enforcement.summary}`);
|
|
246
313
|
if (plan.policy.triggeredRules.length > 0) {
|
|
247
314
|
lines.push(`- Policy triggers: ${plan.policy.triggeredRules.join(', ')}`);
|
|
248
315
|
}
|
|
@@ -322,6 +389,85 @@ function renderCiSummaryMarkdown(plan) {
|
|
|
322
389
|
}
|
|
323
390
|
return lines.join('\n');
|
|
324
391
|
}
|
|
392
|
+
const PLAN_METRICS_EVENTS_PATH = '.e2e-ai-agents/metrics.jsonl';
|
|
393
|
+
const PLAN_METRICS_SUMMARY_PATH = '.e2e-ai-agents/metrics-summary.json';
|
|
394
|
+
function parsePlanMetricLine(line) {
|
|
395
|
+
const trimmed = line.trim();
|
|
396
|
+
if (!trimmed) {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
try {
|
|
400
|
+
const parsed = JSON.parse(trimmed);
|
|
401
|
+
if (!parsed || parsed.schemaVersion !== '1.0.0' || typeof parsed.runId !== 'string') {
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
return parsed;
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function appendPlanMetrics(appRoot, plan) {
|
|
411
|
+
const baseDir = (0, path_1.join)(appRoot, '.e2e-ai-agents');
|
|
412
|
+
(0, fs_1.mkdirSync)(baseDir, { recursive: true });
|
|
413
|
+
const eventsPath = (0, path_1.join)(appRoot, PLAN_METRICS_EVENTS_PATH);
|
|
414
|
+
const summaryPath = (0, path_1.join)(appRoot, PLAN_METRICS_SUMMARY_PATH);
|
|
415
|
+
const event = {
|
|
416
|
+
schemaVersion: '1.0.0',
|
|
417
|
+
timestamp: new Date().toISOString(),
|
|
418
|
+
runId: plan.runId,
|
|
419
|
+
sourceRunId: plan.sourceRunId,
|
|
420
|
+
action: plan.decision.action,
|
|
421
|
+
runSet: plan.runSet,
|
|
422
|
+
confidence: plan.confidence,
|
|
423
|
+
changedFiles: plan.metrics.changedFiles,
|
|
424
|
+
impactedFlows: plan.metrics.impactedFlows,
|
|
425
|
+
uncoveredP0P1Flows: plan.metrics.uncoveredP0P1Flows,
|
|
426
|
+
warnings: plan.metrics.warnings,
|
|
427
|
+
enforcementMode: plan.enforcement.mode,
|
|
428
|
+
enforcementShouldFail: plan.enforcement.shouldFail,
|
|
429
|
+
};
|
|
430
|
+
(0, fs_1.appendFileSync)(eventsPath, `${JSON.stringify(event)}\n`, 'utf-8');
|
|
431
|
+
const allEvents = (0, fs_1.existsSync)(eventsPath)
|
|
432
|
+
? (0, fs_1.readFileSync)(eventsPath, 'utf-8')
|
|
433
|
+
.split('\n')
|
|
434
|
+
.map(parsePlanMetricLine)
|
|
435
|
+
.filter((item) => Boolean(item))
|
|
436
|
+
: [event];
|
|
437
|
+
const byAction = {
|
|
438
|
+
'run-now': 0,
|
|
439
|
+
'must-add-tests': 0,
|
|
440
|
+
'safe-to-merge': 0,
|
|
441
|
+
};
|
|
442
|
+
const byRunSet = {
|
|
443
|
+
smoke: 0,
|
|
444
|
+
targeted: 0,
|
|
445
|
+
full: 0,
|
|
446
|
+
};
|
|
447
|
+
let totalConfidence = 0;
|
|
448
|
+
let blockingRecommendations = 0;
|
|
449
|
+
for (const metricEvent of allEvents) {
|
|
450
|
+
byAction[metricEvent.action] += 1;
|
|
451
|
+
byRunSet[metricEvent.runSet] += 1;
|
|
452
|
+
totalConfidence += metricEvent.confidence;
|
|
453
|
+
if (metricEvent.enforcementShouldFail) {
|
|
454
|
+
blockingRecommendations += 1;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const totalRuns = allEvents.length;
|
|
458
|
+
const summary = {
|
|
459
|
+
schemaVersion: '1.0.0',
|
|
460
|
+
generatedAt: new Date().toISOString(),
|
|
461
|
+
totalRuns,
|
|
462
|
+
averageConfidence: totalRuns > 0 ? Number((totalConfidence / totalRuns).toFixed(2)) : 0,
|
|
463
|
+
byAction,
|
|
464
|
+
byRunSet,
|
|
465
|
+
blockingRecommendations,
|
|
466
|
+
blockingRate: totalRuns > 0 ? Number((blockingRecommendations / totalRuns).toFixed(4)) : 0,
|
|
467
|
+
};
|
|
468
|
+
(0, fs_1.writeFileSync)(summaryPath, JSON.stringify(summary, null, 2), 'utf-8');
|
|
469
|
+
return { eventsPath, summaryPath };
|
|
470
|
+
}
|
|
325
471
|
function writeCiSummary(appRoot, markdown, relativePath = '.e2e-ai-agents/ci-summary.md') {
|
|
326
472
|
const fullPath = (0, path_1.join)(appRoot, relativePath);
|
|
327
473
|
const dir = (0, path_1.dirname)(fullPath);
|
package/dist/agent/report.d.ts
CHANGED
|
@@ -5,6 +5,15 @@ import type { DataTestIdSuggestion } from './selectors.js';
|
|
|
5
5
|
import type { GapTestSuggestion } from './gap_suggestions.js';
|
|
6
6
|
export interface ReportData {
|
|
7
7
|
mode: 'impact' | 'gap';
|
|
8
|
+
runMetadata?: {
|
|
9
|
+
runId: string;
|
|
10
|
+
startedAt: string;
|
|
11
|
+
completedAt: string;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
sinceRef: string;
|
|
14
|
+
appPath: string;
|
|
15
|
+
testsRoot: string;
|
|
16
|
+
};
|
|
8
17
|
changedFiles: string[];
|
|
9
18
|
flows: FlowImpact[];
|
|
10
19
|
coverage: FlowCoverage[];
|
|
@@ -65,6 +74,8 @@ export interface ReportData {
|
|
|
65
74
|
generateStatus: string;
|
|
66
75
|
healStatus?: string;
|
|
67
76
|
error?: string;
|
|
77
|
+
failureCategory?: string;
|
|
78
|
+
failureCode?: string;
|
|
68
79
|
}>;
|
|
69
80
|
warnings: string[];
|
|
70
81
|
mcp?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/agent/report.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,sBAAsB,CAAC;AAG5D,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,WAAW,EAAE,oBAAoB,EAAE,CAAC;IACpC,eAAe,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAEtC,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE;QACV,aAAa,EAAE,OAAO,CAAC;QACvB,WAAW,EAAE,SAAS,GAAG,WAAW,CAAC;QACrC,WAAW,EAAE,SAAS,GAAG,cAAc,GAAG,WAAW,CAAC;QACtD,eAAe,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;QAC3C,YAAY,CAAC,EAAE;YACX,MAAM,EAAE,UAAU,CAAC;YACnB,OAAO,EAAE,OAAO,CAAC;YACjB,YAAY,EAAE,MAAM,CAAC;YACrB,aAAa,EAAE,OAAO,CAAC;YACvB,aAAa,EAAE,MAAM,CAAC;YACtB,aAAa,EAAE,MAAM,CAAC;YACtB,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,MAAM,CAAC;YACnB,YAAY,EAAE,MAAM,CAAC;YACrB,aAAa,EAAE,MAAM,CAAC;SACzB,CAAC;QACF,eAAe,CAAC,EAAE;YACd,MAAM,EAAE,yBAAyB,CAAC;YAClC,OAAO,EAAE,OAAO,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC;YAClB,aAAa,EAAE,MAAM,CAAC;YACtB,aAAa,EAAE,MAAM,CAAC;YACtB,aAAa,EAAE,MAAM,CAAC;YACtB,QAAQ,EAAE,MAAM,CAAC;YACjB,SAAS,EAAE,OAAO,CAAC;SACtB,CAAC;QACF,aAAa,CAAC,EAAE;YACZ,MAAM,EAAE,KAAK,CAAC;YACd,OAAO,EAAE,OAAO,CAAC;YACjB,OAAO,EAAE,MAAM,CAAC;YAChB,QAAQ,EAAE,OAAO,CAAC;YAClB,WAAW,EAAE,MAAM,CAAC;YACpB,YAAY,EAAE,MAAM,CAAC;YACrB,WAAW,EAAE,MAAM,CAAC;YACpB,YAAY,EAAE,MAAM,CAAC;SACxB,CAAC;KACL,CAAC;IACF,QAAQ,CAAC,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,KAAK,CAAC;YACX,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;YACjB,YAAY,EAAE,MAAM,CAAC;YACrB,cAAc,EAAE,MAAM,CAAC;YACvB,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/agent/report.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/report.js
CHANGED
|
@@ -45,6 +45,12 @@ function writeReport(appRoot, config, data) {
|
|
|
45
45
|
const markdownLines = [];
|
|
46
46
|
markdownLines.push(`# ${data.mode === 'impact' ? 'Impact Analysis' : 'Gap Analysis'} Report`);
|
|
47
47
|
markdownLines.push('');
|
|
48
|
+
if (data.runMetadata) {
|
|
49
|
+
markdownLines.push(`Run ID: ${data.runMetadata.runId}`);
|
|
50
|
+
markdownLines.push(`Run window: ${data.runMetadata.startedAt} -> ${data.runMetadata.completedAt}`);
|
|
51
|
+
markdownLines.push(`Run duration (ms): ${data.runMetadata.durationMs}`);
|
|
52
|
+
markdownLines.push(`Since ref: ${data.runMetadata.sinceRef}`);
|
|
53
|
+
}
|
|
48
54
|
markdownLines.push(`Framework: ${data.framework}`);
|
|
49
55
|
markdownLines.push(`Test Patterns: ${data.testPatterns.join(', ') || 'None'}`);
|
|
50
56
|
if (data.flowCatalog) {
|
|
@@ -103,6 +109,9 @@ function writeReport(appRoot, config, data) {
|
|
|
103
109
|
if (result.error) {
|
|
104
110
|
markdownLines.push(` Error: ${result.error}`);
|
|
105
111
|
}
|
|
112
|
+
if (result.failureCategory || result.failureCode) {
|
|
113
|
+
markdownLines.push(` Failure taxonomy: category=${result.failureCategory || 'unknown'} code=${result.failureCode || 'unknown'}`);
|
|
114
|
+
}
|
|
106
115
|
}
|
|
107
116
|
if (data.pipeline.warnings.length > 0) {
|
|
108
117
|
markdownLines.push('Pipeline warnings:');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAoN7C,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,OAAO,CAAC;CAClB;AAYD,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAyMzF;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAsNtF"}
|
package/dist/agent/runner.js
CHANGED
|
@@ -118,11 +118,14 @@ function buildRecommendedTestsFromCoverage(flows, coverage) {
|
|
|
118
118
|
const flow = flowMap.get(entry.flowId);
|
|
119
119
|
const flagSummary = (0, flags_js_1.formatFlags)(flow?.flags || []);
|
|
120
120
|
for (const test of entry.coveredBy) {
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
const normalizedTest = (0, utils_js_1.normalizePath)(test)
|
|
122
|
+
.replace(/^\.\//, '')
|
|
123
|
+
.replace(/^e2e-tests\/playwright\//, '');
|
|
124
|
+
if (!testNotes.has(normalizedTest)) {
|
|
125
|
+
testNotes.set(normalizedTest, new Set());
|
|
123
126
|
}
|
|
124
127
|
if (flagSummary !== 'none') {
|
|
125
|
-
testNotes.get(
|
|
128
|
+
testNotes.get(normalizedTest)?.add(flagSummary);
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
}
|
|
@@ -194,12 +197,24 @@ function classifyImpactModelConfidence(flowMapping, testMapping, dependencyGraph
|
|
|
194
197
|
}
|
|
195
198
|
return 'low';
|
|
196
199
|
}
|
|
200
|
+
function createRunId(mode) {
|
|
201
|
+
const ciRunId = process.env.GITHUB_RUN_ID;
|
|
202
|
+
const entropy = Math.random().toString(36).slice(2, 8);
|
|
203
|
+
const ts = Date.now().toString(36);
|
|
204
|
+
if (ciRunId) {
|
|
205
|
+
return `${mode}-gh-${ciRunId}-${ts}-${entropy}`;
|
|
206
|
+
}
|
|
207
|
+
return `${mode}-local-${ts}-${entropy}`;
|
|
208
|
+
}
|
|
197
209
|
async function runImpact(_config, _options) {
|
|
198
210
|
ensureAppRoot(_config.path);
|
|
199
211
|
if (_config.testsRoot) {
|
|
200
212
|
ensureAppRoot(_config.testsRoot);
|
|
201
213
|
}
|
|
202
214
|
const deadline = Date.now() + _config.timeLimitMinutes * 60 * 1000;
|
|
215
|
+
const runStartedAt = new Date().toISOString();
|
|
216
|
+
const runStartedTs = Date.now();
|
|
217
|
+
const runId = createRunId('impact');
|
|
203
218
|
const warnings = [];
|
|
204
219
|
const testsRoot = _config.testsRoot || _config.path;
|
|
205
220
|
const frameworkDetection = (0, framework_js_1.detectFramework)(testsRoot, _config.framework);
|
|
@@ -272,7 +287,7 @@ async function runImpact(_config, _options) {
|
|
|
272
287
|
coverageMap.set(entry.flowId, entry.coveredBy);
|
|
273
288
|
}
|
|
274
289
|
gaps = computeGaps(flows, coverageMap);
|
|
275
|
-
recommendedTests =
|
|
290
|
+
recommendedTests = buildRecommendedTestsFromCoverage(flows, coverage);
|
|
276
291
|
}
|
|
277
292
|
else {
|
|
278
293
|
const traceability = (0, traceability_js_1.mapTraceabilityToFlows)(testsRoot, _config.impact.traceability, flows);
|
|
@@ -324,6 +339,15 @@ async function runImpact(_config, _options) {
|
|
|
324
339
|
const reportRoot = testsRoot;
|
|
325
340
|
const report = (0, report_js_1.writeReport)(reportRoot, _config, {
|
|
326
341
|
mode: 'impact',
|
|
342
|
+
runMetadata: {
|
|
343
|
+
runId,
|
|
344
|
+
startedAt: runStartedAt,
|
|
345
|
+
completedAt: new Date().toISOString(),
|
|
346
|
+
durationMs: Date.now() - runStartedTs,
|
|
347
|
+
sinceRef: _config.git.since,
|
|
348
|
+
appPath: _config.path,
|
|
349
|
+
testsRoot,
|
|
350
|
+
},
|
|
327
351
|
changedFiles,
|
|
328
352
|
flows: sortFlows(flows),
|
|
329
353
|
coverage,
|
|
@@ -370,6 +394,9 @@ async function runGap(_config, _options) {
|
|
|
370
394
|
ensureAppRoot(_config.testsRoot);
|
|
371
395
|
}
|
|
372
396
|
const deadline = Date.now() + _config.timeLimitMinutes * 60 * 1000;
|
|
397
|
+
const runStartedAt = new Date().toISOString();
|
|
398
|
+
const runStartedTs = Date.now();
|
|
399
|
+
const runId = createRunId('gap');
|
|
373
400
|
const warnings = [];
|
|
374
401
|
const testsRoot = _config.testsRoot || _config.path;
|
|
375
402
|
const frameworkDetection = (0, framework_js_1.detectFramework)(testsRoot, _config.framework);
|
|
@@ -454,7 +481,7 @@ async function runGap(_config, _options) {
|
|
|
454
481
|
coverageMap.set(entry.flowId, entry.coveredBy);
|
|
455
482
|
}
|
|
456
483
|
gaps = computeGaps(flows, coverageMap);
|
|
457
|
-
recommendedTests =
|
|
484
|
+
recommendedTests = buildRecommendedTestsFromCoverage(flows, coverage);
|
|
458
485
|
}
|
|
459
486
|
else {
|
|
460
487
|
const traceability = (0, traceability_js_1.mapTraceabilityToFlows)(testsRoot, _config.impact.traceability, flows);
|
|
@@ -506,6 +533,15 @@ async function runGap(_config, _options) {
|
|
|
506
533
|
const reportRoot = testsRoot;
|
|
507
534
|
const report = (0, report_js_1.writeReport)(reportRoot, _config, {
|
|
508
535
|
mode: 'gap',
|
|
536
|
+
runMetadata: {
|
|
537
|
+
runId,
|
|
538
|
+
startedAt: runStartedAt,
|
|
539
|
+
completedAt: new Date().toISOString(),
|
|
540
|
+
durationMs: Date.now() - runStartedTs,
|
|
541
|
+
sinceRef: _config.git.since,
|
|
542
|
+
appPath: _config.path,
|
|
543
|
+
testsRoot,
|
|
544
|
+
},
|
|
509
545
|
changedFiles,
|
|
510
546
|
flows: sortFlows(flows),
|
|
511
547
|
coverage,
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAKA,OAAO,EAAgB,KAAK,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAEtE,OAAO,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAKA,OAAO,EAAgB,KAAK,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EAOH,KAAK,UAAU,EAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAElD,OAAO,EAAyB,KAAK,6BAA6B,EAAE,KAAK,4BAA4B,EAAC,MAAM,oBAAoB,CAAC;AACjI,OAAO,EAEH,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAChC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAGH,KAAK,yBAAyB,EACjC,MAAM,iCAAiC,CAAC;AAEzC,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACvD,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,yBAAyB,CAAC;CACvC;AAED,MAAM,WAAW,6BAA6B;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AA0BD,wBAAsB,aAAa,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAOzF;AAED,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAOpF;AAED,wBAAsB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyBjG;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,6BAA6B,GAAG,4BAA4B,CAE1G;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,4BAA4B,GAAG,wBAAwB,CASlG;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,6BAA6B,GAAG,yBAAyB,CAkBrG"}
|
package/dist/api.js
CHANGED
|
@@ -70,6 +70,7 @@ async function recommendTests(options = {}) {
|
|
|
70
70
|
const planPath = (0, plan_js_1.writePlanReport)(reportRoot, plan);
|
|
71
71
|
const ciSummaryMarkdown = (0, plan_js_1.renderCiSummaryMarkdown)(plan);
|
|
72
72
|
const ciSummaryPath = (0, plan_js_1.writeCiSummary)(reportRoot, ciSummaryMarkdown);
|
|
73
|
+
(0, plan_js_1.appendPlanMetrics)(reportRoot, plan);
|
|
73
74
|
return {
|
|
74
75
|
report,
|
|
75
76
|
reportPath: impactPath,
|
package/dist/cli.js
CHANGED
|
@@ -89,6 +89,7 @@ function printUsage() {
|
|
|
89
89
|
' --pipeline-base-url Base URL for Playwright runs',
|
|
90
90
|
' --pipeline-browser Browser: chrome|chromium|firefox|webkit',
|
|
91
91
|
' --pipeline-headless Run in headless mode',
|
|
92
|
+
' --pipeline-headed Run in headed mode',
|
|
92
93
|
' --pipeline-project Playwright project name',
|
|
93
94
|
' --pipeline-parallel Enable parallel mode in generator',
|
|
94
95
|
' --pipeline-dry-run Do not execute pipeline (report only)',
|
|
@@ -103,6 +104,8 @@ function printUsage() {
|
|
|
103
104
|
' --policy-safe-merge-confidence <n> Confidence needed for safe-to-merge',
|
|
104
105
|
' --policy-force-full-on-warnings <n> Escalate to full at warning count',
|
|
105
106
|
' --policy-risky-patterns <globs> Comma-separated risky file globs',
|
|
107
|
+
' --policy-enforcement-mode <mode> advisory | warn | block',
|
|
108
|
+
' --policy-block-actions <actions> Comma-separated CI actions to block/warn',
|
|
106
109
|
' --ci-comment-path <path> Write CI markdown summary',
|
|
107
110
|
' --github-output <path> Write GitHub Actions outputs',
|
|
108
111
|
' --fail-on-must-add-tests Exit non-zero on must-add-tests decision',
|
|
@@ -246,6 +249,10 @@ function parseArgs(argv) {
|
|
|
246
249
|
parsed.pipelineHeadless = true;
|
|
247
250
|
continue;
|
|
248
251
|
}
|
|
252
|
+
if (arg === '--pipeline-headed') {
|
|
253
|
+
parsed.pipelineHeadless = false;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
249
256
|
if (arg === '--pipeline-project' && next) {
|
|
250
257
|
parsed.pipelineProject = next;
|
|
251
258
|
i += 1;
|
|
@@ -322,6 +329,21 @@ function parseArgs(argv) {
|
|
|
322
329
|
i += 1;
|
|
323
330
|
continue;
|
|
324
331
|
}
|
|
332
|
+
if (arg === '--policy-enforcement-mode' && next) {
|
|
333
|
+
if (next === 'advisory' || next === 'warn' || next === 'block') {
|
|
334
|
+
parsed.policyEnforcementMode = next;
|
|
335
|
+
}
|
|
336
|
+
i += 1;
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (arg === '--policy-block-actions' && next) {
|
|
340
|
+
parsed.policyBlockActions = next
|
|
341
|
+
.split(',')
|
|
342
|
+
.map((value) => value.trim())
|
|
343
|
+
.filter((value) => (value === 'run-now' || value === 'must-add-tests' || value === 'safe-to-merge'));
|
|
344
|
+
i += 1;
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
325
347
|
if (arg === '--ci-comment-path' && next) {
|
|
326
348
|
parsed.ciCommentPath = next;
|
|
327
349
|
i += 1;
|
|
@@ -796,12 +818,16 @@ async function main() {
|
|
|
796
818
|
policy: args.policyMinConfidence !== undefined ||
|
|
797
819
|
args.policySafeMergeConfidence !== undefined ||
|
|
798
820
|
args.policyWarningsThreshold !== undefined ||
|
|
799
|
-
(args.policyRiskyPatterns && args.policyRiskyPatterns.length > 0)
|
|
821
|
+
(args.policyRiskyPatterns && args.policyRiskyPatterns.length > 0) ||
|
|
822
|
+
args.policyEnforcementMode !== undefined ||
|
|
823
|
+
(args.policyBlockActions && args.policyBlockActions.length > 0)
|
|
800
824
|
? {
|
|
801
825
|
minConfidenceForTargeted: args.policyMinConfidence,
|
|
802
826
|
safeMergeMinConfidence: args.policySafeMergeConfidence,
|
|
803
827
|
forceFullOnWarningsAtOrAbove: args.policyWarningsThreshold,
|
|
804
828
|
riskyFilePatterns: args.policyRiskyPatterns,
|
|
829
|
+
enforcementMode: args.policyEnforcementMode,
|
|
830
|
+
blockOnActions: args.policyBlockActions,
|
|
805
831
|
}
|
|
806
832
|
: undefined,
|
|
807
833
|
});
|
|
@@ -830,24 +856,33 @@ async function main() {
|
|
|
830
856
|
const planPath = (0, plan_js_1.writePlanReport)(reportRoot, plan);
|
|
831
857
|
const summaryMarkdown = (0, plan_js_1.renderCiSummaryMarkdown)(plan);
|
|
832
858
|
const summaryPath = (0, plan_js_1.writeCiSummary)(reportRoot, summaryMarkdown, args.ciCommentPath);
|
|
859
|
+
const metrics = (0, plan_js_1.appendPlanMetrics)(reportRoot, plan);
|
|
833
860
|
const ghaOutput = args.githubOutputPath || process.env.GITHUB_OUTPUT;
|
|
834
861
|
if (ghaOutput) {
|
|
835
862
|
(0, fs_1.appendFileSync)(ghaOutput, `run_set=${plan.runSet}\n`);
|
|
836
863
|
(0, fs_1.appendFileSync)(ghaOutput, `action=${plan.decision.action}\n`);
|
|
837
864
|
(0, fs_1.appendFileSync)(ghaOutput, `confidence=${plan.confidence}\n`);
|
|
865
|
+
(0, fs_1.appendFileSync)(ghaOutput, `enforcement_mode=${plan.enforcement.mode}\n`);
|
|
866
|
+
(0, fs_1.appendFileSync)(ghaOutput, `enforcement_should_fail=${plan.enforcement.shouldFail}\n`);
|
|
838
867
|
(0, fs_1.appendFileSync)(ghaOutput, `recommended_tests_count=${plan.recommendedTests.length}\n`);
|
|
839
868
|
(0, fs_1.appendFileSync)(ghaOutput, `required_new_tests_count=${plan.requiredNewTests.length}\n`);
|
|
840
869
|
(0, fs_1.appendFileSync)(ghaOutput, `plan_path=${planPath}\n`);
|
|
841
870
|
(0, fs_1.appendFileSync)(ghaOutput, `summary_path=${summaryPath}\n`);
|
|
871
|
+
(0, fs_1.appendFileSync)(ghaOutput, `metrics_events_path=${metrics.eventsPath}\n`);
|
|
872
|
+
(0, fs_1.appendFileSync)(ghaOutput, `metrics_summary_path=${metrics.summaryPath}\n`);
|
|
842
873
|
}
|
|
843
874
|
// eslint-disable-next-line no-console
|
|
844
875
|
console.log(`Suggested run set: ${plan.runSet} (confidence ${plan.confidence})`);
|
|
845
876
|
// eslint-disable-next-line no-console
|
|
846
877
|
console.log(`Decision: ${plan.decision.action} - ${plan.decision.summary}`);
|
|
847
878
|
// eslint-disable-next-line no-console
|
|
879
|
+
console.log(`Enforcement: ${plan.enforcement.mode} (shouldFail=${plan.enforcement.shouldFail})`);
|
|
880
|
+
// eslint-disable-next-line no-console
|
|
848
881
|
console.log(`Plan data: ${planPath}`);
|
|
849
882
|
// eslint-disable-next-line no-console
|
|
850
883
|
console.log(`CI summary: ${summaryPath}`);
|
|
884
|
+
// eslint-disable-next-line no-console
|
|
885
|
+
console.log(`Plan metrics: ${metrics.summaryPath}`);
|
|
851
886
|
if (plan.nextActions) {
|
|
852
887
|
// eslint-disable-next-line no-console
|
|
853
888
|
console.log(`Next action (run existing): ${plan.nextActions.runRecommendedTests || plan.nextActions.runSmokeSuite}`);
|
|
@@ -856,7 +891,8 @@ async function main() {
|
|
|
856
891
|
// eslint-disable-next-line no-console
|
|
857
892
|
console.log(`Next action (heal): ${plan.nextActions.healGeneratedTests}`);
|
|
858
893
|
}
|
|
859
|
-
|
|
894
|
+
const failOnLegacyFlag = args.failOnMustAddTests && plan.decision.action === 'must-add-tests';
|
|
895
|
+
if (failOnLegacyFlag || plan.enforcement.shouldFail) {
|
|
860
896
|
process.exit(2);
|
|
861
897
|
}
|
|
862
898
|
return;
|
package/dist/esm/agent/config.js
CHANGED
|
@@ -72,6 +72,7 @@ const DEFAULT_CONFIG = {
|
|
|
72
72
|
scenarios: 3,
|
|
73
73
|
outputDir: 'specs/functional/ai-assisted',
|
|
74
74
|
heal: true,
|
|
75
|
+
project: 'chrome',
|
|
75
76
|
mcp: false,
|
|
76
77
|
mcpAllowFallback: false,
|
|
77
78
|
},
|
|
@@ -120,6 +121,8 @@ const DEFAULT_CONFIG = {
|
|
|
120
121
|
'**/*.sql',
|
|
121
122
|
'**/webhook/**',
|
|
122
123
|
],
|
|
124
|
+
enforcementMode: 'advisory',
|
|
125
|
+
blockOnActions: ['must-add-tests'],
|
|
123
126
|
},
|
|
124
127
|
flags: {
|
|
125
128
|
defaultState: 'on',
|
|
@@ -266,6 +269,18 @@ function normalizeFlagState(value) {
|
|
|
266
269
|
}
|
|
267
270
|
return undefined;
|
|
268
271
|
}
|
|
272
|
+
function normalizePolicyEnforcementMode(value) {
|
|
273
|
+
if (value === 'advisory' || value === 'warn' || value === 'block') {
|
|
274
|
+
return value;
|
|
275
|
+
}
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
function normalizePolicyBlockAction(value) {
|
|
279
|
+
if (value === 'run-now' || value === 'must-add-tests' || value === 'safe-to-merge') {
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
269
284
|
function extractConfigPatch(raw) {
|
|
270
285
|
const patch = {};
|
|
271
286
|
if (typeof raw.path === 'string') {
|
|
@@ -462,6 +477,11 @@ function extractConfigPatch(raw) {
|
|
|
462
477
|
}
|
|
463
478
|
if (raw.policy && typeof raw.policy === 'object') {
|
|
464
479
|
const policy = raw.policy;
|
|
480
|
+
const blockOnActions = Array.isArray(policy.blockOnActions)
|
|
481
|
+
? policy.blockOnActions
|
|
482
|
+
.map((value) => normalizePolicyBlockAction(value))
|
|
483
|
+
.filter((value) => Boolean(value))
|
|
484
|
+
: DEFAULT_CONFIG.policy.blockOnActions;
|
|
465
485
|
patch.policy = {
|
|
466
486
|
minConfidenceForTargeted: coerceNumber(policy.minConfidenceForTargeted) ?? DEFAULT_CONFIG.policy.minConfidenceForTargeted,
|
|
467
487
|
safeMergeMinConfidence: coerceNumber(policy.safeMergeMinConfidence) ?? DEFAULT_CONFIG.policy.safeMergeMinConfidence,
|
|
@@ -475,6 +495,8 @@ function extractConfigPatch(raw) {
|
|
|
475
495
|
riskyFilePatterns: Array.isArray(policy.riskyFilePatterns)
|
|
476
496
|
? policy.riskyFilePatterns.filter((pattern) => typeof pattern === 'string')
|
|
477
497
|
: DEFAULT_CONFIG.policy.riskyFilePatterns,
|
|
498
|
+
enforcementMode: normalizePolicyEnforcementMode(policy.enforcementMode) ?? DEFAULT_CONFIG.policy.enforcementMode,
|
|
499
|
+
blockOnActions: blockOnActions.length > 0 ? blockOnActions : DEFAULT_CONFIG.policy.blockOnActions,
|
|
478
500
|
};
|
|
479
501
|
}
|
|
480
502
|
if (raw.flags && typeof raw.flags === 'object') {
|
|
@@ -610,6 +632,12 @@ export function resolveConfig(cwd, configPath, overrides) {
|
|
|
610
632
|
if (overrides.policy.riskyFilePatterns && overrides.policy.riskyFilePatterns.length > 0) {
|
|
611
633
|
policyPatch.riskyFilePatterns = overrides.policy.riskyFilePatterns;
|
|
612
634
|
}
|
|
635
|
+
if (overrides.policy.enforcementMode !== undefined) {
|
|
636
|
+
policyPatch.enforcementMode = overrides.policy.enforcementMode;
|
|
637
|
+
}
|
|
638
|
+
if (overrides.policy.blockOnActions && overrides.policy.blockOnActions.length > 0) {
|
|
639
|
+
policyPatch.blockOnActions = overrides.policy.blockOnActions;
|
|
640
|
+
}
|
|
613
641
|
config.policy = { ...config.policy, ...policyPatch };
|
|
614
642
|
}
|
|
615
643
|
if (overrides?.specPDF) {
|