@codyswann/lisa 4.42.7 → 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/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/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/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 +15 -1
- 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/package.json +4 -4
- 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/scripts/check-test-case-executed.mjs +184 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type DependenceJob } from "../core/deploy-release-dependence.js";
|
|
2
|
+
/** The guard step's `name:`, identical in every shipped deploy workflow. */
|
|
3
|
+
export declare const GUARD_STEP_NAME = "\uD83D\uDEA8 Confirm the release shipped";
|
|
4
|
+
/**
|
|
5
|
+
* Rewrite one job's condition so a failed release no longer skips it.
|
|
6
|
+
* @param job - The deploy job as parsed
|
|
7
|
+
* @param release - The upstream release job's id
|
|
8
|
+
* @returns The new condition text, or null when it must be left to a human
|
|
9
|
+
*/
|
|
10
|
+
export declare function rewrittenCondition(job: DependenceJob, release: string): string | null;
|
|
11
|
+
//# sourceMappingURL=deploy-outcome-guard-edit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-outcome-guard-edit.d.ts","sourceRoot":"","sources":["../../src/migrations/deploy-outcome-guard-edit.ts"],"names":[],"mappings":"AAgDA,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,sCAAsC,CAAC;AAE9C,4EAA4E;AAC5E,eAAO,MAAM,eAAe,6CAAmC,CAAC;AAqGhE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,IAAI,CASf"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The text surgery behind `ensure-deploy-outcome-guard` (CodySwannGT/lisa#3740).
|
|
3
|
+
*
|
|
4
|
+
* Separated from the migration class so the editing rules can be driven
|
|
5
|
+
* directly by tests: what this decides is which host workflows it is willing to
|
|
6
|
+
* touch, and that judgement is the risky half of the migration, not the file
|
|
7
|
+
* I/O around it.
|
|
8
|
+
*
|
|
9
|
+
* ## Two edits, or neither
|
|
10
|
+
*
|
|
11
|
+
* Repairing this defect means suppressing GitHub's implicit `success()` so the
|
|
12
|
+
* deploy job RUNS when the release failed, and adding a first step that fails
|
|
13
|
+
* it loudly. Doing only the first would be **worse than the bug**: a deploy job
|
|
14
|
+
* that runs on a failed release with nothing checking the release result would
|
|
15
|
+
* attempt to ship. So the two edits are produced together or the file is left
|
|
16
|
+
* alone, and a caller cannot obtain one without the other.
|
|
17
|
+
*
|
|
18
|
+
* ## The guard body is read, never written
|
|
19
|
+
*
|
|
20
|
+
* The step this inserts is lifted verbatim out of Lisa's own shipped deploy
|
|
21
|
+
* template. Hardcoding it here would create a fourth copy of a body that
|
|
22
|
+
* `tests/integration/deploy-outcome-guard.test.ts` exists to keep identical
|
|
23
|
+
* across three — and a copy that test cannot see, which is the shape this
|
|
24
|
+
* repository keeps paying for. If the template cannot be read, the migration
|
|
25
|
+
* declines rather than writing something it made up.
|
|
26
|
+
*
|
|
27
|
+
* ## What it refuses
|
|
28
|
+
*
|
|
29
|
+
* A condition it cannot rewrite without guessing is declined, and the doctor
|
|
30
|
+
* finding reports it instead. Two rewrites are accepted and no others:
|
|
31
|
+
*
|
|
32
|
+
* 1. A condition that never mentions the release result — safe to wrap, since
|
|
33
|
+
* `!cancelled() && (original)` cannot change what the original decides.
|
|
34
|
+
* 2. A flat top-level `&&` chain containing `needs.<release>.result ==
|
|
35
|
+
* 'success'` — the conjunct is dropped and `!cancelled()` prepended.
|
|
36
|
+
*
|
|
37
|
+
* Anything else, including that conjunct nested inside an `||`, is left to a
|
|
38
|
+
* human. Dropping a term from inside a disjunction changes what the condition
|
|
39
|
+
* means in ways this cannot check.
|
|
40
|
+
*
|
|
41
|
+
* ## The self-check
|
|
42
|
+
*
|
|
43
|
+
* Every rewrite is fed back through the same analysis that found the defect,
|
|
44
|
+
* and a rewrite that does not come back `independent` is discarded. A repair
|
|
45
|
+
* that does not repair is refused rather than written.
|
|
46
|
+
* @module migrations/deploy-outcome-guard-edit
|
|
47
|
+
*/
|
|
48
|
+
import { tokenize } from "../core/github-actions-condition.js";
|
|
49
|
+
import { releaseDependence, } from "../core/deploy-release-dependence.js";
|
|
50
|
+
/** The guard step's `name:`, identical in every shipped deploy workflow. */
|
|
51
|
+
export const GUARD_STEP_NAME = "🚨 Confirm the release shipped";
|
|
52
|
+
/** The status function that suppresses GitHub's implicit `success()`. */
|
|
53
|
+
const SUPPRESSOR = "!cancelled()";
|
|
54
|
+
/** Tokens that take no space before them when a condition is re-rendered. */
|
|
55
|
+
const NO_SPACE_BEFORE = new Set([")", ",", "=="]);
|
|
56
|
+
/** Tokens that take no space after them when a condition is re-rendered. */
|
|
57
|
+
const NO_SPACE_AFTER = new Set(["(", "!", "=="]);
|
|
58
|
+
/**
|
|
59
|
+
* Strip a `${{ }}` wrapper and surrounding whitespace from a condition.
|
|
60
|
+
* @param condition - The raw `if:` text
|
|
61
|
+
* @returns The bare expression
|
|
62
|
+
*/
|
|
63
|
+
function bareExpression(condition) {
|
|
64
|
+
return condition
|
|
65
|
+
.trim()
|
|
66
|
+
.replace(/^\$\{\{/, "")
|
|
67
|
+
.replace(/\}\}$/, "")
|
|
68
|
+
.trim();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Re-render a token run as expression text.
|
|
72
|
+
* @param tokens - The tokens, in order
|
|
73
|
+
* @returns Readable expression text
|
|
74
|
+
*/
|
|
75
|
+
function render(tokens) {
|
|
76
|
+
return tokens
|
|
77
|
+
.reduce((text, token, index) => {
|
|
78
|
+
const previous = tokens[index - 1];
|
|
79
|
+
const glued = index === 0 ||
|
|
80
|
+
NO_SPACE_BEFORE.has(token) ||
|
|
81
|
+
(previous !== undefined && NO_SPACE_AFTER.has(previous));
|
|
82
|
+
return glued ? text + token : `${text} ${token}`;
|
|
83
|
+
}, "")
|
|
84
|
+
.replace(/ == /g, " == ")
|
|
85
|
+
.trim();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Split a condition into its top-level `&&` conjuncts.
|
|
89
|
+
* @param tokens - The tokenized condition
|
|
90
|
+
* @returns The conjuncts, or null when the expression is not a flat `&&` chain
|
|
91
|
+
*/
|
|
92
|
+
function topLevelConjuncts(tokens) {
|
|
93
|
+
const split = tokens.reduce((state, token) => {
|
|
94
|
+
const depth = token === "("
|
|
95
|
+
? state.depth + 1
|
|
96
|
+
: token === ")"
|
|
97
|
+
? state.depth - 1
|
|
98
|
+
: state.depth;
|
|
99
|
+
if (state.depth === 0 && token === "||") {
|
|
100
|
+
return { ...state, depth, flat: false };
|
|
101
|
+
}
|
|
102
|
+
if (state.depth === 0 && token === "&&") {
|
|
103
|
+
return {
|
|
104
|
+
depth,
|
|
105
|
+
parts: [...state.parts, state.current],
|
|
106
|
+
current: [],
|
|
107
|
+
flat: state.flat,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return { ...state, depth, current: [...state.current, token] };
|
|
111
|
+
}, { depth: 0, parts: [], current: [], flat: true });
|
|
112
|
+
if (!split.flat)
|
|
113
|
+
return null;
|
|
114
|
+
return [...split.parts, split.current].filter(part => part.length > 0);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Whether a conjunct is exactly `needs.<release>.result == 'success'`.
|
|
118
|
+
* @param conjunct - One top-level conjunct's tokens
|
|
119
|
+
* @param release - The upstream release job's id
|
|
120
|
+
* @returns True when the conjunct is the hand-written success gate
|
|
121
|
+
*/
|
|
122
|
+
function isReleaseSuccessGate(conjunct, release) {
|
|
123
|
+
return (conjunct.length === 3 &&
|
|
124
|
+
conjunct[0] === `needs.${release}.result` &&
|
|
125
|
+
conjunct[1] === "==" &&
|
|
126
|
+
conjunct[2] === "'success'");
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Rewrite one job's condition so a failed release no longer skips it.
|
|
130
|
+
* @param job - The deploy job as parsed
|
|
131
|
+
* @param release - The upstream release job's id
|
|
132
|
+
* @returns The new condition text, or null when it must be left to a human
|
|
133
|
+
*/
|
|
134
|
+
export function rewrittenCondition(job, release) {
|
|
135
|
+
const rewritten = proposedCondition(job, release);
|
|
136
|
+
if (rewritten === null)
|
|
137
|
+
return null;
|
|
138
|
+
// The self-check: a rewrite that does not actually make the job independent
|
|
139
|
+
// of the release result is discarded rather than written.
|
|
140
|
+
return releaseDependence({ ...job, ifCondition: rewritten }, release).kind ===
|
|
141
|
+
"independent"
|
|
142
|
+
? rewritten
|
|
143
|
+
: null;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Propose a rewrite, before the self-check decides whether to keep it.
|
|
147
|
+
* @param job - The deploy job as parsed
|
|
148
|
+
* @param release - The upstream release job's id
|
|
149
|
+
* @returns The candidate condition, or null when no rule applies
|
|
150
|
+
*/
|
|
151
|
+
function proposedCondition(job, release) {
|
|
152
|
+
const original = bareExpression(job.ifCondition);
|
|
153
|
+
if (original === "")
|
|
154
|
+
return SUPPRESSOR;
|
|
155
|
+
const gate = `needs.${release}.result`;
|
|
156
|
+
if (!original.includes(gate)) {
|
|
157
|
+
return `${SUPPRESSOR} && (${original})`;
|
|
158
|
+
}
|
|
159
|
+
const conjuncts = topLevelConjuncts(tryTokenize(original) ?? []);
|
|
160
|
+
if (conjuncts === null || conjuncts.length === 0)
|
|
161
|
+
return null;
|
|
162
|
+
const kept = conjuncts.filter(conjunct => !isReleaseSuccessGate(conjunct, release));
|
|
163
|
+
// Every remaining conjunct must be free of the release result: one nested
|
|
164
|
+
// inside parentheses is exactly the case this refuses to reason about.
|
|
165
|
+
if (kept.length === conjuncts.length)
|
|
166
|
+
return null;
|
|
167
|
+
if (kept.some(conjunct => conjunct.some(token => token === gate)))
|
|
168
|
+
return null;
|
|
169
|
+
return [SUPPRESSOR, ...kept.map(render)].join(" && ");
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Tokenize, returning null instead of throwing on an unsupported expression.
|
|
173
|
+
* @param expression - The bare expression text
|
|
174
|
+
* @returns The tokens, or null when the expression cannot be read
|
|
175
|
+
*/
|
|
176
|
+
function tryTokenize(expression) {
|
|
177
|
+
try {
|
|
178
|
+
return tokenize(expression);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=deploy-outcome-guard-edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-outcome-guard-edit.js","sourceRoot":"","sources":["../../src/migrations/deploy-outcome-guard-edit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,EAEL,iBAAiB,GAClB,MAAM,sCAAsC,CAAC;AAE9C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,gCAAgC,CAAC;AAEhE,yEAAyE;AACzE,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,6EAA6E;AAC7E,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAElD,4EAA4E;AAC5E,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAEjD;;;;GAIG;AACH,SAAS,cAAc,CAAC,SAAiB;IACvC,OAAO,SAAS;SACb,IAAI,EAAE;SACN,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;;;GAIG;AACH,SAAS,MAAM,CAAC,MAAyB;IACvC,OAAO,MAAM;SACV,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QAC7B,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACnC,MAAM,KAAK,GACT,KAAK,KAAK,CAAC;YACX,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;YAC1B,CAAC,QAAQ,KAAK,SAAS,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC3D,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;IACnD,CAAC,EAAE,EAAE,CAAC;SACL,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC;SACxB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CACxB,MAAyB;IAEzB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAMzB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACf,MAAM,KAAK,GACT,KAAK,KAAK,GAAG;YACX,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC;YACjB,CAAC,CAAC,KAAK,KAAK,GAAG;gBACb,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC;gBACjB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;QACpB,IAAI,KAAK,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACxC,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAC1C,CAAC;QACD,IAAI,KAAK,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACxC,OAAO;gBACL,KAAK;gBACL,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;gBACtC,OAAO,EAAE,EAAE;gBACX,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;IACjE,CAAC,EACD,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CACjD,CAAC;IACF,IAAI,CAAC,KAAK,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7B,OAAO,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAC3B,QAA2B,EAC3B,OAAe;IAEf,OAAO,CACL,QAAQ,CAAC,MAAM,KAAK,CAAC;QACrB,QAAQ,CAAC,CAAC,CAAC,KAAK,SAAS,OAAO,SAAS;QACzC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI;QACpB,QAAQ,CAAC,CAAC,CAAC,KAAK,WAAW,CAC5B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAkB,EAClB,OAAe;IAEf,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAClD,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACpC,4EAA4E;IAC5E,0DAA0D;IAC1D,OAAO,iBAAiB,CAAC,EAAE,GAAG,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI;QACxE,aAAa;QACb,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,GAAkB,EAAE,OAAe;IAC5D,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,UAAU,CAAC;IACvC,MAAM,IAAI,GAAG,SAAS,OAAO,SAAS,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,GAAG,UAAU,QAAQ,QAAQ,GAAG,CAAC;IAC1C,CAAC;IACD,MAAM,SAAS,GAAG,iBAAiB,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjE,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9D,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAC3B,QAAQ,CAAC,EAAE,CAAC,CAAC,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CACrD,CAAC;IACF,0EAA0E;IAC1E,uEAAuE;IACvE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAClD,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,UAAkB;IACrC,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line-level editing of a host's `deploy.yml` for `ensure-deploy-outcome-guard`
|
|
3
|
+
* (CodySwannGT/lisa#3740).
|
|
4
|
+
*
|
|
5
|
+
* The file being edited is one the host OWNS — Lisa seeded it once and has
|
|
6
|
+
* never overwritten it since — so the discipline here is the opposite of a
|
|
7
|
+
* template copy: touch the two constructs that carry the defect and leave every
|
|
8
|
+
* other byte, including comments and formatting, exactly as the host left it.
|
|
9
|
+
* That is why this works on lines rather than by re-serializing a parsed
|
|
10
|
+
* document; a YAML round-trip would silently reformat a file somebody reviewed.
|
|
11
|
+
*
|
|
12
|
+
* Every locator returns null rather than a best guess. A workflow whose shape
|
|
13
|
+
* this cannot resolve unambiguously is not edited, and the doctor finding
|
|
14
|
+
* reports it instead — a migration that half-recognises a file and edits it
|
|
15
|
+
* anyway is worse than one that declines.
|
|
16
|
+
* @module migrations/deploy-outcome-guard-yaml
|
|
17
|
+
*/
|
|
18
|
+
/** Where one job's block sits in the file, and how its keys are indented. */
|
|
19
|
+
export interface JobBlock {
|
|
20
|
+
/** Index of the `<job-id>:` line. */
|
|
21
|
+
readonly start: number;
|
|
22
|
+
/** Index one past the job's last line. */
|
|
23
|
+
readonly end: number;
|
|
24
|
+
/** Column the job's own keys (`if:`, `steps:`) begin at. */
|
|
25
|
+
readonly keyIndent: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Locate one job's block by its id.
|
|
29
|
+
* @param lines - The workflow file's lines
|
|
30
|
+
* @param jobId - The job's key in the `jobs:` map
|
|
31
|
+
* @returns Where the job sits, or null when it cannot be located exactly once
|
|
32
|
+
*/
|
|
33
|
+
export declare function locateJob(lines: readonly string[], jobId: string): JobBlock | null;
|
|
34
|
+
/** A span of lines to replace, and the indentation its replacement takes. */
|
|
35
|
+
export interface KeySpan {
|
|
36
|
+
/** Index of the key's first line. */
|
|
37
|
+
readonly start: number;
|
|
38
|
+
/** Index one past the key's last line. */
|
|
39
|
+
readonly end: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Locate one top-level key of a job, including any continuation lines.
|
|
43
|
+
* @param lines - The workflow file's lines
|
|
44
|
+
* @param block - The job's block
|
|
45
|
+
* @param key - The key name, e.g. `if` or `steps`
|
|
46
|
+
* @returns The key's span, or null when the job does not declare it
|
|
47
|
+
*/
|
|
48
|
+
export declare function locateKey(lines: readonly string[], block: JobBlock, key: string): KeySpan | null;
|
|
49
|
+
/**
|
|
50
|
+
* Locate the first entry of a job's `steps:` list.
|
|
51
|
+
* @param lines - The workflow file's lines
|
|
52
|
+
* @param block - The job's block
|
|
53
|
+
* @returns The first step's line index and indentation, or null when absent
|
|
54
|
+
*/
|
|
55
|
+
export declare function locateFirstStep(lines: readonly string[], block: JobBlock): {
|
|
56
|
+
readonly index: number;
|
|
57
|
+
readonly indent: number;
|
|
58
|
+
} | null;
|
|
59
|
+
/**
|
|
60
|
+
* Extract the guard step from a shipped Lisa deploy template.
|
|
61
|
+
*
|
|
62
|
+
* Read rather than reproduced: the body is kept byte-identical across the
|
|
63
|
+
* shipped templates by a test, and a copy inside this module would be a fourth
|
|
64
|
+
* one that test cannot see.
|
|
65
|
+
* @param template - The template workflow's source
|
|
66
|
+
* @param stepName - The guard step's `name:` value
|
|
67
|
+
* @returns The step's lines, de-indented to column zero, or null when absent
|
|
68
|
+
*/
|
|
69
|
+
export declare function extractGuardStep(template: string, stepName: string): readonly string[] | null;
|
|
70
|
+
/**
|
|
71
|
+
* Render the replacement `if:` block for a job.
|
|
72
|
+
* @param condition - The rewritten condition text
|
|
73
|
+
* @param keyIndent - Column the job's keys begin at
|
|
74
|
+
* @returns The lines to write in place of the job's old `if:`
|
|
75
|
+
*/
|
|
76
|
+
export declare function renderCondition(condition: string, keyIndent: number): readonly string[];
|
|
77
|
+
/**
|
|
78
|
+
* Apply both edits to one workflow's source, or return null.
|
|
79
|
+
*
|
|
80
|
+
* The two are produced together on purpose. Suppressing the implicit
|
|
81
|
+
* `success()` without inserting the guard would leave a deploy job that RUNS on
|
|
82
|
+
* a failed release with nothing checking the release result — it would attempt
|
|
83
|
+
* to ship, which is worse than the silence this repairs.
|
|
84
|
+
* @param source - The host workflow's source
|
|
85
|
+
* @param jobId - The deploy job to repair
|
|
86
|
+
* @param condition - The rewritten condition text
|
|
87
|
+
* @param guardStep - The guard step's lines, de-indented to column zero
|
|
88
|
+
* @returns The edited source, or null when the file could not be edited safely
|
|
89
|
+
*/
|
|
90
|
+
export declare function applyGuardEdits(source: string, jobId: string, condition: string, guardStep: readonly string[]): string | null;
|
|
91
|
+
//# sourceMappingURL=deploy-outcome-guard-yaml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-outcome-guard-yaml.d.ts","sourceRoot":"","sources":["../../src/migrations/deploy-outcome-guard-yaml.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,6EAA6E;AAC7E,MAAM,WAAW,QAAQ;IACvB,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAYD;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,KAAK,EAAE,MAAM,GACZ,QAAQ,GAAG,IAAI,CAiBjB;AAED,6EAA6E;AAC7E,MAAM,WAAW,OAAO;IACtB,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,KAAK,EAAE,QAAQ,EACf,GAAG,EAAE,MAAM,GACV,OAAO,GAAG,IAAI,CAahB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,KAAK,EAAE,QAAQ,GACd;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,SAAS,MAAM,EAAE,GAAG,IAAI,CAc1B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,SAAS,MAAM,EAAE,CAkBnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,MAAM,GAAG,IAAI,CA8Bf"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line-level editing of a host's `deploy.yml` for `ensure-deploy-outcome-guard`
|
|
3
|
+
* (CodySwannGT/lisa#3740).
|
|
4
|
+
*
|
|
5
|
+
* The file being edited is one the host OWNS — Lisa seeded it once and has
|
|
6
|
+
* never overwritten it since — so the discipline here is the opposite of a
|
|
7
|
+
* template copy: touch the two constructs that carry the defect and leave every
|
|
8
|
+
* other byte, including comments and formatting, exactly as the host left it.
|
|
9
|
+
* That is why this works on lines rather than by re-serializing a parsed
|
|
10
|
+
* document; a YAML round-trip would silently reformat a file somebody reviewed.
|
|
11
|
+
*
|
|
12
|
+
* Every locator returns null rather than a best guess. A workflow whose shape
|
|
13
|
+
* this cannot resolve unambiguously is not edited, and the doctor finding
|
|
14
|
+
* reports it instead — a migration that half-recognises a file and edits it
|
|
15
|
+
* anyway is worse than one that declines.
|
|
16
|
+
* @module migrations/deploy-outcome-guard-yaml
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Indentation width of one line, or null when the line carries no content.
|
|
20
|
+
* @param line - The raw line
|
|
21
|
+
* @returns Number of leading spaces, or null for a blank or comment-only line
|
|
22
|
+
*/
|
|
23
|
+
function indentOf(line) {
|
|
24
|
+
if (line.trim() === "")
|
|
25
|
+
return null;
|
|
26
|
+
return line.length - line.trimStart().length;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Locate one job's block by its id.
|
|
30
|
+
* @param lines - The workflow file's lines
|
|
31
|
+
* @param jobId - The job's key in the `jobs:` map
|
|
32
|
+
* @returns Where the job sits, or null when it cannot be located exactly once
|
|
33
|
+
*/
|
|
34
|
+
export function locateJob(lines, jobId) {
|
|
35
|
+
const pattern = new RegExp(`^(\\s+)${jobId}:\\s*$`);
|
|
36
|
+
const starts = lines.flatMap((line, index) => pattern.test(line) ? [index] : []);
|
|
37
|
+
if (starts.length !== 1)
|
|
38
|
+
return null;
|
|
39
|
+
const start = starts[0] ?? 0;
|
|
40
|
+
const jobIndent = indentOf(lines[start] ?? "") ?? 0;
|
|
41
|
+
const body = lines
|
|
42
|
+
.slice(start + 1)
|
|
43
|
+
.findIndex(line => (indentOf(line) ?? jobIndent + 1) <= jobIndent);
|
|
44
|
+
const end = body === -1 ? lines.length : start + 1 + body;
|
|
45
|
+
const keyIndent = lines
|
|
46
|
+
.slice(start + 1, end)
|
|
47
|
+
.map(indentOf)
|
|
48
|
+
.find((indent) => indent !== null);
|
|
49
|
+
return keyIndent === undefined ? null : { start, end, keyIndent };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Locate one top-level key of a job, including any continuation lines.
|
|
53
|
+
* @param lines - The workflow file's lines
|
|
54
|
+
* @param block - The job's block
|
|
55
|
+
* @param key - The key name, e.g. `if` or `steps`
|
|
56
|
+
* @returns The key's span, or null when the job does not declare it
|
|
57
|
+
*/
|
|
58
|
+
export function locateKey(lines, block, key) {
|
|
59
|
+
const pattern = new RegExp(`^\\s{${block.keyIndent}}${key}:`);
|
|
60
|
+
const found = lines
|
|
61
|
+
.slice(block.start, block.end)
|
|
62
|
+
.findIndex(line => pattern.test(line));
|
|
63
|
+
if (found === -1)
|
|
64
|
+
return null;
|
|
65
|
+
const start = block.start + found;
|
|
66
|
+
const rest = lines
|
|
67
|
+
.slice(start + 1, block.end)
|
|
68
|
+
.findIndex(line => (indentOf(line) ?? block.keyIndent + 1) <= block.keyIndent);
|
|
69
|
+
return { start, end: rest === -1 ? block.end : start + 1 + rest };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Locate the first entry of a job's `steps:` list.
|
|
73
|
+
* @param lines - The workflow file's lines
|
|
74
|
+
* @param block - The job's block
|
|
75
|
+
* @returns The first step's line index and indentation, or null when absent
|
|
76
|
+
*/
|
|
77
|
+
export function locateFirstStep(lines, block) {
|
|
78
|
+
const steps = locateKey(lines, block, "steps");
|
|
79
|
+
if (steps === null)
|
|
80
|
+
return null;
|
|
81
|
+
const offset = lines
|
|
82
|
+
.slice(steps.start + 1, steps.end)
|
|
83
|
+
.findIndex(line => line.trimStart().startsWith("- "));
|
|
84
|
+
if (offset === -1)
|
|
85
|
+
return null;
|
|
86
|
+
const index = steps.start + 1 + offset;
|
|
87
|
+
return { index, indent: indentOf(lines[index] ?? "") ?? 0 };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Extract the guard step from a shipped Lisa deploy template.
|
|
91
|
+
*
|
|
92
|
+
* Read rather than reproduced: the body is kept byte-identical across the
|
|
93
|
+
* shipped templates by a test, and a copy inside this module would be a fourth
|
|
94
|
+
* one that test cannot see.
|
|
95
|
+
* @param template - The template workflow's source
|
|
96
|
+
* @param stepName - The guard step's `name:` value
|
|
97
|
+
* @returns The step's lines, de-indented to column zero, or null when absent
|
|
98
|
+
*/
|
|
99
|
+
export function extractGuardStep(template, stepName) {
|
|
100
|
+
const lines = template.split("\n");
|
|
101
|
+
const start = lines.findIndex(line => line.trimStart().startsWith(`- name: ${stepName}`));
|
|
102
|
+
if (start === -1)
|
|
103
|
+
return null;
|
|
104
|
+
const indent = indentOf(lines[start] ?? "") ?? 0;
|
|
105
|
+
const after = lines
|
|
106
|
+
.slice(start + 1)
|
|
107
|
+
.findIndex(line => (indentOf(line) ?? indent + 1) <= indent);
|
|
108
|
+
const end = after === -1 ? lines.length : start + 1 + after;
|
|
109
|
+
return lines
|
|
110
|
+
.slice(start, end)
|
|
111
|
+
.map(line => (line.trim() === "" ? "" : line.slice(indent)));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Render the replacement `if:` block for a job.
|
|
115
|
+
* @param condition - The rewritten condition text
|
|
116
|
+
* @param keyIndent - Column the job's keys begin at
|
|
117
|
+
* @returns The lines to write in place of the job's old `if:`
|
|
118
|
+
*/
|
|
119
|
+
export function renderCondition(condition, keyIndent) {
|
|
120
|
+
const pad = " ".repeat(keyIndent);
|
|
121
|
+
const inner = " ".repeat(keyIndent + 2);
|
|
122
|
+
return [
|
|
123
|
+
`${pad}# \`!cancelled()\` suppresses the implicit \`success()\` GitHub would`,
|
|
124
|
+
`${pad}# otherwise AND onto this condition. Without it a failed release`,
|
|
125
|
+
`${pad}# SKIPPED this job, and a skipped job renders as neutral and counts`,
|
|
126
|
+
`${pad}# as a satisfied required check — so a deploy that never happened`,
|
|
127
|
+
`${pad}# left no signal at all. The release result is read by the guard STEP`,
|
|
128
|
+
`${pad}# below, which fails this job loudly instead (#3467, applied by`,
|
|
129
|
+
`${pad}# Lisa's ensure-deploy-outcome-guard migration for #3740).`,
|
|
130
|
+
`${pad}if: >-`,
|
|
131
|
+
...condition
|
|
132
|
+
.split(" && ")
|
|
133
|
+
.map((part, index, parts) => index === parts.length - 1 ? `${inner}${part}` : `${inner}${part} &&`),
|
|
134
|
+
];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Apply both edits to one workflow's source, or return null.
|
|
138
|
+
*
|
|
139
|
+
* The two are produced together on purpose. Suppressing the implicit
|
|
140
|
+
* `success()` without inserting the guard would leave a deploy job that RUNS on
|
|
141
|
+
* a failed release with nothing checking the release result — it would attempt
|
|
142
|
+
* to ship, which is worse than the silence this repairs.
|
|
143
|
+
* @param source - The host workflow's source
|
|
144
|
+
* @param jobId - The deploy job to repair
|
|
145
|
+
* @param condition - The rewritten condition text
|
|
146
|
+
* @param guardStep - The guard step's lines, de-indented to column zero
|
|
147
|
+
* @returns The edited source, or null when the file could not be edited safely
|
|
148
|
+
*/
|
|
149
|
+
export function applyGuardEdits(source, jobId, condition, guardStep) {
|
|
150
|
+
const lines = source.split("\n");
|
|
151
|
+
const block = locateJob(lines, jobId);
|
|
152
|
+
if (block === null)
|
|
153
|
+
return null;
|
|
154
|
+
const step = locateFirstStep(lines, block);
|
|
155
|
+
if (step === null)
|
|
156
|
+
return null;
|
|
157
|
+
const existing = locateKey(lines, block, "if");
|
|
158
|
+
const guardLines = guardStep.map(line => line === "" ? "" : `${" ".repeat(step.indent)}${line}`);
|
|
159
|
+
const conditionLines = renderCondition(condition, block.keyIndent);
|
|
160
|
+
const declared = existing ?? {
|
|
161
|
+
start: block.start + 1,
|
|
162
|
+
end: block.start + 1,
|
|
163
|
+
};
|
|
164
|
+
const withGuard = [
|
|
165
|
+
...lines.slice(0, step.index),
|
|
166
|
+
...guardLines,
|
|
167
|
+
...lines.slice(step.index),
|
|
168
|
+
];
|
|
169
|
+
// Inserting the guard shifts every index at or after it. `steps:` normally
|
|
170
|
+
// follows `if:`, so the span is usually untouched — but YAML mapping keys
|
|
171
|
+
// carry no required order, and a host that wrote them the other way round
|
|
172
|
+
// would otherwise have its file corrupted rather than declined.
|
|
173
|
+
const shift = step.index <= declared.start ? guardLines.length : 0;
|
|
174
|
+
return [
|
|
175
|
+
...withGuard.slice(0, declared.start + shift),
|
|
176
|
+
...conditionLines,
|
|
177
|
+
...withGuard.slice(declared.end + shift),
|
|
178
|
+
].join("\n");
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=deploy-outcome-guard-yaml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-outcome-guard-yaml.js","sourceRoot":"","sources":["../../src/migrations/deploy-outcome-guard-yaml.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAYH;;;;GAIG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CACvB,KAAwB,EACxB,KAAa;IAEb,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAC3C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAClC,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,KAAK;SACf,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;SAChB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,SAAS,GAAG,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC;IAC1D,MAAM,SAAS,GAAG,KAAK;SACpB,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC;SACrB,GAAG,CAAC,QAAQ,CAAC;SACb,IAAI,CAAC,CAAC,MAAM,EAAoB,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;IACvD,OAAO,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AACpE,CAAC;AAUD;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,KAAwB,EACxB,KAAe,EACf,GAAW;IAEX,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,SAAS,IAAI,GAAG,GAAG,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,KAAK;SAChB,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;SAC7B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACzC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IAClC,MAAM,IAAI,GAAG,KAAK;SACf,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC;SAC3B,SAAS,CACR,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,SAAS,CACnE,CAAC;IACJ,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;AACpE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAwB,EACxB,KAAe;IAEf,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC/C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,MAAM,GAAG,KAAK;SACjB,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC;SACjC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,IAAI,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAAgB,EAChB,QAAgB;IAEhB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CACnC,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,WAAW,QAAQ,EAAE,CAAC,CACnD,CAAC;IACF,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,KAAK;SAChB,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;SAChB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC;IAC5D,OAAO,KAAK;SACT,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC;SACjB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAiB,EACjB,SAAiB;IAEjB,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IACxC,OAAO;QACL,GAAG,GAAG,uEAAuE;QAC7E,GAAG,GAAG,kEAAkE;QACxE,GAAG,GAAG,qEAAqE;QAC3E,GAAG,GAAG,mEAAmE;QACzE,GAAG,GAAG,uEAAuE;QAC7E,GAAG,GAAG,iEAAiE;QACvE,GAAG,GAAG,4DAA4D;QAClE,GAAG,GAAG,QAAQ;QACd,GAAG,SAAS;aACT,KAAK,CAAC,MAAM,CAAC;aACb,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAC1B,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,KAAK,CACtE;KACJ,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,KAAa,EACb,SAAiB,EACjB,SAA4B;IAE5B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC3C,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACtC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CACvD,CAAC;IACF,MAAM,cAAc,GAAG,eAAe,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAG,QAAQ,IAAI;QAC3B,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC;QACtB,GAAG,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC;KACrB,CAAC;IACF,MAAM,SAAS,GAAG;QAChB,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC;QAC7B,GAAG,UAAU;QACb,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;KAC3B,CAAC;IACF,2EAA2E;IAC3E,0EAA0E;IAC1E,0EAA0E;IAC1E,gEAAgE;IAChE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO;QACL,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;QAC7C,GAAG,cAAc;QACjB,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,GAAG,KAAK,CAAC;KACzC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Migration, MigrationContext, MigrationResult } from "./migration.interface.js";
|
|
2
|
+
/**
|
|
3
|
+
* Bring an already-seeded deploy workflow up to the #3467 outcome contract.
|
|
4
|
+
*/
|
|
5
|
+
export declare class EnsureDeployOutcomeGuardMigration implements Migration {
|
|
6
|
+
readonly name = "ensure-deploy-outcome-guard";
|
|
7
|
+
readonly description = "Make an already-seeded deploy job fail loudly instead of skipping silently when its release does not succeed";
|
|
8
|
+
/**
|
|
9
|
+
* Whether any host deploy workflow can be repaired.
|
|
10
|
+
* @param ctx - Migration context
|
|
11
|
+
* @returns True when at least one workflow would change
|
|
12
|
+
*/
|
|
13
|
+
applies(ctx: MigrationContext): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* Rewrite every repairable deploy workflow.
|
|
16
|
+
* @param ctx - Migration context
|
|
17
|
+
* @returns Applied or no-op result
|
|
18
|
+
*/
|
|
19
|
+
apply(ctx: MigrationContext): Promise<MigrationResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Work out which host workflows this run would rewrite.
|
|
22
|
+
* @param ctx - Migration context
|
|
23
|
+
* @returns One entry per workflow that can be repaired
|
|
24
|
+
*/
|
|
25
|
+
private plan;
|
|
26
|
+
/**
|
|
27
|
+
* Plan the repair of one workflow.
|
|
28
|
+
* @param ctx - Migration context
|
|
29
|
+
* @param workflow - The parsed workflow
|
|
30
|
+
* @param guardStep - The guard step's lines
|
|
31
|
+
* @returns The planned edit, or null when nothing here can be repaired
|
|
32
|
+
*/
|
|
33
|
+
private planOne;
|
|
34
|
+
/**
|
|
35
|
+
* Read the guard step out of Lisa's own shipped deploy template.
|
|
36
|
+
* @param lisaDir - Lisa installation directory
|
|
37
|
+
* @returns The step's lines, or null when the template cannot be read
|
|
38
|
+
*/
|
|
39
|
+
private readGuardStep;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=ensure-deploy-outcome-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-deploy-outcome-guard.d.ts","sourceRoot":"","sources":["../../src/migrations/ensure-deploy-outcome-guard.ts"],"names":[],"mappings":"AAgEA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAiJlC;;GAEG;AACH,qBAAa,iCAAkC,YAAW,SAAS;IACjE,QAAQ,CAAC,IAAI,iCAAiC;IAC9C,QAAQ,CAAC,WAAW,kHAC6F;IAEjH;;;;OAIG;IACG,OAAO,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAItD;;;;OAIG;IACG,KAAK,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAoB5D;;;;OAIG;YACW,IAAI;IAelB;;;;;;OAMG;YACW,OAAO;IAsBrB;;;;OAIG;YACW,aAAa;CAa5B"}
|