@codyswann/lisa 4.42.6 → 4.43.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/README.md +4 -0
- package/all/copy-overwrite/scripts/check-orphaned-branches.mjs +7 -0
- package/all/copy-overwrite/scripts/lib/process-tree-runner.mjs +12 -2
- package/all/copy-overwrite/scripts/lisa-cross-worktree-guard.mjs +4 -0
- package/all/copy-overwrite/scripts/lisa-environment-prepare.mjs +2 -0
- package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.mjs +31 -3
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +4 -0
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +13 -0
- package/dist/cli/doctor-readiness-delivery.d.ts.map +1 -1
- package/dist/cli/doctor-readiness-delivery.js +13 -6
- package/dist/cli/doctor-readiness-delivery.js.map +1 -1
- package/dist/cli/doctor-readiness-deploy-outcome.d.ts +9 -0
- package/dist/cli/doctor-readiness-deploy-outcome.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-deploy-outcome.js +87 -0
- package/dist/cli/doctor-readiness-deploy-outcome.js.map +1 -0
- package/dist/cli/doctor-readiness-workflows.d.ts +8 -0
- package/dist/cli/doctor-readiness-workflows.d.ts.map +1 -1
- package/dist/cli/doctor-readiness-workflows.js +1 -0
- package/dist/cli/doctor-readiness-workflows.js.map +1 -1
- package/dist/configs/vitest/base.d.ts +1 -1
- package/dist/configs/vitest/base.d.ts.map +1 -1
- package/dist/configs/vitest/base.js +1 -0
- package/dist/configs/vitest/base.js.map +1 -1
- package/dist/configs/vitest/cdk.d.ts +2 -2
- package/dist/configs/vitest/cdk.d.ts.map +1 -1
- package/dist/configs/vitest/cdk.js +5 -2
- package/dist/configs/vitest/cdk.js.map +1 -1
- package/dist/configs/vitest/coverage-reports-directory.d.ts +47 -0
- package/dist/configs/vitest/coverage-reports-directory.d.ts.map +1 -0
- package/dist/configs/vitest/coverage-reports-directory.js +131 -0
- package/dist/configs/vitest/coverage-reports-directory.js.map +1 -0
- package/dist/configs/vitest/harper-fabric.d.ts +2 -2
- package/dist/configs/vitest/harper-fabric.d.ts.map +1 -1
- package/dist/configs/vitest/harper-fabric.js +5 -2
- package/dist/configs/vitest/harper-fabric.js.map +1 -1
- package/dist/configs/vitest/nestjs.d.ts +2 -2
- package/dist/configs/vitest/nestjs.d.ts.map +1 -1
- package/dist/configs/vitest/nestjs.js +5 -2
- package/dist/configs/vitest/nestjs.js.map +1 -1
- package/dist/configs/vitest/phaser.d.ts +2 -2
- package/dist/configs/vitest/phaser.d.ts.map +1 -1
- package/dist/configs/vitest/phaser.js +5 -2
- package/dist/configs/vitest/phaser.js.map +1 -1
- package/dist/configs/vitest/typescript.d.ts +2 -2
- package/dist/configs/vitest/typescript.d.ts.map +1 -1
- package/dist/configs/vitest/typescript.js +5 -2
- package/dist/configs/vitest/typescript.js.map +1 -1
- package/dist/core/deploy-release-dependence.d.ts +72 -0
- package/dist/core/deploy-release-dependence.d.ts.map +1 -0
- package/dist/core/deploy-release-dependence.js +236 -0
- package/dist/core/deploy-release-dependence.js.map +1 -0
- package/dist/core/github-actions-condition.d.ts +78 -0
- package/dist/core/github-actions-condition.d.ts.map +1 -0
- package/dist/core/github-actions-condition.js +307 -0
- package/dist/core/github-actions-condition.js.map +1 -0
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +24 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +45 -24
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/migrations/deploy-outcome-guard-edit.d.ts +11 -0
- package/dist/migrations/deploy-outcome-guard-edit.d.ts.map +1 -0
- package/dist/migrations/deploy-outcome-guard-edit.js +184 -0
- package/dist/migrations/deploy-outcome-guard-edit.js.map +1 -0
- package/dist/migrations/deploy-outcome-guard-yaml.d.ts +91 -0
- package/dist/migrations/deploy-outcome-guard-yaml.d.ts.map +1 -0
- package/dist/migrations/deploy-outcome-guard-yaml.js +180 -0
- package/dist/migrations/deploy-outcome-guard-yaml.js.map +1 -0
- package/dist/migrations/ensure-deploy-outcome-guard.d.ts +41 -0
- package/dist/migrations/ensure-deploy-outcome-guard.d.ts.map +1 -0
- package/dist/migrations/ensure-deploy-outcome-guard.js +238 -0
- package/dist/migrations/ensure-deploy-outcome-guard.js.map +1 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -0
- package/dist/migrations/index.js.map +1 -1
- package/expo/copy-overwrite/scripts/bdd/baseline.mjs +26 -7
- package/package.json +5 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/lisa/hooks/threshold-ratchet.mjs +6 -0
- package/plugins/lisa/hooks/worktree-binding-guard.mjs +31 -3
- package/plugins/lisa/scripts/design-variable-ids.mjs +2 -0
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/design-variable-ids.mjs +2 -0
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa-agy/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- 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-copilot/hooks/threshold-ratchet.mjs +6 -0
- package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +31 -3
- package/plugins/lisa-copilot/scripts/design-variable-ids.mjs +2 -0
- package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa-copilot/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/threshold-ratchet.mjs +6 -0
- package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +31 -3
- package/plugins/lisa-cursor/scripts/design-variable-ids.mjs +2 -0
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/lisa-cursor/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- 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/scripts/ingest-git.mjs +2 -0
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/scripts/ingest-git.mjs +2 -0
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/scripts/ingest-git.mjs +2 -0
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/scripts/ingest-git.mjs +2 -0
- package/plugins/src/base/hooks/threshold-ratchet.mjs +6 -0
- package/plugins/src/base/hooks/worktree-binding-guard.mjs +31 -3
- package/plugins/src/base/scripts/design-variable-ids.mjs +2 -0
- package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +11 -0
- package/plugins/src/base/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +3 -0
- package/plugins/src/base/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +3 -0
- package/plugins/src/base/skills/lisa-secrets-access/scripts/providers.mjs +4 -0
- package/plugins/src/base/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -0
- package/plugins/src/wiki/scripts/ingest-git.mjs +2 -0
- package/rails/copy-overwrite/scripts/check-threshold-ratchet.mjs +6 -0
- package/scripts/check-merge-driver-registration.mjs +2 -0
- package/scripts/check-probe-absence-direction.mjs +611 -0
- package/scripts/check-test-case-executed.mjs +184 -0
- package/scripts/install-generated-artifact-merge-driver.mjs +7 -1
- package/scripts/lib/shell-guard-refusal-coverage.mjs +18 -19
- package/typescript/copy-overwrite/scripts/check-threshold-ratchet.mjs +6 -0
- package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +4 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decide whether a job SKIPS because its release job did not succeed
|
|
3
|
+
* (CodySwannGT/lisa#3740).
|
|
4
|
+
*
|
|
5
|
+
* ## The shape being detected
|
|
6
|
+
*
|
|
7
|
+
* GitHub renders a skipped job as neutral and counts a skipped required check
|
|
8
|
+
* as satisfied. So a deploy that never happened leaves no signal anywhere: the
|
|
9
|
+
* branch still carries its release commit, every status field still says green,
|
|
10
|
+
* and nothing prompts anyone to go read CI history for skipped Deploy jobs. A
|
|
11
|
+
* consuming repository ran eight days that way (#3467).
|
|
12
|
+
*
|
|
13
|
+
* Two spellings produce it, and neither says anything about skipping:
|
|
14
|
+
*
|
|
15
|
+
* - **No `if:` at all.** GitHub ANDs an implicit `success()` onto the job, so a
|
|
16
|
+
* failed release skips it silently. (The rails template's form.)
|
|
17
|
+
* - **An `if:` that names a status function but conjoins
|
|
18
|
+
* `needs.<release>.result == 'success'`.** The status function suppresses the
|
|
19
|
+
* implicit AND, and then the conjunct reintroduces it by hand. (The expo
|
|
20
|
+
* template's form.)
|
|
21
|
+
*
|
|
22
|
+
* ## Why this is answered semantically rather than by pattern
|
|
23
|
+
*
|
|
24
|
+
* Matching those two spellings would find the two templates and miss the third
|
|
25
|
+
* spelling a host wrote by hand — and, worse, would flag a job that skips for a
|
|
26
|
+
* reason having nothing to do with the release. The question is not "does this
|
|
27
|
+
* condition contain a string" but **"does the release result decide whether
|
|
28
|
+
* this job runs"**, and that is answered by evaluating the condition twice:
|
|
29
|
+
*
|
|
30
|
+
* - **released:** the release job reports `success`.
|
|
31
|
+
* - **failed:** the release job reports `failure`.
|
|
32
|
+
*
|
|
33
|
+
* A job that runs under the first and skips under the second is skipping
|
|
34
|
+
* because of the release. A job that skips under both — an unconfigured
|
|
35
|
+
* stack, a path filter, a deliberate `if:` about something else — is skipping
|
|
36
|
+
* for its own reasons and is not this defect. That is the acceptance criteria's
|
|
37
|
+
* third scenario satisfied by construction rather than by a special case.
|
|
38
|
+
*
|
|
39
|
+
* ## The most-permissive assignment, and what it can miss
|
|
40
|
+
*
|
|
41
|
+
* Both evaluations need values for the paths the condition reads that are not
|
|
42
|
+
* the release result — another job's output, a `github.*` field, an input.
|
|
43
|
+
* Those are assigned the value that makes the surrounding comparison hold: a
|
|
44
|
+
* path compared for equality against a literal takes that literal, and anything
|
|
45
|
+
* else takes a non-empty placeholder. The reading is "assuming everything else
|
|
46
|
+
* about this repository is configured, does the release result decide it".
|
|
47
|
+
*
|
|
48
|
+
* Stated rather than implied: this is one assignment, not a search. A condition
|
|
49
|
+
* whose release dependence only appears under some *other* combination of
|
|
50
|
+
* values is not reported. Under-reporting is the deliberate direction — a check
|
|
51
|
+
* that flags a deploy job for a skip it does not have is one that gets turned
|
|
52
|
+
* off, and then the real instances go unreported too.
|
|
53
|
+
*
|
|
54
|
+
* A condition the evaluator cannot parse yields `unreadable`, never `false`.
|
|
55
|
+
* @module core/deploy-release-dependence
|
|
56
|
+
*/
|
|
57
|
+
import { jobRuns, tokenize, } from "./github-actions-condition.js";
|
|
58
|
+
/** Job ids and names that identify the job which cuts the release. */
|
|
59
|
+
const RELEASE_JOB = /(^|[_\-\s])(release|publish)([_\-\s]|$)/i;
|
|
60
|
+
/** Job ids and names that identify a job which ships to an environment. */
|
|
61
|
+
const DEPLOY_JOB = /deploy/i;
|
|
62
|
+
/** The value assigned to a free path with no equality comparison to borrow. */
|
|
63
|
+
const PLACEHOLDER = "lisa-permissive-placeholder";
|
|
64
|
+
/** Context roots whose values this analysis chooses, beyond `github.*`. */
|
|
65
|
+
const FREE_ROOTS = ["inputs"];
|
|
66
|
+
/**
|
|
67
|
+
* Whether an upstream job is the one that cuts the release.
|
|
68
|
+
*
|
|
69
|
+
* Name-based, and that is a stated limit rather than an oversight: a host free
|
|
70
|
+
* to name its jobs anything can name this one something with neither word in
|
|
71
|
+
* it, and such a job is not recognised. The alternative — treating every
|
|
72
|
+
* upstream job as release-like — would report a deploy that skips because an
|
|
73
|
+
* unrelated optional job failed, which is a different property.
|
|
74
|
+
* @param job - The candidate upstream job
|
|
75
|
+
* @returns True when the job looks like the release
|
|
76
|
+
*/
|
|
77
|
+
export function isReleaseJob(job) {
|
|
78
|
+
return RELEASE_JOB.test(job.id) || RELEASE_JOB.test(job.name ?? "");
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Whether a job ships something to an environment.
|
|
82
|
+
*
|
|
83
|
+
* A declared `environment:` is the name-independent half: GitHub's deployment
|
|
84
|
+
* environments exist for exactly this kind of job, so a host that used one has
|
|
85
|
+
* said what the job is without Lisa having to guess from its id.
|
|
86
|
+
* @param job - The candidate job
|
|
87
|
+
* @returns True when the job looks like a deploy
|
|
88
|
+
*/
|
|
89
|
+
export function isDeployJob(job) {
|
|
90
|
+
return (DEPLOY_JOB.test(job.id) ||
|
|
91
|
+
DEPLOY_JOB.test(job.name ?? "") ||
|
|
92
|
+
(job.environment ?? []).length > 0);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The literal a path is compared against, when the comparison is an equality.
|
|
96
|
+
* @param tokens - The tokenized condition
|
|
97
|
+
* @param index - Position of the path token
|
|
98
|
+
* @returns The literal without its quotes, or null when there is none
|
|
99
|
+
*/
|
|
100
|
+
function comparedLiteral(tokens, index) {
|
|
101
|
+
const quoted = (token) => token !== undefined && token.startsWith("'") ? token.slice(1, -1) : null;
|
|
102
|
+
if (tokens[index + 1] === "==")
|
|
103
|
+
return quoted(tokens[index + 2]);
|
|
104
|
+
if (tokens[index - 1] === "==")
|
|
105
|
+
return quoted(tokens[index - 2]);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Choose a value for every non-`needs.*.result` path the condition reads.
|
|
110
|
+
*
|
|
111
|
+
* A path compared for equality against a string literal takes that literal, so
|
|
112
|
+
* the comparison holds; every other path takes a non-empty placeholder, which
|
|
113
|
+
* is truthy and satisfies an inequality. The result is the run in which
|
|
114
|
+
* everything except the release is configured as the condition wants it.
|
|
115
|
+
* @param condition - The raw `if:` text
|
|
116
|
+
* @returns The chosen values, keyed by full dotted path
|
|
117
|
+
*/
|
|
118
|
+
function permissiveAssignment(condition) {
|
|
119
|
+
const tokens = tokenize(condition
|
|
120
|
+
.trim()
|
|
121
|
+
.replace(/^\$\{\{/, "")
|
|
122
|
+
.replace(/\}\}$/, ""));
|
|
123
|
+
const isPath = (token) => /^[A-Za-z_][A-Za-z0-9_.-]*$/.test(token) && !token.endsWith(".result");
|
|
124
|
+
return Object.fromEntries(tokens.flatMap((token, index) => isPath(token)
|
|
125
|
+
? [[token, comparedLiteral(tokens, index) ?? PLACEHOLDER]]
|
|
126
|
+
: []));
|
|
127
|
+
}
|
|
128
|
+
/** An assignment with nothing in it, and the seed for the fold below. */
|
|
129
|
+
const EMPTY_ASSIGNMENT = {
|
|
130
|
+
outputs: {},
|
|
131
|
+
github: {},
|
|
132
|
+
inputs: {},
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Route one chosen path into the half of the scenario that owns it.
|
|
136
|
+
* @param split - The assignment built so far
|
|
137
|
+
* @param entry - One `[path, value]` pair
|
|
138
|
+
* @returns The assignment with that pair routed
|
|
139
|
+
*/
|
|
140
|
+
function routePath(split, entry) {
|
|
141
|
+
const [path, value] = entry;
|
|
142
|
+
const segments = path.split(".");
|
|
143
|
+
const root = segments[0] ?? "";
|
|
144
|
+
if (root === "needs" && segments[2] === "outputs") {
|
|
145
|
+
const job = segments[1] ?? "";
|
|
146
|
+
return {
|
|
147
|
+
...split,
|
|
148
|
+
outputs: {
|
|
149
|
+
...split.outputs,
|
|
150
|
+
[job]: { ...split.outputs[job], [segments[3] ?? ""]: value },
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (root === "github") {
|
|
155
|
+
return { ...split, github: { ...split.github, [path]: value } };
|
|
156
|
+
}
|
|
157
|
+
return FREE_ROOTS.includes(root)
|
|
158
|
+
? { ...split, inputs: { ...split.inputs, [segments[1] ?? ""]: value } }
|
|
159
|
+
: split;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Split the permissive assignment into the shapes the evaluator consumes.
|
|
163
|
+
* @param chosen - The permissive assignment
|
|
164
|
+
* @returns The `needs` outputs, `github.*` values and `inputs.*` values
|
|
165
|
+
*/
|
|
166
|
+
function splitAssignment(chosen) {
|
|
167
|
+
return Object.entries(chosen).reduce((split, entry) => routePath(split, entry), EMPTY_ASSIGNMENT);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Build the run state for one release outcome.
|
|
171
|
+
* @param job - The job under analysis
|
|
172
|
+
* @param release - The release job's id
|
|
173
|
+
* @param releaseResult - What the release job reports in this scenario
|
|
174
|
+
* @param chosen - The permissive assignment
|
|
175
|
+
* @returns A scenario the evaluator can be run against
|
|
176
|
+
*/
|
|
177
|
+
function scenarioFor(job, release, releaseResult, chosen) {
|
|
178
|
+
const { outputs, github, inputs } = splitAssignment(chosen);
|
|
179
|
+
return {
|
|
180
|
+
needs: Object.fromEntries(job.needs.map(id => [
|
|
181
|
+
id,
|
|
182
|
+
{
|
|
183
|
+
result: id === release ? releaseResult : "success",
|
|
184
|
+
outputs: outputs[id] ?? {},
|
|
185
|
+
},
|
|
186
|
+
])),
|
|
187
|
+
github,
|
|
188
|
+
inputs,
|
|
189
|
+
cancelled: false,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Decide whether the release result is what makes this job skip.
|
|
194
|
+
* @param job - The job under analysis
|
|
195
|
+
* @param release - The id of the upstream release job
|
|
196
|
+
* @returns What the two evaluations established
|
|
197
|
+
*/
|
|
198
|
+
export function releaseDependence(job, release) {
|
|
199
|
+
try {
|
|
200
|
+
const chosen = permissiveAssignment(job.ifCondition);
|
|
201
|
+
const runsWhenReleased = jobRuns(job.ifCondition, scenarioFor(job, release, "success", chosen));
|
|
202
|
+
const runsWhenFailed = jobRuns(job.ifCondition, scenarioFor(job, release, "failure", chosen));
|
|
203
|
+
return runsWhenReleased && !runsWhenFailed
|
|
204
|
+
? { kind: "skips-on-failed-release", release }
|
|
205
|
+
: { kind: "independent" };
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
return {
|
|
209
|
+
kind: "unreadable",
|
|
210
|
+
reason: error.message,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Find every deploy job in one workflow that skips when its release fails.
|
|
216
|
+
* @param jobs - Every job the workflow declares
|
|
217
|
+
* @returns The deploy jobs that go silent on a failed release
|
|
218
|
+
*/
|
|
219
|
+
export function deployJobsSkippedByFailedRelease(jobs) {
|
|
220
|
+
const releases = new Set(jobs.filter(isReleaseJob).map(job => job.id));
|
|
221
|
+
return jobs.flatMap(job => {
|
|
222
|
+
if (releases.has(job.id) || !isDeployJob(job))
|
|
223
|
+
return [];
|
|
224
|
+
// Every release-like upstream, not merely the first. A deploy that needs
|
|
225
|
+
// two of them gates on ONE, and which one is not the order `needs:` happens
|
|
226
|
+
// to list. Taking the first and stopping reported `independent` whenever the
|
|
227
|
+
// gating release was listed second — the defect silently unreported, and the
|
|
228
|
+
// migration declining to repair it (CodeRabbit on CodySwannGT/lisa#3740).
|
|
229
|
+
const release = job.needs.find(id => releases.has(id) &&
|
|
230
|
+
releaseDependence(job, id).kind === "skips-on-failed-release");
|
|
231
|
+
if (release === undefined)
|
|
232
|
+
return [];
|
|
233
|
+
return [{ job, release }];
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=deploy-release-dependence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-release-dependence.js","sourceRoot":"","sources":["../../src/core/deploy-release-dependence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A deliberately small evaluator for the subset of GitHub Actions expression
|
|
3
|
+
* syntax that Lisa's deploy workflows use in a job-level `if:`, plus the rule
|
|
4
|
+
* that turns the result into "this job RAN" or "this job was SKIPPED".
|
|
5
|
+
*
|
|
6
|
+
* It exists because the defect in #3467 is invisible to anything that only
|
|
7
|
+
* reads the YAML for the presence or absence of a substring. What went wrong
|
|
8
|
+
* was a job OUTCOME — a deploy that was skipped rather than failed — and an
|
|
9
|
+
* outcome is what has to be established. Lisa never runs a host's deploy
|
|
10
|
+
* workflow itself, so no observation of CI can stand in for that; the
|
|
11
|
+
* expression has to be evaluated against a scenario.
|
|
12
|
+
*
|
|
13
|
+
* ## Why this is production code and not a test helper
|
|
14
|
+
*
|
|
15
|
+
* It began as one, under `tests/integration/`. It moved here when #3740 needed
|
|
16
|
+
* the same question answered in a host repository — *would this job skip
|
|
17
|
+
* because the release failed?* — by `lisa doctor` and by the migration that
|
|
18
|
+
* repairs an already-seeded `deploy.yml`. Reimplementing GitHub's implicit
|
|
19
|
+
* `success()` rule a second time in `src/` would have put two subtly different
|
|
20
|
+
* copies of one semantics in the tree, which is the drift this repository
|
|
21
|
+
* repeatedly pays for. There is one implementation, and the test that made it
|
|
22
|
+
* imports it from here.
|
|
23
|
+
*
|
|
24
|
+
* The evaluator THROWS on anything outside the supported subset rather than
|
|
25
|
+
* guessing. An expression it cannot parse must never quietly evaluate to a
|
|
26
|
+
* plausible-looking boolean: a caller that cannot read a condition must say so,
|
|
27
|
+
* because reporting a confident verdict about an expression nobody understood
|
|
28
|
+
* is the failure mode this whole family of checks exists to catch.
|
|
29
|
+
*
|
|
30
|
+
* Supported: `&&`, `||`, `!`, `==`, `!=`, parentheses, single-quoted strings,
|
|
31
|
+
* `true`/`false`, the status functions `always()` / `cancelled()` / `success()`
|
|
32
|
+
* / `failure()`, the string functions `startsWith()` / `contains()`, and
|
|
33
|
+
* context paths under `needs.`, `github.` and `inputs.`.
|
|
34
|
+
* @module core/github-actions-condition
|
|
35
|
+
*/
|
|
36
|
+
/** The four conclusions a `needs` job can report to a dependent job. */
|
|
37
|
+
export type JobResult = "success" | "failure" | "cancelled" | "skipped";
|
|
38
|
+
/** One upstream job as a dependent job sees it. */
|
|
39
|
+
export interface NeedsEntry {
|
|
40
|
+
readonly result: JobResult;
|
|
41
|
+
readonly outputs?: Readonly<Record<string, string>>;
|
|
42
|
+
}
|
|
43
|
+
/** The run state a job-level `if:` is evaluated against. */
|
|
44
|
+
export interface RunScenario {
|
|
45
|
+
readonly needs: Readonly<Record<string, NeedsEntry>>;
|
|
46
|
+
/** Flattened `github.*` paths, e.g. `github.event.head_commit.message`. */
|
|
47
|
+
readonly github: Readonly<Record<string, string>>;
|
|
48
|
+
/** Flattened `inputs.*` values. */
|
|
49
|
+
readonly inputs?: Readonly<Record<string, string>>;
|
|
50
|
+
/** Whether an operator cancelled the run. */
|
|
51
|
+
readonly cancelled: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Split an expression into tokens.
|
|
55
|
+
* @param source - Raw `if:` text, with any `${{ }}` wrapper already stripped
|
|
56
|
+
* @returns The token list
|
|
57
|
+
*/
|
|
58
|
+
export declare function tokenize(source: string): readonly string[];
|
|
59
|
+
/**
|
|
60
|
+
* Evaluate a job-level `if:` under one scenario.
|
|
61
|
+
* @param condition - The raw `if:` text
|
|
62
|
+
* @param scenario - The run state
|
|
63
|
+
* @returns Whether the condition holds
|
|
64
|
+
*/
|
|
65
|
+
export declare function evaluateCondition(condition: string, scenario: RunScenario): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Whether a job with this `if:` runs, applying GitHub's rule that an implicit
|
|
68
|
+
* `success()` is ANDed on unless the condition names a status function.
|
|
69
|
+
*
|
|
70
|
+
* That implicit AND is the whole mechanism behind the rails half of #3467: the
|
|
71
|
+
* condition there said nothing about the release at all, and still skipped when
|
|
72
|
+
* the release failed.
|
|
73
|
+
* @param condition - The raw `if:` text, or `""` when the job has none
|
|
74
|
+
* @param scenario - The run state
|
|
75
|
+
* @returns True when the job runs, false when GitHub skips it
|
|
76
|
+
*/
|
|
77
|
+
export declare function jobRuns(condition: string, scenario: RunScenario): boolean;
|
|
78
|
+
//# sourceMappingURL=github-actions-condition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-actions-condition.d.ts","sourceRoot":"","sources":["../../src/core/github-actions-condition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAExE,mDAAmD;AACnD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD;AAED,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACrD,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,mCAAmC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,6CAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AA6CD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAO1D;AAyOD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,WAAW,GACpB,OAAO,CAYT;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAYzE"}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A deliberately small evaluator for the subset of GitHub Actions expression
|
|
3
|
+
* syntax that Lisa's deploy workflows use in a job-level `if:`, plus the rule
|
|
4
|
+
* that turns the result into "this job RAN" or "this job was SKIPPED".
|
|
5
|
+
*
|
|
6
|
+
* It exists because the defect in #3467 is invisible to anything that only
|
|
7
|
+
* reads the YAML for the presence or absence of a substring. What went wrong
|
|
8
|
+
* was a job OUTCOME — a deploy that was skipped rather than failed — and an
|
|
9
|
+
* outcome is what has to be established. Lisa never runs a host's deploy
|
|
10
|
+
* workflow itself, so no observation of CI can stand in for that; the
|
|
11
|
+
* expression has to be evaluated against a scenario.
|
|
12
|
+
*
|
|
13
|
+
* ## Why this is production code and not a test helper
|
|
14
|
+
*
|
|
15
|
+
* It began as one, under `tests/integration/`. It moved here when #3740 needed
|
|
16
|
+
* the same question answered in a host repository — *would this job skip
|
|
17
|
+
* because the release failed?* — by `lisa doctor` and by the migration that
|
|
18
|
+
* repairs an already-seeded `deploy.yml`. Reimplementing GitHub's implicit
|
|
19
|
+
* `success()` rule a second time in `src/` would have put two subtly different
|
|
20
|
+
* copies of one semantics in the tree, which is the drift this repository
|
|
21
|
+
* repeatedly pays for. There is one implementation, and the test that made it
|
|
22
|
+
* imports it from here.
|
|
23
|
+
*
|
|
24
|
+
* The evaluator THROWS on anything outside the supported subset rather than
|
|
25
|
+
* guessing. An expression it cannot parse must never quietly evaluate to a
|
|
26
|
+
* plausible-looking boolean: a caller that cannot read a condition must say so,
|
|
27
|
+
* because reporting a confident verdict about an expression nobody understood
|
|
28
|
+
* is the failure mode this whole family of checks exists to catch.
|
|
29
|
+
*
|
|
30
|
+
* Supported: `&&`, `||`, `!`, `==`, `!=`, parentheses, single-quoted strings,
|
|
31
|
+
* `true`/`false`, the status functions `always()` / `cancelled()` / `success()`
|
|
32
|
+
* / `failure()`, the string functions `startsWith()` / `contains()`, and
|
|
33
|
+
* context paths under `needs.`, `github.` and `inputs.`.
|
|
34
|
+
* @module core/github-actions-condition
|
|
35
|
+
*/
|
|
36
|
+
/** The status functions whose presence removes GitHub's implicit `success()`. */
|
|
37
|
+
const STATUS_FUNCTIONS = ["always", "cancelled", "success", "failure"];
|
|
38
|
+
/** The two-character operators, matched before the single-character ones. */
|
|
39
|
+
const PAIR_OPERATORS = ["&&", "||", "==", "!="];
|
|
40
|
+
/**
|
|
41
|
+
* Read the single token at the head of the text.
|
|
42
|
+
* @param text - Expression text with leading whitespace already removed
|
|
43
|
+
* @returns The token, quotes included for a string literal
|
|
44
|
+
*/
|
|
45
|
+
function headToken(text) {
|
|
46
|
+
if (text.startsWith("'")) {
|
|
47
|
+
const close = text.indexOf("'", 1);
|
|
48
|
+
if (close < 0) {
|
|
49
|
+
throw new Error(`unterminated string in expression: ${text}`);
|
|
50
|
+
}
|
|
51
|
+
return text.slice(0, close + 1);
|
|
52
|
+
}
|
|
53
|
+
if (PAIR_OPERATORS.includes(text.slice(0, 2))) {
|
|
54
|
+
return text.slice(0, 2);
|
|
55
|
+
}
|
|
56
|
+
if ("()!,".includes(text.slice(0, 1))) {
|
|
57
|
+
return text.slice(0, 1);
|
|
58
|
+
}
|
|
59
|
+
const word = /^[A-Za-z0-9_.-]+/.exec(text)?.[0];
|
|
60
|
+
if (!word) {
|
|
61
|
+
throw new Error(`unsupported character '${text.slice(0, 1)}' in expression`);
|
|
62
|
+
}
|
|
63
|
+
return word;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Split an expression into tokens.
|
|
67
|
+
* @param source - Raw `if:` text, with any `${{ }}` wrapper already stripped
|
|
68
|
+
* @returns The token list
|
|
69
|
+
*/
|
|
70
|
+
export function tokenize(source) {
|
|
71
|
+
const text = source.trimStart();
|
|
72
|
+
if (text === "") {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
const token = headToken(text);
|
|
76
|
+
return [token, ...tokenize(text.slice(token.length))];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* GitHub's string-to-boolean cast: only the empty string is falsy.
|
|
80
|
+
* @param value - An evaluated operand
|
|
81
|
+
* @returns Its truthiness
|
|
82
|
+
*/
|
|
83
|
+
function truthy(value) {
|
|
84
|
+
return typeof value === "boolean" ? value : value !== "";
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* GitHub compares strings case-insensitively; every operand here is a string or
|
|
88
|
+
* a boolean, so a normalized string comparison is the whole rule.
|
|
89
|
+
* @param left - Left operand
|
|
90
|
+
* @param right - Right operand
|
|
91
|
+
* @returns Whether the two are equal
|
|
92
|
+
*/
|
|
93
|
+
function equal(left, right) {
|
|
94
|
+
return String(left).toLowerCase() === String(right).toLowerCase();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Resolve one `needs.*` path.
|
|
98
|
+
* @param segments - The dot-split path
|
|
99
|
+
* @param scenario - The run state
|
|
100
|
+
* @returns The value
|
|
101
|
+
*/
|
|
102
|
+
function resolveNeeds(segments, scenario) {
|
|
103
|
+
const entry = scenario.needs[segments[1] ?? ""];
|
|
104
|
+
if (!entry) {
|
|
105
|
+
throw new Error(`expression reads ${segments.join(".")}, absent from needs`);
|
|
106
|
+
}
|
|
107
|
+
if (segments[2] === "result") {
|
|
108
|
+
return entry.result;
|
|
109
|
+
}
|
|
110
|
+
if (segments[2] !== "outputs") {
|
|
111
|
+
throw new Error(`unsupported needs path: ${segments.join(".")}`);
|
|
112
|
+
}
|
|
113
|
+
// A job that did not succeed publishes no outputs at all. Modelling that is
|
|
114
|
+
// load-bearing: `needs.x.outputs.y == 'true'` is the shape that silently
|
|
115
|
+
// turns an upstream failure into a skipped dependent.
|
|
116
|
+
return entry.result === "success"
|
|
117
|
+
? (entry.outputs?.[segments[3] ?? ""] ?? "")
|
|
118
|
+
: "";
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Resolve one dotted context path against the scenario.
|
|
122
|
+
* @param path - A path such as `needs.release.result`
|
|
123
|
+
* @param scenario - The run state
|
|
124
|
+
* @returns The value, or `""` for a path that resolves to nothing
|
|
125
|
+
*/
|
|
126
|
+
function resolvePath(path, scenario) {
|
|
127
|
+
if (path === "true" || path === "false") {
|
|
128
|
+
return path === "true";
|
|
129
|
+
}
|
|
130
|
+
const segments = path.split(".");
|
|
131
|
+
if (segments[0] === "needs") {
|
|
132
|
+
return resolveNeeds(segments, scenario);
|
|
133
|
+
}
|
|
134
|
+
if (segments[0] === "github") {
|
|
135
|
+
return scenario.github[path] ?? "";
|
|
136
|
+
}
|
|
137
|
+
if (segments[0] === "inputs") {
|
|
138
|
+
return scenario.inputs?.[segments[1] ?? ""] ?? "";
|
|
139
|
+
}
|
|
140
|
+
throw new Error(`unsupported context path: ${path}`);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Evaluate a call to one of the supported functions.
|
|
144
|
+
* @param name - Function name
|
|
145
|
+
* @param args - Already-evaluated arguments
|
|
146
|
+
* @param scenario - The run state
|
|
147
|
+
* @returns The call's value
|
|
148
|
+
*/
|
|
149
|
+
function callFunction(name, args, scenario) {
|
|
150
|
+
const results = Object.values(scenario.needs).map(entry => entry.result);
|
|
151
|
+
const first = String(args[0] ?? "").toLowerCase();
|
|
152
|
+
const second = String(args[1] ?? "").toLowerCase();
|
|
153
|
+
switch (name) {
|
|
154
|
+
case "always":
|
|
155
|
+
return true;
|
|
156
|
+
case "cancelled":
|
|
157
|
+
return scenario.cancelled;
|
|
158
|
+
case "success":
|
|
159
|
+
return !scenario.cancelled && results.every(r => r === "success");
|
|
160
|
+
case "failure":
|
|
161
|
+
return results.includes("failure");
|
|
162
|
+
case "startsWith":
|
|
163
|
+
return first.startsWith(second);
|
|
164
|
+
case "contains":
|
|
165
|
+
return first.includes(second);
|
|
166
|
+
default:
|
|
167
|
+
throw new Error(`unsupported function: ${name}()`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Collect and evaluate a function call's arguments.
|
|
172
|
+
* @param tokens - The token list
|
|
173
|
+
* @param index - Position just after the opening parenthesis
|
|
174
|
+
* @param scenario - The run state
|
|
175
|
+
* @param collected - Arguments parsed so far
|
|
176
|
+
* @returns The arguments and the position just after the closing parenthesis
|
|
177
|
+
*/
|
|
178
|
+
function callArguments(tokens, index, scenario, collected) {
|
|
179
|
+
if (tokens[index] === ")") {
|
|
180
|
+
return { args: collected, index: index + 1 };
|
|
181
|
+
}
|
|
182
|
+
const argument = expression(tokens, index, scenario);
|
|
183
|
+
const next = tokens[argument.index] === "," ? argument.index + 1 : argument.index;
|
|
184
|
+
return callArguments(tokens, next, scenario, [...collected, argument.value]);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Parse and evaluate a primary term: a negation, a parenthesized expression, a
|
|
188
|
+
* string literal, a function call, or a context path.
|
|
189
|
+
* @param tokens - The token list
|
|
190
|
+
* @param index - Position of the term's first token
|
|
191
|
+
* @param scenario - The run state
|
|
192
|
+
* @returns The term's value and the position after it
|
|
193
|
+
*/
|
|
194
|
+
function primary(tokens, index, scenario) {
|
|
195
|
+
const token = tokens[index];
|
|
196
|
+
if (token === undefined) {
|
|
197
|
+
throw new Error("expression ended early");
|
|
198
|
+
}
|
|
199
|
+
if (token === "!") {
|
|
200
|
+
const inner = primary(tokens, index + 1, scenario);
|
|
201
|
+
return { value: !truthy(inner.value), index: inner.index };
|
|
202
|
+
}
|
|
203
|
+
if (token === "(") {
|
|
204
|
+
const inner = expression(tokens, index + 1, scenario);
|
|
205
|
+
if (tokens[inner.index] !== ")") {
|
|
206
|
+
throw new Error("unbalanced parentheses in expression");
|
|
207
|
+
}
|
|
208
|
+
return { value: inner.value, index: inner.index + 1 };
|
|
209
|
+
}
|
|
210
|
+
if (token.startsWith("'")) {
|
|
211
|
+
return { value: token.slice(1, -1), index: index + 1 };
|
|
212
|
+
}
|
|
213
|
+
if (tokens[index + 1] === "(") {
|
|
214
|
+
const call = callArguments(tokens, index + 2, scenario, []);
|
|
215
|
+
return {
|
|
216
|
+
value: callFunction(token, call.args, scenario),
|
|
217
|
+
index: call.index,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return { value: resolvePath(token, scenario), index: index + 1 };
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Parse and evaluate an equality comparison.
|
|
224
|
+
* @param tokens - The token list
|
|
225
|
+
* @param index - Position of the comparison's first token
|
|
226
|
+
* @param scenario - The run state
|
|
227
|
+
* @returns The comparison's value and the position after it
|
|
228
|
+
*/
|
|
229
|
+
function comparison(tokens, index, scenario) {
|
|
230
|
+
const left = primary(tokens, index, scenario);
|
|
231
|
+
const operator = tokens[left.index];
|
|
232
|
+
if (operator !== "==" && operator !== "!=") {
|
|
233
|
+
return left;
|
|
234
|
+
}
|
|
235
|
+
const right = primary(tokens, left.index + 1, scenario);
|
|
236
|
+
const same = equal(left.value, right.value);
|
|
237
|
+
return { value: operator === "==" ? same : !same, index: right.index };
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Fold the `&&` / `||` operators that follow an already-parsed operand.
|
|
241
|
+
* @param left - The operand parsed so far
|
|
242
|
+
* @param tokens - The token list
|
|
243
|
+
* @param scenario - The run state
|
|
244
|
+
* @returns The folded value and the position after it
|
|
245
|
+
*/
|
|
246
|
+
function logicalTail(left, tokens, scenario) {
|
|
247
|
+
const operator = tokens[left.index];
|
|
248
|
+
if (operator !== "&&" && operator !== "||") {
|
|
249
|
+
return left;
|
|
250
|
+
}
|
|
251
|
+
const right = comparison(tokens, left.index + 1, scenario);
|
|
252
|
+
const value = operator === "&&"
|
|
253
|
+
? truthy(left.value) && truthy(right.value)
|
|
254
|
+
: truthy(left.value) || truthy(right.value);
|
|
255
|
+
return logicalTail({ value, index: right.index }, tokens, scenario);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Parse and evaluate a full expression.
|
|
259
|
+
* @param tokens - The token list
|
|
260
|
+
* @param index - Position of the expression's first token
|
|
261
|
+
* @param scenario - The run state
|
|
262
|
+
* @returns The expression's value and the position after it
|
|
263
|
+
*/
|
|
264
|
+
function expression(tokens, index, scenario) {
|
|
265
|
+
return logicalTail(comparison(tokens, index, scenario), tokens, scenario);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Evaluate a job-level `if:` under one scenario.
|
|
269
|
+
* @param condition - The raw `if:` text
|
|
270
|
+
* @param scenario - The run state
|
|
271
|
+
* @returns Whether the condition holds
|
|
272
|
+
*/
|
|
273
|
+
export function evaluateCondition(condition, scenario) {
|
|
274
|
+
const stripped = condition
|
|
275
|
+
.trim()
|
|
276
|
+
.replace(/^\$\{\{/, "")
|
|
277
|
+
.replace(/\}\}$/, "")
|
|
278
|
+
.trim();
|
|
279
|
+
const tokens = tokenize(stripped);
|
|
280
|
+
const parsed = expression(tokens, 0, scenario);
|
|
281
|
+
if (parsed.index !== tokens.length) {
|
|
282
|
+
throw new Error(`unparsed tail in expression: ${condition}`);
|
|
283
|
+
}
|
|
284
|
+
return truthy(parsed.value);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Whether a job with this `if:` runs, applying GitHub's rule that an implicit
|
|
288
|
+
* `success()` is ANDed on unless the condition names a status function.
|
|
289
|
+
*
|
|
290
|
+
* That implicit AND is the whole mechanism behind the rails half of #3467: the
|
|
291
|
+
* condition there said nothing about the release at all, and still skipped when
|
|
292
|
+
* the release failed.
|
|
293
|
+
* @param condition - The raw `if:` text, or `""` when the job has none
|
|
294
|
+
* @param scenario - The run state
|
|
295
|
+
* @returns True when the job runs, false when GitHub skips it
|
|
296
|
+
*/
|
|
297
|
+
export function jobRuns(condition, scenario) {
|
|
298
|
+
const results = Object.values(scenario.needs).map(entry => entry.result);
|
|
299
|
+
const dependenciesSucceeded = !scenario.cancelled && results.every(result => result === "success");
|
|
300
|
+
if (condition.trim() === "") {
|
|
301
|
+
return dependenciesSucceeded;
|
|
302
|
+
}
|
|
303
|
+
const namesStatusFunction = STATUS_FUNCTIONS.some(name => new RegExp(`\\b${name}\\s*\\(`).test(condition));
|
|
304
|
+
const holds = evaluateCondition(condition, scenario);
|
|
305
|
+
return namesStatusFunction ? holds : holds && dependenciesSucceeded;
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=github-actions-condition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-actions-condition.js","sourceRoot":"","sources":["../../src/core/github-actions-condition.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AACA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AACA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAqjCjC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,+BAA+B,EAAE,QAAQ,CACpD,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAw9BjC,CAAC"}
|