@pipeline-builder/pipeline-manager 0.0.1
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/LICENSE +202 -0
- package/README.md +145 -0
- package/cdk.json +91 -0
- package/config.yml +94 -0
- package/dist/agent/ai.d.ts +48 -0
- package/dist/agent/ai.d.ts.map +1 -0
- package/dist/agent/ai.js +149 -0
- package/dist/agent/bootstrap.d.ts +39 -0
- package/dist/agent/bootstrap.d.ts.map +1 -0
- package/dist/agent/bootstrap.js +66 -0
- package/dist/agent/env-file.d.ts +17 -0
- package/dist/agent/env-file.d.ts.map +1 -0
- package/dist/agent/env-file.js +47 -0
- package/dist/agent/executor.d.ts +30 -0
- package/dist/agent/executor.d.ts.map +1 -0
- package/dist/agent/executor.js +60 -0
- package/dist/agent/health.d.ts +43 -0
- package/dist/agent/health.d.ts.map +1 -0
- package/dist/agent/health.js +109 -0
- package/dist/agent/ports.d.ts +26 -0
- package/dist/agent/ports.d.ts.map +1 -0
- package/dist/agent/ports.js +132 -0
- package/dist/agent/post-steps.d.ts +61 -0
- package/dist/agent/post-steps.d.ts.map +1 -0
- package/dist/agent/post-steps.js +131 -0
- package/dist/agent/prereqs.d.ts +26 -0
- package/dist/agent/prereqs.d.ts.map +1 -0
- package/dist/agent/prereqs.js +134 -0
- package/dist/agent/targets.d.ts +128 -0
- package/dist/agent/targets.d.ts.map +1 -0
- package/dist/agent/targets.js +265 -0
- package/dist/agent/tools.d.ts +13 -0
- package/dist/agent/tools.d.ts.map +1 -0
- package/dist/agent/tools.js +75 -0
- package/dist/agent/troubleshoot.d.ts +30 -0
- package/dist/agent/troubleshoot.d.ts.map +1 -0
- package/dist/agent/troubleshoot.js +87 -0
- package/dist/boilerplate.d.ts +3 -0
- package/dist/boilerplate.d.ts.map +1 -0
- package/dist/boilerplate.js +54 -0
- package/dist/cdk.json +91 -0
- package/dist/cli.d.ts +62 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +463 -0
- package/dist/commands/audit-stacks.d.ts +24 -0
- package/dist/commands/audit-stacks.d.ts.map +1 -0
- package/dist/commands/audit-stacks.js +182 -0
- package/dist/commands/audit-tokens.d.ts +21 -0
- package/dist/commands/audit-tokens.d.ts.map +1 -0
- package/dist/commands/audit-tokens.js +153 -0
- package/dist/commands/bootstrap.d.ts +11 -0
- package/dist/commands/bootstrap.d.ts.map +1 -0
- package/dist/commands/bootstrap.js +159 -0
- package/dist/commands/create-pat.d.ts +27 -0
- package/dist/commands/create-pat.d.ts.map +1 -0
- package/dist/commands/create-pat.js +194 -0
- package/dist/commands/create-pipeline.d.ts +12 -0
- package/dist/commands/create-pipeline.d.ts.map +1 -0
- package/dist/commands/create-pipeline.js +315 -0
- package/dist/commands/deploy.d.ts +15 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +157 -0
- package/dist/commands/entity-get.d.ts +51 -0
- package/dist/commands/entity-get.d.ts.map +1 -0
- package/dist/commands/entity-get.js +69 -0
- package/dist/commands/entity-list.d.ts +39 -0
- package/dist/commands/entity-list.d.ts.map +1 -0
- package/dist/commands/entity-list.js +88 -0
- package/dist/commands/get-pipeline.d.ts +13 -0
- package/dist/commands/get-pipeline.d.ts.map +1 -0
- package/dist/commands/get-pipeline.js +49 -0
- package/dist/commands/get-plugin.d.ts +13 -0
- package/dist/commands/get-plugin.d.ts.map +1 -0
- package/dist/commands/get-plugin.js +51 -0
- package/dist/commands/instantiate-template.d.ts +20 -0
- package/dist/commands/instantiate-template.d.ts.map +1 -0
- package/dist/commands/instantiate-template.js +274 -0
- package/dist/commands/list-pipelines.d.ts +20 -0
- package/dist/commands/list-pipelines.d.ts.map +1 -0
- package/dist/commands/list-pipelines.js +99 -0
- package/dist/commands/list-plugins.d.ts +20 -0
- package/dist/commands/list-plugins.d.ts.map +1 -0
- package/dist/commands/list-plugins.js +92 -0
- package/dist/commands/login.d.ts +21 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +174 -0
- package/dist/commands/new-plugin.d.ts +12 -0
- package/dist/commands/new-plugin.d.ts.map +1 -0
- package/dist/commands/new-plugin.js +129 -0
- package/dist/commands/org-export.d.ts +25 -0
- package/dist/commands/org-export.d.ts.map +1 -0
- package/dist/commands/org-export.js +100 -0
- package/dist/commands/provision.d.ts +122 -0
- package/dist/commands/provision.d.ts.map +1 -0
- package/dist/commands/provision.js +867 -0
- package/dist/commands/redrive-events.d.ts +24 -0
- package/dist/commands/redrive-events.d.ts.map +1 -0
- package/dist/commands/redrive-events.js +127 -0
- package/dist/commands/register.d.ts +38 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +160 -0
- package/dist/commands/setup-events.d.ts +15 -0
- package/dist/commands/setup-events.d.ts.map +1 -0
- package/dist/commands/setup-events.js +168 -0
- package/dist/commands/status.d.ts +11 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/store-token.d.ts +26 -0
- package/dist/commands/store-token.d.ts.map +1 -0
- package/dist/commands/store-token.js +305 -0
- package/dist/commands/synth.d.ts +21 -0
- package/dist/commands/synth.d.ts.map +1 -0
- package/dist/commands/synth.js +158 -0
- package/dist/commands/upload-plugin.d.ts +21 -0
- package/dist/commands/upload-plugin.d.ts.map +1 -0
- package/dist/commands/upload-plugin.js +275 -0
- package/dist/commands/validate-plugin.d.ts +12 -0
- package/dist/commands/validate-plugin.d.ts.map +1 -0
- package/dist/commands/validate-plugin.js +175 -0
- package/dist/commands/validate-templates.d.ts +11 -0
- package/dist/commands/validate-templates.d.ts.map +1 -0
- package/dist/commands/validate-templates.js +116 -0
- package/dist/commands/version.d.ts +12 -0
- package/dist/commands/version.d.ts.map +1 -0
- package/dist/commands/version.js +216 -0
- package/dist/config/cli.constants.d.ts +116 -0
- package/dist/config/cli.constants.d.ts.map +1 -0
- package/dist/config/cli.constants.js +194 -0
- package/dist/config.yml +94 -0
- package/dist/lambda/token-renew-handler.d.ts +2 -0
- package/dist/lambda/token-renew-handler.d.ts.map +1 -0
- package/dist/lambda/token-renew-handler.js +125 -0
- package/dist/templates/events-stack.json +174 -0
- package/dist/templates/token-renew-stack.json +122 -0
- package/dist/types/config.d.ts +53 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +4 -0
- package/dist/types/error.d.ts +61 -0
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/error.js +35 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +11 -0
- package/dist/types/pipeline-template.d.ts +48 -0
- package/dist/types/pipeline-template.d.ts.map +1 -0
- package/dist/types/pipeline-template.js +4 -0
- package/dist/types/pipeline.d.ts +121 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +4 -0
- package/dist/types/plugin.d.ts +135 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +4 -0
- package/dist/utils/api-client.d.ts +26 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +151 -0
- package/dist/utils/audit-log.d.ts +8 -0
- package/dist/utils/audit-log.d.ts.map +1 -0
- package/dist/utils/audit-log.js +57 -0
- package/dist/utils/auth-guard.d.ts +20 -0
- package/dist/utils/auth-guard.d.ts.map +1 -0
- package/dist/utils/auth-guard.js +22 -0
- package/dist/utils/auth-utils.d.ts +68 -0
- package/dist/utils/auth-utils.d.ts.map +1 -0
- package/dist/utils/auth-utils.js +77 -0
- package/dist/utils/aws-env.d.ts +21 -0
- package/dist/utils/aws-env.d.ts.map +1 -0
- package/dist/utils/aws-env.js +34 -0
- package/dist/utils/aws-secrets.d.ts +48 -0
- package/dist/utils/aws-secrets.d.ts.map +1 -0
- package/dist/utils/aws-secrets.js +115 -0
- package/dist/utils/banner.d.ts +19 -0
- package/dist/utils/banner.d.ts.map +1 -0
- package/dist/utils/banner.js +52 -0
- package/dist/utils/cdk-utils.d.ts +74 -0
- package/dist/utils/cdk-utils.d.ts.map +1 -0
- package/dist/utils/cdk-utils.js +152 -0
- package/dist/utils/command-utils.d.ts +75 -0
- package/dist/utils/command-utils.d.ts.map +1 -0
- package/dist/utils/command-utils.js +155 -0
- package/dist/utils/config-loader.d.ts +33 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +154 -0
- package/dist/utils/cron.d.ts +28 -0
- package/dist/utils/cron.d.ts.map +1 -0
- package/dist/utils/cron.js +119 -0
- package/dist/utils/deploy-runner.d.ts +38 -0
- package/dist/utils/deploy-runner.d.ts.map +1 -0
- package/dist/utils/deploy-runner.js +112 -0
- package/dist/utils/error-handler.d.ts +29 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +302 -0
- package/dist/utils/list-command-utils.d.ts +23 -0
- package/dist/utils/list-command-utils.d.ts.map +1 -0
- package/dist/utils/list-command-utils.js +57 -0
- package/dist/utils/output-utils.d.ts +40 -0
- package/dist/utils/output-utils.d.ts.map +1 -0
- package/dist/utils/output-utils.js +250 -0
- package/dist/utils/pipeline-config.d.ts +33 -0
- package/dist/utils/pipeline-config.d.ts.map +1 -0
- package/dist/utils/pipeline-config.js +55 -0
- package/dist/utils/platform-secret.d.ts +27 -0
- package/dist/utils/platform-secret.d.ts.map +1 -0
- package/dist/utils/platform-secret.js +92 -0
- package/dist/utils/plugin-resolver.d.ts +17 -0
- package/dist/utils/plugin-resolver.d.ts.map +1 -0
- package/dist/utils/plugin-resolver.js +101 -0
- package/dist/utils/preflight.d.ts +26 -0
- package/dist/utils/preflight.d.ts.map +1 -0
- package/dist/utils/preflight.js +59 -0
- package/dist/utils/rate-limiter.d.ts +15 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +164 -0
- package/dist/utils/registry.d.ts +86 -0
- package/dist/utils/registry.d.ts.map +1 -0
- package/dist/utils/registry.js +140 -0
- package/dist/utils/response-utils.d.ts +21 -0
- package/dist/utils/response-utils.d.ts.map +1 -0
- package/dist/utils/response-utils.js +70 -0
- package/dist/utils/tls.d.ts +52 -0
- package/dist/utils/tls.d.ts.map +1 -0
- package/dist/utils/tls.js +88 -0
- package/package.json +181 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Registers the `redrive-events` command with the CLI program.
|
|
4
|
+
*
|
|
5
|
+
* Manual fallback for the events Lambda's self-healing redrive (Phase 3): calls
|
|
6
|
+
* SQS `StartMessageMoveTask(DLQ → main queue)` for the `pipeline-builder-events`
|
|
7
|
+
* stack, moving messages that exhausted their receive count in the dead-letter
|
|
8
|
+
* queue back onto `pipeline-builder-events` so the ingestion Lambda re-processes
|
|
9
|
+
* them. Idempotent ingest (dedupe on `idempotencyKey`) prevents double-counting.
|
|
10
|
+
*
|
|
11
|
+
* The Lambda already does this automatically after a successful batch; this
|
|
12
|
+
* command is the operator escape hatch when the Lambda is down or the DLQ needs
|
|
13
|
+
* to be drained on demand. Like the Lambda, it refuses to start a second move
|
|
14
|
+
* task while one is already active (SQS allows only one in-flight task per
|
|
15
|
+
* source queue anyway).
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```bash
|
|
19
|
+
* pipeline-manager infra redrive-events --region us-east-1
|
|
20
|
+
* pipeline-manager infra redrive-events --region us-east-1 --profile prod
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function redriveEvents(program: Command): void;
|
|
24
|
+
//# sourceMappingURL=redrive-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redrive-events.d.ts","sourceRoot":"","sources":["../../src/commands/redrive-events.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8GpD"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { CloudFormationClient, DescribeStacksCommand } from '@aws-sdk/client-cloudformation';
|
|
4
|
+
import { SQSClient, GetQueueAttributesCommand, ListMessageMoveTasksCommand, StartMessageMoveTaskCommand, } from '@aws-sdk/client-sqs';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { EVENTS_STACK_NAME } from '../config/cli.constants.js';
|
|
7
|
+
import { applyAwsProfile, resolveAwsRegion } from '../utils/aws-env.js';
|
|
8
|
+
import { printCommandHeader, withProfileOption, withRegionOption } from '../utils/command-utils.js';
|
|
9
|
+
import { ERROR_CODES, handleError } from '../utils/error-handler.js';
|
|
10
|
+
import { printError, printInfo, printKeyValue, printSection, printSuccess, printWarning } from '../utils/output-utils.js';
|
|
11
|
+
// CFN stack that setup-events deploys — the queues live here.
|
|
12
|
+
const STACK_NAME = EVENTS_STACK_NAME;
|
|
13
|
+
/**
|
|
14
|
+
* Registers the `redrive-events` command with the CLI program.
|
|
15
|
+
*
|
|
16
|
+
* Manual fallback for the events Lambda's self-healing redrive (Phase 3): calls
|
|
17
|
+
* SQS `StartMessageMoveTask(DLQ → main queue)` for the `pipeline-builder-events`
|
|
18
|
+
* stack, moving messages that exhausted their receive count in the dead-letter
|
|
19
|
+
* queue back onto `pipeline-builder-events` so the ingestion Lambda re-processes
|
|
20
|
+
* them. Idempotent ingest (dedupe on `idempotencyKey`) prevents double-counting.
|
|
21
|
+
*
|
|
22
|
+
* The Lambda already does this automatically after a successful batch; this
|
|
23
|
+
* command is the operator escape hatch when the Lambda is down or the DLQ needs
|
|
24
|
+
* to be drained on demand. Like the Lambda, it refuses to start a second move
|
|
25
|
+
* task while one is already active (SQS allows only one in-flight task per
|
|
26
|
+
* source queue anyway).
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```bash
|
|
30
|
+
* pipeline-manager infra redrive-events --region us-east-1
|
|
31
|
+
* pipeline-manager infra redrive-events --region us-east-1 --profile prod
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function redriveEvents(program) {
|
|
35
|
+
withProfileOption(withRegionOption(program
|
|
36
|
+
.command('redrive-events')
|
|
37
|
+
.description('Redrive dead-lettered CodePipeline events back onto the ingestion queue (manual fallback for the Lambda self-healing redrive)')))
|
|
38
|
+
.action(async (options) => {
|
|
39
|
+
const executionId = printCommandHeader('Redrive Events');
|
|
40
|
+
try {
|
|
41
|
+
const region = resolveAwsRegion(options.region);
|
|
42
|
+
// Honor --profile for the SDK clients below (mirrors setup-events) — without
|
|
43
|
+
// this the SDK hits the DEFAULT account while any accompanying CLI call
|
|
44
|
+
// honored --profile (silent split-brain).
|
|
45
|
+
applyAwsProfile(options.profile);
|
|
46
|
+
printInfo('Parameters', { stack: STACK_NAME, region });
|
|
47
|
+
// Step 1: resolve the queue URLs from the stack outputs (source of truth —
|
|
48
|
+
// no hardcoded queue names). setup-events must have run first.
|
|
49
|
+
printSection('Resolve Queues');
|
|
50
|
+
const cfnClient = new CloudFormationClient({ region });
|
|
51
|
+
const describeResult = await cfnClient.send(new DescribeStacksCommand({ StackName: STACK_NAME }));
|
|
52
|
+
const outputs = describeResult.Stacks?.[0]?.Outputs ?? [];
|
|
53
|
+
const outputMap = Object.fromEntries(outputs.map(o => [o.OutputKey ?? '', o.OutputValue ?? '']));
|
|
54
|
+
const eventQueueArn = outputMap.EventQueueArn;
|
|
55
|
+
const eventQueueUrl = outputMap.EventQueueUrl;
|
|
56
|
+
const dlqUrl = outputMap.DeadLetterQueueUrl;
|
|
57
|
+
if (!eventQueueArn || !dlqUrl) {
|
|
58
|
+
printError(`Stack ${STACK_NAME} is missing expected outputs`, {
|
|
59
|
+
hint: 'Run `pipeline-manager infra setup-events` first.',
|
|
60
|
+
});
|
|
61
|
+
throw new Error('Stack outputs EventQueueArn / DeadLetterQueueUrl not found');
|
|
62
|
+
}
|
|
63
|
+
const sqs = new SQSClient({ region });
|
|
64
|
+
// The stack exposes the DLQ URL but not its ARN — StartMessageMoveTask needs
|
|
65
|
+
// the source ARN, so resolve it from the queue's attributes.
|
|
66
|
+
const dlqAttrs = await sqs.send(new GetQueueAttributesCommand({
|
|
67
|
+
QueueUrl: dlqUrl,
|
|
68
|
+
AttributeNames: ['QueueArn', 'ApproximateNumberOfMessages'],
|
|
69
|
+
}));
|
|
70
|
+
const dlqArn = dlqAttrs.Attributes?.QueueArn;
|
|
71
|
+
const dlqDepth = Number(dlqAttrs.Attributes?.ApproximateNumberOfMessages ?? '0');
|
|
72
|
+
if (!dlqArn) {
|
|
73
|
+
throw new Error(`Could not resolve the DLQ ARN from ${dlqUrl}`);
|
|
74
|
+
}
|
|
75
|
+
printKeyValue({
|
|
76
|
+
'Source (DLQ)': dlqArn,
|
|
77
|
+
'Destination (queue)': eventQueueArn,
|
|
78
|
+
'DLQ depth (approx)': String(dlqDepth),
|
|
79
|
+
});
|
|
80
|
+
// Nothing to move — bail early so the operator gets a clear signal instead
|
|
81
|
+
// of a no-op task.
|
|
82
|
+
if (dlqDepth === 0) {
|
|
83
|
+
printSuccess('Dead-letter queue is empty — nothing to redrive.');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// Step 2: refuse to stack move tasks. SQS permits only one in-flight move
|
|
87
|
+
// task per source queue; surface any active one instead of erroring out.
|
|
88
|
+
printSection('Redrive');
|
|
89
|
+
const active = await sqs.send(new ListMessageMoveTasksCommand({ SourceArn: dlqArn }));
|
|
90
|
+
const running = (active.Results ?? []).find(t => t.Status === 'RUNNING');
|
|
91
|
+
if (running) {
|
|
92
|
+
printWarning('A message move task is already running for this DLQ — not starting another.', {
|
|
93
|
+
taskHandle: running.TaskHandle,
|
|
94
|
+
approxMovedSoFar: running.ApproximateNumberOfMessagesMoved,
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Step 3: start the move (DLQ → main queue). DestinationArn is set explicitly
|
|
99
|
+
// even though SQS would default to the original source queue — the main
|
|
100
|
+
// ingestion queue is exactly that target.
|
|
101
|
+
const start = await sqs.send(new StartMessageMoveTaskCommand({
|
|
102
|
+
SourceArn: dlqArn,
|
|
103
|
+
DestinationArn: eventQueueArn,
|
|
104
|
+
}));
|
|
105
|
+
console.log('');
|
|
106
|
+
printSection('Redrive Started');
|
|
107
|
+
printKeyValue({
|
|
108
|
+
'Task Handle': start.TaskHandle ?? '(none returned)',
|
|
109
|
+
'Source (DLQ)': dlqArn,
|
|
110
|
+
'Destination (queue)': eventQueueUrl || eventQueueArn,
|
|
111
|
+
'Messages queued': String(dlqDepth),
|
|
112
|
+
'Status': '✓ Started',
|
|
113
|
+
});
|
|
114
|
+
console.log('');
|
|
115
|
+
printSuccess('Redrive task started. Messages will re-flow through the ingestion Lambda.');
|
|
116
|
+
printInfo('Idempotent ingest dedupes on idempotencyKey, so re-driven events are not double-counted.');
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
handleError(error, ERROR_CODES.API_REQUEST, {
|
|
120
|
+
debug: program.opts().debug,
|
|
121
|
+
exit: true,
|
|
122
|
+
context: { command: 'redrive-events', executionId, stack: STACK_NAME },
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkcml2ZS1ldmVudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbWFuZHMvcmVkcml2ZS1ldmVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUM3RixPQUFPLEVBQ0wsU0FBUyxFQUNULHlCQUF5QixFQUN6QiwyQkFBMkIsRUFDM0IsMkJBQTJCLEdBQzVCLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsZUFBZSxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDcEcsT0FBTyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNyRSxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUUxSCw4REFBOEQ7QUFDOUQsTUFBTSxVQUFVLEdBQUcsaUJBQWlCLENBQUM7QUFFckM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxPQUFnQjtJQUM1QyxpQkFBaUIsQ0FDZixnQkFBZ0IsQ0FBQyxPQUFPO1NBQ3JCLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQztTQUN6QixXQUFXLENBQUMsK0hBQStILENBQUMsQ0FBQyxDQUNqSjtTQUNFLE1BQU0sQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7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QywwRkFBMEYsQ0FBQyxDQUFDO1FBRXhHLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsV0FBVyxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsV0FBVyxFQUFFO2dCQUMxQyxLQUFLLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUs7Z0JBQzNCLElBQUksRUFBRSxJQUFJO2dCQUNWLE9BQU8sRUFBRSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRTthQUN2RSxDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDUCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IENsb3VkRm9ybWF0aW9uQ2xpZW50LCBEZXNjcmliZVN0YWNrc0NvbW1hbmQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtY2xvdWRmb3JtYXRpb24nO1xuaW1wb3J0IHtcbiAgU1FTQ2xpZW50LFxuICBHZXRRdWV1ZUF0dHJpYnV0ZXNDb21tYW5kLFxuICBMaXN0TWVzc2FnZU1vdmVUYXNrc0NvbW1hbmQsXG4gIFN0YXJ0TWVzc2FnZU1vdmVUYXNrQ29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXNxcyc7XG5pbXBvcnQgeyBDb21tYW5kIH0gZnJvbSAnY29tbWFuZGVyJztcbmltcG9ydCB7IEVWRU5UU19TVEFDS19OQU1FIH0gZnJvbSAnLi4vY29uZmlnL2NsaS5jb25zdGFudHMuanMnO1xuaW1wb3J0IHsgYXBwbHlBd3NQcm9maWxlLCByZXNvbHZlQXdzUmVnaW9uIH0gZnJvbSAnLi4vdXRpbHMvYXdzLWVudi5qcyc7XG5pbXBvcnQgeyBwcmludENvbW1hbmRIZWFkZXIsIHdpdGhQcm9maWxlT3B0aW9uLCB3aXRoUmVnaW9uT3B0aW9uIH0gZnJvbSAnLi4vdXRpbHMvY29tbWFuZC11dGlscy5qcyc7XG5pbXBvcnQgeyBFUlJPUl9DT0RFUywgaGFuZGxlRXJyb3IgfSBmcm9tICcuLi91dGlscy9lcnJvci1oYW5kbGVyLmpzJztcbmltcG9ydCB7IHByaW50RXJyb3IsIHByaW50SW5mbywgcHJpbnRLZXlWYWx1ZSwgcHJpbnRTZWN0aW9uLCBwcmludFN1Y2Nlc3MsIHByaW50V2FybmluZyB9IGZyb20gJy4uL3V0aWxzL291dHB1dC11dGlscy5qcyc7XG5cbi8vIENGTiBzdGFjayB0aGF0IHNldHVwLWV2ZW50cyBkZXBsb3lzIOKAlCB0aGUgcXVldWVzIGxpdmUgaGVyZS5cbmNvbnN0IFNUQUNLX05BTUUgPSBFVkVOVFNfU1RBQ0tfTkFNRTtcblxuLyoqXG4gKiBSZWdpc3RlcnMgdGhlIGByZWRyaXZlLWV2ZW50c2AgY29tbWFuZCB3aXRoIHRoZSBDTEkgcHJvZ3JhbS5cbiAqXG4gKiBNYW51YWwgZmFsbGJhY2sgZm9yIHRoZSBldmVudHMgTGFtYmRhJ3Mgc2VsZi1oZWFsaW5nIHJlZHJpdmUgKFBoYXNlIDMpOiBjYWxsc1xuICogU1FTIGBTdGFydE1lc3NhZ2VNb3ZlVGFzayhETFEg4oaSIG1haW4gcXVldWUpYCBmb3IgdGhlIGBwaXBlbGluZS1idWlsZGVyLWV2ZW50c2BcbiAqIHN0YWNrLCBtb3ZpbmcgbWVzc2FnZXMgdGhhdCBleGhhdXN0ZWQgdGhlaXIgcmVjZWl2ZSBjb3VudCBpbiB0aGUgZGVhZC1sZXR0ZXJcbiAqIHF1ZXVlIGJhY2sgb250byBgcGlwZWxpbmUtYnVpbGRlci1ldmVudHNgIHNvIHRoZSBpbmdlc3Rpb24gTGFtYmRhIHJlLXByb2Nlc3Nlc1xuICogdGhlbS4gSWRlbXBvdGVudCBpbmdlc3QgKGRlZHVwZSBvbiBgaWRlbXBvdGVuY3lLZXlgKSBwcmV2ZW50cyBkb3VibGUtY291bnRpbmcuXG4gKlxuICogVGhlIExhbWJkYSBhbHJlYWR5IGRvZXMgdGhpcyBhdXRvbWF0aWNhbGx5IGFmdGVyIGEgc3VjY2Vzc2Z1bCBiYXRjaDsgdGhpc1xuICogY29tbWFuZCBpcyB0aGUgb3BlcmF0b3IgZXNjYXBlIGhhdGNoIHdoZW4gdGhlIExhbWJkYSBpcyBkb3duIG9yIHRoZSBETFEgbmVlZHNcbiAqIHRvIGJlIGRyYWluZWQgb24gZGVtYW5kLiBMaWtlIHRoZSBMYW1iZGEsIGl0IHJlZnVzZXMgdG8gc3RhcnQgYSBzZWNvbmQgbW92ZVxuICogdGFzayB3aGlsZSBvbmUgaXMgYWxyZWFkeSBhY3RpdmUgKFNRUyBhbGxvd3Mgb25seSBvbmUgaW4tZmxpZ2h0IHRhc2sgcGVyXG4gKiBzb3VyY2UgcXVldWUgYW55d2F5KS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgYmFzaFxuICogcGlwZWxpbmUtbWFuYWdlciBpbmZyYSByZWRyaXZlLWV2ZW50cyAtLXJlZ2lvbiB1cy1lYXN0LTFcbiAqIHBpcGVsaW5lLW1hbmFnZXIgaW5mcmEgcmVkcml2ZS1ldmVudHMgLS1yZWdpb24gdXMtZWFzdC0xIC0tcHJvZmlsZSBwcm9kXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZHJpdmVFdmVudHMocHJvZ3JhbTogQ29tbWFuZCk6IHZvaWQge1xuICB3aXRoUHJvZmlsZU9wdGlvbihcbiAgICB3aXRoUmVnaW9uT3B0aW9uKHByb2dyYW1cbiAgICAgIC5jb21tYW5kKCdyZWRyaXZlLWV2ZW50cycpXG4gICAgICAuZGVzY3JpcHRpb24oJ1JlZHJpdmUgZGVhZC1sZXR0ZXJlZCBDb2RlUGlwZWxpbmUgZXZlbnRzIGJhY2sgb250byB0aGUgaW5nZXN0aW9uIHF1ZXVlIChtYW51YWwgZmFsbGJhY2sgZm9yIHRoZSBMYW1iZGEgc2VsZi1oZWFsaW5nIHJlZHJpdmUpJykpLFxuICApXG4gICAgLmFjdGlvbihhc3luYyAob3B0aW9ucykgPT4ge1xuICAgICAgY29uc3QgZXhlY3V0aW9uSWQgPSBwcmludENvbW1hbmRIZWFkZXIoJ1JlZHJpdmUgRXZlbnRzJyk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlZ2lvbiA9IHJlc29sdmVBd3NSZWdpb24ob3B0aW9ucy5yZWdpb24pO1xuICAgICAgICAvLyBIb25vciAtLXByb2ZpbGUgZm9yIHRoZSBTREsgY2xpZW50cyBiZWxvdyAobWlycm9ycyBzZXR1cC1ldmVudHMpIOKAlCB3aXRob3V0XG4gICAgICAgIC8vIHRoaXMgdGhlIFNESyBoaXRzIHRoZSBERUZBVUxUIGFjY291bnQgd2hpbGUgYW55IGFjY29tcGFueWluZyBDTEkgY2FsbFxuICAgICAgICAvLyBob25vcmVkIC0tcHJvZmlsZSAoc2lsZW50IHNwbGl0LWJyYWluKS5cbiAgICAgICAgYXBwbHlBd3NQcm9maWxlKG9wdGlvbnMucHJvZmlsZSk7XG5cbiAgICAgICAgcHJpbnRJbmZvKCdQYXJhbWV0ZXJzJywgeyBzdGFjazogU1RBQ0tfTkFNRSwgcmVnaW9uIH0pO1xuXG4gICAgICAgIC8vIFN0ZXAgMTogcmVzb2x2ZSB0aGUgcXVldWUgVVJMcyBmcm9tIHRoZSBzdGFjayBvdXRwdXRzIChzb3VyY2Ugb2YgdHJ1dGgg4oCUXG4gICAgICAgIC8vIG5vIGhhcmRjb2RlZCBxdWV1ZSBuYW1lcykuIHNldHVwLWV2ZW50cyBtdXN0IGhhdmUgcnVuIGZpcnN0LlxuICAgICAgICBwcmludFNlY3Rpb24oJ1Jlc29sdmUgUXVldWVzJyk7XG5cbiAgICAgICAgY29uc3QgY2ZuQ2xpZW50ID0gbmV3IENsb3VkRm9ybWF0aW9uQ2xpZW50KHsgcmVnaW9uIH0pO1xuICAgICAgICBjb25zdCBkZXNjcmliZVJlc3VsdCA9IGF3YWl0IGNmbkNsaWVudC5zZW5kKG5ldyBEZXNjcmliZVN0YWNrc0NvbW1hbmQoeyBTdGFja05hbWU6IFNUQUNLX05BTUUgfSkpO1xuICAgICAgICBjb25zdCBvdXRwdXRzID0gZGVzY3JpYmVSZXN1bHQuU3RhY2tzPy5bMF0/Lk91dHB1dHMgPz8gW107XG4gICAgICAgIGNvbnN0IG91dHB1dE1hcCA9IE9iamVjdC5mcm9tRW50cmllcyhvdXRwdXRzLm1hcChvID0+IFtvLk91dHB1dEtleSA/PyAnJywgby5PdXRwdXRWYWx1ZSA/PyAnJ10pKTtcblxuICAgICAgICBjb25zdCBldmVudFF1ZXVlQXJuID0gb3V0cHV0TWFwLkV2ZW50UXVldWVBcm47XG4gICAgICAgIGNvbnN0IGV2ZW50UXVldWVVcmwgPSBvdXRwdXRNYXAuRXZlbnRRdWV1ZVVybDtcbiAgICAgICAgY29uc3QgZGxxVXJsID0gb3V0cHV0TWFwLkRlYWRMZXR0ZXJRdWV1ZVVybDtcblxuICAgICAgICBpZiAoIWV2ZW50UXVldWVBcm4gfHwgIWRscVVybCkge1xuICAgICAgICAgIHByaW50RXJyb3IoYFN0YWNrICR7U1RBQ0tfTkFNRX0gaXMgbWlzc2luZyBleHBlY3RlZCBvdXRwdXRzYCwge1xuICAgICAgICAgICAgaGludDogJ1J1biBgcGlwZWxpbmUtbWFuYWdlciBpbmZyYSBzZXR1cC1ldmVudHNgIGZpcnN0LicsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTdGFjayBvdXRwdXRzIEV2ZW50UXVldWVBcm4gLyBEZWFkTGV0dGVyUXVldWVVcmwgbm90IGZvdW5kJyk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzcXMgPSBuZXcgU1FTQ2xpZW50KHsgcmVnaW9uIH0pO1xuXG4gICAgICAgIC8vIFRoZSBzdGFjayBleHBvc2VzIHRoZSBETFEgVVJMIGJ1dCBub3QgaXRzIEFSTiDigJQgU3RhcnRNZXNzYWdlTW92ZVRhc2sgbmVlZHNcbiAgICAgICAgLy8gdGhlIHNvdXJjZSBBUk4sIHNvIHJlc29sdmUgaXQgZnJvbSB0aGUgcXVldWUncyBhdHRyaWJ1dGVzLlxuICAgICAgICBjb25zdCBkbHFBdHRycyA9IGF3YWl0IHNxcy5zZW5kKG5ldyBHZXRRdWV1ZUF0dHJpYnV0ZXNDb21tYW5kKHtcbiAgICAgICAgICBRdWV1ZVVybDogZGxxVXJsLFxuICAgICAgICAgIEF0dHJpYnV0ZU5hbWVzOiBbJ1F1ZXVlQXJuJywgJ0FwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlcyddLFxuICAgICAgICB9KSk7XG4gICAgICAgIGNvbnN0IGRscUFybiA9IGRscUF0dHJzLkF0dHJpYnV0ZXM/LlF1ZXVlQXJuO1xuICAgICAgICBjb25zdCBkbHFEZXB0aCA9IE51bWJlcihkbHFBdHRycy5BdHRyaWJ1dGVzPy5BcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXMgPz8gJzAnKTtcblxuICAgICAgICBpZiAoIWRscUFybikge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IHJlc29sdmUgdGhlIERMUSBBUk4gZnJvbSAke2RscVVybH1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHByaW50S2V5VmFsdWUoe1xuICAgICAgICAgICdTb3VyY2UgKERMUSknOiBkbHFBcm4sXG4gICAgICAgICAgJ0Rlc3RpbmF0aW9uIChxdWV1ZSknOiBldmVudFF1ZXVlQXJuLFxuICAgICAgICAgICdETFEgZGVwdGggKGFwcHJveCknOiBTdHJpbmcoZGxxRGVwdGgpLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBOb3RoaW5nIHRvIG1vdmUg4oCUIGJhaWwgZWFybHkgc28gdGhlIG9wZXJhdG9yIGdldHMgYSBjbGVhciBzaWduYWwgaW5zdGVhZFxuICAgICAgICAvLyBvZiBhIG5vLW9wIHRhc2suXG4gICAgICAgIGlmIChkbHFEZXB0aCA9PT0gMCkge1xuICAgICAgICAgIHByaW50U3VjY2VzcygnRGVhZC1sZXR0ZXIgcXVldWUgaXMgZW1wdHkg4oCUIG5vdGhpbmcgdG8gcmVkcml2ZS4nKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdGVwIDI6IHJlZnVzZSB0byBzdGFjayBtb3ZlIHRhc2tzLiBTUVMgcGVybWl0cyBvbmx5IG9uZSBpbi1mbGlnaHQgbW92ZVxuICAgICAgICAvLyB0YXNrIHBlciBzb3VyY2UgcXVldWU7IHN1cmZhY2UgYW55IGFjdGl2ZSBvbmUgaW5zdGVhZCBvZiBlcnJvcmluZyBvdXQuXG4gICAgICAgIHByaW50U2VjdGlvbignUmVkcml2ZScpO1xuXG4gICAgICAgIGNvbnN0IGFjdGl2ZSA9IGF3YWl0IHNxcy5zZW5kKG5ldyBMaXN0TWVzc2FnZU1vdmVUYXNrc0NvbW1hbmQoeyBTb3VyY2VBcm46IGRscUFybiB9KSk7XG4gICAgICAgIGNvbnN0IHJ1bm5pbmcgPSAoYWN0aXZlLlJlc3VsdHMgPz8gW10pLmZpbmQodCA9PiB0LlN0YXR1cyA9PT0gJ1JVTk5JTkcnKTtcbiAgICAgICAgaWYgKHJ1bm5pbmcpIHtcbiAgICAgICAgICBwcmludFdhcm5pbmcoJ0EgbWVzc2FnZSBtb3ZlIHRhc2sgaXMgYWxyZWFkeSBydW5uaW5nIGZvciB0aGlzIERMUSDigJQgbm90IHN0YXJ0aW5nIGFub3RoZXIuJywge1xuICAgICAgICAgICAgdGFza0hhbmRsZTogcnVubmluZy5UYXNrSGFuZGxlLFxuICAgICAgICAgICAgYXBwcm94TW92ZWRTb0ZhcjogcnVubmluZy5BcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXNNb3ZlZCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdGVwIDM6IHN0YXJ0IHRoZSBtb3ZlIChETFEg4oaSIG1haW4gcXVldWUpLiBEZXN0aW5hdGlvbkFybiBpcyBzZXQgZXhwbGljaXRseVxuICAgICAgICAvLyBldmVuIHRob3VnaCBTUVMgd291bGQgZGVmYXVsdCB0byB0aGUgb3JpZ2luYWwgc291cmNlIHF1ZXVlIOKAlCB0aGUgbWFpblxuICAgICAgICAvLyBpbmdlc3Rpb24gcXVldWUgaXMgZXhhY3RseSB0aGF0IHRhcmdldC5cbiAgICAgICAgY29uc3Qgc3RhcnQgPSBhd2FpdCBzcXMuc2VuZChuZXcgU3RhcnRNZXNzYWdlTW92ZVRhc2tDb21tYW5kKHtcbiAgICAgICAgICBTb3VyY2VBcm46IGRscUFybixcbiAgICAgICAgICBEZXN0aW5hdGlvbkFybjogZXZlbnRRdWV1ZUFybixcbiAgICAgICAgfSkpO1xuXG4gICAgICAgIGNvbnNvbGUubG9nKCcnKTtcbiAgICAgICAgcHJpbnRTZWN0aW9uKCdSZWRyaXZlIFN0YXJ0ZWQnKTtcbiAgICAgICAgcHJpbnRLZXlWYWx1ZSh7XG4gICAgICAgICAgJ1Rhc2sgSGFuZGxlJzogc3RhcnQuVGFza0hhbmRsZSA/PyAnKG5vbmUgcmV0dXJuZWQpJyxcbiAgICAgICAgICAnU291cmNlIChETFEpJzogZGxxQXJuLFxuICAgICAgICAgICdEZXN0aW5hdGlvbiAocXVldWUpJzogZXZlbnRRdWV1ZVVybCB8fCBldmVudFF1ZXVlQXJuLFxuICAgICAgICAgICdNZXNzYWdlcyBxdWV1ZWQnOiBTdHJpbmcoZGxxRGVwdGgpLFxuICAgICAgICAgICdTdGF0dXMnOiAn4pyTIFN0YXJ0ZWQnLFxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zb2xlLmxvZygnJyk7XG4gICAgICAgIHByaW50U3VjY2VzcygnUmVkcml2ZSB0YXNrIHN0YXJ0ZWQuIE1lc3NhZ2VzIHdpbGwgcmUtZmxvdyB0aHJvdWdoIHRoZSBpbmdlc3Rpb24gTGFtYmRhLicpO1xuICAgICAgICBwcmludEluZm8oJ0lkZW1wb3RlbnQgaW5nZXN0IGRlZHVwZXMgb24gaWRlbXBvdGVuY3lLZXksIHNvIHJlLWRyaXZlbiBldmVudHMgYXJlIG5vdCBkb3VibGUtY291bnRlZC4nKTtcblxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaGFuZGxlRXJyb3IoZXJyb3IsIEVSUk9SX0NPREVTLkFQSV9SRVFVRVNULCB7XG4gICAgICAgICAgZGVidWc6IHByb2dyYW0ub3B0cygpLmRlYnVnLFxuICAgICAgICAgIGV4aXQ6IHRydWUsXG4gICAgICAgICAgY29udGV4dDogeyBjb21tYW5kOiAncmVkcml2ZS1ldmVudHMnLCBleGVjdXRpb25JZCwgc3RhY2s6IFNUQUNLX05BTUUgfSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG59XG4iXX0=
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Registers the `register` command with the CLI program.
|
|
4
|
+
*
|
|
5
|
+
* Two purposes — both targeted at recovering from a deploy whose registration
|
|
6
|
+
* step didn't land:
|
|
7
|
+
*
|
|
8
|
+
* 1. Explicit re-register (`--id <pipelineId>`) — recomputes the ARN from
|
|
9
|
+
* STS + region and POSTs it to the platform. Useful when the platform
|
|
10
|
+
* was unreachable during `deploy`, when the registry row was deleted by
|
|
11
|
+
* mistake, or for any other reason a deployed stack has no registry row.
|
|
12
|
+
*
|
|
13
|
+
* 2. Drain pending intents (every invocation) — `deploy` writes a local
|
|
14
|
+
* file under `~/.pipeline-manager/pending-registrations/` whenever its
|
|
15
|
+
* registration POST fails. Each `register` invocation tries to drain
|
|
16
|
+
* every such file. On success the file is deleted; on failure it stays
|
|
17
|
+
* and surfaces as a warning.
|
|
18
|
+
*
|
|
19
|
+
* Flags:
|
|
20
|
+
* - `--id <pipelineId>` — re-register a specific pipeline by ID
|
|
21
|
+
* - `--region <region>` — AWS region (default: AWS_REGION env / us-east-1)
|
|
22
|
+
* - `--no-drain` — skip draining pending intents
|
|
23
|
+
*
|
|
24
|
+
* Exit codes:
|
|
25
|
+
* - 0: requested registration succeeded AND no pending intents remain
|
|
26
|
+
* - 1: at least one registration (explicit or pending) still failed
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```bash
|
|
30
|
+
* # Retry a registration that failed during deploy
|
|
31
|
+
* pipeline-manager pipeline register --id pipe-123
|
|
32
|
+
*
|
|
33
|
+
* # Just drain pending intents from disk, no specific registration
|
|
34
|
+
* pipeline-manager pipeline register
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function register(program: Command): void;
|
|
38
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwG/C"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import {} from '../types/index.js';
|
|
5
|
+
import { createAuthenticatedClient, printCommandHeader, printSslWarning, withRegionOption, withSslOptions } from '../utils/command-utils.js';
|
|
6
|
+
import { ERROR_CODES, handleError } from '../utils/error-handler.js';
|
|
7
|
+
import { printError, printInfo, printKeyValue, printSection, printSuccess, printWarning } from '../utils/output-utils.js';
|
|
8
|
+
import { buildRegistryPayload, clearPendingIntent, readPendingIntents, writePendingIntent, } from '../utils/registry.js';
|
|
9
|
+
import { extractSingleResponse } from '../utils/response-utils.js';
|
|
10
|
+
/**
|
|
11
|
+
* Registers the `register` command with the CLI program.
|
|
12
|
+
*
|
|
13
|
+
* Two purposes — both targeted at recovering from a deploy whose registration
|
|
14
|
+
* step didn't land:
|
|
15
|
+
*
|
|
16
|
+
* 1. Explicit re-register (`--id <pipelineId>`) — recomputes the ARN from
|
|
17
|
+
* STS + region and POSTs it to the platform. Useful when the platform
|
|
18
|
+
* was unreachable during `deploy`, when the registry row was deleted by
|
|
19
|
+
* mistake, or for any other reason a deployed stack has no registry row.
|
|
20
|
+
*
|
|
21
|
+
* 2. Drain pending intents (every invocation) — `deploy` writes a local
|
|
22
|
+
* file under `~/.pipeline-manager/pending-registrations/` whenever its
|
|
23
|
+
* registration POST fails. Each `register` invocation tries to drain
|
|
24
|
+
* every such file. On success the file is deleted; on failure it stays
|
|
25
|
+
* and surfaces as a warning.
|
|
26
|
+
*
|
|
27
|
+
* Flags:
|
|
28
|
+
* - `--id <pipelineId>` — re-register a specific pipeline by ID
|
|
29
|
+
* - `--region <region>` — AWS region (default: AWS_REGION env / us-east-1)
|
|
30
|
+
* - `--no-drain` — skip draining pending intents
|
|
31
|
+
*
|
|
32
|
+
* Exit codes:
|
|
33
|
+
* - 0: requested registration succeeded AND no pending intents remain
|
|
34
|
+
* - 1: at least one registration (explicit or pending) still failed
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```bash
|
|
38
|
+
* # Retry a registration that failed during deploy
|
|
39
|
+
* pipeline-manager pipeline register --id pipe-123
|
|
40
|
+
*
|
|
41
|
+
* # Just drain pending intents from disk, no specific registration
|
|
42
|
+
* pipeline-manager pipeline register
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function register(program) {
|
|
46
|
+
withSslOptions(withRegionOption(program
|
|
47
|
+
.command('register')
|
|
48
|
+
.description('Register a deployed pipeline ARN with the platform (retry path for failed registrations)')
|
|
49
|
+
.option('-i, --id <id>', 'Pipeline ID to register (re-derives ARN from STS)'))
|
|
50
|
+
.option('--no-drain', 'Skip draining pending intents from prior failed deploys'))
|
|
51
|
+
.action(async (options) => {
|
|
52
|
+
const executionId = printCommandHeader('Register Pipeline');
|
|
53
|
+
printSslWarning(options.verifySsl);
|
|
54
|
+
let anyFailed = false;
|
|
55
|
+
let registeredCount = 0;
|
|
56
|
+
try {
|
|
57
|
+
const client = createAuthenticatedClient(options);
|
|
58
|
+
const pipelineUrl = client.getConfig().api.pipelineUrl;
|
|
59
|
+
// ── Drain pending intents first ──
|
|
60
|
+
// We drain before the explicit registration so a queued failure for
|
|
61
|
+
// the same pipelineId is replaced (not double-applied) by the fresh
|
|
62
|
+
// payload below.
|
|
63
|
+
const drained = new Set();
|
|
64
|
+
if (options.drain !== false) {
|
|
65
|
+
const intents = await readPendingIntents();
|
|
66
|
+
if (intents.length > 0) {
|
|
67
|
+
printSection('Draining pending intents');
|
|
68
|
+
printInfo('Found pending registrations from prior failed deploys', {
|
|
69
|
+
count: String(intents.length),
|
|
70
|
+
});
|
|
71
|
+
for (const intent of intents) {
|
|
72
|
+
// Skip the explicit pipeline — we'll re-build a fresh payload below.
|
|
73
|
+
if (options.id && intent.pipelineId === options.id)
|
|
74
|
+
continue;
|
|
75
|
+
const ok = await postRegistration(client, pipelineUrl, intent, intent.pipelineId);
|
|
76
|
+
if (ok) {
|
|
77
|
+
await clearPendingIntent(intent.pipelineId);
|
|
78
|
+
drained.add(intent.pipelineId);
|
|
79
|
+
registeredCount++;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
anyFailed = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// ── Explicit registration ──
|
|
88
|
+
if (options.id) {
|
|
89
|
+
printSection('Re-registering pipeline');
|
|
90
|
+
const pipelineRes = await client.get(`${pipelineUrl}/${options.id}`);
|
|
91
|
+
const pipeline = extractSingleResponse(pipelineRes, 'pipeline', 'id');
|
|
92
|
+
if (!pipeline) {
|
|
93
|
+
printError('Pipeline not found in platform');
|
|
94
|
+
throw new Error(`No pipeline returned for id ${options.id}`);
|
|
95
|
+
}
|
|
96
|
+
if (!pipeline.orgId) {
|
|
97
|
+
printError('Pipeline has no orgId — cannot register');
|
|
98
|
+
throw new Error(`Pipeline ${pipeline.id} is missing orgId`);
|
|
99
|
+
}
|
|
100
|
+
const payload = await buildRegistryPayload({
|
|
101
|
+
id: pipeline.id,
|
|
102
|
+
orgId: pipeline.orgId,
|
|
103
|
+
pipelineName: pipeline.pipelineName,
|
|
104
|
+
project: pipeline.project,
|
|
105
|
+
organization: pipeline.organization,
|
|
106
|
+
}, options.region);
|
|
107
|
+
// Clear any stale intent for this pipelineId before retrying so we
|
|
108
|
+
// don't leave a duplicate file behind on success.
|
|
109
|
+
await clearPendingIntent(payload.pipelineId);
|
|
110
|
+
const ok = await postRegistration(client, pipelineUrl, payload, payload.pipelineId);
|
|
111
|
+
if (ok) {
|
|
112
|
+
registeredCount++;
|
|
113
|
+
printSuccess('Pipeline registered for event reporting', {
|
|
114
|
+
pipelineId: payload.pipelineId,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
anyFailed = true;
|
|
119
|
+
const path = await writePendingIntent(payload);
|
|
120
|
+
printWarning('Registration failed; intent saved for retry', { intent: path });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
printSection('Summary');
|
|
124
|
+
printKeyValue({
|
|
125
|
+
'Registered': String(registeredCount),
|
|
126
|
+
'Drained from queue': String(drained.size),
|
|
127
|
+
'Status': anyFailed ? 'Some registrations still pending' : 'All clear',
|
|
128
|
+
'Execution ID': executionId,
|
|
129
|
+
});
|
|
130
|
+
process.exit(anyFailed ? 1 : 0);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
handleError(error, ERROR_CODES.API_REQUEST, {
|
|
134
|
+
debug: program.opts().debug,
|
|
135
|
+
exit: false,
|
|
136
|
+
context: { command: 'register', executionId, pipelineId: options.id },
|
|
137
|
+
});
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* POST a registration payload to the platform. On failure, the caller decides
|
|
144
|
+
* whether to write/preserve a pending intent — this helper just reports.
|
|
145
|
+
*/
|
|
146
|
+
async function postRegistration(client, pipelineUrl, payload, pipelineId) {
|
|
147
|
+
try {
|
|
148
|
+
await client.post(`${pipelineUrl}/registry`, payload);
|
|
149
|
+
printInfo('Registered', { pipelineId });
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
printWarning('Registration failed', {
|
|
154
|
+
pipelineId,
|
|
155
|
+
error: err instanceof Error ? err.message : String(err),
|
|
156
|
+
});
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbWFuZHMvcmVnaXN0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3BDLE9BQU8sRUFBd0MsTUFBTSxtQkFBbUIsQ0FBQztBQUN6RSxPQUFPLEVBQUUseUJBQXlCLEVBQUUsa0JBQWtCLEVBQUUsZUFBZSxFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzdJLE9BQU8sRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDckUsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsYUFBYSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDMUgsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixrQkFBa0IsRUFDbEIsa0JBQWtCLEVBQ2xCLGtCQUFrQixHQUVuQixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRW5FOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0NHO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FBQyxPQUFnQjtJQUN2QyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsT0FBTztTQUNwQyxPQUFPLENBQUMsVUFBVSxDQUFDO1NBQ25CLFdBQVcsQ0FBQywwRkFBMEYsQ0FBQztTQUN2RyxNQUFNLENBQUMsZUFBZSxFQUFFLG1EQUFtRCxDQUFDLENBQUM7U0FDN0UsTUFBTSxDQUFDLFlBQVksRUFBRSx5REFBeUQsQ0FBQyxDQUFDO1NBQ2hGLE1BQU0sQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7UUFDeEIsTUFBTSxXQUFXLEdBQUcsa0JBQWtC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QUssRUFBRSxXQUFXLENBQUMsV0FBVyxFQUFFO2dCQUMxQyxLQUFLLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUs7Z0JBQzNCLElBQUksRUFBRSxLQUFLO2dCQUNYLE9BQU8sRUFBRSxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFO2FBQ3RFLENBQUMsQ0FBQztZQUNILE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEIsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQztBQUVEOzs7R0FHRztBQUNILEtBQUssVUFBVSxnQkFBZ0IsQ0FDN0IsTUFBb0QsRUFDcEQsV0FBbUIsRUFDbkIsT0FBd0IsRUFDeEIsVUFBa0I7SUFFbEIsSUFBSSxDQUFDO1FBQ0gsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsV0FBVyxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDdEQsU0FBUyxDQUFDLFlBQVksRUFBRSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDeEMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLFlBQVksQ0FBQyxxQkFBcUIsRUFBRTtZQUNsQyxVQUFVO1lBQ1YsS0FBSyxFQUFFLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7U0FDeEQsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBDb21tYW5kIH0gZnJvbSAnY29tbWFuZGVyJztcbmltcG9ydCB7IHR5cGUgUGlwZWxpbmUsIHR5cGUgUGlwZWxpbmVSZXNwb25zZSB9IGZyb20gJy4uL3R5cGVzL2luZGV4LmpzJztcbmltcG9ydCB7IGNyZWF0ZUF1dGhlbnRpY2F0ZWRDbGllbnQsIHByaW50Q29tbWFuZEhlYWRlciwgcHJpbnRTc2xXYXJuaW5nLCB3aXRoUmVnaW9uT3B0aW9uLCB3aXRoU3NsT3B0aW9ucyB9IGZyb20gJy4uL3V0aWxzL2NvbW1hbmQtdXRpbHMuanMnO1xuaW1wb3J0IHsgRVJST1JfQ09ERVMsIGhhbmRsZUVycm9yIH0gZnJvbSAnLi4vdXRpbHMvZXJyb3ItaGFuZGxlci5qcyc7XG5pbXBvcnQgeyBwcmludEVycm9yLCBwcmludEluZm8sIHByaW50S2V5VmFsdWUsIHByaW50U2VjdGlvbiwgcHJpbnRTdWNjZXNzLCBwcmludFdhcm5pbmcgfSBmcm9tICcuLi91dGlscy9vdXRwdXQtdXRpbHMuanMnO1xuaW1wb3J0IHtcbiAgYnVpbGRSZWdpc3RyeVBheWxvYWQsXG4gIGNsZWFyUGVuZGluZ0ludGVudCxcbiAgcmVhZFBlbmRpbmdJbnRlbnRzLFxuICB3cml0ZVBlbmRpbmdJbnRlbnQsXG4gIHR5cGUgUmVnaXN0cnlQYXlsb2FkLFxufSBmcm9tICcuLi91dGlscy9yZWdpc3RyeS5qcyc7XG5pbXBvcnQgeyBleHRyYWN0U2luZ2xlUmVzcG9uc2UgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZS11dGlscy5qcyc7XG5cbi8qKlxuICogUmVnaXN0ZXJzIHRoZSBgcmVnaXN0ZXJgIGNvbW1hbmQgd2l0aCB0aGUgQ0xJIHByb2dyYW0uXG4gKlxuICogVHdvIHB1cnBvc2VzIOKAlCBib3RoIHRhcmdldGVkIGF0IHJlY292ZXJpbmcgZnJvbSBhIGRlcGxveSB3aG9zZSByZWdpc3RyYXRpb25cbiAqIHN0ZXAgZGlkbid0IGxhbmQ6XG4gKlxuICogICAxLiBFeHBsaWNpdCByZS1yZWdpc3RlciAoYC0taWQgPHBpcGVsaW5lSWQ+YCkg4oCUIHJlY29tcHV0ZXMgdGhlIEFSTiBmcm9tXG4gKiAgICAgIFNUUyArIHJlZ2lvbiBhbmQgUE9TVHMgaXQgdG8gdGhlIHBsYXRmb3JtLiBVc2VmdWwgd2hlbiB0aGUgcGxhdGZvcm1cbiAqICAgICAgd2FzIHVucmVhY2hhYmxlIGR1cmluZyBgZGVwbG95YCwgd2hlbiB0aGUgcmVnaXN0cnkgcm93IHdhcyBkZWxldGVkIGJ5XG4gKiAgICAgIG1pc3Rha2UsIG9yIGZvciBhbnkgb3RoZXIgcmVhc29uIGEgZGVwbG95ZWQgc3RhY2sgaGFzIG5vIHJlZ2lzdHJ5IHJvdy5cbiAqXG4gKiAgIDIuIERyYWluIHBlbmRpbmcgaW50ZW50cyAoZXZlcnkgaW52b2NhdGlvbikg4oCUIGBkZXBsb3lgIHdyaXRlcyBhIGxvY2FsXG4gKiAgICAgIGZpbGUgdW5kZXIgYH4vLnBpcGVsaW5lLW1hbmFnZXIvcGVuZGluZy1yZWdpc3RyYXRpb25zL2Agd2hlbmV2ZXIgaXRzXG4gKiAgICAgIHJlZ2lzdHJhdGlvbiBQT1NUIGZhaWxzLiBFYWNoIGByZWdpc3RlcmAgaW52b2NhdGlvbiB0cmllcyB0byBkcmFpblxuICogICAgICBldmVyeSBzdWNoIGZpbGUuIE9uIHN1Y2Nlc3MgdGhlIGZpbGUgaXMgZGVsZXRlZDsgb24gZmFpbHVyZSBpdCBzdGF5c1xuICogICAgICBhbmQgc3VyZmFjZXMgYXMgYSB3YXJuaW5nLlxuICpcbiAqIEZsYWdzOlxuICogICAtIGAtLWlkIDxwaXBlbGluZUlkPmAg4oCUIHJlLXJlZ2lzdGVyIGEgc3BlY2lmaWMgcGlwZWxpbmUgYnkgSURcbiAqICAgLSBgLS1yZWdpb24gPHJlZ2lvbj5gIOKAlCBBV1MgcmVnaW9uIChkZWZhdWx0OiBBV1NfUkVHSU9OIGVudiAvIHVzLWVhc3QtMSlcbiAqICAgLSBgLS1uby1kcmFpbmAg4oCUIHNraXAgZHJhaW5pbmcgcGVuZGluZyBpbnRlbnRzXG4gKlxuICogRXhpdCBjb2RlczpcbiAqICAgLSAwOiByZXF1ZXN0ZWQgcmVnaXN0cmF0aW9uIHN1Y2NlZWRlZCBBTkQgbm8gcGVuZGluZyBpbnRlbnRzIHJlbWFpblxuICogICAtIDE6IGF0IGxlYXN0IG9uZSByZWdpc3RyYXRpb24gKGV4cGxpY2l0IG9yIHBlbmRpbmcpIHN0aWxsIGZhaWxlZFxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGBiYXNoXG4gKiAjIFJldHJ5IGEgcmVnaXN0cmF0aW9uIHRoYXQgZmFpbGVkIGR1cmluZyBkZXBsb3lcbiAqIHBpcGVsaW5lLW1hbmFnZXIgcGlwZWxpbmUgcmVnaXN0ZXIgLS1pZCBwaXBlLTEyM1xuICpcbiAqICMgSnVzdCBkcmFpbiBwZW5kaW5nIGludGVudHMgZnJvbSBkaXNrLCBubyBzcGVjaWZpYyByZWdpc3RyYXRpb25cbiAqIHBpcGVsaW5lLW1hbmFnZXIgcGlwZWxpbmUgcmVnaXN0ZXJcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXIocHJvZ3JhbTogQ29tbWFuZCk6IHZvaWQge1xuICB3aXRoU3NsT3B0aW9ucyh3aXRoUmVnaW9uT3B0aW9uKHByb2dyYW1cbiAgICAuY29tbWFuZCgncmVnaXN0ZXInKVxuICAgIC5kZXNjcmlwdGlvbignUmVnaXN0ZXIgYSBkZXBsb3llZCBwaXBlbGluZSBBUk4gd2l0aCB0aGUgcGxhdGZvcm0gKHJldHJ5IHBhdGggZm9yIGZhaWxlZCByZWdpc3RyYXRpb25zKScpXG4gICAgLm9wdGlvbignLWksIC0taWQgPGlkPicsICdQaXBlbGluZSBJRCB0byByZWdpc3RlciAocmUtZGVyaXZlcyBBUk4gZnJvbSBTVFMpJykpXG4gICAgLm9wdGlvbignLS1uby1kcmFpbicsICdTa2lwIGRyYWluaW5nIHBlbmRpbmcgaW50ZW50cyBmcm9tIHByaW9yIGZhaWxlZCBkZXBsb3lzJykpXG4gICAgLmFjdGlvbihhc3luYyAob3B0aW9ucykgPT4ge1xuICAgICAgY29uc3QgZXhlY3V0aW9uSWQgPSBwcmludENvbW1hbmRIZWFkZXIoJ1JlZ2lzdGVyIFBpcGVsaW5lJyk7XG4gICAgICBwcmludFNzbFdhcm5pbmcob3B0aW9ucy52ZXJpZnlTc2wpO1xuXG4gICAgICBsZXQgYW55RmFpbGVkID0gZmFsc2U7XG4gICAgICBsZXQgcmVnaXN0ZXJlZENvdW50ID0gMDtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY2xpZW50ID0gY3JlYXRlQXV0aGVudGljYXRlZENsaWVudChvcHRpb25zKTtcbiAgICAgICAgY29uc3QgcGlwZWxpbmVVcmwgPSBjbGllbnQuZ2V0Q29uZmlnKCkuYXBpLnBpcGVsaW5lVXJsO1xuXG4gICAgICAgIC8vIOKUgOKUgCBEcmFpbiBwZW5kaW5nIGludGVudHMgZmlyc3Qg4pSA4pSAXG4gICAgICAgIC8vIFdlIGRyYWluIGJlZm9yZSB0aGUgZXhwbGljaXQgcmVnaXN0cmF0aW9uIHNvIGEgcXVldWVkIGZhaWx1cmUgZm9yXG4gICAgICAgIC8vIHRoZSBzYW1lIHBpcGVsaW5lSWQgaXMgcmVwbGFjZWQgKG5vdCBkb3VibGUtYXBwbGllZCkgYnkgdGhlIGZyZXNoXG4gICAgICAgIC8vIHBheWxvYWQgYmVsb3cuXG4gICAgICAgIGNvbnN0IGRyYWluZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgaWYgKG9wdGlvbnMuZHJhaW4gIT09IGZhbHNlKSB7XG4gICAgICAgICAgY29uc3QgaW50ZW50cyA9IGF3YWl0IHJlYWRQZW5kaW5nSW50ZW50cygpO1xuICAgICAgICAgIGlmIChpbnRlbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHByaW50U2VjdGlvbignRHJhaW5pbmcgcGVuZGluZyBpbnRlbnRzJyk7XG4gICAgICAgICAgICBwcmludEluZm8oJ0ZvdW5kIHBlbmRpbmcgcmVnaXN0cmF0aW9ucyBmcm9tIHByaW9yIGZhaWxlZCBkZXBsb3lzJywge1xuICAgICAgICAgICAgICBjb3VudDogU3RyaW5nKGludGVudHMubGVuZ3RoKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZm9yIChjb25zdCBpbnRlbnQgb2YgaW50ZW50cykge1xuICAgICAgICAgICAgICAvLyBTa2lwIHRoZSBleHBsaWNpdCBwaXBlbGluZSDigJQgd2UnbGwgcmUtYnVpbGQgYSBmcmVzaCBwYXlsb2FkIGJlbG93LlxuICAgICAgICAgICAgICBpZiAob3B0aW9ucy5pZCAmJiBpbnRlbnQucGlwZWxpbmVJZCA9PT0gb3B0aW9ucy5pZCkgY29udGludWU7XG4gICAgICAgICAgICAgIGNvbnN0IG9rID0gYXdhaXQgcG9zdFJlZ2lzdHJhdGlvbihjbGllbnQsIHBpcGVsaW5lVXJsLCBpbnRlbnQsIGludGVudC5waXBlbGluZUlkKTtcbiAgICAgICAgICAgICAgaWYgKG9rKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgY2xlYXJQZW5kaW5nSW50ZW50KGludGVudC5waXBlbGluZUlkKTtcbiAgICAgICAgICAgICAgICBkcmFpbmVkLmFkZChpbnRlbnQucGlwZWxpbmVJZCk7XG4gICAgICAgICAgICAgICAgcmVnaXN0ZXJlZENvdW50Kys7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYW55RmFpbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIOKUgOKUgCBFeHBsaWNpdCByZWdpc3RyYXRpb24g4pSA4pSAXG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgcHJpbnRTZWN0aW9uKCdSZS1yZWdpc3RlcmluZyBwaXBlbGluZScpO1xuICAgICAgICAgIGNvbnN0IHBpcGVsaW5lUmVzID0gYXdhaXQgY2xpZW50LmdldDxQaXBlbGluZVJlc3BvbnNlPihgJHtwaXBlbGluZVVybH0vJHtvcHRpb25zLmlkfWApO1xuICAgICAgICAgIGNvbnN0IHBpcGVsaW5lID0gZXh0cmFjdFNpbmdsZVJlc3BvbnNlPFBpcGVsaW5lPihwaXBlbGluZVJlcywgJ3BpcGVsaW5lJywgJ2lkJyk7XG4gICAgICAgICAgaWYgKCFwaXBlbGluZSkge1xuICAgICAgICAgICAgcHJpbnRFcnJvcignUGlwZWxpbmUgbm90IGZvdW5kIGluIHBsYXRmb3JtJyk7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHBpcGVsaW5lIHJldHVybmVkIGZvciBpZCAke29wdGlvbnMuaWR9YCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFwaXBlbGluZS5vcmdJZCkge1xuICAgICAgICAgICAgcHJpbnRFcnJvcignUGlwZWxpbmUgaGFzIG5vIG9yZ0lkIOKAlCBjYW5ub3QgcmVnaXN0ZXInKTtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUGlwZWxpbmUgJHtwaXBlbGluZS5pZH0gaXMgbWlzc2luZyBvcmdJZGApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBwYXlsb2FkID0gYXdhaXQgYnVpbGRSZWdpc3RyeVBheWxvYWQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGlkOiBwaXBlbGluZS5pZCxcbiAgICAgICAgICAgICAgb3JnSWQ6IHBpcGVsaW5lLm9yZ0lkLFxuICAgICAgICAgICAgICBwaXBlbGluZU5hbWU6IHBpcGVsaW5lLnBpcGVsaW5lTmFtZSxcbiAgICAgICAgICAgICAgcHJvamVjdDogcGlwZWxpbmUucHJvamVjdCxcbiAgICAgICAgICAgICAgb3JnYW5pemF0aW9uOiBwaXBlbGluZS5vcmdhbml6YXRpb24sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb3B0aW9ucy5yZWdpb24sXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIENsZWFyIGFueSBzdGFsZSBpbnRlbnQgZm9yIHRoaXMgcGlwZWxpbmVJZCBiZWZvcmUgcmV0cnlpbmcgc28gd2VcbiAgICAgICAgICAvLyBkb24ndCBsZWF2ZSBhIGR1cGxpY2F0ZSBmaWxlIGJlaGluZCBvbiBzdWNjZXNzLlxuICAgICAgICAgIGF3YWl0IGNsZWFyUGVuZGluZ0ludGVudChwYXlsb2FkLnBpcGVsaW5lSWQpO1xuXG4gICAgICAgICAgY29uc3Qgb2sgPSBhd2FpdCBwb3N0UmVnaXN0cmF0aW9uKGNsaWVudCwgcGlwZWxpbmVVcmwsIHBheWxvYWQsIHBheWxvYWQucGlwZWxpbmVJZCk7XG4gICAgICAgICAgaWYgKG9rKSB7XG4gICAgICAgICAgICByZWdpc3RlcmVkQ291bnQrKztcbiAgICAgICAgICAgIHByaW50U3VjY2VzcygnUGlwZWxpbmUgcmVnaXN0ZXJlZCBmb3IgZXZlbnQgcmVwb3J0aW5nJywge1xuICAgICAgICAgICAgICBwaXBlbGluZUlkOiBwYXlsb2FkLnBpcGVsaW5lSWQsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYW55RmFpbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHBhdGggPSBhd2FpdCB3cml0ZVBlbmRpbmdJbnRlbnQocGF5bG9hZCk7XG4gICAgICAgICAgICBwcmludFdhcm5pbmcoJ1JlZ2lzdHJhdGlvbiBmYWlsZWQ7IGludGVudCBzYXZlZCBmb3IgcmV0cnknLCB7IGludGVudDogcGF0aCB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBwcmludFNlY3Rpb24oJ1N1bW1hcnknKTtcbiAgICAgICAgcHJpbnRLZXlWYWx1ZSh7XG4gICAgICAgICAgJ1JlZ2lzdGVyZWQnOiBTdHJpbmcocmVnaXN0ZXJlZENvdW50KSxcbiAgICAgICAgICAnRHJhaW5lZCBmcm9tIHF1ZXVlJzogU3RyaW5nKGRyYWluZWQuc2l6ZSksXG4gICAgICAgICAgJ1N0YXR1cyc6IGFueUZhaWxlZCA/ICdTb21lIHJlZ2lzdHJhdGlvbnMgc3RpbGwgcGVuZGluZycgOiAnQWxsIGNsZWFyJyxcbiAgICAgICAgICAnRXhlY3V0aW9uIElEJzogZXhlY3V0aW9uSWQsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHByb2Nlc3MuZXhpdChhbnlGYWlsZWQgPyAxIDogMCk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBoYW5kbGVFcnJvcihlcnJvciwgRVJST1JfQ09ERVMuQVBJX1JFUVVFU1QsIHtcbiAgICAgICAgICBkZWJ1ZzogcHJvZ3JhbS5vcHRzKCkuZGVidWcsXG4gICAgICAgICAgZXhpdDogZmFsc2UsXG4gICAgICAgICAgY29udGV4dDogeyBjb21tYW5kOiAncmVnaXN0ZXInLCBleGVjdXRpb25JZCwgcGlwZWxpbmVJZDogb3B0aW9ucy5pZCB9LFxuICAgICAgICB9KTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuICAgIH0pO1xufVxuXG4vKipcbiAqIFBPU1QgYSByZWdpc3RyYXRpb24gcGF5bG9hZCB0byB0aGUgcGxhdGZvcm0uIE9uIGZhaWx1cmUsIHRoZSBjYWxsZXIgZGVjaWRlc1xuICogd2hldGhlciB0byB3cml0ZS9wcmVzZXJ2ZSBhIHBlbmRpbmcgaW50ZW50IOKAlCB0aGlzIGhlbHBlciBqdXN0IHJlcG9ydHMuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHBvc3RSZWdpc3RyYXRpb24oXG4gIGNsaWVudDogUmV0dXJuVHlwZTx0eXBlb2YgY3JlYXRlQXV0aGVudGljYXRlZENsaWVudD4sXG4gIHBpcGVsaW5lVXJsOiBzdHJpbmcsXG4gIHBheWxvYWQ6IFJlZ2lzdHJ5UGF5bG9hZCxcbiAgcGlwZWxpbmVJZDogc3RyaW5nLFxuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIHRyeSB7XG4gICAgYXdhaXQgY2xpZW50LnBvc3QoYCR7cGlwZWxpbmVVcmx9L3JlZ2lzdHJ5YCwgcGF5bG9hZCk7XG4gICAgcHJpbnRJbmZvKCdSZWdpc3RlcmVkJywgeyBwaXBlbGluZUlkIH0pO1xuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBwcmludFdhcm5pbmcoJ1JlZ2lzdHJhdGlvbiBmYWlsZWQnLCB7XG4gICAgICBwaXBlbGluZUlkLFxuICAgICAgZXJyb3I6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSxcbiAgICB9KTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Registers the `setup-events` command with the CLI program.
|
|
4
|
+
*
|
|
5
|
+
* Deploys EventBridge → SQS → Lambda infrastructure for pipeline reporting.
|
|
6
|
+
*
|
|
7
|
+
* 1. Deploys CloudFormation stack (rule + queue + Lambda shell + IAM)
|
|
8
|
+
* 2. Downloads @pipeline-builder/pipeline-events from npm registry
|
|
9
|
+
* 3. Uploads handler code directly to Lambda (no S3 needed)
|
|
10
|
+
*
|
|
11
|
+
* Uses PLATFORM_BASE_URL from environment (same as all other commands).
|
|
12
|
+
* Idempotent — running again updates the stack and code.
|
|
13
|
+
*/
|
|
14
|
+
export declare function setupEvents(program: Command): void;
|
|
15
|
+
//# sourceMappingURL=setup-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-events.d.ts","sourceRoot":"","sources":["../../src/commands/setup-events.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4JlD"}
|