-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(core): Stages #8423
chore(core): Stages #8423
Conversation
Stages synthesize to embedded Cloud Assemblies. Ideally there should be CLI support for embedded Cloud Assemblies, but there isn't yet. It will be coming soon, I promise. To implement this, had to grab the reins of synthesis back from the constructs library. I've taken the liberty to declare synthesis in constructs deprecated. Took the opportunity where we're declaring a new type of construct in the construct hierarchy to clean up the default stack name generation (get rid of the hashes and add a prefix, which will make deploying multiple Stages in the same environment just naturally work out nicely in a non-ugly way). Started to write a section in the README on Stacks and Stages, but I couldn't figure out how to write about the use for Stages without referencing unreleased things, so I gave up. For the same reason, made this a chore as there is no user value right now so why would this show up in the CHANGELOG? Also moved the "artifacts" classes in cx-api together to unclutter the file structure. Primary author: @rix0rrr
so we can now revert changes to test.stack.ts and stack.prepare
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
The name is weak and it does not add additional value above the "Stage" concept.
It should not be possible to specify the output directory for a nested stage, only for apps. Also, make assemblyBuilder internal. It is only needed from the private "synthesize.ts" module (and the reason it is a separate module is for backwards compat. in an ideal world synthesis will be implemented the same file). There is no need for "addToParentAssembly" because we already do that when we create the nested assembly.
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
### Updated PR Since we introduced [`stages`](#8423) which had the unintended side effect of the CDK not supporting adding an Aspect via another Aspect, we have not seen any issues reported beside #8536, that was resolved without requiring this capability. Given that, and the fact this features has many sharp edges we decided to leave it unsupported, and add a warning in the meantime. ----------- Following up on #8536 If an aspect is added via another aspect, the inner aspect will not be invoked. Take for example this code: ```typescript const app = new cdk.App(); app.node.applyAspect({ visit(construct: cdk.IConstruct) { construct.node.applyAspect({ visit(construct: cdk.IConstruct) { console.info("Invoking aspect on construct: " + construct.node.id); // This will not be called } }) } }); ``` Since aspects are added only on the top level node, if an aspect is added while `InvokeAspects` is called on that node, it will be ignored since it will not be added to list of aspects to invoke (`allAspectsHere` in the bellow code): ```typescript function invokeAspects(root: IConstruct) { recurse(root, []); function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) { // hackery to be able to access some private members with strong types (yack!) const node: NodeWithAspectPrivatesHangingOut = construct.node._actualNode as any; const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects]; for (const aspect of allAspectsHere) { if (node.invokedAspects.includes(aspect)) { continue; } aspect.visit(construct); <-- an aspect that was added here will not be added to `allAspectsHere` and will be ignored node.invokedAspects.push(aspect); } for (const child of construct.node.children) { if (!Stage.isStage(child)) { recurse(child, allAspectsHere); } } } } ``` Assuming this is not something we want to support**, we can detect it by comparing the size of `node._aspects` before and after the call to `aspect.visit`, and emit a warning if there has been a change. Note that while the aspect will not be invoked it will be added to every child construct during the recursive visit. Emitting a warning for each child construct will result in a noisy console, to prevent this I have added a flag that will only allow adding **one warning per application**, given this limitation I'm not sure there is a lot of value in adding the warning, thoughts? If we decide to add it I will add tests. (** theoretically we could support it by adding the aspects to `allAspectsHere` during the loop, but this will require a non trivial implementation in order to avoid infinite recursion) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
### Updated PR Since we introduced [`stages`](#8423) which had the unintended side effect of the CDK not supporting adding an Aspect via another Aspect, we have not seen any issues reported beside #8536, that was resolved without requiring this capability. Given that, and the fact this features has many sharp edges we decided to leave it unsupported, and add a warning in the meantime. ----------- Following up on #8536 If an aspect is added via another aspect, the inner aspect will not be invoked. Take for example this code: ```typescript const app = new cdk.App(); app.node.applyAspect({ visit(construct: cdk.IConstruct) { construct.node.applyAspect({ visit(construct: cdk.IConstruct) { console.info("Invoking aspect on construct: " + construct.node.id); // This will not be called } }) } }); ``` Since aspects are added only on the top level node, if an aspect is added while `InvokeAspects` is called on that node, it will be ignored since it will not be added to list of aspects to invoke (`allAspectsHere` in the bellow code): ```typescript function invokeAspects(root: IConstruct) { recurse(root, []); function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) { // hackery to be able to access some private members with strong types (yack!) const node: NodeWithAspectPrivatesHangingOut = construct.node._actualNode as any; const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects]; for (const aspect of allAspectsHere) { if (node.invokedAspects.includes(aspect)) { continue; } aspect.visit(construct); <-- an aspect that was added here will not be added to `allAspectsHere` and will be ignored node.invokedAspects.push(aspect); } for (const child of construct.node.children) { if (!Stage.isStage(child)) { recurse(child, allAspectsHere); } } } } ``` Assuming this is not something we want to support**, we can detect it by comparing the size of `node._aspects` before and after the call to `aspect.visit`, and emit a warning if there has been a change. Note that while the aspect will not be invoked it will be added to every child construct during the recursive visit. Emitting a warning for each child construct will result in a noisy console, to prevent this I have added a flag that will only allow adding **one warning per application**, given this limitation I'm not sure there is a lot of value in adding the warning, thoughts? If we decide to add it I will add tests. (** theoretically we could support it by adding the aspects to `allAspectsHere` during the loop, but this will require a non trivial implementation in order to avoid infinite recursion) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
### Updated PR Since we introduced [`stages`](aws#8423) which had the unintended side effect of the CDK not supporting adding an Aspect via another Aspect, we have not seen any issues reported beside aws#8536, that was resolved without requiring this capability. Given that, and the fact this features has many sharp edges we decided to leave it unsupported, and add a warning in the meantime. ----------- Following up on aws#8536 If an aspect is added via another aspect, the inner aspect will not be invoked. Take for example this code: ```typescript const app = new cdk.App(); app.node.applyAspect({ visit(construct: cdk.IConstruct) { construct.node.applyAspect({ visit(construct: cdk.IConstruct) { console.info("Invoking aspect on construct: " + construct.node.id); // This will not be called } }) } }); ``` Since aspects are added only on the top level node, if an aspect is added while `InvokeAspects` is called on that node, it will be ignored since it will not be added to list of aspects to invoke (`allAspectsHere` in the bellow code): ```typescript function invokeAspects(root: IConstruct) { recurse(root, []); function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) { // hackery to be able to access some private members with strong types (yack!) const node: NodeWithAspectPrivatesHangingOut = construct.node._actualNode as any; const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects]; for (const aspect of allAspectsHere) { if (node.invokedAspects.includes(aspect)) { continue; } aspect.visit(construct); <-- an aspect that was added here will not be added to `allAspectsHere` and will be ignored node.invokedAspects.push(aspect); } for (const child of construct.node.children) { if (!Stage.isStage(child)) { recurse(child, allAspectsHere); } } } } ``` Assuming this is not something we want to support**, we can detect it by comparing the size of `node._aspects` before and after the call to `aspect.visit`, and emit a warning if there has been a change. Note that while the aspect will not be invoked it will be added to every child construct during the recursive visit. Emitting a warning for each child construct will result in a noisy console, to prevent this I have added a flag that will only allow adding **one warning per application**, given this limitation I'm not sure there is a lot of value in adding the warning, thoughts? If we decide to add it I will add tests. (** theoretically we could support it by adding the aspects to `allAspectsHere` during the loop, but this will require a non trivial implementation in order to avoid infinite recursion) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Stages are self-contained application units that synthesize as a cloud assembly. This change centralizes prepare + synthesis logic into the stage level and changes
App
to extendStage
.Once
stage.synth()
is called, the stage becomes (practically) immutable. This means that subsequent synths will return the same output.The cloud assembly produced by stages is nested as an artifact inside another cloud assembly (either the App's top-level assembly) or a child.
Authors: @rix0rrr, @eladb
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license