@formigio/fazemos-cli 0.10.19 → 0.10.20
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/index.js +65 -0
- package/dist/index.js.map +1 -1
- package/dist/wait-for-pipeline.d.ts +120 -0
- package/dist/wait-for-pipeline.js +337 -0
- package/dist/wait-for-pipeline.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wait-for-pipeline — deterministic CodePipeline deploy-completion gate (P8/I55).
|
|
3
|
+
*
|
|
4
|
+
* Polls CodePipeline `get-pipeline-execution` until each awaited execution reaches
|
|
5
|
+
* a terminal state, mapping terminal states to distinct process exit codes so a
|
|
6
|
+
* script step (no LLM) can branch on exit code alone. See the P8→I55 tech spec
|
|
7
|
+
* §3 and the manifest `cli.wait_for_pipeline` block — that contract is binding.
|
|
8
|
+
*
|
|
9
|
+
* Implementation is shelled out to the `aws` CLI via `execSync` (the CLI carries
|
|
10
|
+
* no `@aws-sdk` dependency — consistent with the existing execSync pattern in
|
|
11
|
+
* index.ts). Credentials reach the `aws` CLI via the ECS task-role metadata
|
|
12
|
+
* service inside the agent container; no env plumbing is required here.
|
|
13
|
+
*
|
|
14
|
+
* Exit-code contract (spec §3.3):
|
|
15
|
+
* 0 all awaited pipelines reached Succeeded (or empty map — CLI-only no-op)
|
|
16
|
+
* 2 a pipeline reached Failed or Stopped
|
|
17
|
+
* 3 a pipeline was Superseded
|
|
18
|
+
* 4 the timeout budget was exceeded before a terminal state
|
|
19
|
+
* 5 an aws-cli call failed (after retries) — distinct from a pipeline Failed
|
|
20
|
+
*/
|
|
21
|
+
export declare const EXIT: {
|
|
22
|
+
readonly SUCCESS: 0;
|
|
23
|
+
readonly PIPELINE_FAILED: 2;
|
|
24
|
+
readonly SUPERSEDED: 3;
|
|
25
|
+
readonly TIMEOUT: 4;
|
|
26
|
+
readonly AWS_CALL_FAILED: 5;
|
|
27
|
+
};
|
|
28
|
+
/** Floor for --poll-interval. Poll a status signal; never retry the action faster. */
|
|
29
|
+
export declare const POLL_INTERVAL_FLOOR_SECONDS = 60;
|
|
30
|
+
/** Default total wall-clock budget when --timeout is absent. */
|
|
31
|
+
export declare const DEFAULT_TIMEOUT_SECONDS: number;
|
|
32
|
+
/** Default per-poll sleep when --poll-interval is absent. */
|
|
33
|
+
export declare const DEFAULT_POLL_INTERVAL_SECONDS = 60;
|
|
34
|
+
/** Retries on a transient aws-cli error before mapping to AWS_CALL_FAILED. */
|
|
35
|
+
export declare const AWS_CALL_RETRIES = 3;
|
|
36
|
+
/** Default region when neither --region nor AWS_REGION/AWS_DEFAULT_REGION is set (M3). */
|
|
37
|
+
export declare const DEFAULT_REGION = "us-west-2";
|
|
38
|
+
/**
|
|
39
|
+
* Build a POSIX-safe shell command from an argv array by single-quoting every
|
|
40
|
+
* token (escaping embedded single-quotes via the `'\''` idiom). Each element of
|
|
41
|
+
* `args` round-trips as exactly one inert shell word — no token can introduce a
|
|
42
|
+
* metacharacter (`;`, `&&`, `$(...)`, newline, …) that the shell would act on.
|
|
43
|
+
*
|
|
44
|
+
* Exported so the shell-quoting boundary is unit-tested against hostile inputs
|
|
45
|
+
* rather than living as an untestable inline closure in index.ts.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildAwsCommand(args: string[]): string;
|
|
48
|
+
/**
|
|
49
|
+
* Validate a (pipeline, executionId) pair against the allowed charsets. Throws
|
|
50
|
+
* with a clear diagnostic on the first violation — the caller surfaces the
|
|
51
|
+
* message and exits via the standard input-validation path (exit 1).
|
|
52
|
+
*/
|
|
53
|
+
export declare function validateExecutionEntry(pipeline: string, executionId: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* Parse a duration string to whole seconds.
|
|
56
|
+
* Accepts `15m`, `900s`, or a bare `900` (interpreted as seconds).
|
|
57
|
+
* Throws on anything else — the caller surfaces the message and exits.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseDuration(input: string): number;
|
|
60
|
+
/**
|
|
61
|
+
* Resolve the region: explicit --region wins, then AWS_REGION, then
|
|
62
|
+
* AWS_DEFAULT_REGION, then the us-west-2 default (M3). The IAM ARN is
|
|
63
|
+
* region-scoped and the agent task defs set no AWS_REGION, so the resolved
|
|
64
|
+
* value is always passed explicitly on every `aws codepipeline` call.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolveRegion(explicit: string | undefined, env?: NodeJS.ProcessEnv): string;
|
|
67
|
+
/**
|
|
68
|
+
* Parse the `--executions-json` map. Accepts a JSON object of
|
|
69
|
+
* `{ pipelineName: executionId }`. An empty/whitespace value or `{}` yields an
|
|
70
|
+
* empty map (the documented CLI-only no-op). Throws on malformed JSON or a
|
|
71
|
+
* non-object/invalid-entry shape.
|
|
72
|
+
*/
|
|
73
|
+
export declare function parseExecutionsJson(input: string): Array<{
|
|
74
|
+
pipeline: string;
|
|
75
|
+
executionId: string;
|
|
76
|
+
}>;
|
|
77
|
+
/** A function that runs an aws-cli command and returns its stdout, or throws. */
|
|
78
|
+
export type AwsRunner = (args: string[]) => string;
|
|
79
|
+
/** Sleep injection (overridable in tests). */
|
|
80
|
+
export type Sleeper = (seconds: number) => Promise<void>;
|
|
81
|
+
/** Clock injection (overridable in tests). */
|
|
82
|
+
export type Clock = () => number;
|
|
83
|
+
/** Logger injection (defaults to console). */
|
|
84
|
+
export interface Logger {
|
|
85
|
+
out: (msg: string) => void;
|
|
86
|
+
err: (msg: string) => void;
|
|
87
|
+
}
|
|
88
|
+
export interface WaitOptions {
|
|
89
|
+
timeoutSeconds: number;
|
|
90
|
+
pollIntervalSeconds: number;
|
|
91
|
+
region: string;
|
|
92
|
+
}
|
|
93
|
+
export interface WaitDeps {
|
|
94
|
+
aws: AwsRunner;
|
|
95
|
+
sleep?: Sleeper;
|
|
96
|
+
clock?: Clock;
|
|
97
|
+
logger?: Logger;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Wait for every (pipeline, executionId) pair in `executions`. Partial-failure
|
|
101
|
+
* semantics: poll all entries; the overall exit code is the FIRST non-zero
|
|
102
|
+
* result encountered (Failed/Stopped→2, Superseded→3, timeout→4, aws-fail→5),
|
|
103
|
+
* SUCCESS only if every pipeline reached Succeeded. An empty list is the
|
|
104
|
+
* documented CLI-only no-op (exit 0 with a note).
|
|
105
|
+
*
|
|
106
|
+
* Returns the process exit code; callers `process.exit(code)`.
|
|
107
|
+
*/
|
|
108
|
+
export declare function waitForPipelines(executions: Array<{
|
|
109
|
+
pipeline: string;
|
|
110
|
+
executionId: string;
|
|
111
|
+
}>, options: WaitOptions, deps: WaitDeps): Promise<number>;
|
|
112
|
+
/**
|
|
113
|
+
* Resolve raw CLI flag values into a validated WaitOptions, clamping the poll
|
|
114
|
+
* interval to its 60s floor and warning on stderr when clamped.
|
|
115
|
+
*/
|
|
116
|
+
export declare function resolveWaitOptions(flags: {
|
|
117
|
+
timeout?: string;
|
|
118
|
+
pollInterval?: string;
|
|
119
|
+
region?: string;
|
|
120
|
+
}, env?: NodeJS.ProcessEnv, logger?: Logger): WaitOptions;
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wait-for-pipeline — deterministic CodePipeline deploy-completion gate (P8/I55).
|
|
3
|
+
*
|
|
4
|
+
* Polls CodePipeline `get-pipeline-execution` until each awaited execution reaches
|
|
5
|
+
* a terminal state, mapping terminal states to distinct process exit codes so a
|
|
6
|
+
* script step (no LLM) can branch on exit code alone. See the P8→I55 tech spec
|
|
7
|
+
* §3 and the manifest `cli.wait_for_pipeline` block — that contract is binding.
|
|
8
|
+
*
|
|
9
|
+
* Implementation is shelled out to the `aws` CLI via `execSync` (the CLI carries
|
|
10
|
+
* no `@aws-sdk` dependency — consistent with the existing execSync pattern in
|
|
11
|
+
* index.ts). Credentials reach the `aws` CLI via the ECS task-role metadata
|
|
12
|
+
* service inside the agent container; no env plumbing is required here.
|
|
13
|
+
*
|
|
14
|
+
* Exit-code contract (spec §3.3):
|
|
15
|
+
* 0 all awaited pipelines reached Succeeded (or empty map — CLI-only no-op)
|
|
16
|
+
* 2 a pipeline reached Failed or Stopped
|
|
17
|
+
* 3 a pipeline was Superseded
|
|
18
|
+
* 4 the timeout budget was exceeded before a terminal state
|
|
19
|
+
* 5 an aws-cli call failed (after retries) — distinct from a pipeline Failed
|
|
20
|
+
*/
|
|
21
|
+
export const EXIT = {
|
|
22
|
+
SUCCESS: 0,
|
|
23
|
+
PIPELINE_FAILED: 2, // Failed | Stopped
|
|
24
|
+
SUPERSEDED: 3,
|
|
25
|
+
TIMEOUT: 4,
|
|
26
|
+
AWS_CALL_FAILED: 5,
|
|
27
|
+
};
|
|
28
|
+
/** CodePipeline terminal/non-terminal status set (from get-pipeline-execution). */
|
|
29
|
+
const TERMINAL_FAIL = new Set(['Failed', 'Stopped']);
|
|
30
|
+
const NON_TERMINAL = new Set(['InProgress', 'Stopping']);
|
|
31
|
+
/** Floor for --poll-interval. Poll a status signal; never retry the action faster. */
|
|
32
|
+
export const POLL_INTERVAL_FLOOR_SECONDS = 60;
|
|
33
|
+
/** Default total wall-clock budget when --timeout is absent. */
|
|
34
|
+
export const DEFAULT_TIMEOUT_SECONDS = 15 * 60; // 15m
|
|
35
|
+
/** Default per-poll sleep when --poll-interval is absent. */
|
|
36
|
+
export const DEFAULT_POLL_INTERVAL_SECONDS = 60; // 60s
|
|
37
|
+
/** Retries on a transient aws-cli error before mapping to AWS_CALL_FAILED. */
|
|
38
|
+
export const AWS_CALL_RETRIES = 3;
|
|
39
|
+
/** Default region when neither --region nor AWS_REGION/AWS_DEFAULT_REGION is set (M3). */
|
|
40
|
+
export const DEFAULT_REGION = 'us-west-2';
|
|
41
|
+
/**
|
|
42
|
+
* Build a POSIX-safe shell command from an argv array by single-quoting every
|
|
43
|
+
* token (escaping embedded single-quotes via the `'\''` idiom). Each element of
|
|
44
|
+
* `args` round-trips as exactly one inert shell word — no token can introduce a
|
|
45
|
+
* metacharacter (`;`, `&&`, `$(...)`, newline, …) that the shell would act on.
|
|
46
|
+
*
|
|
47
|
+
* Exported so the shell-quoting boundary is unit-tested against hostile inputs
|
|
48
|
+
* rather than living as an untestable inline closure in index.ts.
|
|
49
|
+
*/
|
|
50
|
+
export function buildAwsCommand(args) {
|
|
51
|
+
return ['aws', ...args.map((a) => `'${String(a).replace(/'/g, "'\\''")}'`)].join(' ');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Allowed CodePipeline pipeline-name charset. CodePipeline names are restricted
|
|
55
|
+
* to letters, digits, and `.`, `_`, `-`; reject anything else up-front so a
|
|
56
|
+
* malformed/hostile name never even reaches the (already-escaped) shell.
|
|
57
|
+
*/
|
|
58
|
+
const PIPELINE_NAME_RE = /^[A-Za-z0-9._-]+$/;
|
|
59
|
+
/**
|
|
60
|
+
* Allowed execution-id charset. CodePipeline execution ids are UUIDs; accept a
|
|
61
|
+
* permissive UUID-ish hex+dash set rather than a strict UUID to tolerate any
|
|
62
|
+
* future id format while still excluding shell metacharacters.
|
|
63
|
+
*/
|
|
64
|
+
const EXECUTION_ID_RE = /^[A-Za-z0-9-]+$/;
|
|
65
|
+
/**
|
|
66
|
+
* Validate a (pipeline, executionId) pair against the allowed charsets. Throws
|
|
67
|
+
* with a clear diagnostic on the first violation — the caller surfaces the
|
|
68
|
+
* message and exits via the standard input-validation path (exit 1).
|
|
69
|
+
*/
|
|
70
|
+
export function validateExecutionEntry(pipeline, executionId) {
|
|
71
|
+
if (!PIPELINE_NAME_RE.test(pipeline)) {
|
|
72
|
+
throw new Error(`Invalid pipeline name "${pipeline}": only letters, digits, and . _ - are allowed`);
|
|
73
|
+
}
|
|
74
|
+
if (!EXECUTION_ID_RE.test(executionId)) {
|
|
75
|
+
throw new Error(`Invalid execution id "${executionId}" for pipeline "${pipeline}": only letters, digits, and - are allowed`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Parse a duration string to whole seconds.
|
|
80
|
+
* Accepts `15m`, `900s`, or a bare `900` (interpreted as seconds).
|
|
81
|
+
* Throws on anything else — the caller surfaces the message and exits.
|
|
82
|
+
*/
|
|
83
|
+
export function parseDuration(input) {
|
|
84
|
+
const raw = String(input).trim();
|
|
85
|
+
const m = /^(\d+)\s*(m|s)?$/.exec(raw);
|
|
86
|
+
if (!m) {
|
|
87
|
+
throw new Error(`Invalid duration: "${input}" (expected forms: 15m, 900s, or 900)`);
|
|
88
|
+
}
|
|
89
|
+
const value = parseInt(m[1], 10);
|
|
90
|
+
const unit = m[2] ?? 's';
|
|
91
|
+
return unit === 'm' ? value * 60 : value;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Resolve the region: explicit --region wins, then AWS_REGION, then
|
|
95
|
+
* AWS_DEFAULT_REGION, then the us-west-2 default (M3). The IAM ARN is
|
|
96
|
+
* region-scoped and the agent task defs set no AWS_REGION, so the resolved
|
|
97
|
+
* value is always passed explicitly on every `aws codepipeline` call.
|
|
98
|
+
*/
|
|
99
|
+
export function resolveRegion(explicit, env = process.env) {
|
|
100
|
+
return explicit || env.AWS_REGION || env.AWS_DEFAULT_REGION || DEFAULT_REGION;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parse the `--executions-json` map. Accepts a JSON object of
|
|
104
|
+
* `{ pipelineName: executionId }`. An empty/whitespace value or `{}` yields an
|
|
105
|
+
* empty map (the documented CLI-only no-op). Throws on malformed JSON or a
|
|
106
|
+
* non-object/invalid-entry shape.
|
|
107
|
+
*/
|
|
108
|
+
export function parseExecutionsJson(input) {
|
|
109
|
+
const raw = String(input ?? '').trim();
|
|
110
|
+
if (raw === '' || raw === '{}')
|
|
111
|
+
return [];
|
|
112
|
+
let obj;
|
|
113
|
+
try {
|
|
114
|
+
obj = JSON.parse(raw);
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
throw new Error(`Invalid --executions-json: not valid JSON (${e.message})`);
|
|
118
|
+
}
|
|
119
|
+
if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
|
|
120
|
+
throw new Error(`Invalid --executions-json: expected a JSON object of {pipelineName: executionId}`);
|
|
121
|
+
}
|
|
122
|
+
const entries = [];
|
|
123
|
+
for (const [pipeline, executionId] of Object.entries(obj)) {
|
|
124
|
+
if (typeof executionId !== 'string' || executionId.trim() === '') {
|
|
125
|
+
throw new Error(`Invalid --executions-json: execution id for "${pipeline}" must be a non-empty string`);
|
|
126
|
+
}
|
|
127
|
+
const trimmed = executionId.trim();
|
|
128
|
+
validateExecutionEntry(pipeline, trimmed);
|
|
129
|
+
entries.push({ pipeline, executionId: trimmed });
|
|
130
|
+
}
|
|
131
|
+
return entries;
|
|
132
|
+
}
|
|
133
|
+
const defaultSleep = (seconds) => new Promise((res) => setTimeout(res, seconds * 1000));
|
|
134
|
+
const defaultClock = () => Date.now();
|
|
135
|
+
const defaultLogger = {
|
|
136
|
+
out: (msg) => console.log(msg),
|
|
137
|
+
err: (msg) => console.error(msg),
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Wait for a single (pipeline, executionId) pair to reach a terminal state.
|
|
141
|
+
* Returns the mapped exit code. Never throws — aws-cli failures map to
|
|
142
|
+
* EXIT.AWS_CALL_FAILED after retries.
|
|
143
|
+
*/
|
|
144
|
+
async function waitForOne(pipeline, executionId, opts, deps) {
|
|
145
|
+
const { aws, sleep, clock, logger } = deps;
|
|
146
|
+
const deadline = clock() + opts.timeoutSeconds * 1000;
|
|
147
|
+
const start = clock();
|
|
148
|
+
let polls = 0;
|
|
149
|
+
let lastStatus = 'InProgress';
|
|
150
|
+
// eslint-disable-next-line no-constant-condition
|
|
151
|
+
while (true) {
|
|
152
|
+
polls += 1;
|
|
153
|
+
let stdout;
|
|
154
|
+
let attempt = 0;
|
|
155
|
+
// Transient aws-cli error retry loop (network/credential blip).
|
|
156
|
+
while (true) {
|
|
157
|
+
try {
|
|
158
|
+
stdout = aws([
|
|
159
|
+
'codepipeline',
|
|
160
|
+
'get-pipeline-execution',
|
|
161
|
+
'--pipeline-name',
|
|
162
|
+
pipeline,
|
|
163
|
+
'--pipeline-execution-id',
|
|
164
|
+
executionId,
|
|
165
|
+
'--region',
|
|
166
|
+
opts.region,
|
|
167
|
+
'--output',
|
|
168
|
+
'json',
|
|
169
|
+
]);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
attempt += 1;
|
|
174
|
+
const detail = e;
|
|
175
|
+
const captured = (detail.stderr || detail.message || '').toString().trim();
|
|
176
|
+
if (attempt > AWS_CALL_RETRIES) {
|
|
177
|
+
logger.err('wait-for-pipeline: FAILED');
|
|
178
|
+
logger.err(` pipeline: ${pipeline}`);
|
|
179
|
+
logger.err(` execution_id: ${executionId}`);
|
|
180
|
+
logger.err(` aws_call_failed: ${captured}`);
|
|
181
|
+
logger.err(` retries_exhausted: ${AWS_CALL_RETRIES}`);
|
|
182
|
+
return { exitCode: EXIT.AWS_CALL_FAILED };
|
|
183
|
+
}
|
|
184
|
+
// brief backoff equal to the poll interval before retrying the call
|
|
185
|
+
await sleep(opts.pollIntervalSeconds);
|
|
186
|
+
if (clock() >= deadline) {
|
|
187
|
+
return timeoutResult(pipeline, executionId, lastStatus, opts, start, clock, polls, logger);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
let status;
|
|
192
|
+
try {
|
|
193
|
+
const parsed = JSON.parse(stdout);
|
|
194
|
+
status = parsed?.pipelineExecution?.status ?? 'Unknown';
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Unparseable response → treat as an aws-call failure (fail-closed).
|
|
198
|
+
logger.err('wait-for-pipeline: FAILED');
|
|
199
|
+
logger.err(` pipeline: ${pipeline}`);
|
|
200
|
+
logger.err(` execution_id: ${executionId}`);
|
|
201
|
+
logger.err(' aws_call_failed: could not parse get-pipeline-execution JSON');
|
|
202
|
+
return { exitCode: EXIT.AWS_CALL_FAILED };
|
|
203
|
+
}
|
|
204
|
+
lastStatus = status;
|
|
205
|
+
const waited = Math.round((clock() - start) / 1000);
|
|
206
|
+
if (status === 'Succeeded') {
|
|
207
|
+
logger.out(`wait-for-pipeline: ${pipeline} execution ${executionId} reached Succeeded after ${waited}s (${polls} polls)`);
|
|
208
|
+
return { exitCode: EXIT.SUCCESS };
|
|
209
|
+
}
|
|
210
|
+
if (TERMINAL_FAIL.has(status)) {
|
|
211
|
+
const stage = stageAttribution(pipeline, opts, aws);
|
|
212
|
+
logger.err('wait-for-pipeline: FAILED');
|
|
213
|
+
logger.err(` pipeline: ${pipeline}`);
|
|
214
|
+
logger.err(` execution_id: ${executionId}`);
|
|
215
|
+
logger.err(` terminal_state: ${status}`);
|
|
216
|
+
logger.err(` failed_stage: ${stage || 'unknown'}`);
|
|
217
|
+
logger.err(` waited: ${waited}s (${polls} polls)`);
|
|
218
|
+
return { exitCode: EXIT.PIPELINE_FAILED };
|
|
219
|
+
}
|
|
220
|
+
if (status === 'Superseded') {
|
|
221
|
+
const stage = stageAttribution(pipeline, opts, aws);
|
|
222
|
+
logger.err('wait-for-pipeline: FAILED');
|
|
223
|
+
logger.err(` pipeline: ${pipeline}`);
|
|
224
|
+
logger.err(` execution_id: ${executionId}`);
|
|
225
|
+
logger.err(' terminal_state: Superseded');
|
|
226
|
+
logger.err(` failed_stage: ${stage || 'unknown'}`);
|
|
227
|
+
logger.err(` waited: ${waited}s (${polls} polls)`);
|
|
228
|
+
logger.err(' note: a newer execution superseded this one — see Superseded handling');
|
|
229
|
+
return { exitCode: EXIT.SUPERSEDED };
|
|
230
|
+
}
|
|
231
|
+
// Non-terminal (InProgress / Stopping / Unknown) → sleep and re-poll,
|
|
232
|
+
// unless we have crossed the deadline.
|
|
233
|
+
if (!NON_TERMINAL.has(status) && status !== 'Unknown') {
|
|
234
|
+
// Defensive: an unexpected status string. Treat as still-running and keep
|
|
235
|
+
// polling until the deadline rather than guessing a terminal mapping.
|
|
236
|
+
}
|
|
237
|
+
if (clock() >= deadline) {
|
|
238
|
+
return timeoutResult(pipeline, executionId, lastStatus, opts, start, clock, polls, logger);
|
|
239
|
+
}
|
|
240
|
+
await sleep(opts.pollIntervalSeconds);
|
|
241
|
+
if (clock() >= deadline) {
|
|
242
|
+
return timeoutResult(pipeline, executionId, lastStatus, opts, start, clock, polls, logger);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function timeoutResult(pipeline, executionId, lastStatus, opts, start, clock, polls, logger) {
|
|
247
|
+
const waited = Math.round((clock() - start) / 1000);
|
|
248
|
+
logger.err('wait-for-pipeline: FAILED');
|
|
249
|
+
logger.err(` pipeline: ${pipeline}`);
|
|
250
|
+
logger.err(` execution_id: ${executionId}`);
|
|
251
|
+
logger.err(` terminal_state: ${lastStatus}`);
|
|
252
|
+
logger.err(` timeout: ${opts.timeoutSeconds}s exceeded`);
|
|
253
|
+
logger.err(` last_stage: ${lastStatus}`);
|
|
254
|
+
logger.err(` waited: ${waited}s (${polls} polls)`);
|
|
255
|
+
return { exitCode: EXIT.TIMEOUT };
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Stage-attribution fallback (spec §3.3): parse get-pipeline-state for the
|
|
259
|
+
* stage whose latest execution is not Succeeded. Best-effort — returns '' on
|
|
260
|
+
* any failure (the primary diagnostic still names the pipeline + state).
|
|
261
|
+
*/
|
|
262
|
+
function stageAttribution(pipeline, opts, aws) {
|
|
263
|
+
try {
|
|
264
|
+
const stdout = aws([
|
|
265
|
+
'codepipeline',
|
|
266
|
+
'get-pipeline-state',
|
|
267
|
+
'--name',
|
|
268
|
+
pipeline,
|
|
269
|
+
'--region',
|
|
270
|
+
opts.region,
|
|
271
|
+
'--output',
|
|
272
|
+
'json',
|
|
273
|
+
]);
|
|
274
|
+
const parsed = JSON.parse(stdout);
|
|
275
|
+
const stages = parsed?.stageStates ?? [];
|
|
276
|
+
for (const s of stages) {
|
|
277
|
+
const st = s?.latestExecution?.status;
|
|
278
|
+
if (st && st !== 'Succeeded')
|
|
279
|
+
return s.stageName ?? '';
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
/* best-effort only */
|
|
284
|
+
}
|
|
285
|
+
return '';
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Wait for every (pipeline, executionId) pair in `executions`. Partial-failure
|
|
289
|
+
* semantics: poll all entries; the overall exit code is the FIRST non-zero
|
|
290
|
+
* result encountered (Failed/Stopped→2, Superseded→3, timeout→4, aws-fail→5),
|
|
291
|
+
* SUCCESS only if every pipeline reached Succeeded. An empty list is the
|
|
292
|
+
* documented CLI-only no-op (exit 0 with a note).
|
|
293
|
+
*
|
|
294
|
+
* Returns the process exit code; callers `process.exit(code)`.
|
|
295
|
+
*/
|
|
296
|
+
export async function waitForPipelines(executions, options, deps) {
|
|
297
|
+
const resolved = {
|
|
298
|
+
aws: deps.aws,
|
|
299
|
+
sleep: deps.sleep ?? defaultSleep,
|
|
300
|
+
clock: deps.clock ?? defaultClock,
|
|
301
|
+
logger: deps.logger ?? defaultLogger,
|
|
302
|
+
};
|
|
303
|
+
if (executions.length === 0) {
|
|
304
|
+
resolved.logger.out('wait-for-pipeline: no CodePipeline-backed repos deployed (empty execution map) — nothing to wait for');
|
|
305
|
+
return EXIT.SUCCESS;
|
|
306
|
+
}
|
|
307
|
+
let worstExit = EXIT.SUCCESS;
|
|
308
|
+
for (const { pipeline, executionId } of executions) {
|
|
309
|
+
const result = await waitForOne(pipeline, executionId, options, resolved);
|
|
310
|
+
if (result.exitCode !== EXIT.SUCCESS && worstExit === EXIT.SUCCESS) {
|
|
311
|
+
worstExit = result.exitCode;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return worstExit;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Resolve raw CLI flag values into a validated WaitOptions, clamping the poll
|
|
318
|
+
* interval to its 60s floor and warning on stderr when clamped.
|
|
319
|
+
*/
|
|
320
|
+
export function resolveWaitOptions(flags, env = process.env, logger = defaultLogger) {
|
|
321
|
+
const timeoutSeconds = flags.timeout
|
|
322
|
+
? parseDuration(flags.timeout)
|
|
323
|
+
: DEFAULT_TIMEOUT_SECONDS;
|
|
324
|
+
let pollIntervalSeconds = flags.pollInterval
|
|
325
|
+
? parseDuration(flags.pollInterval)
|
|
326
|
+
: DEFAULT_POLL_INTERVAL_SECONDS;
|
|
327
|
+
if (pollIntervalSeconds < POLL_INTERVAL_FLOOR_SECONDS) {
|
|
328
|
+
logger.err(`wait-for-pipeline: --poll-interval ${pollIntervalSeconds}s is below the ${POLL_INTERVAL_FLOOR_SECONDS}s floor; clamping to ${POLL_INTERVAL_FLOOR_SECONDS}s`);
|
|
329
|
+
pollIntervalSeconds = POLL_INTERVAL_FLOOR_SECONDS;
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
timeoutSeconds,
|
|
333
|
+
pollIntervalSeconds,
|
|
334
|
+
region: resolveRegion(flags.region, env),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=wait-for-pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-for-pipeline.js","sourceRoot":"","sources":["../src/wait-for-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,OAAO,EAAE,CAAC;IACV,eAAe,EAAE,CAAC,EAAE,mBAAmB;IACvC,UAAU,EAAE,CAAC;IACb,OAAO,EAAE,CAAC;IACV,eAAe,EAAE,CAAC;CACV,CAAC;AAEX,mFAAmF;AACnF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AACrD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;AAEzD,sFAAsF;AACtF,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAC9C,gEAAgE;AAChE,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM;AACtD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,CAAC,CAAC,MAAM;AACvD,8EAA8E;AAC9E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAClC,0FAA0F;AAC1F,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,OAAO,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxF,CAAC;AAED;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAC7C;;;;GAIG;AACH,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAE1C;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAAgB,EAAE,WAAmB;IAC1E,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,0BAA0B,QAAQ,gDAAgD,CACnF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,yBAAyB,WAAW,mBAAmB,QAAQ,4CAA4C,CAC5G,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CACb,sBAAsB,KAAK,uCAAuC,CACnE,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IACzB,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,QAA4B,EAC5B,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,QAAQ,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,kBAAkB,IAAI,cAAc,CAAC;AAChF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAa;IAEb,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC1C,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,8CAA+C,CAAW,CAAC,OAAO,GAAG,CACtE,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CACb,kFAAkF,CACnF,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAqD,EAAE,CAAC;IACrE,KAAK,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAClD,GAA8B,CAC/B,EAAE,CAAC;QACF,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CACb,gDAAgD,QAAQ,8BAA8B,CACvF,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;QACnC,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAcD,MAAM,YAAY,GAAY,CAAC,OAAO,EAAE,EAAE,CACxC,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;AAExD,MAAM,YAAY,GAAU,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;AAE7C,MAAM,aAAa,GAAW;IAC5B,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;IAC9B,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;CACjC,CAAC;AAmBF;;;;GAIG;AACH,KAAK,UAAU,UAAU,CACvB,QAAgB,EAChB,WAAmB,EACnB,IAAiB,EACjB,IAAwB;IAExB,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3C,MAAM,QAAQ,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IACtD,MAAM,KAAK,GAAG,KAAK,EAAE,CAAC;IACtB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,UAAU,GAAG,YAAY,CAAC;IAE9B,iDAAiD;IACjD,OAAO,IAAI,EAAE,CAAC;QACZ,KAAK,IAAI,CAAC,CAAC;QACX,IAAI,MAAc,CAAC;QACnB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,gEAAgE;QAChE,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,CAAC;oBACX,cAAc;oBACd,wBAAwB;oBACxB,iBAAiB;oBACjB,QAAQ;oBACR,yBAAyB;oBACzB,WAAW;oBACX,UAAU;oBACV,IAAI,CAAC,MAAM;oBACX,UAAU;oBACV,MAAM;iBACP,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,IAAI,CAAC,CAAC;gBACb,MAAM,MAAM,GAAI,CAA2C,CAAC;gBAC5D,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;gBAC3E,IAAI,OAAO,GAAG,gBAAgB,EAAE,CAAC;oBAC/B,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;oBACxC,MAAM,CAAC,GAAG,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;oBACtC,MAAM,CAAC,GAAG,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;oBAC7C,MAAM,CAAC,GAAG,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;oBAC7C,MAAM,CAAC,GAAG,CAAC,wBAAwB,gBAAgB,EAAE,CAAC,CAAC;oBACvD,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC5C,CAAC;gBACD,oEAAoE;gBACpE,MAAM,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;gBACtC,IAAI,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;oBACxB,OAAO,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;gBAC7F,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAO,CAAC,CAAC;YACnC,MAAM,GAAG,MAAM,EAAE,iBAAiB,EAAE,MAAM,IAAI,SAAS,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACxC,MAAM,CAAC,GAAG,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;YACtC,MAAM,CAAC,GAAG,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;YAC7C,MAAM,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;YAC7E,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,CAAC;QAED,UAAU,GAAG,MAAM,CAAC;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;QAEpD,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,CACR,sBAAsB,QAAQ,cAAc,WAAW,4BAA4B,MAAM,MAAM,KAAK,SAAS,CAC9G,CAAC;YACF,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,CAAC;QAED,IAAI,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YACpD,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACxC,MAAM,CAAC,GAAG,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;YACtC,MAAM,CAAC,GAAG,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;YAC7C,MAAM,CAAC,GAAG,CAAC,qBAAqB,MAAM,EAAE,CAAC,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,mBAAmB,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;YACpD,MAAM,CAAC,GAAG,CAAC,aAAa,MAAM,MAAM,KAAK,SAAS,CAAC,CAAC;YACpD,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,CAAC;QAED,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YACpD,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACxC,MAAM,CAAC,GAAG,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;YACtC,MAAM,CAAC,GAAG,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;YAC7C,MAAM,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;YAC3C,MAAM,CAAC,GAAG,CAAC,mBAAmB,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;YACpD,MAAM,CAAC,GAAG,CAAC,aAAa,MAAM,MAAM,KAAK,SAAS,CAAC,CAAC;YACpD,MAAM,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC;YACtF,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;QACvC,CAAC;QAED,sEAAsE;QACtE,uCAAuC;QACvC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACtD,0EAA0E;YAC1E,sEAAsE;QACxE,CAAC;QAED,IAAI,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;YACxB,OAAO,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC7F,CAAC;QACD,MAAM,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACtC,IAAI,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;YACxB,OAAO,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CACpB,QAAgB,EAChB,WAAmB,EACnB,UAAkB,EAClB,IAAiB,EACjB,KAAa,EACb,KAAY,EACZ,KAAa,EACb,MAAc;IAEd,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;IACtC,MAAM,CAAC,GAAG,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;IAC7C,MAAM,CAAC,GAAG,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,cAAc,YAAY,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;IAC1C,MAAM,CAAC,GAAG,CAAC,aAAa,MAAM,MAAM,KAAK,SAAS,CAAC,CAAC;IACpD,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CACvB,QAAgB,EAChB,IAAiB,EACjB,GAAc;IAEd,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,GAAG,CAAC;YACjB,cAAc;YACd,oBAAoB;YACpB,QAAQ;YACR,QAAQ;YACR,UAAU;YACV,IAAI,CAAC,MAAM;YACX,UAAU;YACV,MAAM;SACP,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,MAAM,GACV,MAAM,EAAE,WAAW,IAAI,EAAE,CAAC;QAC5B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,EAAE,GAAG,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC;YACtC,IAAI,EAAE,IAAI,EAAE,KAAK,WAAW;gBAAE,OAAO,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;QACzD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAA4D,EAC5D,OAAoB,EACpB,IAAc;IAEd,MAAM,QAAQ,GAAuB;QACnC,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,YAAY;QACjC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,YAAY;QACjC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,aAAa;KACrC,CAAC;IAEF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,QAAQ,CAAC,MAAM,CAAC,GAAG,CACjB,sGAAsG,CACvG,CAAC;QACF,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,IAAI,SAAS,GAAW,IAAI,CAAC,OAAO,CAAC;IACrC,KAAK,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,UAAU,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,OAAO,IAAI,SAAS,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;YACnE,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAIC,EACD,MAAyB,OAAO,CAAC,GAAG,EACpC,SAAiB,aAAa;IAE9B,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO;QAClC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC;QAC9B,CAAC,CAAC,uBAAuB,CAAC;IAC5B,IAAI,mBAAmB,GAAG,KAAK,CAAC,YAAY;QAC1C,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC;QACnC,CAAC,CAAC,6BAA6B,CAAC;IAClC,IAAI,mBAAmB,GAAG,2BAA2B,EAAE,CAAC;QACtD,MAAM,CAAC,GAAG,CACR,sCAAsC,mBAAmB,kBAAkB,2BAA2B,wBAAwB,2BAA2B,GAAG,CAC7J,CAAC;QACF,mBAAmB,GAAG,2BAA2B,CAAC;IACpD,CAAC;IACD,OAAO;QACL,cAAc;QACd,mBAAmB;QACnB,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC;KACzC,CAAC;AACJ,CAAC"}
|