|
| 1 | +import { ConfigIO } from '../../../lib/index.js'; |
1 | 2 | import { getErrorMessage } from '../../errors'; |
| 3 | +import { withCommandRunTelemetry } from '../../telemetry/cli-command-run.js'; |
2 | 4 | import { COMMAND_DESCRIPTIONS } from '../../tui/copy'; |
3 | 5 | import { requireProject, requireTTY } from '../../tui/guards'; |
4 | 6 | import { DeployScreen } from '../../tui/screens/deploy/DeployScreen'; |
5 | 7 | import { handleDeploy } from './actions'; |
6 | | -import type { DeployOptions } from './types'; |
| 8 | +import type { DeployOptions, DeployResult } from './types'; |
| 9 | +import { DEFAULT_DEPLOY_ATTRS, computeDeployAttrs } from './utils'; |
7 | 10 | import { validateDeployOptions } from './validate'; |
8 | 11 | import type { Command } from '@commander-js/extra-typings'; |
9 | 12 | import { Text, render } from 'ink'; |
@@ -38,6 +41,45 @@ async function handleDeployCLI(options: DeployOptions): Promise<void> { |
38 | 41 | process.exit(1); |
39 | 42 | } |
40 | 43 |
|
| 44 | + // Compute attrs upfront from project spec (available before deploy) |
| 45 | + const mode = options.diff ? 'diff' : options.plan ? 'dry-run' : 'deploy'; |
| 46 | + const attrs = await new ConfigIO() |
| 47 | + .readProjectSpec() |
| 48 | + .then(spec => computeDeployAttrs(spec, mode)) |
| 49 | + .catch(() => ({ ...DEFAULT_DEPLOY_ATTRS, mode }) as const); |
| 50 | + |
| 51 | + const { deployResult } = await withCommandRunTelemetry('deploy', attrs, async () => { |
| 52 | + const result = await executeDeploy(options).catch( |
| 53 | + (e): DeployResult => ({ success: false, error: getErrorMessage(e) }) |
| 54 | + ); |
| 55 | + if (!result.success) { |
| 56 | + return { success: false as const, error: result.error ?? 'Deploy failed', deployResult: result }; |
| 57 | + } |
| 58 | + return { success: true as const, deployResult: result }; |
| 59 | + }); |
| 60 | + |
| 61 | + // ALL output happens here, after telemetry |
| 62 | + if (!deployResult.success) { |
| 63 | + if (options.json) { |
| 64 | + console.log(JSON.stringify(deployResult)); |
| 65 | + } else { |
| 66 | + console.error(deployResult.error ?? 'Deploy failed'); |
| 67 | + if (deployResult.logPath) { |
| 68 | + console.error(`Log: ${deployResult.logPath}`); |
| 69 | + } |
| 70 | + } |
| 71 | + process.exit(1); |
| 72 | + } |
| 73 | + |
| 74 | + printDeployResult(deployResult, options); |
| 75 | + |
| 76 | + if (deployResult.postDeployWarnings && deployResult.postDeployWarnings.length > 0) { |
| 77 | + process.exit(2); |
| 78 | + } |
| 79 | + process.exit(0); |
| 80 | +} |
| 81 | + |
| 82 | +async function executeDeploy(options: DeployOptions): Promise<DeployResult> { |
41 | 83 | let spinner: NodeJS.Timeout | undefined; |
42 | 84 |
|
43 | 85 | // Progress callback for --progress mode |
@@ -84,55 +126,52 @@ async function handleDeployCLI(options: DeployOptions): Promise<void> { |
84 | 126 | process.stdout.write('\r\x1b[K'); |
85 | 127 | } |
86 | 128 |
|
| 129 | + return result; |
| 130 | +} |
| 131 | + |
| 132 | +function printDeployResult(result: DeployResult, options: DeployOptions): void { |
87 | 133 | if (options.json) { |
88 | 134 | console.log(JSON.stringify(result)); |
89 | | - } else if (result.success) { |
90 | | - if (options.diff) { |
91 | | - console.log(`\n✓ Diff complete for '${result.targetName}' (stack: ${result.stackName})`); |
92 | | - } else if (options.plan) { |
93 | | - console.log(`\n✓ Dry run complete for '${result.targetName}' (stack: ${result.stackName})`); |
94 | | - console.log('\nRun `agentcore deploy` to deploy.'); |
95 | | - } else { |
96 | | - console.log(`\n✓ Deployed to '${result.targetName}' (stack: ${result.stackName})`); |
| 135 | + return; |
| 136 | + } |
97 | 137 |
|
98 | | - // Show stack outputs in non-JSON mode |
99 | | - if (result.outputs && Object.keys(result.outputs).length > 0) { |
100 | | - console.log('\nOutputs:'); |
101 | | - for (const [key, value] of Object.entries(result.outputs)) { |
102 | | - console.log(` ${key}: ${value}`); |
103 | | - } |
104 | | - } |
| 138 | + if (options.diff) { |
| 139 | + console.log(`\n✓ Diff complete for '${result.targetName}' (stack: ${result.stackName})`); |
| 140 | + } else if (options.plan) { |
| 141 | + console.log(`\n✓ Dry run complete for '${result.targetName}' (stack: ${result.stackName})`); |
| 142 | + console.log('\nRun `agentcore deploy` to deploy.'); |
| 143 | + } else { |
| 144 | + console.log(`\n✓ Deployed to '${result.targetName}' (stack: ${result.stackName})`); |
105 | 145 |
|
106 | | - if (result.postDeployWarnings && result.postDeployWarnings.length > 0) { |
107 | | - console.log('\n⚠ Post-deploy warnings:'); |
108 | | - for (const warning of result.postDeployWarnings) { |
109 | | - console.log(` ${warning}`); |
110 | | - } |
| 146 | + // Show stack outputs in non-JSON mode |
| 147 | + if (result.outputs && Object.keys(result.outputs).length > 0) { |
| 148 | + console.log('\nOutputs:'); |
| 149 | + for (const [key, value] of Object.entries(result.outputs)) { |
| 150 | + console.log(` ${key}: ${value}`); |
111 | 151 | } |
| 152 | + } |
112 | 153 |
|
113 | | - if (result.notes && result.notes.length > 0) { |
114 | | - for (const note of result.notes) { |
115 | | - console.log(`\nNote: ${note}`); |
116 | | - } |
| 154 | + if (result.postDeployWarnings && result.postDeployWarnings.length > 0) { |
| 155 | + console.log('\n⚠ Post-deploy warnings:'); |
| 156 | + for (const warning of result.postDeployWarnings) { |
| 157 | + console.log(` ${warning}`); |
117 | 158 | } |
| 159 | + } |
118 | 160 |
|
119 | | - if (result.nextSteps && result.nextSteps.length > 0) { |
120 | | - console.log(`Next: ${result.nextSteps.join(' | ')}`); |
| 161 | + if (result.notes && result.notes.length > 0) { |
| 162 | + for (const note of result.notes) { |
| 163 | + console.log(`\nNote: ${note}`); |
121 | 164 | } |
122 | 165 | } |
123 | 166 |
|
124 | | - if (result.logPath) { |
125 | | - console.log(`\nLog: ${result.logPath}`); |
126 | | - } |
127 | | - } else { |
128 | | - console.error(result.error); |
129 | | - if (result.logPath) { |
130 | | - console.error(`Log: ${result.logPath}`); |
| 167 | + if (result.nextSteps && result.nextSteps.length > 0) { |
| 168 | + console.log(`Next: ${result.nextSteps.join(' | ')}`); |
131 | 169 | } |
132 | 170 | } |
133 | 171 |
|
134 | | - const hasPostDeployWarnings = result.success && result.postDeployWarnings && result.postDeployWarnings.length > 0; |
135 | | - process.exit(result.success ? (hasPostDeployWarnings ? 2 : 0) : 1); |
| 172 | + if (result.logPath) { |
| 173 | + console.log(`\nLog: ${result.logPath}`); |
| 174 | + } |
136 | 175 | } |
137 | 176 |
|
138 | 177 | export const registerDeploy = (program: Command) => { |
|
0 commit comments