feat: implement project deploy command - #2001
Open
notgitika wants to merge 3 commits into
Open
Conversation
Deploys a project by synthesizing it, bootstrapping each target environment, then deploying every stack. Synthesis reuses build's code path so what deploys is what was just synthesized, and build's dependency check runs before anything touches AWS. Stack environments come from agentcore/aws-targets.json, which create() scaffolds empty. An empty list is an error naming the file to fill in rather than an account resolved from the active credentials, which would let deploy guess where the user's infrastructure belongs. Bootstrap is idempotent and no-ops quickly on a current environment, so it runs every deploy instead of probing CloudFormation first; --skip-bootstrap opts out. Targets sharing an environment are bootstrapped once. Bootstrap and deploy drive @aws-cdk/toolkit-lib in-process rather than shelling out to npx cdk, so progress arrives as structured messages and failures as typed errors instead of scraped stdout. src/io/cdk.ts adapts the toolkit's push-based IIoHost to the generator the manager pulls from, and is injectable so tests exercise deploy without reaching AWS. Deploy reads the cdk.out assembly synthesis just wrote instead of re-synthesizing, which both avoids a second synth and makes "deploy exactly what was synthesized" structural. A deploy runs for minutes, so those messages stream to stderr as they arrive: ProjectEvent gains an output variant carrying the toolkit's own wording, with debug and trace levels left in the debug log rather than on screen.
deploy shipped every stack in the assembly, so a project with a staging and a prod target reached both at once. It now takes --target, defaulting to "default", and bootstraps and deploys only that target. The target is resolved from aws-targets.json before synthesizing, so a misspelled --target costs no build and the error lists the configured names. Which stack belongs to the target comes from the synthesized manifest, matched on the agentcore:target-name tag the generated CDK app writes, rather than from the CLI reproducing that app's naming convention. The lookup runs before bootstrap so a mismatch fails in seconds, and the toolkit selects with PATTERN_MUST_MATCH so a name the assembly does not contain fails loudly instead of deploying nothing.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## refactor #2001 +/- ##
============================================
- Coverage 96.96% 96.69% -0.27%
============================================
Files 364 367 +3
Lines 20758 20977 +219
============================================
+ Hits 20127 20283 +156
- Misses 631 694 +63 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
notgitika
commented
Aug 14, 2026
Comment on lines
+4
to
+13
| import { | ||
| BaseCredentials, | ||
| BootstrapEnvironments, | ||
| BootstrapStackParameters, | ||
| StackSelectionStrategy, | ||
| Toolkit, | ||
| type IIoHost, | ||
| type IoMessageLevel, | ||
| } from "@aws-cdk/toolkit-lib"; | ||
|
|
Contributor
Author
There was a problem hiding this comment.
this static import is increasing the binary size and startup latency by a lot. looking into solutions
Contributor
Author
|
increasing test coverage |
The toolkit is the heaviest dependency in the CLI and src/io/index.ts
re-exports runCdk, so a static import made every command load it:
agentcore --help ran in 2.7s from source, 0.7s once the import moved
inside the function that builds the toolkit. The compiled binary is
unchanged either way, since --compile embeds the module regardless.
src/io/cdk.ts splits into the three things a run does -- load the
toolkit, perform one operation with it, bridge its reporting to a
generator -- so each is reachable from a test. src/io/cdk.test.ts covers
them against the real toolkit package: constructing a Toolkit and its
BootstrapEnvironments, BootstrapStackParameters, and
StackSelectionStrategy helpers resolves no credentials and calls no API,
so the arguments a deploy passes are asserted against the values the
toolkit itself defines rather than stand-ins. What the tests assert
includes the ones a caller cannot see and a fake cannot check: that
messages are yielded while the operation is still running, that a
failure surfaces only after the output explaining it, that a request is
answered with its suggested default rather than prompting, and that
createCustomerMasterKey and PATTERN_MUST_MATCH reach the toolkit.
The fake in TestCoreClient still buffers rather than streams; it now
says so, and names the test that covers the real behaviour.
ProjectEvent becomes a discriminated union. It documented that exactly
one of step and output is set while typing both optional, which allowed
{} and both-at-once and spread `if (event.output)` checks through three
handlers. Both variants carry `message`, so a consumer that only writes
text needs no switch, and those checks are gone.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds the project deploy command. it resolves the deployment target, synthesizes, bootstraps that target's environment, then deploys its stack. Synth reuses build's code path, so build's dependency check runs before anything touches AWS.
stack environments come from
agentcore/aws-targets.json, which create() scaffolds empty. An empty list is an error naming the file to fill in, rather than an account resolved from the active credentials, deploy shouldn't guess where the user's infra belongs. It's checked before synth, so an empty list fails without running anything.one deploy ships one target.
--targetselects it and defaults to default, so a project with a staging and a prod target can't reach prod by accident. The target is resolved before synth, so a misspelled --target costs no build and the error lists the configured names. which stack belongs to the target comes from the synthesized manifest, matched on theagentcore:target-nametag the generated CDK app already writes, so the CLI never has to reproduce that app's stack-naming convention.bootstrap is idempotent, so it runs every deploy instead of probing CloudFormation first;
--skip-bootstrapopts out. It passescreateCustomerMasterKey: trueto match the original CLI, so a default deploy provisions a KMS key for the staging bucket. Worth knowing when reviewing: that means a deploy can alter an existing CDKToolkit that was bootstrapped without a CMK.Not in this PR:
This is the synth -> bootstrap -> deploy spine. Everything else the existing deploy does is deliberately left out for now: