@codyswann/lisa 3.48.7 → 3.50.0
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/cli/doctor-hook-copy-parity.d.ts +8 -0
- package/dist/cli/doctor-hook-copy-parity.d.ts.map +1 -0
- package/dist/cli/doctor-hook-copy-parity.js +121 -0
- package/dist/cli/doctor-hook-copy-parity.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +6 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/gate-report-agent-hooks.d.ts +40 -0
- package/dist/cli/gate-report-agent-hooks.d.ts.map +1 -0
- package/dist/cli/gate-report-agent-hooks.js +226 -0
- package/dist/cli/gate-report-agent-hooks.js.map +1 -0
- package/dist/cli/gate-report-assemble.d.ts +37 -0
- package/dist/cli/gate-report-assemble.d.ts.map +1 -0
- package/dist/cli/gate-report-assemble.js +69 -0
- package/dist/cli/gate-report-assemble.js.map +1 -0
- package/dist/cli/gate-report-cells.d.ts +27 -2
- package/dist/cli/gate-report-cells.d.ts.map +1 -1
- package/dist/cli/gate-report-cells.js +59 -14
- package/dist/cli/gate-report-cells.js.map +1 -1
- package/dist/cli/gate-report-contexts.d.ts +70 -0
- package/dist/cli/gate-report-contexts.d.ts.map +1 -0
- package/dist/cli/gate-report-contexts.js +72 -0
- package/dist/cli/gate-report-contexts.js.map +1 -0
- package/dist/cli/gate-report-facade.d.ts +62 -0
- package/dist/cli/gate-report-facade.d.ts.map +1 -0
- package/dist/cli/gate-report-facade.js +224 -0
- package/dist/cli/gate-report-facade.js.map +1 -0
- package/dist/cli/gate-report-fragment.d.ts +11 -0
- package/dist/cli/gate-report-fragment.d.ts.map +1 -0
- package/dist/cli/gate-report-fragment.js +100 -0
- package/dist/cli/gate-report-fragment.js.map +1 -0
- package/dist/cli/gate-report-html.d.ts +47 -0
- package/dist/cli/gate-report-html.d.ts.map +1 -0
- package/dist/cli/gate-report-html.js +49 -0
- package/dist/cli/gate-report-html.js.map +1 -0
- package/dist/cli/gate-report-joins.d.ts +37 -0
- package/dist/cli/gate-report-joins.d.ts.map +1 -0
- package/dist/cli/gate-report-joins.js +104 -0
- package/dist/cli/gate-report-joins.js.map +1 -0
- package/dist/cli/gate-report-merge.d.ts +22 -0
- package/dist/cli/gate-report-merge.d.ts.map +1 -0
- package/dist/cli/gate-report-merge.js +79 -0
- package/dist/cli/gate-report-merge.js.map +1 -0
- package/dist/cli/gate-report-preview.d.ts +0 -18
- package/dist/cli/gate-report-preview.d.ts.map +1 -1
- package/dist/cli/gate-report-preview.js +35 -266
- package/dist/cli/gate-report-preview.js.map +1 -1
- package/dist/cli/gate-report-rows.d.ts +39 -0
- package/dist/cli/gate-report-rows.d.ts.map +1 -0
- package/dist/cli/gate-report-rows.js +209 -0
- package/dist/cli/gate-report-rows.js.map +1 -0
- package/dist/cli/gate-report-sections.d.ts +32 -0
- package/dist/cli/gate-report-sections.d.ts.map +1 -0
- package/dist/cli/gate-report-sections.js +164 -0
- package/dist/cli/gate-report-sections.js.map +1 -0
- package/dist/cli/gate-report-style.d.ts +19 -0
- package/dist/cli/gate-report-style.d.ts.map +1 -0
- package/dist/cli/gate-report-style.js +97 -0
- package/dist/cli/gate-report-style.js.map +1 -0
- package/dist/cli/gate-report-summary.d.ts.map +1 -1
- package/dist/cli/gate-report-summary.js +3 -0
- package/dist/cli/gate-report-summary.js.map +1 -1
- package/dist/cli/gate-report-types.d.ts +132 -1
- package/dist/cli/gate-report-types.d.ts.map +1 -1
- package/dist/cli/gate-report-types.js +1 -1
- package/dist/cli/gate-report-upstream.d.ts +70 -0
- package/dist/cli/gate-report-upstream.d.ts.map +1 -0
- package/dist/cli/gate-report-upstream.js +90 -0
- package/dist/cli/gate-report-upstream.js.map +1 -0
- package/dist/cli/gate-report.d.ts +2 -0
- package/dist/cli/gate-report.d.ts.map +1 -1
- package/dist/cli/gate-report.js +98 -140
- package/dist/cli/gate-report.js.map +1 -1
- package/dist/cli/ui-cmd.d.ts +4 -0
- package/dist/cli/ui-cmd.d.ts.map +1 -1
- package/dist/cli/ui-cmd.js +10 -2
- package/dist/cli/ui-cmd.js.map +1 -1
- package/dist/cli/ui-gate-report.d.ts +57 -0
- package/dist/cli/ui-gate-report.d.ts.map +1 -0
- package/dist/cli/ui-gate-report.js +95 -0
- package/dist/cli/ui-gate-report.js.map +1 -0
- package/dist/core/hook-copy-parity.d.ts +81 -0
- package/dist/core/hook-copy-parity.d.ts.map +1 -0
- package/dist/core/hook-copy-parity.js +111 -0
- package/dist/core/hook-copy-parity.js.map +1 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +28 -2
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/ui/README.md +56 -3
- package/ui/index.html +52 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 3 — whether a CI job reads the declaration or runs a hardcoded command.
|
|
3
|
+
*
|
|
4
|
+
* That answer is written in `.github/workflows/quality.yml`, and a consumer
|
|
5
|
+
* holds no copy of it: it calls the reusable workflow by ref. So for most
|
|
6
|
+
* projects the honest answer is that the question cannot be answered here.
|
|
7
|
+
*
|
|
8
|
+
* It was, however, being refused UNCONDITIONALLY — including in the one
|
|
9
|
+
* repository where the file is present, which is Lisa's own. A refusal that
|
|
10
|
+
* does not look is indistinguishable from a refusal that looked and failed,
|
|
11
|
+
* and only one of those is true. So: when the workflow is on disk, read it and
|
|
12
|
+
* answer.
|
|
13
|
+
*
|
|
14
|
+
* The read is a deterministic YAML parse and nothing else. No agent, no
|
|
15
|
+
* judgement, no network. A job's façade is wired when its steps carry the
|
|
16
|
+
* resolve step — `id: gate` with a `GATE_ID` in its environment — which is the
|
|
17
|
+
* same signal `tests/integration/quality-gate-skip-jobs-mapping.test.ts`
|
|
18
|
+
* derives the shipped job table from, so the two cannot answer differently.
|
|
19
|
+
*
|
|
20
|
+
* Sibling workflows are scanned too, because a job that moved to a workflow of
|
|
21
|
+
* its own took its façade with it. Reading `quality.yml` alone would report a
|
|
22
|
+
* moved job as unwired on the grounds that it is no longer next door.
|
|
23
|
+
* @module cli/gate-report-facade
|
|
24
|
+
*/
|
|
25
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
26
|
+
import * as path from "node:path";
|
|
27
|
+
import { loadYaml } from "../utils/yaml.js";
|
|
28
|
+
/** The workflow Tier 3 is written in. */
|
|
29
|
+
const QUALITY_YML = "quality.yml";
|
|
30
|
+
/** Where a repository keeps its workflows. */
|
|
31
|
+
const WORKFLOW_DIR = path.join(".github", "workflows");
|
|
32
|
+
/** The step id every façade resolve step carries. */
|
|
33
|
+
const RESOLVE_STEP_ID = "gate";
|
|
34
|
+
/** The refusal a project with no copy of the workflow gets. */
|
|
35
|
+
export const TIER_THREE_UNKNOWABLE = {
|
|
36
|
+
state: "unknown",
|
|
37
|
+
reason: "determined-by-quality-yml",
|
|
38
|
+
message: "Whether the CI job reads this declaration or runs a hardcoded command is written in quality.yml, which this project does not have — it calls the reusable workflow by ref.",
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The gate one job's façade resolves, if it has one.
|
|
42
|
+
* @param job - One parsed job definition
|
|
43
|
+
* @returns The declared `GATE_ID`, or null
|
|
44
|
+
*/
|
|
45
|
+
function gateOfJob(job) {
|
|
46
|
+
if (job === null || typeof job !== "object")
|
|
47
|
+
return null;
|
|
48
|
+
const steps = Reflect.get(job, "steps");
|
|
49
|
+
if (!Array.isArray(steps))
|
|
50
|
+
return null;
|
|
51
|
+
const resolve = steps.find(step => step !== null &&
|
|
52
|
+
typeof step === "object" &&
|
|
53
|
+
Reflect.get(step, "id") === RESOLVE_STEP_ID);
|
|
54
|
+
if (resolve === undefined)
|
|
55
|
+
return null;
|
|
56
|
+
const environment = Reflect.get(resolve, "env");
|
|
57
|
+
if (environment === null || typeof environment !== "object")
|
|
58
|
+
return null;
|
|
59
|
+
const id = Reflect.get(environment, "GATE_ID");
|
|
60
|
+
return typeof id === "string" ? id : null;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Parse one workflow file into its name and its jobs.
|
|
64
|
+
* @param file - Absolute path
|
|
65
|
+
* @returns The parsed workflow, or null when it could not be read
|
|
66
|
+
*/
|
|
67
|
+
async function parseWorkflow(file) {
|
|
68
|
+
const source = await readFile(file, "utf8").catch(() => undefined);
|
|
69
|
+
if (source === undefined)
|
|
70
|
+
return null;
|
|
71
|
+
try {
|
|
72
|
+
const parsed = loadYaml(source);
|
|
73
|
+
if (parsed === null || typeof parsed !== "object")
|
|
74
|
+
return null;
|
|
75
|
+
const jobs = Reflect.get(parsed, "jobs");
|
|
76
|
+
if (jobs === null || typeof jobs !== "object")
|
|
77
|
+
return null;
|
|
78
|
+
const workflowName = Reflect.get(parsed, "name");
|
|
79
|
+
return {
|
|
80
|
+
workflowName: typeof workflowName === "string" ? workflowName : null,
|
|
81
|
+
jobs: jobs,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The contexts one job could post, in both spellings GitHub uses.
|
|
90
|
+
* @param workflowName - The declaring workflow's name
|
|
91
|
+
* @param job - The job definition
|
|
92
|
+
* @param jobId - The job's id, used when it declares no name
|
|
93
|
+
* @returns Candidate context strings
|
|
94
|
+
*/
|
|
95
|
+
function contextsOfJob(workflowName, job, jobId) {
|
|
96
|
+
const declared = job !== null && typeof job === "object" ? Reflect.get(job, "name") : null;
|
|
97
|
+
const name = typeof declared === "string" ? declared : jobId;
|
|
98
|
+
return workflowName === null ? [name] : [name, `${workflowName} / ${name}`];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Every `run:` block one job declares, concatenated.
|
|
102
|
+
* @param job - The job definition
|
|
103
|
+
* @returns The shell the job runs
|
|
104
|
+
*/
|
|
105
|
+
function shellOf(job) {
|
|
106
|
+
if (job === null || typeof job !== "object")
|
|
107
|
+
return "";
|
|
108
|
+
const steps = Reflect.get(job, "steps");
|
|
109
|
+
if (!Array.isArray(steps))
|
|
110
|
+
return "";
|
|
111
|
+
return steps
|
|
112
|
+
.map(step => {
|
|
113
|
+
if (step === null || typeof step !== "object")
|
|
114
|
+
return "";
|
|
115
|
+
const run = Reflect.get(step, "run");
|
|
116
|
+
return typeof run === "string" ? run : "";
|
|
117
|
+
})
|
|
118
|
+
.join("\n");
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Every workflow file in the project, sorted so the report is stable.
|
|
122
|
+
* @param projectRoot - Project root
|
|
123
|
+
* @returns File names, sorted
|
|
124
|
+
*/
|
|
125
|
+
async function listWorkflowFiles(projectRoot) {
|
|
126
|
+
const entries = await readdir(path.join(projectRoot, WORKFLOW_DIR), {
|
|
127
|
+
withFileTypes: true,
|
|
128
|
+
}).catch(() => undefined);
|
|
129
|
+
if (entries === undefined)
|
|
130
|
+
return [];
|
|
131
|
+
return entries
|
|
132
|
+
.filter(entry => entry.isFile() &&
|
|
133
|
+
(entry.name.endsWith(".yml") || entry.name.endsWith(".yaml")))
|
|
134
|
+
.map(entry => entry.name)
|
|
135
|
+
.sort((left, right) => left.localeCompare(right));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Read what the project's own workflows say about façade wiring.
|
|
139
|
+
* @param projectRoot - Project root
|
|
140
|
+
* @returns The facts, empty when the project holds no workflows
|
|
141
|
+
*/
|
|
142
|
+
export async function readFacadeFacts(projectRoot) {
|
|
143
|
+
const names = await listWorkflowFiles(projectRoot);
|
|
144
|
+
const parsed = await Promise.all(names.map(async (name) => ({
|
|
145
|
+
name,
|
|
146
|
+
parsed: await parseWorkflow(path.join(projectRoot, WORKFLOW_DIR, name)),
|
|
147
|
+
})));
|
|
148
|
+
const readable = parsed.filter((entry) => entry.parsed !== null);
|
|
149
|
+
const sites = readable.flatMap(entry => Object.entries(entry.parsed.jobs).map(([job, definition]) => {
|
|
150
|
+
const contexts = contextsOfJob(entry.parsed.workflowName, definition, job);
|
|
151
|
+
return {
|
|
152
|
+
id: job,
|
|
153
|
+
name: contexts[0] ?? job,
|
|
154
|
+
contexts,
|
|
155
|
+
shell: shellOf(definition),
|
|
156
|
+
gate: gateOfJob(definition),
|
|
157
|
+
};
|
|
158
|
+
}));
|
|
159
|
+
const jobSites = [...sites].sort(byJobId);
|
|
160
|
+
const gatePairs = jobSites.flatMap((site) => site.gate === null ? [] : [[site.id, site.gate]]);
|
|
161
|
+
return {
|
|
162
|
+
qualityYmlPresent: readable.some(entry => entry.name === QUALITY_YML),
|
|
163
|
+
files: readable.map(entry => `${WORKFLOW_DIR}/${entry.name}`),
|
|
164
|
+
// Declaration order wins for a duplicated job id, because that is the job
|
|
165
|
+
// GitHub itself would run: a Map built from pairs keeps the LAST, so the
|
|
166
|
+
// list is reversed before it is built.
|
|
167
|
+
gatesByJob: new Map([...gatePairs].reverse()),
|
|
168
|
+
jobs: new Set(jobSites.map(site => site.id)),
|
|
169
|
+
projectContexts: new Set(jobSites.flatMap(site => site.contexts)),
|
|
170
|
+
jobSites,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Order two jobs by id, so the report is stable across machines.
|
|
175
|
+
* @param left - One job
|
|
176
|
+
* @param right - Another job
|
|
177
|
+
* @returns A comparison result
|
|
178
|
+
*/
|
|
179
|
+
function byJobId(left, right) {
|
|
180
|
+
return left.id.localeCompare(right.id);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* How the report names the workflows it read.
|
|
184
|
+
* @param facts - The parsed workflow facts
|
|
185
|
+
* @returns The source block
|
|
186
|
+
*/
|
|
187
|
+
export function facadeSourceOf(facts) {
|
|
188
|
+
return { present: facts.qualityYmlPresent, files: facts.files };
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Whether the CI job for one gate reads the declaration.
|
|
192
|
+
*
|
|
193
|
+
* Three answers, and the third is not a fourth state smuggled in: a job the
|
|
194
|
+
* workflow does not declare at all is a different fact from a job that runs a
|
|
195
|
+
* hardcoded command, and calling the first one `false` would report a gate as
|
|
196
|
+
* unwired on the strength of never having found it.
|
|
197
|
+
* @param facts - The parsed workflow facts
|
|
198
|
+
* @param gateId - The gate being reported
|
|
199
|
+
* @param qualityJob - The CI job the static table pairs with it
|
|
200
|
+
* @returns Whether that job's façade resolves this gate
|
|
201
|
+
*/
|
|
202
|
+
export function facadeFinding(facts, gateId, qualityJob) {
|
|
203
|
+
if (qualityJob === null) {
|
|
204
|
+
return {
|
|
205
|
+
state: "not-applicable",
|
|
206
|
+
reason: "no-mapped-job",
|
|
207
|
+
message: "Lisa's static job table pairs no CI job with this gate, so there is no job whose wiring could be read.",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (!facts.qualityYmlPresent)
|
|
211
|
+
return TIER_THREE_UNKNOWABLE;
|
|
212
|
+
const resolved = facts.gatesByJob.get(qualityJob);
|
|
213
|
+
if (resolved !== undefined) {
|
|
214
|
+
return { state: "verified", value: resolved === gateId };
|
|
215
|
+
}
|
|
216
|
+
if (facts.jobs.has(qualityJob))
|
|
217
|
+
return { state: "verified", value: false };
|
|
218
|
+
return {
|
|
219
|
+
state: "unknown",
|
|
220
|
+
reason: "job-absent-from-this-workflow",
|
|
221
|
+
message: `quality.yml is present here but declares no job called ${qualityJob}, so whether that job reads this declaration cannot be read from this checkout.`,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=gate-report-facade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-facade.js","sourceRoot":"","sources":["../../src/cli/gate-report-facade.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GateReport } from "./gate-report-types.js";
|
|
2
|
+
/** The class every rule in the report's stylesheet is scoped to. */
|
|
3
|
+
export declare const GATE_REPORT_ROOT_CLASS = "lisa-gate-report";
|
|
4
|
+
/**
|
|
5
|
+
* Render the report as a fragment for the console tab.
|
|
6
|
+
* @param report - The emitter's output
|
|
7
|
+
* @param projectLabel - How to name the project being reported on
|
|
8
|
+
* @returns HTML with no document wrapper, safe to inject into the console
|
|
9
|
+
*/
|
|
10
|
+
export declare function renderGateReportFragment(report: GateReport, projectLabel: string): string;
|
|
11
|
+
//# sourceMappingURL=gate-report-fragment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-fragment.d.ts","sourceRoot":"","sources":["../../src/cli/gate-report-fragment.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,oEAAoE;AACpE,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAwCzD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,MAAM,GACnB,MAAM,CA8BR"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gate report as an HTML fragment, for the Doctor tab in `lisa ui`.
|
|
3
|
+
*
|
|
4
|
+
* A fragment rather than a document because the ruling is that this is one
|
|
5
|
+
* surface: a tab alongside the console's other tabs, not a second page on a
|
|
6
|
+
* second port served by a second server.
|
|
7
|
+
*
|
|
8
|
+
* It is composed HERE and injected by the server at request time, and that is
|
|
9
|
+
* deliberate. `ui/index.html` is a single 13,000-line zero-build file with a
|
|
10
|
+
* known concurrent-edit hazard where union merges lose braces; appending a
|
|
11
|
+
* section of this size to it would make a bad merge materially worse and would
|
|
12
|
+
* put a second copy of this markup somewhere no test renders. The console
|
|
13
|
+
* gains a small block that asks the server for this string, so the file grows
|
|
14
|
+
* by tens of lines rather than hundreds, and opening `ui/index.html` straight
|
|
15
|
+
* from disk still works — the tab then says, in the report's own vocabulary,
|
|
16
|
+
* that it could not be derived without a server rather than showing an empty
|
|
17
|
+
* panel.
|
|
18
|
+
*
|
|
19
|
+
* Pure and total: report in, string out, no I/O, so the same emitter output
|
|
20
|
+
* always produces the same bytes.
|
|
21
|
+
* @module cli/gate-report-fragment
|
|
22
|
+
*/
|
|
23
|
+
import { chip, escapeHtml } from "./gate-report-html.js";
|
|
24
|
+
import { gateRow } from "./gate-report-rows.js";
|
|
25
|
+
import { agentHooksSection, requiredContextsSection, rulesetSection, summarySection, upstreamSection, } from "./gate-report-sections.js";
|
|
26
|
+
import { GATE_REPORT_STYLE } from "./gate-report-style.js";
|
|
27
|
+
/** The class every rule in the report's stylesheet is scoped to. */
|
|
28
|
+
export const GATE_REPORT_ROOT_CLASS = "lisa-gate-report";
|
|
29
|
+
/**
|
|
30
|
+
* The legend, which is where the three states are named for the reader.
|
|
31
|
+
* @returns A block of HTML
|
|
32
|
+
*/
|
|
33
|
+
function legend() {
|
|
34
|
+
return [
|
|
35
|
+
'<div class="lgr-legend">',
|
|
36
|
+
`<span><span class="lgr-state lgr-required">must</span> declared required</span>`,
|
|
37
|
+
`<span><span class="lgr-state lgr-optional">tells</span> declared optional</span>`,
|
|
38
|
+
`<span><span class="lgr-state lgr-off">off</span> declared off — different from never declared</span>`,
|
|
39
|
+
`<span><span class="lgr-state lgr-undeclared">not declared</span> the settings file never mentions it here</span>`,
|
|
40
|
+
`<span>${chip("b-A", "A")} declared, and something reads the declaration</span>`,
|
|
41
|
+
`<span>${chip("b-B", "B")} something runs it anyway; the settings file has no say</span>`,
|
|
42
|
+
`<span>${chip("b-C", "C")} declared, but nothing can run it</span>`,
|
|
43
|
+
`<span>${chip("b-D", "D")} nothing declares it and nothing runs it</span>`,
|
|
44
|
+
`<span>${chip("unknown", "not checked here")} this run could not determine it — NOT a pass</span>`,
|
|
45
|
+
"</div>",
|
|
46
|
+
].join("");
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The footer, which names what the report was derived from.
|
|
50
|
+
* @param report - The whole report
|
|
51
|
+
* @returns A block of HTML
|
|
52
|
+
*/
|
|
53
|
+
function footer(report) {
|
|
54
|
+
const runner = report.runner.state === "verified" ? report.runner.value : "unknown";
|
|
55
|
+
const problems = report.declarationProblems.length === 0
|
|
56
|
+
? ""
|
|
57
|
+
: ` · <strong>${report.declarationProblems.length} declaration problem(s)</strong>: ${escapeHtml(report.declarationProblems.join("; "))}`;
|
|
58
|
+
const facade = report.facadeSource.present
|
|
59
|
+
? `the workflow file was read from this checkout (${report.facadeSource.files.length} workflow file(s))`
|
|
60
|
+
: "this project holds no copy of the workflow, so what each cloud job does with a declaration could not be read";
|
|
61
|
+
return `<div class="lgr-foot"><p>Report format v${report.version} · registry read from the running Lisa package · runner <code>${escapeHtml(runner)}</code> · ${escapeHtml(facade)}${problems}</p></div>`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Render the report as a fragment for the console tab.
|
|
65
|
+
* @param report - The emitter's output
|
|
66
|
+
* @param projectLabel - How to name the project being reported on
|
|
67
|
+
* @returns HTML with no document wrapper, safe to inject into the console
|
|
68
|
+
*/
|
|
69
|
+
export function renderGateReportFragment(report, projectLabel) {
|
|
70
|
+
const axis = report.momentAxis;
|
|
71
|
+
const head = axis
|
|
72
|
+
.map(moment => `<th class="lgr-m">${escapeHtml(moment)}</th>`)
|
|
73
|
+
.join("");
|
|
74
|
+
return [
|
|
75
|
+
`<div class="${GATE_REPORT_ROOT_CLASS}">`,
|
|
76
|
+
`<style>${GATE_REPORT_STYLE}</style>`,
|
|
77
|
+
`<p class="lgr-sub">Derived, not written. Every number below comes from ${escapeHtml(projectLabel)}'s own settings file, package scripts, git hooks and workflows, joined against Lisa's check registry. Nothing here is a language model's summary of those files.</p>`,
|
|
78
|
+
summarySection(report),
|
|
79
|
+
"<h2>Every check, and what governs it</h2>",
|
|
80
|
+
'<p class="lgr-lede">One row per check. One column per moment this project can declare a check at — there is no bare "deploy" column, because Lisa has no such moment: the deploy families take an environment suffix and only appear once a project names one.</p>',
|
|
81
|
+
legend(),
|
|
82
|
+
'<div class="lgr-scroll"><table>',
|
|
83
|
+
`<thead><tr><th>Check</th><th>What a pass proves</th><th>Command</th>${head}<th class="lgr-m">Blocks a merge</th><th>Cloud job</th></tr></thead>`,
|
|
84
|
+
`<tbody>${report.gates.map(row => gateRow(row, axis)).join("")}</tbody>`,
|
|
85
|
+
"</table></div>",
|
|
86
|
+
"<h2>What your settings imply, against what the repository requires</h2>",
|
|
87
|
+
'<p class="lgr-lede">The contexts the settings file implies, beside the ones the repository\'s branch-protection rules really require. Nothing compares these two automatically, so they are only ever equal by hand.</p>',
|
|
88
|
+
rulesetSection(report),
|
|
89
|
+
"<h2>What else gates my merges, and where does it come from</h2>",
|
|
90
|
+
'<p class="lgr-lede">Everything above describes Lisa\'s own jobs. This is every required check standing between a change and a merge, whoever put it there — including the ones Lisa neither ships nor governs.</p>',
|
|
91
|
+
requiredContextsSection(report),
|
|
92
|
+
"<h2>What runs on every edit</h2>",
|
|
93
|
+
agentHooksSection(report),
|
|
94
|
+
`<h2>${report.projectIsUpstream ? "Lisa's own limitations — and this project is Lisa" : "Not this project's — Lisa's"}</h2>`,
|
|
95
|
+
upstreamSection(report),
|
|
96
|
+
footer(report),
|
|
97
|
+
"</div>",
|
|
98
|
+
].join("");
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=gate-report-fragment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-fragment.js","sourceRoot":"","sources":["../../src/cli/gate-report-fragment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The report's HTML primitives.
|
|
3
|
+
*
|
|
4
|
+
* One escaper and one chip vocabulary, shared by every renderer, so a state
|
|
5
|
+
* cannot acquire a second spelling. The rule the chips exist to hold: an
|
|
6
|
+
* `unknown` must never look like a pass, and — the gap that shipped in the
|
|
7
|
+
* first cut — it must never look like nothing either. A caller that omits a
|
|
8
|
+
* chip because it had nothing to show has invented a fourth outcome the
|
|
9
|
+
* three-state design never sanctioned, and silence is the one outcome a reader
|
|
10
|
+
* cannot tell from "fine".
|
|
11
|
+
* @module cli/gate-report-html
|
|
12
|
+
*/
|
|
13
|
+
import type { Finding } from "./gate-report-types.js";
|
|
14
|
+
/**
|
|
15
|
+
* Escape a string for interpolation into HTML.
|
|
16
|
+
* @param value - Raw text
|
|
17
|
+
* @returns Escaped text
|
|
18
|
+
*/
|
|
19
|
+
export declare function escapeHtml(value: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* One chip.
|
|
22
|
+
* @param variant - The chip's state class
|
|
23
|
+
* @param text - Its label
|
|
24
|
+
* @param title - Hover text explaining it
|
|
25
|
+
* @returns One chip of HTML
|
|
26
|
+
*/
|
|
27
|
+
export declare function chip(variant: string, text: string, title?: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* The chip for a finding this run could not determine.
|
|
30
|
+
*
|
|
31
|
+
* Carries the human message as hover text rather than dropping it: a report
|
|
32
|
+
* that says "not checked here" without saying why is indistinguishable from a
|
|
33
|
+
* bug in the report.
|
|
34
|
+
* @param finding - An unknown or not-applicable finding
|
|
35
|
+
* @param label - What to call it
|
|
36
|
+
* @returns One chip of HTML
|
|
37
|
+
*/
|
|
38
|
+
export declare function unknownChip(finding: Extract<Finding<unknown>, {
|
|
39
|
+
reason: string;
|
|
40
|
+
}>, label?: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* One monospaced fragment.
|
|
43
|
+
* @param value - Raw text
|
|
44
|
+
* @returns The text inside a `code` element, escaped
|
|
45
|
+
*/
|
|
46
|
+
export declare function code(value: string): string;
|
|
47
|
+
//# sourceMappingURL=gate-report-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-html.d.ts","sourceRoot":"","sources":["../../src/cli/gate-report-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAWtD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAGtE;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EACtD,KAAK,SAAqB,GACzB,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Characters that must not reach the browser as markup. */
|
|
2
|
+
const ESCAPES = {
|
|
3
|
+
"&": "&",
|
|
4
|
+
"<": "<",
|
|
5
|
+
">": ">",
|
|
6
|
+
'"': """,
|
|
7
|
+
"'": "'",
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Escape a string for interpolation into HTML.
|
|
11
|
+
* @param value - Raw text
|
|
12
|
+
* @returns Escaped text
|
|
13
|
+
*/
|
|
14
|
+
export function escapeHtml(value) {
|
|
15
|
+
return value.replace(/[&<>"']/g, character => ESCAPES[character] ?? character);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* One chip.
|
|
19
|
+
* @param variant - The chip's state class
|
|
20
|
+
* @param text - Its label
|
|
21
|
+
* @param title - Hover text explaining it
|
|
22
|
+
* @returns One chip of HTML
|
|
23
|
+
*/
|
|
24
|
+
export function chip(variant, text, title = "") {
|
|
25
|
+
const attribute = title === "" ? "" : ` title="${escapeHtml(title)}"`;
|
|
26
|
+
return `<span class="lgr-chip lgr-${escapeHtml(variant)}"${attribute}>${escapeHtml(text)}</span>`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The chip for a finding this run could not determine.
|
|
30
|
+
*
|
|
31
|
+
* Carries the human message as hover text rather than dropping it: a report
|
|
32
|
+
* that says "not checked here" without saying why is indistinguishable from a
|
|
33
|
+
* bug in the report.
|
|
34
|
+
* @param finding - An unknown or not-applicable finding
|
|
35
|
+
* @param label - What to call it
|
|
36
|
+
* @returns One chip of HTML
|
|
37
|
+
*/
|
|
38
|
+
export function unknownChip(finding, label = "not checked here") {
|
|
39
|
+
return chip("unknown", label, finding.message);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* One monospaced fragment.
|
|
43
|
+
* @param value - Raw text
|
|
44
|
+
* @returns The text inside a `code` element, escaped
|
|
45
|
+
*/
|
|
46
|
+
export function code(value) {
|
|
47
|
+
return `<code>${escapeHtml(value)}</code>`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=gate-report-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-html.js","sourceRoot":"","sources":["../../src/cli/gate-report-html.ts"],"names":[],"mappings":"AAcA,4DAA4D;AAC5D,MAAM,OAAO,GAAqC;IAChD,GAAG,EAAE,OAAO;IACZ,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,OAAO;CACb,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAClB,UAAU,EACV,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,SAAS,CAC7C,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAC,OAAe,EAAE,IAAY,EAAE,KAAK,GAAG,EAAE;IAC5D,MAAM,SAAS,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;IACtE,OAAO,6BAA6B,UAAU,CAAC,OAAO,CAAC,IAAI,SAAS,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;AACpG,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CACzB,OAAsD,EACtD,KAAK,GAAG,kBAAkB;IAE1B,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,KAAa;IAChC,OAAO,SAAS,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { FacadeFacts } from "./gate-report-facade.js";
|
|
2
|
+
import type { GateRegistryModule } from "./gate-report-registry.js";
|
|
3
|
+
import type { Finding, MergeBlock, RequiredContextRow, RulesetComparison } from "./gate-report-types.js";
|
|
4
|
+
/** Everything the joins need about this run. */
|
|
5
|
+
export interface JoinContext {
|
|
6
|
+
/** The shipped registry. */
|
|
7
|
+
readonly registry: GateRegistryModule;
|
|
8
|
+
/** The project's gates block. */
|
|
9
|
+
readonly gates: Record<string, unknown>;
|
|
10
|
+
/** The live required contexts, or an unknown. */
|
|
11
|
+
readonly contexts: Finding<readonly string[]>;
|
|
12
|
+
/** What the project's own workflows say. */
|
|
13
|
+
readonly facade: FacadeFacts;
|
|
14
|
+
/** The moment a ruleset guards. */
|
|
15
|
+
readonly mergeMoment: string;
|
|
16
|
+
/** The workflow name a run gate's context is built from. */
|
|
17
|
+
readonly workflowName: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The Tier 2 answer for one cell, never defaulted to a verdict.
|
|
21
|
+
* @param context - The join inputs
|
|
22
|
+
* @returns A resolver for one cell's expected context
|
|
23
|
+
*/
|
|
24
|
+
export declare function mergeBlockResolver(context: JoinContext): (moment: string, expectedContext: string | null) => Finding<MergeBlock>;
|
|
25
|
+
/**
|
|
26
|
+
* The ruleset comparison, or the same unknown the contexts came back with.
|
|
27
|
+
* @param context - The join inputs
|
|
28
|
+
* @returns The comparison
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildRulesetFinding(context: JoinContext): Finding<RulesetComparison>;
|
|
31
|
+
/**
|
|
32
|
+
* Every context a merge is blocked on, with who owns it.
|
|
33
|
+
* @param context - The join inputs
|
|
34
|
+
* @returns One row per required context, or the same unknown
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildRequiredContexts(context: JoinContext): Finding<readonly RequiredContextRow[]>;
|
|
37
|
+
//# sourceMappingURL=gate-report-joins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-joins.d.ts","sourceRoot":"","sources":["../../src/cli/gate-report-joins.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,OAAO,KAAK,EACV,OAAO,EACP,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IAC9C,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,mCAAmC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAkBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,WAAW,GACnB,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,UAAU,CAAC,CAwBzE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,iBAAiB,CAAC,CAe5B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAaxC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The joins between one project's declarations and the world outside it.
|
|
3
|
+
*
|
|
4
|
+
* Three of them, and each is a place two sources of truth are compared for the
|
|
5
|
+
* first time: the ruleset against the declaration (#2854's finding — nothing
|
|
6
|
+
* compares these today, so they are only ever equal by hand), every required
|
|
7
|
+
* context against who owns it, and one gate's implied context against the
|
|
8
|
+
* moment a ruleset can actually guard.
|
|
9
|
+
*
|
|
10
|
+
* Kept out of the report assembly because the assembly is a list of steps and
|
|
11
|
+
* these are the reasoning. Every one of them carries an unknown through rather
|
|
12
|
+
* than resolving it: a run that could not read branch protection has nothing to
|
|
13
|
+
* compare, and an empty comparison would report agreement.
|
|
14
|
+
* @module cli/gate-report-joins
|
|
15
|
+
*/
|
|
16
|
+
import { classifyRequiredContexts, lisaContextUniverse, } from "./gate-report-contexts.js";
|
|
17
|
+
import { compareContexts } from "./gate-report-ruleset.js";
|
|
18
|
+
/**
|
|
19
|
+
* The contexts a gates block implies at the merge moment.
|
|
20
|
+
* @param context - The join inputs
|
|
21
|
+
* @returns The contexts, or null when the block cannot be resolved
|
|
22
|
+
*/
|
|
23
|
+
function declaredContexts(context) {
|
|
24
|
+
try {
|
|
25
|
+
return context.registry.contextsFor(context.gates, {
|
|
26
|
+
moment: context.mergeMoment,
|
|
27
|
+
workflowName: context.workflowName,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The Tier 2 answer for one cell, never defaulted to a verdict.
|
|
36
|
+
* @param context - The join inputs
|
|
37
|
+
* @returns A resolver for one cell's expected context
|
|
38
|
+
*/
|
|
39
|
+
export function mergeBlockResolver(context) {
|
|
40
|
+
return (moment, expectedContext) => {
|
|
41
|
+
if (moment !== context.mergeMoment) {
|
|
42
|
+
return {
|
|
43
|
+
state: "not-applicable",
|
|
44
|
+
reason: "moment-produces-no-merge-context",
|
|
45
|
+
message: `A ruleset guards a merge, and only the ${context.mergeMoment} gate set produces the status contexts it names. A declaration at ${moment} is enforced by a hook, not by branch protection.`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (expectedContext === null) {
|
|
49
|
+
return {
|
|
50
|
+
state: "not-applicable",
|
|
51
|
+
reason: "no-required-declaration",
|
|
52
|
+
message: "Only a `required` declaration produces a status context, so there is nothing here for a ruleset to require.",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (context.contexts.state !== "verified")
|
|
56
|
+
return context.contexts;
|
|
57
|
+
const required = context.contexts.value.includes(expectedContext);
|
|
58
|
+
return {
|
|
59
|
+
state: "verified",
|
|
60
|
+
value: { required, context: required ? expectedContext : null },
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The ruleset comparison, or the same unknown the contexts came back with.
|
|
66
|
+
* @param context - The join inputs
|
|
67
|
+
* @returns The comparison
|
|
68
|
+
*/
|
|
69
|
+
export function buildRulesetFinding(context) {
|
|
70
|
+
if (context.contexts.state !== "verified")
|
|
71
|
+
return context.contexts;
|
|
72
|
+
const declared = declaredContexts(context);
|
|
73
|
+
if (declared === null) {
|
|
74
|
+
return {
|
|
75
|
+
state: "unknown",
|
|
76
|
+
reason: "declarations-unresolvable",
|
|
77
|
+
message: "The gates block could not be resolved, so the contexts it implies cannot be compared with the ruleset.",
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
state: "verified",
|
|
82
|
+
value: compareContexts(declared, context.contexts.value),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Every context a merge is blocked on, with who owns it.
|
|
87
|
+
* @param context - The join inputs
|
|
88
|
+
* @returns One row per required context, or the same unknown
|
|
89
|
+
*/
|
|
90
|
+
export function buildRequiredContexts(context) {
|
|
91
|
+
return classifyRequiredContexts(context.contexts, {
|
|
92
|
+
declared: declaredContexts(context) ?? [],
|
|
93
|
+
lisaUniverse: lisaContextUniverse({
|
|
94
|
+
gateIds: Object.entries(context.registry.REGISTRY)
|
|
95
|
+
.filter(([, gate]) => gate.moments.includes(context.mergeMoment))
|
|
96
|
+
.map(([id]) => id),
|
|
97
|
+
moment: context.mergeMoment,
|
|
98
|
+
workflowName: context.workflowName,
|
|
99
|
+
contextsFor: context.registry.contextsFor,
|
|
100
|
+
}),
|
|
101
|
+
projectContexts: context.facade.projectContexts,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=gate-report-joins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-joins.js","sourceRoot":"","sources":["../../src/cli/gate-report-joins.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type FacadeFacts } from "./gate-report-facade.js";
|
|
2
|
+
import type { Finding, MergeVerdict } from "./gate-report-types.js";
|
|
3
|
+
/** Everything one row's verdict is derived from. */
|
|
4
|
+
export interface MergeVerdictInputs {
|
|
5
|
+
/** The context this gate's own `required` declaration implies, if any. */
|
|
6
|
+
readonly expectedContext: string | null;
|
|
7
|
+
/** The task this gate resolves to at the merge moment. */
|
|
8
|
+
readonly task: string | null;
|
|
9
|
+
/** This gate's own CI job name, so another job's name can be told apart. */
|
|
10
|
+
readonly label: string;
|
|
11
|
+
/** The live required contexts, or an unknown. */
|
|
12
|
+
readonly required: Finding<readonly string[]>;
|
|
13
|
+
/** What the project's own workflows say. */
|
|
14
|
+
readonly facade: FacadeFacts;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Whether a merge is blocked on one gate, and under whose name.
|
|
18
|
+
* @param inputs - Verdict inputs
|
|
19
|
+
* @returns The verdict, or the honest refusal to give one
|
|
20
|
+
*/
|
|
21
|
+
export declare function mergeVerdict(inputs: MergeVerdictInputs): Finding<MergeVerdict>;
|
|
22
|
+
//# sourceMappingURL=gate-report-merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-report-merge.d.ts","sourceRoot":"","sources":["../../src/cli/gate-report-merge.ts"],"names":[],"mappings":"AAsBA,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEpE,oDAAoD;AACpD,MAAM,WAAW,kBAAkB;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IAC9C,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAsBD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,YAAY,CAAC,CA4BvB"}
|