codepipeline-event-notifier 0.1.8 → 0.2.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/.jsii +167 -20
- package/API.md +229 -9
- package/README.md +55 -11
- package/assets/funcs/notifier.lambda/index.js +34 -21
- package/assets/funcs/notifier.lambda/index.js.map +3 -3
- package/lib/constructs/codepipeline-event-notifier.d.ts +45 -1
- package/lib/constructs/codepipeline-event-notifier.js +27 -20
- package/lib/funcs/notifier-predicates.d.ts +29 -0
- package/lib/funcs/notifier-predicates.js +37 -0
- package/lib/funcs/notifier.lambda.d.ts +1 -1
- package/lib/funcs/notifier.lambda.js +23 -24
- package/lib/index.d.ts +1 -3
- package/lib/index.js +4 -10
- package/package.json +1 -1
|
@@ -201,6 +201,18 @@ module.exports = __toCommonJS(notifier_lambda_exports);
|
|
|
201
201
|
var import_client_codepipeline = require("@aws-sdk/client-codepipeline");
|
|
202
202
|
var import_client_sns = require("@aws-sdk/client-sns");
|
|
203
203
|
var import_strict_env_resolver = __toESM(require_lib());
|
|
204
|
+
|
|
205
|
+
// src/funcs/notifier-predicates.ts
|
|
206
|
+
var normalizeExecutionStatus = (statusRaw) => String(statusRaw ?? "UNKNOWN").toUpperCase();
|
|
207
|
+
var isTerminalExecutionStatus = (status) => status === "SUCCEEDED" || status === "FAILED" || status === "STOPPED" || status === "SUPERSEDED";
|
|
208
|
+
var resolvePipelineExecutionIdentity = (pipelineName, executionId) => {
|
|
209
|
+
if (!pipelineName || !executionId) {
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
return { pipelineName, executionId };
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// src/funcs/notifier.lambda.ts
|
|
204
216
|
var sns = new import_client_sns.SNSClient({});
|
|
205
217
|
var codepipeline = new import_client_codepipeline.CodePipelineClient({});
|
|
206
218
|
var mustEnv = (name) => import_strict_env_resolver.StrictEnvResolver.resolve(name, import_strict_env_resolver.StrictEnvType.String, { trim: true });
|
|
@@ -211,16 +223,16 @@ var publish = async (topicArn, payload) => {
|
|
|
211
223
|
Message: JSON.stringify(payload)
|
|
212
224
|
}));
|
|
213
225
|
};
|
|
214
|
-
var
|
|
226
|
+
var waitPipelineExecution = async (params) => {
|
|
215
227
|
const {
|
|
216
228
|
topicArn,
|
|
217
229
|
pipelineName,
|
|
218
230
|
executionId,
|
|
219
|
-
|
|
220
|
-
|
|
231
|
+
waitIntervalSeconds,
|
|
232
|
+
maxWaitMinutes,
|
|
221
233
|
startEvent
|
|
222
234
|
} = params;
|
|
223
|
-
const deadline = Date.now() +
|
|
235
|
+
const deadline = Date.now() + maxWaitMinutes * 6e4;
|
|
224
236
|
let lastStatus;
|
|
225
237
|
await publish(topicArn, {
|
|
226
238
|
type: "codepipeline.execution",
|
|
@@ -236,39 +248,40 @@ var pollPipelineExecution = async (params) => {
|
|
|
236
248
|
pipelineName,
|
|
237
249
|
pipelineExecutionId: executionId
|
|
238
250
|
}));
|
|
239
|
-
const
|
|
240
|
-
const status = String(statusRaw).toUpperCase();
|
|
251
|
+
const status = normalizeExecutionStatus(res.pipelineExecution?.status);
|
|
241
252
|
if (status !== lastStatus) {
|
|
242
253
|
lastStatus = status;
|
|
243
254
|
await publish(topicArn, {
|
|
244
255
|
type: "codepipeline.execution",
|
|
245
|
-
phase: "
|
|
256
|
+
phase: "wait",
|
|
246
257
|
pipelineName,
|
|
247
258
|
executionId,
|
|
248
259
|
observedState: status,
|
|
249
260
|
observedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
250
261
|
});
|
|
251
262
|
}
|
|
252
|
-
if (status
|
|
263
|
+
if (isTerminalExecutionStatus(status)) {
|
|
253
264
|
return;
|
|
254
265
|
}
|
|
255
|
-
await sleep(
|
|
266
|
+
await sleep(waitIntervalSeconds * 1e3);
|
|
256
267
|
}
|
|
257
268
|
await publish(topicArn, {
|
|
258
269
|
type: "codepipeline.execution",
|
|
259
|
-
phase: "
|
|
270
|
+
phase: "wait",
|
|
260
271
|
pipelineName,
|
|
261
272
|
executionId,
|
|
262
273
|
observedState: lastStatus ?? "UNKNOWN",
|
|
263
274
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
264
|
-
note: "
|
|
275
|
+
note: "Waiting timed out before terminal state."
|
|
265
276
|
});
|
|
266
277
|
};
|
|
267
278
|
var handler = async (event) => {
|
|
268
279
|
const topicArn = mustEnv("SNS_TOPIC_ARN");
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
280
|
+
const identity = resolvePipelineExecutionIdentity(
|
|
281
|
+
event.detail?.pipeline,
|
|
282
|
+
event.detail?.["execution-id"]
|
|
283
|
+
);
|
|
284
|
+
if (!identity) {
|
|
272
285
|
await publish(topicArn, {
|
|
273
286
|
type: "codepipeline.execution",
|
|
274
287
|
phase: "eventbridge",
|
|
@@ -278,14 +291,14 @@ var handler = async (event) => {
|
|
|
278
291
|
});
|
|
279
292
|
return;
|
|
280
293
|
}
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
await
|
|
294
|
+
const waitIntervalSeconds = import_strict_env_resolver.StrictEnvResolver.resolve("WAIT_INTERVAL_SECONDS", import_strict_env_resolver.StrictEnvType.Number, { default: 10 });
|
|
295
|
+
const maxWaitMinutes = import_strict_env_resolver.StrictEnvResolver.resolve("MAX_WAIT_MINUTES", import_strict_env_resolver.StrictEnvType.Number, { default: 14 });
|
|
296
|
+
await waitPipelineExecution({
|
|
284
297
|
topicArn,
|
|
285
|
-
pipelineName,
|
|
286
|
-
executionId,
|
|
287
|
-
|
|
288
|
-
|
|
298
|
+
pipelineName: identity.pipelineName,
|
|
299
|
+
executionId: identity.executionId,
|
|
300
|
+
waitIntervalSeconds: waitIntervalSeconds > 0 ? waitIntervalSeconds : 10,
|
|
301
|
+
maxWaitMinutes: maxWaitMinutes > 0 ? maxWaitMinutes : 14,
|
|
289
302
|
startEvent: event
|
|
290
303
|
});
|
|
291
304
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../node_modules/strict-env-resolver/src/index.ts", "../../../src/funcs/notifier.lambda.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Spec for a string environment variable.\n * Returned as-is by default (`trim` defaults to `false`). Set `trim: true` in options to trim\n * whitespace and treat whitespace-only values as missing.\n * The default value is passed via the third argument of `resolve` or a `[spec, options]` tuple in `resolveAll`, not in the spec.\n */\nexport type StrictEnvTypeString = { type: 'string'; default?: string };\n\n/**\n * Spec for a numeric environment variable.\n * Values are parsed with `Number()`; `NaN`, `Infinity`, and `-Infinity` are rejected.\n * The default value is passed via the third argument of `resolve` or a `[spec, options]` tuple in `resolveAll`, not in the spec.\n */\nexport type StrictEnvTypeNumber = { type: 'number'; default?: number };\n\n/**\n * Pattern for boolean env values that parse as `true`.\n * Matches `1`, `true`, `yes`, and `on` (case-insensitive) on the full trimmed string.\n */\nconst TRUE_BOOLEAN_PATTERN = /^(1|true|yes|on)$/i;\n\n/**\n * Parses a string as a finite number for environment variables.\n *\n * @param raw - Trimmed environment variable value.\n * @returns Parsed number, or `undefined` when the value is not a finite number.\n */\nconst parseNumber = (raw: string): number | undefined => {\n const n = Number(raw);\n if (!Number.isFinite(n)) {\n return undefined;\n }\n return n;\n};\n\n/**\n * Parses a trimmed string as a boolean environment variable value.\n *\n * @param normalizedRaw - Trimmed raw environment variable value.\n * @returns `true` for `1`/`true`/`yes`/`on` (case-insensitive); otherwise `false`.\n */\nconst parseBooleanEnvValue = (normalizedRaw: string): boolean => TRUE_BOOLEAN_PATTERN.test(normalizedRaw);\n\n/**\n * Spec for a boolean environment variable.\n * Parses `1`, `true`, `yes`, `on` (case-insensitive, after trim) as `true`; any other non-empty value as `false`.\n * Trims leading/trailing whitespace by default (see `StrictEnvOptions.trim`).\n * The default value is passed via the third argument of `resolve` or a `[spec, options]` tuple in `resolveAll`, not in the spec.\n */\nexport type StrictEnvTypeBoolean = { type: 'boolean'; default?: boolean };\n\n/**\n * Spec for an enum environment variable with a fixed set of choices.\n * The value must be one of `choices` (compared after trim); otherwise validation fails.\n * Trims leading/trailing whitespace by default (see `StrictEnvOptions.trim`).\n * The default value is passed via the third argument of `resolve` or a `[spec, options]` tuple in `resolveAll`, not in the spec.\n *\n * @template T - Literal string union of allowed values.\n */\nexport type StrictEnvTypeEnum<T extends string = string> = { type: 'enum'; choices: readonly T[]; default?: T };\n\n/** Union of all environment variable spec types. */\nexport type StrictEnvSpec =\n | StrictEnvTypeString\n | StrictEnvTypeNumber\n | StrictEnvTypeBoolean\n | StrictEnvTypeEnum;\n\n/**\n * Discriminated union of error kinds emitted during environment variable parsing.\n *\n * - `missing` — Variable unset, empty string, or whitespace-only (when trim is enabled) without a default.\n * - `invalid_number` — Value is not a finite number (see `StrictEnvTypeNumber`).\n * - `invalid_enum` — Value is not one of the allowed enum choices.\n */\nexport type StrictEnvErrorKind = 'missing' | 'invalid_number' | 'invalid_enum';\n\n/**\n * A structured validation error entry for a single environment variable.\n *\n * @template K - Environment variable key type.\n */\nexport type StrictEnvValidationEntry<K extends string = string> = {\n /** Environment variable name. */\n key: K;\n /** Human-readable error message. */\n message: string;\n /** Raw value from `process.env`, if present. */\n raw?: string;\n /** Error category for programmatic handling. */\n kind: StrictEnvErrorKind;\n};\n\n/**\n * Base error class for this package.\n *\n * @example\n * ```ts\n * try {\n * StrictEnvResolver.resolve('PORT', StrictEnvType.Number);\n * } catch (e) {\n * if (e instanceof StrictEnvError) {\n * // Handle all strict-env-resolver errors\n * }\n * }\n * ```\n */\nexport abstract class StrictEnvError extends Error {\n /**\n * @param message - Error message.\n */\n protected constructor(message: string) {\n super(message);\n this.name = 'StrictEnvError';\n }\n}\n\n/**\n * Validation error that carries one or more environment variable issues.\n *\n * Thrown by `StrictEnvResolver.resolve()` (single-entry `errors`) and\n * `StrictEnvResolver.resolveAll()` (multi-entry `errors`).\n * Individual entries are produced by the internal `parseEnvValue` helper.\n *\n * @template K - Union of environment variable keys included in `errors`.\n */\nexport class StrictEnvValidationError<K extends string = string> extends StrictEnvError {\n /**\n * Formats validation errors into a human-readable error message.\n *\n * @template K - Environment variable key type.\n * @param errors - Validation error entries to format.\n * @returns Multi-line summary listing each key and message.\n */\n public static format<K extends string>(errors: readonly StrictEnvValidationEntry<K>[]): string {\n const lines = errors.map((e) => `- ${e.key}: ${e.message}${e.raw == null ? '' : ` (raw=\"${e.raw}\")`}`);\n return `Invalid environment variables (${errors.length}):\\n${lines.join('\\n')}`;\n }\n\n /**\n * Structured list of validation errors.\n */\n public readonly errors: readonly StrictEnvValidationEntry<K>[];\n /**\n * Convenience list of keys included in `errors`.\n */\n public readonly keys: readonly K[];\n\n /**\n * Creates a new validation error from one or more `StrictEnvValidationEntry` entries.\n *\n * @param errors - One or more structured validation errors.\n */\n public constructor(errors: readonly StrictEnvValidationEntry<K>[]) {\n const msg = StrictEnvValidationError.format(errors);\n super(msg);\n this.name = 'StrictEnvValidationError';\n this.errors = errors;\n this.keys = errors.map((e) => e.key);\n }\n}\n\n/**\n * Predefined spec constants for use with `resolve` or as schema values in `resolveAll`.\n * Provide defaults via the third argument of `resolve` or a `[spec, { default }]` tuple in `resolveAll`.\n */\nexport const StrictEnvType = {\n /** Spec for a string value (returned as-is unless `trim: true` is set in options). */\n String: { type: 'string' } as const satisfies StrictEnvTypeString,\n /**\n * Spec for a finite numeric value (`Number()` parsing; rejects `NaN` and `Infinity`).\n */\n Number: { type: 'number' } as const satisfies StrictEnvTypeNumber,\n /** Spec for a boolean value (`1`/`true`/`yes`/`on` → `true`; other non-empty values → `false`). */\n Boolean: { type: 'boolean' } as const satisfies StrictEnvTypeBoolean,\n /**\n * Returns a spec that restricts the value to one of the given choices.\n *\n * @param choices - Allowed string literals.\n * @returns Enum spec for use with `resolve` or `resolveAll`.\n */\n Enum: <T extends string>(choices: readonly T[]) => ({ type: 'enum', choices }) as StrictEnvTypeEnum<T>,\n} as const;\n\n/**\n * Infers the return type from the given spec.\n * @template S - A `StrictEnvSpec` variant.\n */\nexport type StrictEnvSpecToType<S> =\n S extends StrictEnvTypeString ? string\n : S extends StrictEnvTypeNumber ? number\n : S extends StrictEnvTypeBoolean ? boolean\n : S extends StrictEnvTypeEnum<infer T> ? T\n : never;\n\n/**\n * Options for reading an environment variable with an optional default.\n * Used as the third argument to `resolve` or as the second element of a `[spec, options]` tuple in `resolveAll`.\n *\n * `trim` defaults to `true` for `number`, `boolean`, and `enum` specs (whitespace-only values are\n * treated as missing). For `string` specs it defaults to `false` (values are returned as-is).\n *\n * @template S - Environment variable spec type.\n */\nexport type StrictEnvOptions<S extends StrictEnvSpec> = {\n default?: StrictEnvSpecToType<S>;\n /** When `true`, trims leading/trailing whitespace before validation. */\n trim?: boolean;\n};\n\n/**\n * Schema entry for a single env var.\n *\n * Either provide a spec directly, or a tuple of `[spec, options]` to attach a default.\n */\nexport type StrictEnvSchemaEntry<S extends StrictEnvSpec = StrictEnvSpec> = S | readonly [S, StrictEnvOptions<S>];\n\n/**\n * Schema object used by `resolveAll()`.\n *\n * Keys are env var names, values are specs (optionally with defaults).\n */\nexport type StrictEnvSchema = Record<string, StrictEnvSchemaEntry>;\n\n/**\n * Extracts the spec type from a schema entry or `[spec, options]` tuple.\n *\n * @template E - Schema entry type.\n */\ntype StrictEnvSchemaEntryToSpec<E> = E extends readonly [infer S, unknown] ? S : E;\n\n/**\n * Maps a schema object to the resulting parsed environment object type.\n *\n * @template TSchema - Schema object type passed to `resolveAll`.\n */\nexport type StrictEnvSchemaToType<TSchema extends StrictEnvSchema> = {\n [K in keyof TSchema]: StrictEnvSpecToType<StrictEnvSchemaEntryToSpec<TSchema[K]> & StrictEnvSpec>;\n};\n\n/**\n * Discriminated result of parsing a single environment variable.\n *\n * On success, `value` holds the parsed result. On failure, `error` holds a structured\n * `StrictEnvValidationEntry` entry (never throws).\n *\n * @template K - Environment variable key type.\n * @template S - Environment variable spec type.\n */\ntype ParseEnvValueResult<K extends string, S extends StrictEnvSpec> =\n | { ok: true; value: StrictEnvSpecToType<S> }\n | { ok: false; error: StrictEnvValidationEntry<K> };\n\n/**\n * Default trim behavior per spec type.\n * Parsed types trim by default; strings preserve the raw value unless opted in.\n *\n * @param spec - Environment variable spec.\n * @returns Whether leading/trailing whitespace should be trimmed before validation.\n */\nconst defaultTrimForSpec = (spec: StrictEnvSpec): boolean => spec.type !== 'string';\n\n/**\n * Normalizes a raw environment variable value before validation.\n *\n * @param raw - Raw value from `process.env`, if present.\n * @param trim - Whether to trim leading/trailing whitespace.\n * @returns Normalized value, or `undefined` when unset.\n */\nconst normalizeEnvRaw = (raw: string | undefined, trim: boolean): string | undefined => {\n if (raw == null) {\n return undefined;\n }\n if (!trim) {\n return raw;\n }\n return raw.trim();\n};\n\n/** Options accepted by `parseEnvValue` (subset of `StrictEnvOptions`). */\ntype ParseEnvValueOptions<S extends StrictEnvSpec> = Pick<StrictEnvOptions<S>, 'trim'>;\n\n/**\n * Resolves a schema entry into its spec and optional per-key options.\n *\n * @param entry - Schema entry or `[spec, options]` tuple.\n * @returns Parsed spec and options for `resolveAll`.\n */\nconst resolveSchemaEntry = (\n entry: StrictEnvSchemaEntry,\n): { spec: StrictEnvSpec; options: StrictEnvOptions<StrictEnvSpec> | undefined } => ({\n spec: (Array.isArray(entry) ? entry[0] : entry) as StrictEnvSpec,\n options: (Array.isArray(entry) ? entry[1] : undefined) as StrictEnvOptions<StrictEnvSpec> | undefined,\n});\n\n/**\n * Parses a single environment variable according to the given spec.\n *\n * Central validation helper shared by `resolve` and `resolveAll`. Does not throw;\n * callers decide whether to throw immediately or collect errors.\n *\n * Missing or empty (`\"\"`) values use `defaultValue` when provided. When `trim` is enabled,\n * whitespace-only values are treated as empty. Number specs delegate to `parseNumber`.\n * Boolean specs treat `1`/`true`/`yes`/`on` (case-insensitive, after trim) as `true`.\n * Enum specs require an exact match in `choices` (after trim).\n *\n * @template K - Environment variable key type.\n * @template S - Environment variable spec type.\n * @param key - Environment variable name.\n * @param spec - Type spec for the value.\n * @param raw - Raw value from `process.env`, if present.\n * @param defaultValue - Fallback when `raw` is missing or empty.\n * @param options - Optional trim override (`trim` defaults per spec type).\n * @returns Parsed value or a structured validation error.\n */\nconst parseEnvValue = <K extends string, S extends StrictEnvSpec>(\n key: K,\n spec: S,\n raw: string | undefined,\n defaultValue: StrictEnvSpecToType<S> | undefined,\n options?: ParseEnvValueOptions<S>,\n): ParseEnvValueResult<K, S> => {\n const trim = options?.trim ?? defaultTrimForSpec(spec);\n const normalizedRaw = normalizeEnvRaw(raw, trim);\n const hasDefault = defaultValue !== undefined;\n\n if (normalizedRaw == null || normalizedRaw === '') {\n if (hasDefault) {\n return { ok: true, value: defaultValue as StrictEnvSpecToType<S> };\n }\n return {\n ok: false,\n error: { key, message: `Missing required environment variable: ${key}`, raw, kind: 'missing' },\n };\n }\n\n switch (spec.type) {\n case 'number': {\n const n = parseNumber(normalizedRaw);\n if (n === undefined) {\n return {\n ok: false,\n error: { key, message: `Env ${key}: expected number, got \"${raw}\"`, raw, kind: 'invalid_number' },\n };\n }\n return { ok: true, value: n as StrictEnvSpecToType<S> };\n }\n case 'boolean':\n return { ok: true, value: parseBooleanEnvValue(normalizedRaw) as StrictEnvSpecToType<S> };\n case 'enum':\n if (!spec.choices.includes(normalizedRaw)) {\n return {\n ok: false,\n error: {\n key,\n message: `Env ${key}: must be one of [${spec.choices.join(', ')}]`,\n raw,\n kind: 'invalid_enum',\n },\n };\n }\n return { ok: true, value: normalizedRaw as StrictEnvSpecToType<S> };\n default:\n return { ok: true, value: normalizedRaw as StrictEnvSpecToType<S> };\n }\n};\n\n/**\n * Reads and parses an environment variable according to the given spec.\n *\n * Delegates validation to `parseEnvValue`. Missing or empty (`\"\"`) values use\n * `options.default` when provided; otherwise a `StrictEnvValidationError` is thrown.\n * For `StrictEnvType.Number`, values are parsed as finite numbers (see `StrictEnvTypeNumber`).\n *\n * @template K - Environment variable key type.\n * @template S - Environment variable spec type.\n * @param key - Environment variable name (e.g. `\"PORT\"`, `\"NODE_ENV\"`).\n * @param spec - Type spec; defaults to `StrictEnvType.String` when omitted.\n * @param options - Optional `{ default, trim }`; see {@link StrictEnvOptions}.\n * @returns Parsed value with type inferred from `spec`.\n * @throws {StrictEnvValidationError} When the variable is missing, empty without a default, or invalid for the spec.\n */\nconst resolve = <K extends string, S extends StrictEnvSpec = StrictEnvTypeString>(\n key: K,\n spec: S = StrictEnvType.String as S,\n options?: StrictEnvOptions<S>,\n): StrictEnvSpecToType<S> => {\n const result = parseEnvValue(key, spec, process.env[key], options?.default, options);\n if (!result.ok) {\n throw new StrictEnvValidationError([result.error]);\n }\n return result.value;\n};\n\n/**\n * Reads and parses multiple environment variables according to the given schema.\n *\n * Always evaluates every key in `schema`. Each entry is validated via `parseEnvValue`;\n * all errors are collected and thrown once in a single `StrictEnvValidationError`.\n * Number specs use the same finite-number rules as `resolve`.\n *\n * @template TSchema - Schema object type.\n * @param schema - Map of environment variable names to specs, optionally with per-key defaults via `[spec, { default }]`.\n * @returns Parsed environment object with types inferred from the schema.\n * @throws {StrictEnvValidationError} When one or more variables are missing, empty without a default, or invalid.\n */\nconst resolveAll = <TSchema extends StrictEnvSchema>(schema: TSchema): StrictEnvSchemaToType<TSchema> => {\n const envs: Partial<StrictEnvSchemaToType<TSchema>> = {};\n const errors: StrictEnvValidationEntry<Extract<keyof TSchema, string>>[] = [];\n\n for (const key of Object.keys(schema) as Array<Extract<keyof TSchema, string>>) {\n const { spec, options } = resolveSchemaEntry(schema[key]);\n\n const result = parseEnvValue(key, spec, process.env[key], options?.default, options);\n if (!result.ok) {\n errors.push(result.error);\n continue;\n }\n envs[key] = result.value as StrictEnvSchemaToType<TSchema>[typeof key];\n }\n\n if (errors.length > 0) throw new StrictEnvValidationError(errors);\n return envs as StrictEnvSchemaToType<TSchema>;\n};\n\n/**\n * Type-safe environment variable resolver for Node.js `process.env`.\n *\n * @example\n * ```ts\n * const port = StrictEnvResolver.resolve('PORT', StrictEnvType.Number);\n * const envs = StrictEnvResolver.resolveAll({\n * PORT: StrictEnvType.Number,\n * DEBUG: [StrictEnvType.Boolean, { default: false }],\n * });\n * ```\n */\nexport const StrictEnvResolver = {\n /** Reads and parses a single environment variable. See {@link resolve}. */\n resolve,\n /** Reads and parses multiple environment variables in one pass. See {@link resolveAll}. */\n resolveAll,\n} as const;\n", "import { CodePipelineClient, GetPipelineExecutionCommand } from '@aws-sdk/client-codepipeline';\nimport { PublishCommand, SNSClient } from '@aws-sdk/client-sns';\nimport type { EventBridgeEvent } from 'aws-lambda';\nimport { StrictEnvResolver, StrictEnvType } from 'strict-env-resolver';\n\n/**\n * EventBridge detail payload for CodePipeline execution state-change events.\n */\ntype CodePipelineExecutionStartedDetail = {\n 'pipeline'?: string;\n 'state'?: string;\n 'version'?: string;\n 'execution-id'?: string;\n};\n\n/**\n * EventBridge event for CodePipeline execution state-change notifications.\n */\ntype CodePipelineExecutionStartedEvent = EventBridgeEvent<\n 'CodePipeline Pipeline Execution State Change',\n CodePipelineExecutionStartedDetail\n>;\n\n/**\n * SNS client used to publish notifications.\n */\nconst sns = new SNSClient({});\n\n/**\n * CodePipeline client used to poll execution state.\n */\nconst codepipeline = new CodePipelineClient({});\n\n/**\n * Reads a required environment variable.\n */\nconst mustEnv = (name: string): string => StrictEnvResolver.resolve(name, StrictEnvType.String, { trim: true });\n\n/**\n * Sleeps for the specified number of milliseconds.\n */\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Publishes a JSON payload to the given SNS topic ARN.\n */\nconst publish = async (topicArn: string, payload: unknown): Promise<void> => {\n await sns.send(new PublishCommand({\n TopicArn: topicArn,\n Message: JSON.stringify(payload),\n }));\n};\n\n/**\n * Polls a CodePipeline execution and publishes notifications whenever the execution status changes.\n */\nconst pollPipelineExecution = async (params: {\n topicArn: string;\n pipelineName: string;\n executionId: string;\n pollIntervalSeconds: number;\n maxPollMinutes: number;\n startEvent: CodePipelineExecutionStartedEvent;\n}): Promise<void> => {\n const {\n topicArn,\n pipelineName,\n executionId,\n pollIntervalSeconds,\n maxPollMinutes,\n startEvent,\n } = params;\n\n const deadline = Date.now() + maxPollMinutes * 60_000;\n let lastStatus: string | undefined;\n\n // \u6700\u521D\u306B STARTED \u3092\u901A\u77E5\uFF08EventBridge\u7531\u6765\uFF09\n await publish(topicArn, {\n type: 'codepipeline.execution',\n phase: 'eventbridge',\n pipelineName,\n executionId,\n observedState: startEvent.detail?.state ?? 'STARTED',\n observedAt: new Date().toISOString(),\n event: startEvent,\n });\n\n while (Date.now() < deadline) {\n const res = await codepipeline.send(new GetPipelineExecutionCommand({\n pipelineName,\n pipelineExecutionId: executionId,\n }));\n\n const statusRaw = res.pipelineExecution?.status ?? 'UNKNOWN';\n const status = String(statusRaw).toUpperCase();\n if (status !== lastStatus) {\n lastStatus = status;\n await publish(topicArn, {\n type: 'codepipeline.execution',\n phase: 'poll',\n pipelineName,\n executionId,\n observedState: status,\n observedAt: new Date().toISOString(),\n });\n }\n\n if (status === 'SUCCEEDED' || status === 'FAILED' || status === 'STOPPED' || status === 'SUPERSEDED') {\n return;\n }\n\n await sleep(pollIntervalSeconds * 1000);\n }\n\n await publish(topicArn, {\n type: 'codepipeline.execution',\n phase: 'poll',\n pipelineName,\n executionId,\n observedState: lastStatus ?? 'UNKNOWN',\n observedAt: new Date().toISOString(),\n note: 'Polling timed out before terminal state.',\n });\n};\n\n/**\n * Lambda handler triggered by EventBridge when a pipeline execution transitions to STARTED.\n * It polls the execution status until it reaches a terminal state or times out.\n */\nexport const handler = async (event: CodePipelineExecutionStartedEvent): Promise<void> => {\n const topicArn = mustEnv('SNS_TOPIC_ARN');\n const pipelineName = event.detail?.pipeline;\n const executionId = event.detail?.['execution-id'];\n\n if (!pipelineName || !executionId) {\n await publish(topicArn, {\n type: 'codepipeline.execution',\n phase: 'eventbridge',\n observedAt: new Date().toISOString(),\n note: 'Missing pipelineName or executionId in event.detail',\n event,\n });\n return;\n }\n\n const pollIntervalSeconds = StrictEnvResolver.resolve('POLL_INTERVAL_SECONDS', StrictEnvType.Number, { default: 10 });\n const maxPollMinutes = StrictEnvResolver.resolve('MAX_POLL_MINUTES', StrictEnvType.Number, { default: 14 });\n\n await pollPipelineExecution({\n topicArn,\n pipelineName,\n executionId,\n pollIntervalSeconds: pollIntervalSeconds > 0 ? pollIntervalSeconds : 10,\n maxPollMinutes: maxPollMinutes > 0 ? maxPollMinutes : 14,\n startEvent: event,\n });\n};\n"],
|
|
5
|
-
"mappings": "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
|
|
3
|
+
"sources": ["../../../node_modules/strict-env-resolver/src/index.ts", "../../../src/funcs/notifier.lambda.ts", "../../../src/funcs/notifier-predicates.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Spec for a string environment variable.\n * Returned as-is by default (`trim` defaults to `false`). Set `trim: true` in options to trim\n * whitespace and treat whitespace-only values as missing.\n * The default value is passed via the third argument of `resolve` or a `[spec, options]` tuple in `resolveAll`, not in the spec.\n */\nexport type StrictEnvTypeString = { type: 'string'; default?: string };\n\n/**\n * Spec for a numeric environment variable.\n * Values are parsed with `Number()`; `NaN`, `Infinity`, and `-Infinity` are rejected.\n * The default value is passed via the third argument of `resolve` or a `[spec, options]` tuple in `resolveAll`, not in the spec.\n */\nexport type StrictEnvTypeNumber = { type: 'number'; default?: number };\n\n/**\n * Pattern for boolean env values that parse as `true`.\n * Matches `1`, `true`, `yes`, and `on` (case-insensitive) on the full trimmed string.\n */\nconst TRUE_BOOLEAN_PATTERN = /^(1|true|yes|on)$/i;\n\n/**\n * Parses a string as a finite number for environment variables.\n *\n * @param raw - Trimmed environment variable value.\n * @returns Parsed number, or `undefined` when the value is not a finite number.\n */\nconst parseNumber = (raw: string): number | undefined => {\n const n = Number(raw);\n if (!Number.isFinite(n)) {\n return undefined;\n }\n return n;\n};\n\n/**\n * Parses a trimmed string as a boolean environment variable value.\n *\n * @param normalizedRaw - Trimmed raw environment variable value.\n * @returns `true` for `1`/`true`/`yes`/`on` (case-insensitive); otherwise `false`.\n */\nconst parseBooleanEnvValue = (normalizedRaw: string): boolean => TRUE_BOOLEAN_PATTERN.test(normalizedRaw);\n\n/**\n * Spec for a boolean environment variable.\n * Parses `1`, `true`, `yes`, `on` (case-insensitive, after trim) as `true`; any other non-empty value as `false`.\n * Trims leading/trailing whitespace by default (see `StrictEnvOptions.trim`).\n * The default value is passed via the third argument of `resolve` or a `[spec, options]` tuple in `resolveAll`, not in the spec.\n */\nexport type StrictEnvTypeBoolean = { type: 'boolean'; default?: boolean };\n\n/**\n * Spec for an enum environment variable with a fixed set of choices.\n * The value must be one of `choices` (compared after trim); otherwise validation fails.\n * Trims leading/trailing whitespace by default (see `StrictEnvOptions.trim`).\n * The default value is passed via the third argument of `resolve` or a `[spec, options]` tuple in `resolveAll`, not in the spec.\n *\n * @template T - Literal string union of allowed values.\n */\nexport type StrictEnvTypeEnum<T extends string = string> = { type: 'enum'; choices: readonly T[]; default?: T };\n\n/** Union of all environment variable spec types. */\nexport type StrictEnvSpec =\n | StrictEnvTypeString\n | StrictEnvTypeNumber\n | StrictEnvTypeBoolean\n | StrictEnvTypeEnum;\n\n/**\n * Discriminated union of error kinds emitted during environment variable parsing.\n *\n * - `missing` — Variable unset, empty string, or whitespace-only (when trim is enabled) without a default.\n * - `invalid_number` — Value is not a finite number (see `StrictEnvTypeNumber`).\n * - `invalid_enum` — Value is not one of the allowed enum choices.\n */\nexport type StrictEnvErrorKind = 'missing' | 'invalid_number' | 'invalid_enum';\n\n/**\n * A structured validation error entry for a single environment variable.\n *\n * @template K - Environment variable key type.\n */\nexport type StrictEnvValidationEntry<K extends string = string> = {\n /** Environment variable name. */\n key: K;\n /** Human-readable error message. */\n message: string;\n /** Raw value from `process.env`, if present. */\n raw?: string;\n /** Error category for programmatic handling. */\n kind: StrictEnvErrorKind;\n};\n\n/**\n * Base error class for this package.\n *\n * @example\n * ```ts\n * try {\n * StrictEnvResolver.resolve('PORT', StrictEnvType.Number);\n * } catch (e) {\n * if (e instanceof StrictEnvError) {\n * // Handle all strict-env-resolver errors\n * }\n * }\n * ```\n */\nexport abstract class StrictEnvError extends Error {\n /**\n * @param message - Error message.\n */\n protected constructor(message: string) {\n super(message);\n this.name = 'StrictEnvError';\n }\n}\n\n/**\n * Validation error that carries one or more environment variable issues.\n *\n * Thrown by `StrictEnvResolver.resolve()` (single-entry `errors`) and\n * `StrictEnvResolver.resolveAll()` (multi-entry `errors`).\n * Individual entries are produced by the internal `parseEnvValue` helper.\n *\n * @template K - Union of environment variable keys included in `errors`.\n */\nexport class StrictEnvValidationError<K extends string = string> extends StrictEnvError {\n /**\n * Formats validation errors into a human-readable error message.\n *\n * @template K - Environment variable key type.\n * @param errors - Validation error entries to format.\n * @returns Multi-line summary listing each key and message.\n */\n public static format<K extends string>(errors: readonly StrictEnvValidationEntry<K>[]): string {\n const lines = errors.map((e) => `- ${e.key}: ${e.message}${e.raw == null ? '' : ` (raw=\"${e.raw}\")`}`);\n return `Invalid environment variables (${errors.length}):\\n${lines.join('\\n')}`;\n }\n\n /**\n * Structured list of validation errors.\n */\n public readonly errors: readonly StrictEnvValidationEntry<K>[];\n /**\n * Convenience list of keys included in `errors`.\n */\n public readonly keys: readonly K[];\n\n /**\n * Creates a new validation error from one or more `StrictEnvValidationEntry` entries.\n *\n * @param errors - One or more structured validation errors.\n */\n public constructor(errors: readonly StrictEnvValidationEntry<K>[]) {\n const msg = StrictEnvValidationError.format(errors);\n super(msg);\n this.name = 'StrictEnvValidationError';\n this.errors = errors;\n this.keys = errors.map((e) => e.key);\n }\n}\n\n/**\n * Predefined spec constants for use with `resolve` or as schema values in `resolveAll`.\n * Provide defaults via the third argument of `resolve` or a `[spec, { default }]` tuple in `resolveAll`.\n */\nexport const StrictEnvType = {\n /** Spec for a string value (returned as-is unless `trim: true` is set in options). */\n String: { type: 'string' } as const satisfies StrictEnvTypeString,\n /**\n * Spec for a finite numeric value (`Number()` parsing; rejects `NaN` and `Infinity`).\n */\n Number: { type: 'number' } as const satisfies StrictEnvTypeNumber,\n /** Spec for a boolean value (`1`/`true`/`yes`/`on` → `true`; other non-empty values → `false`). */\n Boolean: { type: 'boolean' } as const satisfies StrictEnvTypeBoolean,\n /**\n * Returns a spec that restricts the value to one of the given choices.\n *\n * @param choices - Allowed string literals.\n * @returns Enum spec for use with `resolve` or `resolveAll`.\n */\n Enum: <T extends string>(choices: readonly T[]) => ({ type: 'enum', choices }) as StrictEnvTypeEnum<T>,\n} as const;\n\n/**\n * Infers the return type from the given spec.\n * @template S - A `StrictEnvSpec` variant.\n */\nexport type StrictEnvSpecToType<S> =\n S extends StrictEnvTypeString ? string\n : S extends StrictEnvTypeNumber ? number\n : S extends StrictEnvTypeBoolean ? boolean\n : S extends StrictEnvTypeEnum<infer T> ? T\n : never;\n\n/**\n * Options for reading an environment variable with an optional default.\n * Used as the third argument to `resolve` or as the second element of a `[spec, options]` tuple in `resolveAll`.\n *\n * `trim` defaults to `true` for `number`, `boolean`, and `enum` specs (whitespace-only values are\n * treated as missing). For `string` specs it defaults to `false` (values are returned as-is).\n *\n * @template S - Environment variable spec type.\n */\nexport type StrictEnvOptions<S extends StrictEnvSpec> = {\n default?: StrictEnvSpecToType<S>;\n /** When `true`, trims leading/trailing whitespace before validation. */\n trim?: boolean;\n};\n\n/**\n * Schema entry for a single env var.\n *\n * Either provide a spec directly, or a tuple of `[spec, options]` to attach a default.\n */\nexport type StrictEnvSchemaEntry<S extends StrictEnvSpec = StrictEnvSpec> = S | readonly [S, StrictEnvOptions<S>];\n\n/**\n * Schema object used by `resolveAll()`.\n *\n * Keys are env var names, values are specs (optionally with defaults).\n */\nexport type StrictEnvSchema = Record<string, StrictEnvSchemaEntry>;\n\n/**\n * Extracts the spec type from a schema entry or `[spec, options]` tuple.\n *\n * @template E - Schema entry type.\n */\ntype StrictEnvSchemaEntryToSpec<E> = E extends readonly [infer S, unknown] ? S : E;\n\n/**\n * Maps a schema object to the resulting parsed environment object type.\n *\n * @template TSchema - Schema object type passed to `resolveAll`.\n */\nexport type StrictEnvSchemaToType<TSchema extends StrictEnvSchema> = {\n [K in keyof TSchema]: StrictEnvSpecToType<StrictEnvSchemaEntryToSpec<TSchema[K]> & StrictEnvSpec>;\n};\n\n/**\n * Discriminated result of parsing a single environment variable.\n *\n * On success, `value` holds the parsed result. On failure, `error` holds a structured\n * `StrictEnvValidationEntry` entry (never throws).\n *\n * @template K - Environment variable key type.\n * @template S - Environment variable spec type.\n */\ntype ParseEnvValueResult<K extends string, S extends StrictEnvSpec> =\n | { ok: true; value: StrictEnvSpecToType<S> }\n | { ok: false; error: StrictEnvValidationEntry<K> };\n\n/**\n * Default trim behavior per spec type.\n * Parsed types trim by default; strings preserve the raw value unless opted in.\n *\n * @param spec - Environment variable spec.\n * @returns Whether leading/trailing whitespace should be trimmed before validation.\n */\nconst defaultTrimForSpec = (spec: StrictEnvSpec): boolean => spec.type !== 'string';\n\n/**\n * Normalizes a raw environment variable value before validation.\n *\n * @param raw - Raw value from `process.env`, if present.\n * @param trim - Whether to trim leading/trailing whitespace.\n * @returns Normalized value, or `undefined` when unset.\n */\nconst normalizeEnvRaw = (raw: string | undefined, trim: boolean): string | undefined => {\n if (raw == null) {\n return undefined;\n }\n if (!trim) {\n return raw;\n }\n return raw.trim();\n};\n\n/** Options accepted by `parseEnvValue` (subset of `StrictEnvOptions`). */\ntype ParseEnvValueOptions<S extends StrictEnvSpec> = Pick<StrictEnvOptions<S>, 'trim'>;\n\n/**\n * Resolves a schema entry into its spec and optional per-key options.\n *\n * @param entry - Schema entry or `[spec, options]` tuple.\n * @returns Parsed spec and options for `resolveAll`.\n */\nconst resolveSchemaEntry = (\n entry: StrictEnvSchemaEntry,\n): { spec: StrictEnvSpec; options: StrictEnvOptions<StrictEnvSpec> | undefined } => ({\n spec: (Array.isArray(entry) ? entry[0] : entry) as StrictEnvSpec,\n options: (Array.isArray(entry) ? entry[1] : undefined) as StrictEnvOptions<StrictEnvSpec> | undefined,\n});\n\n/**\n * Parses a single environment variable according to the given spec.\n *\n * Central validation helper shared by `resolve` and `resolveAll`. Does not throw;\n * callers decide whether to throw immediately or collect errors.\n *\n * Missing or empty (`\"\"`) values use `defaultValue` when provided. When `trim` is enabled,\n * whitespace-only values are treated as empty. Number specs delegate to `parseNumber`.\n * Boolean specs treat `1`/`true`/`yes`/`on` (case-insensitive, after trim) as `true`.\n * Enum specs require an exact match in `choices` (after trim).\n *\n * @template K - Environment variable key type.\n * @template S - Environment variable spec type.\n * @param key - Environment variable name.\n * @param spec - Type spec for the value.\n * @param raw - Raw value from `process.env`, if present.\n * @param defaultValue - Fallback when `raw` is missing or empty.\n * @param options - Optional trim override (`trim` defaults per spec type).\n * @returns Parsed value or a structured validation error.\n */\nconst parseEnvValue = <K extends string, S extends StrictEnvSpec>(\n key: K,\n spec: S,\n raw: string | undefined,\n defaultValue: StrictEnvSpecToType<S> | undefined,\n options?: ParseEnvValueOptions<S>,\n): ParseEnvValueResult<K, S> => {\n const trim = options?.trim ?? defaultTrimForSpec(spec);\n const normalizedRaw = normalizeEnvRaw(raw, trim);\n const hasDefault = defaultValue !== undefined;\n\n if (normalizedRaw == null || normalizedRaw === '') {\n if (hasDefault) {\n return { ok: true, value: defaultValue as StrictEnvSpecToType<S> };\n }\n return {\n ok: false,\n error: { key, message: `Missing required environment variable: ${key}`, raw, kind: 'missing' },\n };\n }\n\n switch (spec.type) {\n case 'number': {\n const n = parseNumber(normalizedRaw);\n if (n === undefined) {\n return {\n ok: false,\n error: { key, message: `Env ${key}: expected number, got \"${raw}\"`, raw, kind: 'invalid_number' },\n };\n }\n return { ok: true, value: n as StrictEnvSpecToType<S> };\n }\n case 'boolean':\n return { ok: true, value: parseBooleanEnvValue(normalizedRaw) as StrictEnvSpecToType<S> };\n case 'enum':\n if (!spec.choices.includes(normalizedRaw)) {\n return {\n ok: false,\n error: {\n key,\n message: `Env ${key}: must be one of [${spec.choices.join(', ')}]`,\n raw,\n kind: 'invalid_enum',\n },\n };\n }\n return { ok: true, value: normalizedRaw as StrictEnvSpecToType<S> };\n default:\n return { ok: true, value: normalizedRaw as StrictEnvSpecToType<S> };\n }\n};\n\n/**\n * Reads and parses an environment variable according to the given spec.\n *\n * Delegates validation to `parseEnvValue`. Missing or empty (`\"\"`) values use\n * `options.default` when provided; otherwise a `StrictEnvValidationError` is thrown.\n * For `StrictEnvType.Number`, values are parsed as finite numbers (see `StrictEnvTypeNumber`).\n *\n * @template K - Environment variable key type.\n * @template S - Environment variable spec type.\n * @param key - Environment variable name (e.g. `\"PORT\"`, `\"NODE_ENV\"`).\n * @param spec - Type spec; defaults to `StrictEnvType.String` when omitted.\n * @param options - Optional `{ default, trim }`; see {@link StrictEnvOptions}.\n * @returns Parsed value with type inferred from `spec`.\n * @throws {StrictEnvValidationError} When the variable is missing, empty without a default, or invalid for the spec.\n */\nconst resolve = <K extends string, S extends StrictEnvSpec = StrictEnvTypeString>(\n key: K,\n spec: S = StrictEnvType.String as S,\n options?: StrictEnvOptions<S>,\n): StrictEnvSpecToType<S> => {\n const result = parseEnvValue(key, spec, process.env[key], options?.default, options);\n if (!result.ok) {\n throw new StrictEnvValidationError([result.error]);\n }\n return result.value;\n};\n\n/**\n * Reads and parses multiple environment variables according to the given schema.\n *\n * Always evaluates every key in `schema`. Each entry is validated via `parseEnvValue`;\n * all errors are collected and thrown once in a single `StrictEnvValidationError`.\n * Number specs use the same finite-number rules as `resolve`.\n *\n * @template TSchema - Schema object type.\n * @param schema - Map of environment variable names to specs, optionally with per-key defaults via `[spec, { default }]`.\n * @returns Parsed environment object with types inferred from the schema.\n * @throws {StrictEnvValidationError} When one or more variables are missing, empty without a default, or invalid.\n */\nconst resolveAll = <TSchema extends StrictEnvSchema>(schema: TSchema): StrictEnvSchemaToType<TSchema> => {\n const envs: Partial<StrictEnvSchemaToType<TSchema>> = {};\n const errors: StrictEnvValidationEntry<Extract<keyof TSchema, string>>[] = [];\n\n for (const key of Object.keys(schema) as Array<Extract<keyof TSchema, string>>) {\n const { spec, options } = resolveSchemaEntry(schema[key]);\n\n const result = parseEnvValue(key, spec, process.env[key], options?.default, options);\n if (!result.ok) {\n errors.push(result.error);\n continue;\n }\n envs[key] = result.value as StrictEnvSchemaToType<TSchema>[typeof key];\n }\n\n if (errors.length > 0) throw new StrictEnvValidationError(errors);\n return envs as StrictEnvSchemaToType<TSchema>;\n};\n\n/**\n * Type-safe environment variable resolver for Node.js `process.env`.\n *\n * @example\n * ```ts\n * const port = StrictEnvResolver.resolve('PORT', StrictEnvType.Number);\n * const envs = StrictEnvResolver.resolveAll({\n * PORT: StrictEnvType.Number,\n * DEBUG: [StrictEnvType.Boolean, { default: false }],\n * });\n * ```\n */\nexport const StrictEnvResolver = {\n /** Reads and parses a single environment variable. See {@link resolve}. */\n resolve,\n /** Reads and parses multiple environment variables in one pass. See {@link resolveAll}. */\n resolveAll,\n} as const;\n", "import { CodePipelineClient, GetPipelineExecutionCommand } from '@aws-sdk/client-codepipeline';\nimport { PublishCommand, SNSClient } from '@aws-sdk/client-sns';\nimport type { EventBridgeEvent } from 'aws-lambda';\nimport { StrictEnvResolver, StrictEnvType } from 'strict-env-resolver';\nimport {\n isTerminalExecutionStatus,\n normalizeExecutionStatus,\n resolvePipelineExecutionIdentity,\n} from './notifier-predicates';\n\n/**\n * EventBridge detail payload for CodePipeline execution state-change events.\n */\ntype CodePipelineExecutionStartedDetail = {\n 'pipeline'?: string;\n 'state'?: string;\n 'version'?: string;\n 'execution-id'?: string;\n};\n\n/**\n * EventBridge event for CodePipeline execution state-change notifications.\n */\ntype CodePipelineExecutionStartedEvent = EventBridgeEvent<\n 'CodePipeline Pipeline Execution State Change',\n CodePipelineExecutionStartedDetail\n>;\n\n/**\n * SNS client used to publish notifications.\n */\nconst sns = new SNSClient({});\n\n/**\n * CodePipeline client used to wait for execution state changes.\n */\nconst codepipeline = new CodePipelineClient({});\n\n/**\n * Reads a required environment variable.\n */\nconst mustEnv = (name: string): string => StrictEnvResolver.resolve(name, StrictEnvType.String, { trim: true });\n\n/**\n * Sleeps for the specified number of milliseconds.\n */\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Publishes a JSON payload to the given SNS topic ARN.\n */\nconst publish = async (topicArn: string, payload: unknown): Promise<void> => {\n await sns.send(new PublishCommand({\n TopicArn: topicArn,\n Message: JSON.stringify(payload),\n }));\n};\n\n/**\n * Waits on a CodePipeline execution and publishes notifications whenever the execution status changes.\n */\nconst waitPipelineExecution = async (params: {\n topicArn: string;\n pipelineName: string;\n executionId: string;\n waitIntervalSeconds: number;\n maxWaitMinutes: number;\n startEvent: CodePipelineExecutionStartedEvent;\n}): Promise<void> => {\n const {\n topicArn,\n pipelineName,\n executionId,\n waitIntervalSeconds,\n maxWaitMinutes,\n startEvent,\n } = params;\n\n const deadline = Date.now() + maxWaitMinutes * 60_000;\n let lastStatus: string | undefined;\n\n // \u6700\u521D\u306B STARTED \u3092\u901A\u77E5\uFF08EventBridge\u7531\u6765\uFF09\n await publish(topicArn, {\n type: 'codepipeline.execution',\n phase: 'eventbridge',\n pipelineName,\n executionId,\n observedState: startEvent.detail?.state ?? 'STARTED',\n observedAt: new Date().toISOString(),\n event: startEvent,\n });\n\n while (Date.now() < deadline) {\n const res = await codepipeline.send(new GetPipelineExecutionCommand({\n pipelineName,\n pipelineExecutionId: executionId,\n }));\n\n const status = normalizeExecutionStatus(res.pipelineExecution?.status);\n if (status !== lastStatus) {\n lastStatus = status;\n await publish(topicArn, {\n type: 'codepipeline.execution',\n phase: 'wait',\n pipelineName,\n executionId,\n observedState: status,\n observedAt: new Date().toISOString(),\n });\n }\n\n if (isTerminalExecutionStatus(status)) {\n return;\n }\n\n await sleep(waitIntervalSeconds * 1000);\n }\n\n await publish(topicArn, {\n type: 'codepipeline.execution',\n phase: 'wait',\n pipelineName,\n executionId,\n observedState: lastStatus ?? 'UNKNOWN',\n observedAt: new Date().toISOString(),\n note: 'Waiting timed out before terminal state.',\n });\n};\n\n/**\n * Lambda handler triggered by EventBridge when a pipeline execution transitions to STARTED.\n * It waits for the execution status until it reaches a terminal state or times out.\n */\nexport const handler = async (event: CodePipelineExecutionStartedEvent): Promise<void> => {\n const topicArn = mustEnv('SNS_TOPIC_ARN');\n const identity = resolvePipelineExecutionIdentity(\n event.detail?.pipeline,\n event.detail?.['execution-id'],\n );\n\n if (!identity) {\n await publish(topicArn, {\n type: 'codepipeline.execution',\n phase: 'eventbridge',\n observedAt: new Date().toISOString(),\n note: 'Missing pipelineName or executionId in event.detail',\n event,\n });\n return;\n }\n\n const waitIntervalSeconds = StrictEnvResolver.resolve('WAIT_INTERVAL_SECONDS', StrictEnvType.Number, { default: 10 });\n const maxWaitMinutes = StrictEnvResolver.resolve('MAX_WAIT_MINUTES', StrictEnvType.Number, { default: 14 });\n\n await waitPipelineExecution({\n topicArn,\n pipelineName: identity.pipelineName,\n executionId: identity.executionId,\n waitIntervalSeconds: waitIntervalSeconds > 0 ? waitIntervalSeconds : 10,\n maxWaitMinutes: maxWaitMinutes > 0 ? maxWaitMinutes : 14,\n startEvent: event,\n });\n};\n", "/**\n * Pipeline and execution identifiers required to wait on a CodePipeline execution.\n */\nexport interface PipelineExecutionIdentity {\n readonly pipelineName: string;\n readonly executionId: string;\n}\n\n/**\n * Normalizes a raw CodePipeline execution status for comparison.\n *\n * @param statusRaw the status returned by GetPipelineExecution\n * @returns upper-cased status, or `UNKNOWN` when missing\n */\nexport const normalizeExecutionStatus = (statusRaw: string | undefined): string =>\n String(statusRaw ?? 'UNKNOWN').toUpperCase();\n\n/**\n * Returns whether a normalized CodePipeline execution status is terminal.\n *\n * @param status normalized execution status\n * @returns true when waiting should stop\n */\nexport const isTerminalExecutionStatus = (status: string): boolean => (\n status === 'SUCCEEDED'\n || status === 'FAILED'\n || status === 'STOPPED'\n || status === 'SUPERSEDED'\n);\n\n/**\n * Resolves pipeline/execution identifiers from EventBridge detail fields.\n *\n * @param pipelineName pipeline name from the event detail\n * @param executionId execution id from the event detail\n * @returns identifiers when both are present; otherwise undefined\n */\nexport const resolvePipelineExecutionIdentity = (\n pipelineName: string | undefined,\n executionId: string | undefined,\n): PipelineExecutionIdentity | undefined => {\n if (!pipelineName || !executionId) {\n return undefined;\n }\n return { pipelineName, executionId };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["exports"]
|
|
7
7
|
}
|
|
@@ -1,12 +1,56 @@
|
|
|
1
|
+
import { Duration, aws_events as events, aws_sns as sns } from 'aws-cdk-lib';
|
|
1
2
|
import { Construct } from 'constructs';
|
|
3
|
+
/**
|
|
4
|
+
* Properties for {@link CodePipelineEventNotifier}.
|
|
5
|
+
*/
|
|
6
|
+
export interface CodePipelineEventNotifierProps {
|
|
7
|
+
/**
|
|
8
|
+
* SNS topic that receives CodePipeline execution notifications.
|
|
9
|
+
* Subscriptions (email/HTTP/etc.) are intentionally not managed by this construct.
|
|
10
|
+
*
|
|
11
|
+
* @default - a new topic is created
|
|
12
|
+
*/
|
|
13
|
+
readonly topic?: sns.ITopic;
|
|
14
|
+
/**
|
|
15
|
+
* Interval between `GetPipelineExecution` waits.
|
|
16
|
+
*
|
|
17
|
+
* @default Duration.seconds(10)
|
|
18
|
+
*/
|
|
19
|
+
readonly waitInterval?: Duration;
|
|
20
|
+
/**
|
|
21
|
+
* Maximum duration to wait for execution state changes.
|
|
22
|
+
* Mapped to the notifier Lambda environment variable `MAX_WAIT_MINUTES`.
|
|
23
|
+
*
|
|
24
|
+
* @default Duration.minutes(14)
|
|
25
|
+
*/
|
|
26
|
+
readonly maxWaitDuration?: Duration;
|
|
27
|
+
/**
|
|
28
|
+
* Timeout for the notifier Lambda function.
|
|
29
|
+
* Should be greater than {@link maxWaitDuration}.
|
|
30
|
+
*
|
|
31
|
+
* @default Duration.minutes(15)
|
|
32
|
+
*/
|
|
33
|
+
readonly timeout?: Duration;
|
|
34
|
+
/**
|
|
35
|
+
* EventBridge event pattern that triggers the notifier.
|
|
36
|
+
*
|
|
37
|
+
* @default CodePipeline Pipeline Execution State Change with `state=STARTED`
|
|
38
|
+
*/
|
|
39
|
+
readonly eventPattern?: events.EventPattern;
|
|
40
|
+
}
|
|
2
41
|
/**
|
|
3
42
|
* Provisions an EventBridge rule that listens for CodePipeline execution STARTED events,
|
|
4
43
|
* then invokes a notifier Lambda which publishes execution state changes to an SNS topic.
|
|
5
44
|
*/
|
|
6
45
|
export declare class CodePipelineEventNotifier extends Construct {
|
|
46
|
+
/**
|
|
47
|
+
* SNS topic that receives CodePipeline execution notifications.
|
|
48
|
+
*/
|
|
49
|
+
readonly topic: sns.ITopic;
|
|
7
50
|
/**
|
|
8
51
|
* @param scope the construct scope
|
|
9
52
|
* @param id the construct id
|
|
53
|
+
* @param props construct properties
|
|
10
54
|
*/
|
|
11
|
-
constructor(scope: Construct, id: string);
|
|
55
|
+
constructor(scope: Construct, id: string, props?: CodePipelineEventNotifierProps);
|
|
12
56
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CodePipelineEventNotifier = void 0;
|
|
4
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
4
5
|
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
6
|
const constructs_1 = require("constructs");
|
|
6
7
|
const notifier_function_1 = require("../funcs/notifier-function");
|
|
@@ -9,45 +10,51 @@ const notifier_function_1 = require("../funcs/notifier-function");
|
|
|
9
10
|
* then invokes a notifier Lambda which publishes execution state changes to an SNS topic.
|
|
10
11
|
*/
|
|
11
12
|
class CodePipelineEventNotifier extends constructs_1.Construct {
|
|
13
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "codepipeline-event-notifier.CodePipelineEventNotifier", version: "0.2.0" };
|
|
14
|
+
/**
|
|
15
|
+
* SNS topic that receives CodePipeline execution notifications.
|
|
16
|
+
*/
|
|
17
|
+
topic;
|
|
12
18
|
/**
|
|
13
19
|
* @param scope the construct scope
|
|
14
20
|
* @param id the construct id
|
|
21
|
+
* @param props construct properties
|
|
15
22
|
*/
|
|
16
|
-
constructor(scope, id) {
|
|
23
|
+
constructor(scope, id, props = {}) {
|
|
17
24
|
super(scope, id);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
25
|
+
this.topic = props.topic ?? new aws_cdk_lib_1.aws_sns.Topic(this, 'PipelineEventTopic');
|
|
26
|
+
const waitInterval = props.waitInterval ?? aws_cdk_lib_1.Duration.seconds(10);
|
|
27
|
+
const maxWaitDuration = props.maxWaitDuration ?? aws_cdk_lib_1.Duration.minutes(14);
|
|
28
|
+
const timeout = props.timeout ?? aws_cdk_lib_1.Duration.minutes(15);
|
|
29
|
+
const eventPattern = props.eventPattern ?? {
|
|
30
|
+
source: ['aws.codepipeline'],
|
|
31
|
+
detailType: ['CodePipeline Pipeline Execution State Change'],
|
|
32
|
+
detail: {
|
|
33
|
+
state: ['STARTED'],
|
|
34
|
+
},
|
|
35
|
+
};
|
|
23
36
|
const fn = new notifier_function_1.NotifierFunction(this, 'NotifierFunction', {
|
|
24
37
|
environment: {
|
|
25
|
-
SNS_TOPIC_ARN: topic.topicArn,
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
SNS_TOPIC_ARN: this.topic.topicArn,
|
|
39
|
+
WAIT_INTERVAL_SECONDS: String(waitInterval.toSeconds()),
|
|
40
|
+
MAX_WAIT_MINUTES: String(maxWaitDuration.toMinutes({ integral: false })),
|
|
28
41
|
},
|
|
29
|
-
timeout
|
|
42
|
+
timeout,
|
|
30
43
|
});
|
|
31
44
|
// Allow the notifier to publish notifications.
|
|
32
|
-
topic.grantPublish(fn);
|
|
45
|
+
this.topic.grantPublish(fn);
|
|
33
46
|
fn.addToRolePolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
|
|
34
47
|
actions: [
|
|
35
48
|
'codepipeline:GetPipelineExecution',
|
|
36
49
|
],
|
|
37
50
|
resources: ['*'],
|
|
38
51
|
}));
|
|
39
|
-
// Trigger the notifier when
|
|
52
|
+
// Trigger the notifier when matching CodePipeline execution events arrive.
|
|
40
53
|
new aws_cdk_lib_1.aws_events.Rule(this, 'OnPipelineExecutionStartedRule', {
|
|
41
|
-
eventPattern
|
|
42
|
-
source: ['aws.codepipeline'],
|
|
43
|
-
detailType: ['CodePipeline Pipeline Execution State Change'],
|
|
44
|
-
detail: {
|
|
45
|
-
state: ['STARTED'],
|
|
46
|
-
},
|
|
47
|
-
},
|
|
54
|
+
eventPattern,
|
|
48
55
|
targets: [new aws_cdk_lib_1.aws_events_targets.LambdaFunction(fn)],
|
|
49
56
|
});
|
|
50
57
|
}
|
|
51
58
|
}
|
|
52
59
|
exports.CodePipelineEventNotifier = CodePipelineEventNotifier;
|
|
53
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
60
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29kZXBpcGVsaW5lLWV2ZW50LW5vdGlmaWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnN0cnVjdHMvY29kZXBpcGVsaW5lLWV2ZW50LW5vdGlmaWVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSw2Q0FBNEg7QUFDNUgsMkNBQXVDO0FBQ3ZDLGtFQUE4RDtBQTZDOUQ7OztHQUdHO0FBQ0gsTUFBYSx5QkFBMEIsU0FBUSxzQkFBUzs7SUFDdEQ7O09BRUc7SUFDYSxLQUFLLENBQWE7SUFFbEM7Ozs7T0FJRztJQUNILFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsUUFBd0MsRUFBRTtRQUNsRixLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssSUFBSSxJQUFJLHFCQUFHLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1FBRXRFLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxZQUFZLElBQUksc0JBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDaEUsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLGVBQWUsSUFBSSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN0RSxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxJQUFJLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3RELE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxZQUFZLElBQUk7WUFDekMsTUFBTSxFQUFFLENBQUMsa0JBQWtCLENBQUM7WUFDNUIsVUFBVSxFQUFFLENBQUMsOENBQThDLENBQUM7WUFDNUQsTUFBTSxFQUFFO2dCQUNOLEtBQUssRUFBRSxDQUFDLFNBQVMsQ0FBQzthQUNuQjtTQUNGLENBQUM7UUFFRixNQUFNLEVBQUUsR0FBRyxJQUFJLG9DQUFnQixDQUFDLElBQUksRUFBRSxrQkFBa0IsRUFBRTtZQUN4RCxXQUFXLEVBQUU7Z0JBQ1gsYUFBYSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUTtnQkFDbEMscUJBQXFCLEVBQUUsTUFBTSxDQUFDLFlBQVksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDdkQsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzthQUN6RTtZQUNELE9BQU87U0FDUixDQUFDLENBQUM7UUFFSCwrQ0FBK0M7UUFDL0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDNUIsRUFBRSxDQUFDLGVBQWUsQ0FBQyxJQUFJLHFCQUFHLENBQUMsZUFBZSxDQUFDO1lBQ3pDLE9BQU8sRUFBRTtnQkFDUCxtQ0FBbUM7YUFDcEM7WUFDRCxTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUM7U0FDakIsQ0FBQyxDQUFDLENBQUM7UUFFSiwyRUFBMkU7UUFDM0UsSUFBSSx3QkFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsZ0NBQWdDLEVBQUU7WUFDdEQsWUFBWTtZQUNaLE9BQU8sRUFBRSxDQUFDLElBQUksZ0NBQU8sQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7U0FDMUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7QUFsREgsOERBbURDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRHVyYXRpb24sIGF3c19ldmVudHMgYXMgZXZlbnRzLCBhd3NfZXZlbnRzX3RhcmdldHMgYXMgdGFyZ2V0cywgYXdzX2lhbSBhcyBpYW0sIGF3c19zbnMgYXMgc25zIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBOb3RpZmllckZ1bmN0aW9uIH0gZnJvbSAnLi4vZnVuY3Mvbm90aWZpZXItZnVuY3Rpb24nO1xuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIHtAbGluayBDb2RlUGlwZWxpbmVFdmVudE5vdGlmaWVyfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb2RlUGlwZWxpbmVFdmVudE5vdGlmaWVyUHJvcHMge1xuICAvKipcbiAgICogU05TIHRvcGljIHRoYXQgcmVjZWl2ZXMgQ29kZVBpcGVsaW5lIGV4ZWN1dGlvbiBub3RpZmljYXRpb25zLlxuICAgKiBTdWJzY3JpcHRpb25zIChlbWFpbC9IVFRQL2V0Yy4pIGFyZSBpbnRlbnRpb25hbGx5IG5vdCBtYW5hZ2VkIGJ5IHRoaXMgY29uc3RydWN0LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGEgbmV3IHRvcGljIGlzIGNyZWF0ZWRcbiAgICovXG4gIHJlYWRvbmx5IHRvcGljPzogc25zLklUb3BpYztcblxuICAvKipcbiAgICogSW50ZXJ2YWwgYmV0d2VlbiBgR2V0UGlwZWxpbmVFeGVjdXRpb25gIHdhaXRzLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5zZWNvbmRzKDEwKVxuICAgKi9cbiAgcmVhZG9ubHkgd2FpdEludGVydmFsPzogRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIE1heGltdW0gZHVyYXRpb24gdG8gd2FpdCBmb3IgZXhlY3V0aW9uIHN0YXRlIGNoYW5nZXMuXG4gICAqIE1hcHBlZCB0byB0aGUgbm90aWZpZXIgTGFtYmRhIGVudmlyb25tZW50IHZhcmlhYmxlIGBNQVhfV0FJVF9NSU5VVEVTYC5cbiAgICpcbiAgICogQGRlZmF1bHQgRHVyYXRpb24ubWludXRlcygxNClcbiAgICovXG4gIHJlYWRvbmx5IG1heFdhaXREdXJhdGlvbj86IER1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBUaW1lb3V0IGZvciB0aGUgbm90aWZpZXIgTGFtYmRhIGZ1bmN0aW9uLlxuICAgKiBTaG91bGQgYmUgZ3JlYXRlciB0aGFuIHtAbGluayBtYXhXYWl0RHVyYXRpb259LlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDE1KVxuICAgKi9cbiAgcmVhZG9ubHkgdGltZW91dD86IER1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBFdmVudEJyaWRnZSBldmVudCBwYXR0ZXJuIHRoYXQgdHJpZ2dlcnMgdGhlIG5vdGlmaWVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCBDb2RlUGlwZWxpbmUgUGlwZWxpbmUgRXhlY3V0aW9uIFN0YXRlIENoYW5nZSB3aXRoIGBzdGF0ZT1TVEFSVEVEYFxuICAgKi9cbiAgcmVhZG9ubHkgZXZlbnRQYXR0ZXJuPzogZXZlbnRzLkV2ZW50UGF0dGVybjtcbn1cblxuLyoqXG4gKiBQcm92aXNpb25zIGFuIEV2ZW50QnJpZGdlIHJ1bGUgdGhhdCBsaXN0ZW5zIGZvciBDb2RlUGlwZWxpbmUgZXhlY3V0aW9uIFNUQVJURUQgZXZlbnRzLFxuICogdGhlbiBpbnZva2VzIGEgbm90aWZpZXIgTGFtYmRhIHdoaWNoIHB1Ymxpc2hlcyBleGVjdXRpb24gc3RhdGUgY2hhbmdlcyB0byBhbiBTTlMgdG9waWMuXG4gKi9cbmV4cG9ydCBjbGFzcyBDb2RlUGlwZWxpbmVFdmVudE5vdGlmaWVyIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAqIFNOUyB0b3BpYyB0aGF0IHJlY2VpdmVzIENvZGVQaXBlbGluZSBleGVjdXRpb24gbm90aWZpY2F0aW9ucy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB0b3BpYzogc25zLklUb3BpYztcblxuICAvKipcbiAgICogQHBhcmFtIHNjb3BlIHRoZSBjb25zdHJ1Y3Qgc2NvcGVcbiAgICogQHBhcmFtIGlkIHRoZSBjb25zdHJ1Y3QgaWRcbiAgICogQHBhcmFtIHByb3BzIGNvbnN0cnVjdCBwcm9wZXJ0aWVzXG4gICAqL1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogQ29kZVBpcGVsaW5lRXZlbnROb3RpZmllclByb3BzID0ge30pIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy50b3BpYyA9IHByb3BzLnRvcGljID8/IG5ldyBzbnMuVG9waWModGhpcywgJ1BpcGVsaW5lRXZlbnRUb3BpYycpO1xuXG4gICAgY29uc3Qgd2FpdEludGVydmFsID0gcHJvcHMud2FpdEludGVydmFsID8/IER1cmF0aW9uLnNlY29uZHMoMTApO1xuICAgIGNvbnN0IG1heFdhaXREdXJhdGlvbiA9IHByb3BzLm1heFdhaXREdXJhdGlvbiA/PyBEdXJhdGlvbi5taW51dGVzKDE0KTtcbiAgICBjb25zdCB0aW1lb3V0ID0gcHJvcHMudGltZW91dCA/PyBEdXJhdGlvbi5taW51dGVzKDE1KTtcbiAgICBjb25zdCBldmVudFBhdHRlcm4gPSBwcm9wcy5ldmVudFBhdHRlcm4gPz8ge1xuICAgICAgc291cmNlOiBbJ2F3cy5jb2RlcGlwZWxpbmUnXSxcbiAgICAgIGRldGFpbFR5cGU6IFsnQ29kZVBpcGVsaW5lIFBpcGVsaW5lIEV4ZWN1dGlvbiBTdGF0ZSBDaGFuZ2UnXSxcbiAgICAgIGRldGFpbDoge1xuICAgICAgICBzdGF0ZTogWydTVEFSVEVEJ10sXG4gICAgICB9LFxuICAgIH07XG5cbiAgICBjb25zdCBmbiA9IG5ldyBOb3RpZmllckZ1bmN0aW9uKHRoaXMsICdOb3RpZmllckZ1bmN0aW9uJywge1xuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgU05TX1RPUElDX0FSTjogdGhpcy50b3BpYy50b3BpY0FybixcbiAgICAgICAgV0FJVF9JTlRFUlZBTF9TRUNPTkRTOiBTdHJpbmcod2FpdEludGVydmFsLnRvU2Vjb25kcygpKSxcbiAgICAgICAgTUFYX1dBSVRfTUlOVVRFUzogU3RyaW5nKG1heFdhaXREdXJhdGlvbi50b01pbnV0ZXMoeyBpbnRlZ3JhbDogZmFsc2UgfSkpLFxuICAgICAgfSxcbiAgICAgIHRpbWVvdXQsXG4gICAgfSk7XG5cbiAgICAvLyBBbGxvdyB0aGUgbm90aWZpZXIgdG8gcHVibGlzaCBub3RpZmljYXRpb25zLlxuICAgIHRoaXMudG9waWMuZ3JhbnRQdWJsaXNoKGZuKTtcbiAgICBmbi5hZGRUb1JvbGVQb2xpY3kobmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgYWN0aW9uczogW1xuICAgICAgICAnY29kZXBpcGVsaW5lOkdldFBpcGVsaW5lRXhlY3V0aW9uJyxcbiAgICAgIF0sXG4gICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgIH0pKTtcblxuICAgIC8vIFRyaWdnZXIgdGhlIG5vdGlmaWVyIHdoZW4gbWF0Y2hpbmcgQ29kZVBpcGVsaW5lIGV4ZWN1dGlvbiBldmVudHMgYXJyaXZlLlxuICAgIG5ldyBldmVudHMuUnVsZSh0aGlzLCAnT25QaXBlbGluZUV4ZWN1dGlvblN0YXJ0ZWRSdWxlJywge1xuICAgICAgZXZlbnRQYXR0ZXJuLFxuICAgICAgdGFyZ2V0czogW25ldyB0YXJnZXRzLkxhbWJkYUZ1bmN0aW9uKGZuKV0sXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline and execution identifiers required to wait on a CodePipeline execution.
|
|
3
|
+
*/
|
|
4
|
+
export interface PipelineExecutionIdentity {
|
|
5
|
+
readonly pipelineName: string;
|
|
6
|
+
readonly executionId: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Normalizes a raw CodePipeline execution status for comparison.
|
|
10
|
+
*
|
|
11
|
+
* @param statusRaw the status returned by GetPipelineExecution
|
|
12
|
+
* @returns upper-cased status, or `UNKNOWN` when missing
|
|
13
|
+
*/
|
|
14
|
+
export declare const normalizeExecutionStatus: (statusRaw: string | undefined) => string;
|
|
15
|
+
/**
|
|
16
|
+
* Returns whether a normalized CodePipeline execution status is terminal.
|
|
17
|
+
*
|
|
18
|
+
* @param status normalized execution status
|
|
19
|
+
* @returns true when waiting should stop
|
|
20
|
+
*/
|
|
21
|
+
export declare const isTerminalExecutionStatus: (status: string) => boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Resolves pipeline/execution identifiers from EventBridge detail fields.
|
|
24
|
+
*
|
|
25
|
+
* @param pipelineName pipeline name from the event detail
|
|
26
|
+
* @param executionId execution id from the event detail
|
|
27
|
+
* @returns identifiers when both are present; otherwise undefined
|
|
28
|
+
*/
|
|
29
|
+
export declare const resolvePipelineExecutionIdentity: (pipelineName: string | undefined, executionId: string | undefined) => PipelineExecutionIdentity | undefined;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvePipelineExecutionIdentity = exports.isTerminalExecutionStatus = exports.normalizeExecutionStatus = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Normalizes a raw CodePipeline execution status for comparison.
|
|
6
|
+
*
|
|
7
|
+
* @param statusRaw the status returned by GetPipelineExecution
|
|
8
|
+
* @returns upper-cased status, or `UNKNOWN` when missing
|
|
9
|
+
*/
|
|
10
|
+
const normalizeExecutionStatus = (statusRaw) => String(statusRaw ?? 'UNKNOWN').toUpperCase();
|
|
11
|
+
exports.normalizeExecutionStatus = normalizeExecutionStatus;
|
|
12
|
+
/**
|
|
13
|
+
* Returns whether a normalized CodePipeline execution status is terminal.
|
|
14
|
+
*
|
|
15
|
+
* @param status normalized execution status
|
|
16
|
+
* @returns true when waiting should stop
|
|
17
|
+
*/
|
|
18
|
+
const isTerminalExecutionStatus = (status) => (status === 'SUCCEEDED'
|
|
19
|
+
|| status === 'FAILED'
|
|
20
|
+
|| status === 'STOPPED'
|
|
21
|
+
|| status === 'SUPERSEDED');
|
|
22
|
+
exports.isTerminalExecutionStatus = isTerminalExecutionStatus;
|
|
23
|
+
/**
|
|
24
|
+
* Resolves pipeline/execution identifiers from EventBridge detail fields.
|
|
25
|
+
*
|
|
26
|
+
* @param pipelineName pipeline name from the event detail
|
|
27
|
+
* @param executionId execution id from the event detail
|
|
28
|
+
* @returns identifiers when both are present; otherwise undefined
|
|
29
|
+
*/
|
|
30
|
+
const resolvePipelineExecutionIdentity = (pipelineName, executionId) => {
|
|
31
|
+
if (!pipelineName || !executionId) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return { pipelineName, executionId };
|
|
35
|
+
};
|
|
36
|
+
exports.resolvePipelineExecutionIdentity = resolvePipelineExecutionIdentity;
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpZXItcHJlZGljYXRlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mdW5jcy9ub3RpZmllci1wcmVkaWNhdGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQVFBOzs7OztHQUtHO0FBQ0ksTUFBTSx3QkFBd0IsR0FBRyxDQUFDLFNBQTZCLEVBQVUsRUFBRSxDQUNoRixNQUFNLENBQUMsU0FBUyxJQUFJLFNBQVMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBRGxDLFFBQUEsd0JBQXdCLDRCQUNVO0FBRS9DOzs7OztHQUtHO0FBQ0ksTUFBTSx5QkFBeUIsR0FBRyxDQUFDLE1BQWMsRUFBVyxFQUFFLENBQUMsQ0FDcEUsTUFBTSxLQUFLLFdBQVc7T0FDbkIsTUFBTSxLQUFLLFFBQVE7T0FDbkIsTUFBTSxLQUFLLFNBQVM7T0FDcEIsTUFBTSxLQUFLLFlBQVksQ0FDM0IsQ0FBQztBQUxXLFFBQUEseUJBQXlCLDZCQUtwQztBQUVGOzs7Ozs7R0FNRztBQUNJLE1BQU0sZ0NBQWdDLEdBQUcsQ0FDOUMsWUFBZ0MsRUFDaEMsV0FBK0IsRUFDUSxFQUFFO0lBQ3pDLElBQUksQ0FBQyxZQUFZLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNsQyxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBQ0QsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUN2QyxDQUFDLENBQUM7QUFSVyxRQUFBLGdDQUFnQyxvQ0FRM0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFBpcGVsaW5lIGFuZCBleGVjdXRpb24gaWRlbnRpZmllcnMgcmVxdWlyZWQgdG8gd2FpdCBvbiBhIENvZGVQaXBlbGluZSBleGVjdXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGlwZWxpbmVFeGVjdXRpb25JZGVudGl0eSB7XG4gIHJlYWRvbmx5IHBpcGVsaW5lTmFtZTogc3RyaW5nO1xuICByZWFkb25seSBleGVjdXRpb25JZDogc3RyaW5nO1xufVxuXG4vKipcbiAqIE5vcm1hbGl6ZXMgYSByYXcgQ29kZVBpcGVsaW5lIGV4ZWN1dGlvbiBzdGF0dXMgZm9yIGNvbXBhcmlzb24uXG4gKlxuICogQHBhcmFtIHN0YXR1c1JhdyB0aGUgc3RhdHVzIHJldHVybmVkIGJ5IEdldFBpcGVsaW5lRXhlY3V0aW9uXG4gKiBAcmV0dXJucyB1cHBlci1jYXNlZCBzdGF0dXMsIG9yIGBVTktOT1dOYCB3aGVuIG1pc3NpbmdcbiAqL1xuZXhwb3J0IGNvbnN0IG5vcm1hbGl6ZUV4ZWN1dGlvblN0YXR1cyA9IChzdGF0dXNSYXc6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZyA9PlxuICBTdHJpbmcoc3RhdHVzUmF3ID8/ICdVTktOT1dOJykudG9VcHBlckNhc2UoKTtcblxuLyoqXG4gKiBSZXR1cm5zIHdoZXRoZXIgYSBub3JtYWxpemVkIENvZGVQaXBlbGluZSBleGVjdXRpb24gc3RhdHVzIGlzIHRlcm1pbmFsLlxuICpcbiAqIEBwYXJhbSBzdGF0dXMgbm9ybWFsaXplZCBleGVjdXRpb24gc3RhdHVzXG4gKiBAcmV0dXJucyB0cnVlIHdoZW4gd2FpdGluZyBzaG91bGQgc3RvcFxuICovXG5leHBvcnQgY29uc3QgaXNUZXJtaW5hbEV4ZWN1dGlvblN0YXR1cyA9IChzdGF0dXM6IHN0cmluZyk6IGJvb2xlYW4gPT4gKFxuICBzdGF0dXMgPT09ICdTVUNDRUVERUQnXG4gIHx8IHN0YXR1cyA9PT0gJ0ZBSUxFRCdcbiAgfHwgc3RhdHVzID09PSAnU1RPUFBFRCdcbiAgfHwgc3RhdHVzID09PSAnU1VQRVJTRURFRCdcbik7XG5cbi8qKlxuICogUmVzb2x2ZXMgcGlwZWxpbmUvZXhlY3V0aW9uIGlkZW50aWZpZXJzIGZyb20gRXZlbnRCcmlkZ2UgZGV0YWlsIGZpZWxkcy5cbiAqXG4gKiBAcGFyYW0gcGlwZWxpbmVOYW1lIHBpcGVsaW5lIG5hbWUgZnJvbSB0aGUgZXZlbnQgZGV0YWlsXG4gKiBAcGFyYW0gZXhlY3V0aW9uSWQgZXhlY3V0aW9uIGlkIGZyb20gdGhlIGV2ZW50IGRldGFpbFxuICogQHJldHVybnMgaWRlbnRpZmllcnMgd2hlbiBib3RoIGFyZSBwcmVzZW50OyBvdGhlcndpc2UgdW5kZWZpbmVkXG4gKi9cbmV4cG9ydCBjb25zdCByZXNvbHZlUGlwZWxpbmVFeGVjdXRpb25JZGVudGl0eSA9IChcbiAgcGlwZWxpbmVOYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIGV4ZWN1dGlvbklkOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4pOiBQaXBlbGluZUV4ZWN1dGlvbklkZW50aXR5IHwgdW5kZWZpbmVkID0+IHtcbiAgaWYgKCFwaXBlbGluZU5hbWUgfHwgIWV4ZWN1dGlvbklkKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICByZXR1cm4geyBwaXBlbGluZU5hbWUsIGV4ZWN1dGlvbklkIH07XG59O1xuIl19
|
|
@@ -14,7 +14,7 @@ type CodePipelineExecutionStartedDetail = {
|
|
|
14
14
|
type CodePipelineExecutionStartedEvent = EventBridgeEvent<'CodePipeline Pipeline Execution State Change', CodePipelineExecutionStartedDetail>;
|
|
15
15
|
/**
|
|
16
16
|
* Lambda handler triggered by EventBridge when a pipeline execution transitions to STARTED.
|
|
17
|
-
* It
|
|
17
|
+
* It waits for the execution status until it reaches a terminal state or times out.
|
|
18
18
|
*/
|
|
19
19
|
export declare const handler: (event: CodePipelineExecutionStartedEvent) => Promise<void>;
|
|
20
20
|
export {};
|