@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/esm/agent/report.js
CHANGED
|
@@ -42,6 +42,12 @@ export function writeReport(appRoot, config, data) {
|
|
|
42
42
|
const markdownLines = [];
|
|
43
43
|
markdownLines.push(`# ${data.mode === 'impact' ? 'Impact Analysis' : 'Gap Analysis'} Report`);
|
|
44
44
|
markdownLines.push('');
|
|
45
|
+
if (data.runMetadata) {
|
|
46
|
+
markdownLines.push(`Run ID: ${data.runMetadata.runId}`);
|
|
47
|
+
markdownLines.push(`Run window: ${data.runMetadata.startedAt} -> ${data.runMetadata.completedAt}`);
|
|
48
|
+
markdownLines.push(`Run duration (ms): ${data.runMetadata.durationMs}`);
|
|
49
|
+
markdownLines.push(`Since ref: ${data.runMetadata.sinceRef}`);
|
|
50
|
+
}
|
|
45
51
|
markdownLines.push(`Framework: ${data.framework}`);
|
|
46
52
|
markdownLines.push(`Test Patterns: ${data.testPatterns.join(', ') || 'None'}`);
|
|
47
53
|
if (data.flowCatalog) {
|
|
@@ -100,6 +106,9 @@ export function writeReport(appRoot, config, data) {
|
|
|
100
106
|
if (result.error) {
|
|
101
107
|
markdownLines.push(` Error: ${result.error}`);
|
|
102
108
|
}
|
|
109
|
+
if (result.failureCategory || result.failureCode) {
|
|
110
|
+
markdownLines.push(` Failure taxonomy: category=${result.failureCategory || 'unknown'} code=${result.failureCode || 'unknown'}`);
|
|
111
|
+
}
|
|
103
112
|
}
|
|
104
113
|
if (data.pipeline.warnings.length > 0) {
|
|
105
114
|
markdownLines.push('Pipeline warnings:');
|
package/dist/esm/agent/runner.js
CHANGED
|
@@ -114,11 +114,14 @@ function buildRecommendedTestsFromCoverage(flows, coverage) {
|
|
|
114
114
|
const flow = flowMap.get(entry.flowId);
|
|
115
115
|
const flagSummary = formatFlags(flow?.flags || []);
|
|
116
116
|
for (const test of entry.coveredBy) {
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
const normalizedTest = normalizePath(test)
|
|
118
|
+
.replace(/^\.\//, '')
|
|
119
|
+
.replace(/^e2e-tests\/playwright\//, '');
|
|
120
|
+
if (!testNotes.has(normalizedTest)) {
|
|
121
|
+
testNotes.set(normalizedTest, new Set());
|
|
119
122
|
}
|
|
120
123
|
if (flagSummary !== 'none') {
|
|
121
|
-
testNotes.get(
|
|
124
|
+
testNotes.get(normalizedTest)?.add(flagSummary);
|
|
122
125
|
}
|
|
123
126
|
}
|
|
124
127
|
}
|
|
@@ -190,12 +193,24 @@ function classifyImpactModelConfidence(flowMapping, testMapping, dependencyGraph
|
|
|
190
193
|
}
|
|
191
194
|
return 'low';
|
|
192
195
|
}
|
|
196
|
+
function createRunId(mode) {
|
|
197
|
+
const ciRunId = process.env.GITHUB_RUN_ID;
|
|
198
|
+
const entropy = Math.random().toString(36).slice(2, 8);
|
|
199
|
+
const ts = Date.now().toString(36);
|
|
200
|
+
if (ciRunId) {
|
|
201
|
+
return `${mode}-gh-${ciRunId}-${ts}-${entropy}`;
|
|
202
|
+
}
|
|
203
|
+
return `${mode}-local-${ts}-${entropy}`;
|
|
204
|
+
}
|
|
193
205
|
export async function runImpact(_config, _options) {
|
|
194
206
|
ensureAppRoot(_config.path);
|
|
195
207
|
if (_config.testsRoot) {
|
|
196
208
|
ensureAppRoot(_config.testsRoot);
|
|
197
209
|
}
|
|
198
210
|
const deadline = Date.now() + _config.timeLimitMinutes * 60 * 1000;
|
|
211
|
+
const runStartedAt = new Date().toISOString();
|
|
212
|
+
const runStartedTs = Date.now();
|
|
213
|
+
const runId = createRunId('impact');
|
|
199
214
|
const warnings = [];
|
|
200
215
|
const testsRoot = _config.testsRoot || _config.path;
|
|
201
216
|
const frameworkDetection = detectFramework(testsRoot, _config.framework);
|
|
@@ -268,7 +283,7 @@ export async function runImpact(_config, _options) {
|
|
|
268
283
|
coverageMap.set(entry.flowId, entry.coveredBy);
|
|
269
284
|
}
|
|
270
285
|
gaps = computeGaps(flows, coverageMap);
|
|
271
|
-
recommendedTests =
|
|
286
|
+
recommendedTests = buildRecommendedTestsFromCoverage(flows, coverage);
|
|
272
287
|
}
|
|
273
288
|
else {
|
|
274
289
|
const traceability = mapTraceabilityToFlows(testsRoot, _config.impact.traceability, flows);
|
|
@@ -320,6 +335,15 @@ export async function runImpact(_config, _options) {
|
|
|
320
335
|
const reportRoot = testsRoot;
|
|
321
336
|
const report = writeReport(reportRoot, _config, {
|
|
322
337
|
mode: 'impact',
|
|
338
|
+
runMetadata: {
|
|
339
|
+
runId,
|
|
340
|
+
startedAt: runStartedAt,
|
|
341
|
+
completedAt: new Date().toISOString(),
|
|
342
|
+
durationMs: Date.now() - runStartedTs,
|
|
343
|
+
sinceRef: _config.git.since,
|
|
344
|
+
appPath: _config.path,
|
|
345
|
+
testsRoot,
|
|
346
|
+
},
|
|
323
347
|
changedFiles,
|
|
324
348
|
flows: sortFlows(flows),
|
|
325
349
|
coverage,
|
|
@@ -366,6 +390,9 @@ export async function runGap(_config, _options) {
|
|
|
366
390
|
ensureAppRoot(_config.testsRoot);
|
|
367
391
|
}
|
|
368
392
|
const deadline = Date.now() + _config.timeLimitMinutes * 60 * 1000;
|
|
393
|
+
const runStartedAt = new Date().toISOString();
|
|
394
|
+
const runStartedTs = Date.now();
|
|
395
|
+
const runId = createRunId('gap');
|
|
369
396
|
const warnings = [];
|
|
370
397
|
const testsRoot = _config.testsRoot || _config.path;
|
|
371
398
|
const frameworkDetection = detectFramework(testsRoot, _config.framework);
|
|
@@ -450,7 +477,7 @@ export async function runGap(_config, _options) {
|
|
|
450
477
|
coverageMap.set(entry.flowId, entry.coveredBy);
|
|
451
478
|
}
|
|
452
479
|
gaps = computeGaps(flows, coverageMap);
|
|
453
|
-
recommendedTests =
|
|
480
|
+
recommendedTests = buildRecommendedTestsFromCoverage(flows, coverage);
|
|
454
481
|
}
|
|
455
482
|
else {
|
|
456
483
|
const traceability = mapTraceabilityToFlows(testsRoot, _config.impact.traceability, flows);
|
|
@@ -502,6 +529,15 @@ export async function runGap(_config, _options) {
|
|
|
502
529
|
const reportRoot = testsRoot;
|
|
503
530
|
const report = writeReport(reportRoot, _config, {
|
|
504
531
|
mode: 'gap',
|
|
532
|
+
runMetadata: {
|
|
533
|
+
runId,
|
|
534
|
+
startedAt: runStartedAt,
|
|
535
|
+
completedAt: new Date().toISOString(),
|
|
536
|
+
durationMs: Date.now() - runStartedTs,
|
|
537
|
+
sinceRef: _config.git.since,
|
|
538
|
+
appPath: _config.path,
|
|
539
|
+
testsRoot,
|
|
540
|
+
},
|
|
505
541
|
changedFiles,
|
|
506
542
|
flows: sortFlows(flows),
|
|
507
543
|
coverage,
|
package/dist/esm/api.js
CHANGED
|
@@ -4,7 +4,7 @@ import { existsSync, readFileSync } from 'fs';
|
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { resolveConfig } from './agent/config.js';
|
|
6
6
|
import { runGap, runImpact } from './agent/runner.js';
|
|
7
|
-
import { attachDeveloperActions, buildPlanFromImpactReport, renderCiSummaryMarkdown, writeCiSummary, writePlanReport, } from './agent/plan.js';
|
|
7
|
+
import { appendPlanMetrics, attachDeveloperActions, buildPlanFromImpactReport, renderCiSummaryMarkdown, writeCiSummary, writePlanReport, } from './agent/plan.js';
|
|
8
8
|
import { applyOperationalInsights } from './agent/operational_insights.js';
|
|
9
9
|
import { finalizeGeneratedTests } from './agent/handoff.js';
|
|
10
10
|
import { ingestTraceabilityInput, } from './agent/traceability_ingest.js';
|
|
@@ -62,6 +62,7 @@ export async function recommendTests(options = {}) {
|
|
|
62
62
|
const planPath = writePlanReport(reportRoot, plan);
|
|
63
63
|
const ciSummaryMarkdown = renderCiSummaryMarkdown(plan);
|
|
64
64
|
const ciSummaryPath = writeCiSummary(reportRoot, ciSummaryMarkdown);
|
|
65
|
+
appendPlanMetrics(reportRoot, plan);
|
|
65
66
|
return {
|
|
66
67
|
report,
|
|
67
68
|
reportPath: impactPath,
|
package/dist/esm/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { resolveConfig } from './agent/config.js';
|
|
|
7
7
|
import { AnthropicProvider } from './anthropic_provider.js';
|
|
8
8
|
import { LLMProviderError } from './provider_interface.js';
|
|
9
9
|
import { runGap, runImpact } from './agent/runner.js';
|
|
10
|
-
import { attachDeveloperActions, buildPlanFromImpactReport, renderCiSummaryMarkdown, writeCiSummary, writePlanReport } from './agent/plan.js';
|
|
10
|
+
import { appendPlanMetrics, attachDeveloperActions, buildPlanFromImpactReport, renderCiSummaryMarkdown, writeCiSummary, writePlanReport, } from './agent/plan.js';
|
|
11
11
|
import { applyOperationalInsights } from './agent/operational_insights.js';
|
|
12
12
|
import { appendFeedbackAndRecompute } from './agent/feedback.js';
|
|
13
13
|
import { finalizeGeneratedTests } from './agent/handoff.js';
|
|
@@ -87,6 +87,7 @@ function printUsage() {
|
|
|
87
87
|
' --pipeline-base-url Base URL for Playwright runs',
|
|
88
88
|
' --pipeline-browser Browser: chrome|chromium|firefox|webkit',
|
|
89
89
|
' --pipeline-headless Run in headless mode',
|
|
90
|
+
' --pipeline-headed Run in headed mode',
|
|
90
91
|
' --pipeline-project Playwright project name',
|
|
91
92
|
' --pipeline-parallel Enable parallel mode in generator',
|
|
92
93
|
' --pipeline-dry-run Do not execute pipeline (report only)',
|
|
@@ -101,6 +102,8 @@ function printUsage() {
|
|
|
101
102
|
' --policy-safe-merge-confidence <n> Confidence needed for safe-to-merge',
|
|
102
103
|
' --policy-force-full-on-warnings <n> Escalate to full at warning count',
|
|
103
104
|
' --policy-risky-patterns <globs> Comma-separated risky file globs',
|
|
105
|
+
' --policy-enforcement-mode <mode> advisory | warn | block',
|
|
106
|
+
' --policy-block-actions <actions> Comma-separated CI actions to block/warn',
|
|
104
107
|
' --ci-comment-path <path> Write CI markdown summary',
|
|
105
108
|
' --github-output <path> Write GitHub Actions outputs',
|
|
106
109
|
' --fail-on-must-add-tests Exit non-zero on must-add-tests decision',
|
|
@@ -244,6 +247,10 @@ function parseArgs(argv) {
|
|
|
244
247
|
parsed.pipelineHeadless = true;
|
|
245
248
|
continue;
|
|
246
249
|
}
|
|
250
|
+
if (arg === '--pipeline-headed') {
|
|
251
|
+
parsed.pipelineHeadless = false;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
247
254
|
if (arg === '--pipeline-project' && next) {
|
|
248
255
|
parsed.pipelineProject = next;
|
|
249
256
|
i += 1;
|
|
@@ -320,6 +327,21 @@ function parseArgs(argv) {
|
|
|
320
327
|
i += 1;
|
|
321
328
|
continue;
|
|
322
329
|
}
|
|
330
|
+
if (arg === '--policy-enforcement-mode' && next) {
|
|
331
|
+
if (next === 'advisory' || next === 'warn' || next === 'block') {
|
|
332
|
+
parsed.policyEnforcementMode = next;
|
|
333
|
+
}
|
|
334
|
+
i += 1;
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (arg === '--policy-block-actions' && next) {
|
|
338
|
+
parsed.policyBlockActions = next
|
|
339
|
+
.split(',')
|
|
340
|
+
.map((value) => value.trim())
|
|
341
|
+
.filter((value) => (value === 'run-now' || value === 'must-add-tests' || value === 'safe-to-merge'));
|
|
342
|
+
i += 1;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
323
345
|
if (arg === '--ci-comment-path' && next) {
|
|
324
346
|
parsed.ciCommentPath = next;
|
|
325
347
|
i += 1;
|
|
@@ -794,12 +816,16 @@ async function main() {
|
|
|
794
816
|
policy: args.policyMinConfidence !== undefined ||
|
|
795
817
|
args.policySafeMergeConfidence !== undefined ||
|
|
796
818
|
args.policyWarningsThreshold !== undefined ||
|
|
797
|
-
(args.policyRiskyPatterns && args.policyRiskyPatterns.length > 0)
|
|
819
|
+
(args.policyRiskyPatterns && args.policyRiskyPatterns.length > 0) ||
|
|
820
|
+
args.policyEnforcementMode !== undefined ||
|
|
821
|
+
(args.policyBlockActions && args.policyBlockActions.length > 0)
|
|
798
822
|
? {
|
|
799
823
|
minConfidenceForTargeted: args.policyMinConfidence,
|
|
800
824
|
safeMergeMinConfidence: args.policySafeMergeConfidence,
|
|
801
825
|
forceFullOnWarningsAtOrAbove: args.policyWarningsThreshold,
|
|
802
826
|
riskyFilePatterns: args.policyRiskyPatterns,
|
|
827
|
+
enforcementMode: args.policyEnforcementMode,
|
|
828
|
+
blockOnActions: args.policyBlockActions,
|
|
803
829
|
}
|
|
804
830
|
: undefined,
|
|
805
831
|
});
|
|
@@ -828,24 +854,33 @@ async function main() {
|
|
|
828
854
|
const planPath = writePlanReport(reportRoot, plan);
|
|
829
855
|
const summaryMarkdown = renderCiSummaryMarkdown(plan);
|
|
830
856
|
const summaryPath = writeCiSummary(reportRoot, summaryMarkdown, args.ciCommentPath);
|
|
857
|
+
const metrics = appendPlanMetrics(reportRoot, plan);
|
|
831
858
|
const ghaOutput = args.githubOutputPath || process.env.GITHUB_OUTPUT;
|
|
832
859
|
if (ghaOutput) {
|
|
833
860
|
appendFileSync(ghaOutput, `run_set=${plan.runSet}\n`);
|
|
834
861
|
appendFileSync(ghaOutput, `action=${plan.decision.action}\n`);
|
|
835
862
|
appendFileSync(ghaOutput, `confidence=${plan.confidence}\n`);
|
|
863
|
+
appendFileSync(ghaOutput, `enforcement_mode=${plan.enforcement.mode}\n`);
|
|
864
|
+
appendFileSync(ghaOutput, `enforcement_should_fail=${plan.enforcement.shouldFail}\n`);
|
|
836
865
|
appendFileSync(ghaOutput, `recommended_tests_count=${plan.recommendedTests.length}\n`);
|
|
837
866
|
appendFileSync(ghaOutput, `required_new_tests_count=${plan.requiredNewTests.length}\n`);
|
|
838
867
|
appendFileSync(ghaOutput, `plan_path=${planPath}\n`);
|
|
839
868
|
appendFileSync(ghaOutput, `summary_path=${summaryPath}\n`);
|
|
869
|
+
appendFileSync(ghaOutput, `metrics_events_path=${metrics.eventsPath}\n`);
|
|
870
|
+
appendFileSync(ghaOutput, `metrics_summary_path=${metrics.summaryPath}\n`);
|
|
840
871
|
}
|
|
841
872
|
// eslint-disable-next-line no-console
|
|
842
873
|
console.log(`Suggested run set: ${plan.runSet} (confidence ${plan.confidence})`);
|
|
843
874
|
// eslint-disable-next-line no-console
|
|
844
875
|
console.log(`Decision: ${plan.decision.action} - ${plan.decision.summary}`);
|
|
845
876
|
// eslint-disable-next-line no-console
|
|
877
|
+
console.log(`Enforcement: ${plan.enforcement.mode} (shouldFail=${plan.enforcement.shouldFail})`);
|
|
878
|
+
// eslint-disable-next-line no-console
|
|
846
879
|
console.log(`Plan data: ${planPath}`);
|
|
847
880
|
// eslint-disable-next-line no-console
|
|
848
881
|
console.log(`CI summary: ${summaryPath}`);
|
|
882
|
+
// eslint-disable-next-line no-console
|
|
883
|
+
console.log(`Plan metrics: ${metrics.summaryPath}`);
|
|
849
884
|
if (plan.nextActions) {
|
|
850
885
|
// eslint-disable-next-line no-console
|
|
851
886
|
console.log(`Next action (run existing): ${plan.nextActions.runRecommendedTests || plan.nextActions.runSmokeSuite}`);
|
|
@@ -854,7 +889,8 @@ async function main() {
|
|
|
854
889
|
// eslint-disable-next-line no-console
|
|
855
890
|
console.log(`Next action (heal): ${plan.nextActions.healGeneratedTests}`);
|
|
856
891
|
}
|
|
857
|
-
|
|
892
|
+
const failOnLegacyFlag = args.failOnMustAddTests && plan.decision.action === 'must-add-tests';
|
|
893
|
+
if (failOnLegacyFlag || plan.enforcement.shouldFail) {
|
|
858
894
|
process.exit(2);
|
|
859
895
|
}
|
|
860
896
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yasserkhanorg/e2e-agents",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Pluggable LLM provider library for AI-powered test automation. Use Claude, Ollama, or your own LLM. Integrate with Playwright, Jest, or any test framework. MCP server for test agents, cost tracking, and hybrid provider mode.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -18,6 +18,28 @@
|
|
|
18
18
|
"mode": {
|
|
19
19
|
"const": "impact"
|
|
20
20
|
},
|
|
21
|
+
"runMetadata": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"required": [
|
|
24
|
+
"runId",
|
|
25
|
+
"startedAt",
|
|
26
|
+
"completedAt",
|
|
27
|
+
"durationMs",
|
|
28
|
+
"sinceRef",
|
|
29
|
+
"appPath",
|
|
30
|
+
"testsRoot"
|
|
31
|
+
],
|
|
32
|
+
"properties": {
|
|
33
|
+
"runId": {"type": "string"},
|
|
34
|
+
"startedAt": {"type": "string", "format": "date-time"},
|
|
35
|
+
"completedAt": {"type": "string", "format": "date-time"},
|
|
36
|
+
"durationMs": {"type": "number"},
|
|
37
|
+
"sinceRef": {"type": "string"},
|
|
38
|
+
"appPath": {"type": "string"},
|
|
39
|
+
"testsRoot": {"type": "string"}
|
|
40
|
+
},
|
|
41
|
+
"additionalProperties": false
|
|
42
|
+
},
|
|
21
43
|
"changedFiles": {
|
|
22
44
|
"type": "array",
|
|
23
45
|
"items": {
|
|
@@ -370,6 +392,21 @@
|
|
|
370
392
|
},
|
|
371
393
|
"error": {
|
|
372
394
|
"type": "string"
|
|
395
|
+
},
|
|
396
|
+
"failureCategory": {
|
|
397
|
+
"enum": [
|
|
398
|
+
"config",
|
|
399
|
+
"environment",
|
|
400
|
+
"generation",
|
|
401
|
+
"validation",
|
|
402
|
+
"runtime",
|
|
403
|
+
"quality",
|
|
404
|
+
"path-safety",
|
|
405
|
+
"unknown"
|
|
406
|
+
]
|
|
407
|
+
},
|
|
408
|
+
"failureCode": {
|
|
409
|
+
"type": "string"
|
|
373
410
|
}
|
|
374
411
|
},
|
|
375
412
|
"additionalProperties": false
|
package/schemas/plan.schema.json
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": [
|
|
7
7
|
"schemaVersion",
|
|
8
|
+
"runId",
|
|
8
9
|
"generatedAt",
|
|
9
10
|
"source",
|
|
10
11
|
"runSet",
|
|
@@ -14,12 +15,19 @@
|
|
|
14
15
|
"requiredNewTests",
|
|
15
16
|
"policy",
|
|
16
17
|
"decision",
|
|
18
|
+
"enforcement",
|
|
17
19
|
"metrics"
|
|
18
20
|
],
|
|
19
21
|
"properties": {
|
|
20
22
|
"schemaVersion": {
|
|
21
23
|
"const": "1.0.0"
|
|
22
24
|
},
|
|
25
|
+
"runId": {
|
|
26
|
+
"type": "string"
|
|
27
|
+
},
|
|
28
|
+
"sourceRunId": {
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
23
31
|
"generatedAt": {
|
|
24
32
|
"type": "string",
|
|
25
33
|
"format": "date-time"
|
|
@@ -108,6 +116,15 @@
|
|
|
108
116
|
"items": {
|
|
109
117
|
"type": "string"
|
|
110
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"enforcementMode": {
|
|
121
|
+
"enum": ["advisory", "warn", "block"]
|
|
122
|
+
},
|
|
123
|
+
"blockOnActions": {
|
|
124
|
+
"type": "array",
|
|
125
|
+
"items": {
|
|
126
|
+
"enum": ["run-now", "must-add-tests", "safe-to-merge"]
|
|
127
|
+
}
|
|
111
128
|
}
|
|
112
129
|
},
|
|
113
130
|
"additionalProperties": false
|
|
@@ -139,6 +156,37 @@
|
|
|
139
156
|
},
|
|
140
157
|
"additionalProperties": false
|
|
141
158
|
},
|
|
159
|
+
"enforcement": {
|
|
160
|
+
"type": "object",
|
|
161
|
+
"required": [
|
|
162
|
+
"mode",
|
|
163
|
+
"blockOnActions",
|
|
164
|
+
"matchedAction",
|
|
165
|
+
"shouldFail",
|
|
166
|
+
"summary"
|
|
167
|
+
],
|
|
168
|
+
"properties": {
|
|
169
|
+
"mode": {
|
|
170
|
+
"enum": ["advisory", "warn", "block"]
|
|
171
|
+
},
|
|
172
|
+
"blockOnActions": {
|
|
173
|
+
"type": "array",
|
|
174
|
+
"items": {
|
|
175
|
+
"enum": ["run-now", "must-add-tests", "safe-to-merge"]
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"matchedAction": {
|
|
179
|
+
"type": "boolean"
|
|
180
|
+
},
|
|
181
|
+
"shouldFail": {
|
|
182
|
+
"type": "boolean"
|
|
183
|
+
},
|
|
184
|
+
"summary": {
|
|
185
|
+
"type": "string"
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"additionalProperties": false
|
|
189
|
+
},
|
|
142
190
|
"insights": {
|
|
143
191
|
"type": "object",
|
|
144
192
|
"properties": {
|