├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cdk.json ├── codes └── lambda │ └── cicd-event-state │ ├── src │ └── handler.py │ └── test │ ├── event_STARTED.json │ └── event_SUCCEEDED.json ├── config ├── app-config-sample1.json ├── app-config-sample2.json ├── app-config-sample3-prod-cross.json ├── app-config-sample3-prod.json ├── app-config-sample3-test.json └── app-config-sample3.json ├── docs └── asset │ ├── cross-account-pipeline.png │ ├── how-to-use-approach.png │ ├── pipeline-usecase1.png │ ├── pipeline-usecase2.png │ ├── pipeline-usecase3.png │ ├── sample2-case1.png │ ├── sample2-case2.png │ ├── sample2-case3.png │ ├── sample2-case4.png │ └── sample3-multiple-target.png ├── infra ├── app-main.ts └── stack │ ├── sample1 │ ├── approach1-pipeline-stack.ts │ ├── approach2-pipeline-stack.ts │ ├── approach3-pipeline-stack.ts │ └── sample1-service-stack.ts │ ├── sample2 │ ├── sample2-pipeline-stack.ts │ └── sample2-service-stack.ts │ └── sample3 │ ├── sample3-action-event-stack.ts │ ├── sample3-buildproject-customizing1-stack.ts │ ├── sample3-buildproject-customizing2-stack.ts │ ├── sample3-codepipeline-customizing1-stack.ts │ ├── sample3-codepipeline-customizing2-stack.ts │ ├── sample3-cross-account-stack.ts │ ├── sample3-multiple-target-stack.ts │ ├── sample3-prepost-command-stack.ts │ ├── sample3-role-customizing2-stack.ts │ ├── sample3-role-customzing1-stack.ts │ ├── sample3-service-stack.ts │ └── sample3-temporary-disable-stack.ts ├── jest.config.js ├── package-lock.json ├── package.json ├── test └── sample-stack.test.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | !jest.config.js 2 | node_modules 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | 8 | # python 9 | **/*.pyc 10 | __pycache__ 11 | .codes/**/__pycache__/ 12 | 13 | # vsc 14 | **/.DS_Store 15 | .vscode/** -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS CDK Deploy Pipeline using AWS CodePipeline 2 | 3 | This repository describes how to customize AWS CodePipeline to deploy AWS CDK application. Specifically, this repository describes how to implement a deployment pipeline optimized for [AWS CDK Project Template for DevOps](https://github.com/aws-samples/aws-cdk-project-template-for-devops) in the simplest way with the least amount of effort. That is, if you specify only a name of source repository and the names of AWS CDK Stack you want to deploy selectively, a pipeline is automatically created for this. 4 | 5 | ## Agenda 6 | 7 | 1. [Solution](#solution) 8 | 9 | 1.1 [How to work](#how-to-work) 10 | 11 | 1.2 [Prerequisite](#prerequisite) 12 | 13 | 1.3 [How to use pipelines](#how-to-use-pipelines) 14 | 15 | 1.4 [How to configure pipelines](#how-to-configure-pipelines) 16 | 17 | 1.5 [Environment Variables](#environment-variables) 18 | 19 | 2. [Advanced Usecases](#advanced-usecases) 20 | 21 | 2.1 [Multiple Target Deployment](#multiple-target-deployment) 22 | 23 | 2.2 [Cross-Account Target Deployment](#cross-account-target-deployment) 24 | 25 | 2.3 [PrePost Build Commands Injection](#prepost-build-commands-injection) 26 | 27 | 2.4 [Action Event Handling](#action-event-handling) 28 | 29 | 2.5 [Temporary Deactivation](#temporary-deactivation) 30 | 31 | 2.6 [Role Customizing](#role-customizing) 32 | 33 | 2.7 [Build Project Customizing](#build-project-customizing) 34 | 35 | 2.8 [CodePipeline Customizing](#codepipeline-customizing) 36 | 37 | 3. [Limitation](#limitation) 38 | 39 | 4. [Security](#security) 40 | 41 | 5. [License](#license) 42 | 43 | ## Solution 44 | 45 | Configuring CDK application deployment pipeline is just as important as configuring AWS cloud resources with AWS CDK. To solve this purpose, an official pipeline-[CDK Pipelines](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines-readme.html) is being provided, and it fundamentally utilizes AWS CloudFormation Action in AWS CodePipeline's Deploy. As explained in the official documentation, this is not easy to customize as it is purpose-built. 46 | 47 | ### How to work 48 | 49 | This repository introduces a new CDK deployment pipeline for minimal effort and maximum customization without changes to existing CDK applications. By default, AWS CodeBuild is used so that you can insert any build scripts or AWS CLI commands with AWS CDK CLI commands you want as if you were running in your local development environment. In particular, this is abstracted so that it can be conveniently deployed in a stack unit without writing ```cdk deploy``` command in BuildSpec of AWS CodeBuild by yourself. If you simply list the names of the stacks you want to deploy, a AWS CodeBuild's BuildSpec document tailored to the AWS CDK deployment is created internally. 50 | 51 | This new pipeline opimized for AWS CDK deployment covers the following AWS CDK Application deployment cases. 52 | 53 | [Usecase 1] Test and Prod deployments in the same account & region 54 | 55 | ![pipeline-usecase1](docs/asset/pipeline-usecase1.png) 56 | 57 | [Usecase 2] Test and Prod deployments in the same account & different region 58 | 59 | ![pipeline-usecase1](docs/asset/pipeline-usecase2.png) 60 | 61 | [Usecase 3] Test and Prod deployments in the different account & region 62 | 63 | ![pipeline-usecase1](docs/asset/pipeline-usecase3.png) 64 | 65 | ### Prerequisite 66 | 67 | * It must have been cdk-bootstrapped in the target account/region beforehand. 68 | * ```Stage``` and ```Action``` terminologies are same as AWS CodePipeline. 69 | * A AWS CodeCommit Repository named ```sample-repo``` and branch named ```release_cicd``` should be prepared in advance for the practice. 70 | * The basic configuration concept(Stack dependency management, configuration-based stack deployment) was implemented on [AWS CDK Project Template for DevOps](https://github.com/aws-samples/aws-cdk-project-template-for-devops) project. We recommend that you read this project first. 71 | * Because template framework is in [AWS CDK Project Template for DevOps](https://github.com/aws-samples/aws-cdk-project-template-for-devops), please prepare the source code like this. Specifically these repositories provide both CDK v1 and v2 through branch, please append branch name to identify them! 72 | 73 | ```bash 74 | git clone https://github.com/aws-samples/aws-cdk-project-template-for-devops.git -b release_cdk_v1 or release_cdk_v2 75 | git clone https://github.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline.git -b release_cdk_v1 or release_cdk_v2 76 | cp -r aws-cdk-project-template-for-devops/lib aws-cdk-deploy-pipeline-using-aws-codepipeline 77 | ``` 78 | 79 | * Caution: You may be charged a small fee if you deploy through hands-on practice. For hands-on practice, account in ```config/app-config-xxxx.json``` file must be updated according to your environment. 80 | 81 | ### How to use pipelines 82 | 83 | Basically, this provides a pipeline ```CDK Construct``` optimized for CDK deployment, and provides 3 approaches to make it convenient to use. 84 | 85 | ![how-to-use-approach](docs/asset/how-to-use-approach.png) 86 | 87 | For now, don't worry about the detailed configuration, just understand the approach to how to use it. Detailed configuration will be described below. The example codes below are saved in the following [infra/stack/sample1](infra/stack/sample1), and you can deploy it right away by specifying a config file as follows. 88 | 89 | ```bash 90 | export APP_CONFIG=config/app-config-sample1.json 91 | cdk list 92 | 93 | PipelineSample1-Approach1PipelineStack 94 | PipelineSample1-Approach2PipelineStack 95 | PipelineSample1-Approach3PipelineStack 96 | PipelineSample1-Sample1Service1Stack 97 | ``` 98 | 99 | **Approach 1**: Use ```PipelineSimplePattern``` construct class directly 100 | 101 | In any your Stack, use this construct class directly with specific options. In this case, you have to care all options by yourself. ```ActionFlow``` option is the most important, and you'll set it the same for any other approach. 102 | 103 | ```typescript 104 | import * as base from '../../../lib/template/stack/base/base-stack'; 105 | import { AppContext } from '../../../lib/template/app-context'; 106 | 107 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 108 | 109 | 110 | export class Approach1PipelineStack extends base.BaseStack { 111 | 112 | constructor(appContext: AppContext, stackConfig: any) { 113 | super(appContext, stackConfig); 114 | 115 | new pipeline.PipelineSimplePattern(this, 'Approach1', { 116 | projectPrefix: this.projectPrefix, 117 | stackConfig: this.stackConfig, 118 | stackName: this.stackName, 119 | env: this.commonProps.env!, 120 | pipelineName: 'Approach1Pipeline', 121 | actionFlow: [ 122 | { 123 | Name: 'GitClone', 124 | Stage: 'SourceStage', 125 | Kind: pipeline.ActionKind.SourceCodeCommit, 126 | Enable: true, 127 | Detail: { 128 | RepositoryName: 'sample-repo', 129 | BranchName: 'release_cicd' 130 | } 131 | }, 132 | { 133 | Name: 'DeployAllStacks', 134 | Stage: "DevDeployStage", 135 | Kind: pipeline.ActionKind.BuildCodeBuild, 136 | Enable: true, 137 | Detail: { 138 | AppConfigFile: "config/app-config-sample1.json", 139 | BuildDeployStacks: { 140 | StackNameList: ['Sample1Service1Stack'], 141 | } 142 | } 143 | } 144 | ] 145 | }); 146 | } 147 | } 148 | ``` 149 | 150 | **Approach 2**: Generalize ```PipelineBaseStack``` base class 151 | 152 | Create a new Stack, where this stack have to generalize ```PipelineBaseStack``` base class. Becase this class is a abstract class, we have to override some methods. [Template Method Pattern in OOP](https://en.wikipedia.org/wiki/Template_method_pattern) is applied for guiding pipeline configuration. This approach only requires passing in a minimal set of options, as the base class knows all of the default options. If you want to create additional resources, you can start with ```onPostConstructor()``` method instead of ```constructor()``` method. 153 | 154 | ```typescript 155 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 156 | import { AppContext } from '../../../lib/template/app-context'; 157 | import { Override } from '../../../lib/template/stack/base/base-stack'; 158 | 159 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 160 | 161 | 162 | export class Approach2PipelineStack extends base.PipelineBaseStack { 163 | private pipeline: pipeline.PipelineSimplePattern; 164 | 165 | constructor(appContext: AppContext, stackConfig: any) { 166 | super(appContext, stackConfig); 167 | } 168 | 169 | @Override 170 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 171 | this.pipeline = pipeline; 172 | } 173 | 174 | @Override 175 | onPipelineName(): string { 176 | return 'Approach2Pipeline'; 177 | } 178 | 179 | @Override 180 | onActionFlow(): pipeline.ActionProps[] { 181 | return [ 182 | { 183 | Name: 'GitClone', 184 | Stage: 'SourceStage', 185 | Kind: pipeline.ActionKind.SourceCodeCommit, 186 | Enable: true, 187 | Detail: { 188 | RepositoryName: 'sample-repo', 189 | BranchName: 'release_cicd' 190 | } 191 | }, 192 | { 193 | Name: 'DeployAllStacks', 194 | Stage: "DevDeployStage", 195 | Kind: pipeline.ActionKind.BuildCodeBuild, 196 | Enable: true, 197 | Detail: { 198 | AppConfigFile: "config/app-config-sample1.json", 199 | BuildDeployStacks: { 200 | StackNameList: ['Sample1Service1Stack'], 201 | } 202 | } 203 | } 204 | ]; 205 | } 206 | } 207 | ``` 208 | 209 | **Approach 3**: Generalize ```PipelineBaseStack``` base class and inject pipeline configuration using config file 210 | 211 | This approach is same to approach 2, but in here we don't configure pipeline options directly in a Stack class. All options are configured in an external json file such as config/app-config-xxx.json. 212 | 213 | ```typescript 214 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 215 | import { AppContext } from '../../../lib/template/app-context'; 216 | import { Override } from '../../../lib/template/stack/base/base-stack'; 217 | 218 | import * as cicd from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 219 | 220 | 221 | export class Approach3PipelineStack extends base.PipelineBaseStack { 222 | private pipeline: cicd.PipelineSimplePattern; 223 | 224 | constructor(appContext: AppContext, stackConfig: any) { 225 | super(appContext, stackConfig); 226 | } 227 | 228 | @Override 229 | onPostConstructor(pipeline: cicd.PipelineSimplePattern): void { 230 | this.pipeline = pipeline; 231 | } 232 | 233 | @Override 234 | onPipelineName(): string { 235 | return this.stackConfig.PipelineName; 236 | } 237 | 238 | @Override 239 | onActionFlow(): cicd.ActionProps[] { 240 | return this.stackConfig.ActionFlow; 241 | } 242 | } 243 | ``` 244 | 245 | Stack class implementation is very simple, and it can be reused by changing the config file only externally. The json shown below is an example of a config file that is set externally and injected. 246 | 247 | ```json 248 | "Approach3Pipeline": { 249 | "Name": "Approach3PipelineStack", 250 | 251 | "PipelineName": "Approach3Pipeline", 252 | 253 | "ActionFlow": [ 254 | { 255 | "Name": "GitClone", 256 | "Stage": "SourceStage", 257 | "Kind": "SourceCodeCommit", 258 | "Enable": true, 259 | 260 | "Detail": { 261 | "RepositoryName": "sample-repo", 262 | "BranchName": "release_cicd" 263 | } 264 | }, 265 | { 266 | "Name": "DeployAllStacks", 267 | "Stage": "DevDeployStage", 268 | "Kind": "BuildCodeBuild", 269 | "Enable": true, 270 | "Detail": { 271 | "AppConfigFile": "config/app-config-sample1.json", 272 | "BuildDeployStacks": { 273 | "StackNameList": ["Sample1Service1Stack"] 274 | } 275 | } 276 | } 277 | ] 278 | } 279 | ``` 280 | 281 | The configuration shown above is injected from app-main.ts like this: 282 | 283 | ```typescript 284 | new Approach3PipelineStack(appContext, appContext.appConfig.Stack.Approach3Pipeline); 285 | ``` 286 | 287 | ### How to configure pipelines 288 | 289 | A pipeline can be defined as a ```AcionFlow``` option, and which is a sequence of ```Actions```. ActionFlow option must adhere to the following rules: 290 | 291 | * The first item of the ```ActionFlow``` must be a ```Source``` kind such as ```SourceCodeCommit``` or ```SourceS3Bucket``` 292 | * The ```ActionFlow``` must contain at least two items, that means Source Action kind + Other Action kinds 293 | 294 | For detailed explanation, suppose we have 3 MSA service stacks and 1 pipeline stack like this: 295 | 296 | ```bash 297 | export APP_CONFIG=config/app-config-sample2.json 298 | cdk list 299 | 300 | PipelineSample2-Sample2Service1Stack 301 | PipelineSample2-Sample2Service2Stack 302 | PipelineSample2-Sample2Service3Stack 303 | PipelineSample2-Sample2PipelineStack 304 | ``` 305 | 306 | Depending on the dependencies of the stacks and the deployment strategy, we can think of a pipeline configuration by dividing it into four cases as follows. Full source code is ready in [infra/stack/sample2/sample2-pipeline-stack.ts](infra/stack/sample2/sample2-pipeline-stack.ts). 307 | 308 | **Case 1**: Deploy all stacks in a single AWS CodeBuild project within a Stage 309 | 310 | If the stacks are tightly dependent on each other and of cource deployment lifecycle is same, this approach is suitable. The following settings will deploy three stacks sequentially in one AWS CodeBuild project in one Stage. 311 | 312 | ```typescript 313 | private createCase1Pipeline() { 314 | new pipeline.PipelineSimplePattern(this, 'case1', { 315 | projectPrefix: this.projectPrefix, 316 | stackConfig: this.stackConfig, 317 | stackName: this.stackName, 318 | env: this.commonProps.env!, 319 | pipelineName: 'Case1Pipeline', 320 | actionFlow: [ 321 | { 322 | Name: 'GitClone', 323 | Stage: 'SourceStage', 324 | Kind: pipeline.ActionKind.SourceCodeCommit, 325 | Enable: true, 326 | Detail: { 327 | RepositoryName: 'sample-repo', 328 | BranchName: 'release_cicd' 329 | } 330 | }, 331 | { 332 | Name: 'DeployAllStacks', 333 | Stage: "DevDeployStage", 334 | Kind: pipeline.ActionKind.BuildCodeBuild, 335 | Enable: true, 336 | Detail: { 337 | AppConfigFile: "config/app-config-sample2.json", 338 | BuildDeployStacks: { 339 | StackNameList: ['Sample2Service1Stack', 'Sample2Service2Stack', 'Sample2Service3Stack'], 340 | } 341 | } 342 | } 343 | ] 344 | }) 345 | } 346 | ``` 347 | 348 | The configuration shown above will automatically generate the following BuildSpec file. Internally, it sets up creates AWS CDK environment and deployment commands. Particularly, ```StackNameList: ['Sample2Service1Stack', 'Sample2Service2Stack', 'Sample2Service3Stack']``` option will generate ```cdk deploy *StackName* --require-approval never``` command list. 349 | 350 | ```yaml 351 | { 352 | "version": "0.2", 353 | "phases": { 354 | "install": { 355 | "runtime-versions": { 356 | "nodejs": 14 357 | }, 358 | "commands": [ 359 | "npm install -g aws-cdk@1", 360 | "npm install" 361 | ] 362 | }, 363 | "pre_build": {}, 364 | "build": { 365 | "commands": [ 366 | "cdk deploy *Sample2Service1Stack* --require-approval never", 367 | "cdk deploy *Sample2Service2Stack* --require-approval never", 368 | "cdk deploy *Sample2Service3Stack* --require-approval never" 369 | ] 370 | }, 371 | "post_build": {} 372 | }, 373 | "artifacts": { 374 | "files": [ 375 | "**/*" 376 | ], 377 | "exclude-paths": [ 378 | "cdk.out/", 379 | "node_modules/", 380 | ".git/" 381 | ] 382 | } 383 | } 384 | ``` 385 | 386 | Here's the final deployed pipeline: 387 | 388 | ![sample2-case1](docs/asset/sample2-case1.png) 389 | 390 | **Case2**: Deploy each stack in each AWS CodeBuild project in one Stage. 391 | 392 | If the stacks are loosely coupled on each other and deployment lifecycle is same, this approach is suitable. The following settings will deploy three stacks sequentially in each AWS CodeBuild project in one Stage. 393 | 394 | ```typescript 395 | private createCase2Pipeline() { 396 | new pipeline.PipelineSimplePattern(this, 'case2', { 397 | projectPrefix: this.projectPrefix, 398 | stackConfig: this.stackConfig, 399 | stackName: this.stackName, 400 | env: this.commonProps.env!, 401 | pipelineName: 'Case2Pipeline', 402 | actionFlow: [ 403 | { 404 | Name: 'GitClone', 405 | Stage: 'SourceStage', 406 | Kind: pipeline.ActionKind.SourceCodeCommit, 407 | Enable: true, 408 | Detail: { 409 | RepositoryName: 'sample-repo', 410 | BranchName: 'release_cicd' 411 | } 412 | }, 413 | { 414 | Name: 'DeployService1Stack', 415 | Stage: "DevDeployStage", 416 | Kind: pipeline.ActionKind.BuildCodeBuild, 417 | Enable: true, 418 | Order: 1, 419 | Detail: { 420 | AppConfigFile: "config/app-config-sample2.json", 421 | BuildDeployStacks: { 422 | StackNameList: ['Sample2Service1Stack'], 423 | } 424 | } 425 | }, 426 | { 427 | Name: 'DeployService2Stack', 428 | Stage: "DevDeployStage", 429 | Kind: pipeline.ActionKind.BuildCodeBuild, 430 | Enable: true, 431 | Order: 2, 432 | Detail: { 433 | AppConfigFile: "config/app-config-sample2.json", 434 | BuildDeployStacks: { 435 | StackNameList: ['Sample2Service2Stack'], 436 | } 437 | } 438 | }, 439 | { 440 | Name: 'DeployService3Stack', 441 | Stage: "DevDeployStage", 442 | Kind: pipeline.ActionKind.BuildCodeBuild, 443 | Enable: true, 444 | Order: 3, 445 | Detail: { 446 | AppConfigFile: "config/app-config-sample2.json", 447 | BuildDeployStacks: { 448 | StackNameList: ['Sample2Service3Stack'], 449 | } 450 | } 451 | } 452 | ] 453 | }) 454 | } 455 | ``` 456 | 457 | It is important here that the stage names are all the same. Bacause all stage names are same with different action name, this will result in the following commands internally in each AWS CodeBuild project. 458 | 459 | 1st Build Project 460 | 461 | ```bash 462 | cdk deploy *Sample2Service1Stack* 463 | ``` 464 | 465 | 2nd Build Project 466 | 467 | ```bash 468 | cdk deploy *Sample2Service1Stack* 469 | ``` 470 | 471 | 3rd Build Project 472 | 473 | ```bash 474 | cdk deploy *Sample3Service1Stack* 475 | ``` 476 | 477 | Here's the final deployed pipeline: 478 | 479 | ![sample2-case2](docs/asset/sample2-case2.png) 480 | 481 | **Case3**: Deploy each stack in each AWS CodeBuild project of each Stage 482 | 483 | If the stacks are to be deployed sequentially, each in an independent environment, this approach is suitable. The following settings will deploy three stacks sequentially in each AWS CodeBuild project in different Stages. 484 | 485 | ```typescript 486 | private createCase3Pipeline() { 487 | new pipeline.PipelineSimplePattern(this, 'case3', { 488 | projectPrefix: this.projectPrefix, 489 | stackConfig: this.stackConfig, 490 | stackName: this.stackName, 491 | env: this.commonProps.env!, 492 | pipelineName: 'Case3Pipeline', 493 | actionFlow: [ 494 | { 495 | Name: 'GitClone', 496 | Stage: 'SourceStage', 497 | Kind: pipeline.ActionKind.SourceCodeCommit, 498 | Enable: true, 499 | Detail: { 500 | RepositoryName: 'sample-repo', 501 | BranchName: 'release_cicd' 502 | } 503 | }, 504 | { 505 | Name: 'DeployService1Stack', 506 | Stage: "DevDeployStage1", 507 | Kind: pipeline.ActionKind.BuildCodeBuild, 508 | Enable: true, 509 | Detail: { 510 | AppConfigFile: "config/app-config-sample2.json", 511 | BuildDeployStacks: { 512 | StackNameList: ['Sample2Service1Stack'], 513 | } 514 | } 515 | }, 516 | { 517 | Name: 'DeployService2Stack', 518 | Stage: "DevDeployStage2", 519 | Kind: pipeline.ActionKind.BuildCodeBuild, 520 | Enable: true, 521 | Detail: { 522 | AppConfigFile: "config/app-config-sample2.json", 523 | BuildDeployStacks: { 524 | StackNameList: ['Sample2Service2Stack'], 525 | } 526 | } 527 | }, 528 | { 529 | Name: 'DeployService3Stack', 530 | Stage: "DevDeployStage3", 531 | Kind: pipeline.ActionKind.BuildCodeBuild, 532 | Enable: true, 533 | Detail: { 534 | AppConfigFile: "config/app-config-sample2.json", 535 | BuildDeployStacks: { 536 | StackNameList: ['Sample2Service3Stack'], 537 | } 538 | } 539 | } 540 | ] 541 | }) 542 | } 543 | ``` 544 | 545 | Note that both Action name and Stage name are different. Here's the final deployed pipeline: 546 | 547 | ![sample2-case3](docs/asset/sample2-case3.png) 548 | 549 | **Case4**: Deploy all stacks simultaneously in each AWS CodeBuild project of a single Stage 550 | 551 | If the stacks are completely independent on each other and deployment lifecycle is same, this approach is suitable. The following settings will deploy three stacks at the same time in each AWS CodeBuild project within one Stage. 552 | 553 | ```typescript 554 | private createCase4Pipeline() { 555 | new pipeline.PipelineSimplePattern(this, 'case4', { 556 | projectPrefix: this.projectPrefix, 557 | stackConfig: this.stackConfig, 558 | stackName: this.stackName, 559 | env: this.commonProps.env!, 560 | pipelineName: 'Case4Pipeline', 561 | actionFlow: [ 562 | { 563 | Name: 'GitClone', 564 | Stage: 'SourceStage', 565 | Kind: pipeline.ActionKind.SourceCodeCommit, 566 | Enable: true, 567 | Detail: { 568 | RepositoryName: 'sample-repo', 569 | BranchName: 'release_cicd' 570 | } 571 | }, 572 | { 573 | Name: 'DeployService1Stack', 574 | Stage: "DevDeployStage", 575 | Kind: pipeline.ActionKind.BuildCodeBuild, 576 | Enable: true, 577 | Order: 1, 578 | Detail: { 579 | AppConfigFile: "config/app-config-sample2.json", 580 | BuildDeployStacks: { 581 | StackNameList: ['Sample2Service1Stack'], 582 | } 583 | } 584 | }, 585 | { 586 | Name: 'DeployService2Stack', 587 | Stage: "DevDeployStage", 588 | Kind: pipeline.ActionKind.BuildCodeBuild, 589 | Enable: true, 590 | Order: 1, 591 | Detail: { 592 | AppConfigFile: "config/app-config-sample2.json", 593 | BuildDeployStacks: { 594 | StackNameList: ['Sample2Service2Stack'], 595 | } 596 | } 597 | }, 598 | { 599 | Name: 'DeployService3Stack', 600 | Stage: "DevDeployStage", 601 | Kind: pipeline.ActionKind.BuildCodeBuild, 602 | Enable: true, 603 | Order: 1, 604 | Detail: { 605 | AppConfigFile: "config/app-config-sample2.json", 606 | BuildDeployStacks: { 607 | StackNameList: ['Sample2Service3Stack'], 608 | } 609 | } 610 | } 611 | ] 612 | }) 613 | } 614 | ``` 615 | 616 | Because Stage name is the same, they are grouped into one stage, and because ```Order``` is the same, they are deployed at the same time. 617 | 618 | Here's the final deployed pipeline: 619 | 620 | ![sample2-case4](docs/asset/sample2-case4.png) 621 | 622 | ### Environment Variables 623 | 624 | The following environment variables are provided to the build project. You can use these when you write a customized build commands. 625 | 626 | The example values were written based on ```app-config-sample2.json``` config file. 627 | 628 | |Variable Name|Example Value| 629 | |-------|-------------------| 630 | |ACCOUNT|12345678901| 631 | |REGION|us-east-2| 632 | |PROJECT_NAME|Pipeline| 633 | |PROJECT_STAGE|Sample2| 634 | |PROJECT_PREFIX|PipelineSample2| 635 | |APP_CONFIG|config/app-config-sample2.json| 636 | |ON_PIPELINE|YES| 637 | ||| 638 | 639 | ## Advanced Usecases 640 | 641 | Full source code is ready in [infra/stack/sample3](infra/stack/sample3). 642 | 643 | ### Multiple Target Deployment 644 | 645 | You can deploy test/prod stages step by step by using the config files that have the target environment, and you can put an approval step in the middle. 646 | 647 | ```typescript 648 | { 649 | Name: "TestDeployStacks", 650 | Stage: "TestStage", 651 | Kind: pipeline.ActionKind.BuildCodeBuild, 652 | Enable: true, 653 | Detail: { 654 | AppConfigFile: "config/app-config-sample3-test.json", 655 | BuildDeployStacks: { 656 | StackNameList: ["Sample3Service1Stack"], 657 | } 658 | } 659 | }, 660 | { 661 | Name: "ApproveManually", 662 | Stage: "ApproveStage", 663 | Kind: pipeline.ActionKind.ApproveManual, 664 | Enable: true, 665 | Detail: { 666 | Description: "Must check stacks before prod" 667 | } 668 | }, 669 | { 670 | Name: "ProdDeployStacks", 671 | Stage: "ProdStage", 672 | Kind: pipeline.ActionKind.BuildCodeBuild, 673 | Enable: true, 674 | Detail: { 675 | AppConfigFile: "config/app-config-sample3-prod.json", 676 | BuildDeployStacks: { 677 | StackNameList: ["Sample3Service1Stack"], 678 | } 679 | } 680 | } 681 | ``` 682 | 683 | In here, ```app-config-sample3-test.json```'s destination is ```us-east-2```, ```app-config-sample3-prod.json```'s destination is ```us-east-1```. That is, Test-Stage deploy the stacks to ```us-east-2``` and Prod-Stage deploy the stacks to ```us-east-1```. This is a example case for cross-region distribution. 684 | 685 | For deployment, execute the following command. 686 | 687 | ```bash 688 | export APP_CONFIG=config/app-config-sample3.json 689 | cdk list 690 | ... 691 | ... 692 | PipelineSample3-Sample3PipelineStack 693 | 694 | cdk deploy *Sample3PipelineStack 695 | ... 696 | ... 697 | 698 | git push [remote repo name] [branch name] 699 | ``` 700 | 701 | Here's the final deployed pipeline: 702 | 703 | ![sample3-multiple-target](docs/asset/sample3-multiple-target.png) 704 | 705 | ### Cross-Account Target Deployment 706 | 707 | You can deploy each test/prod stage to the difference account/region. Mostly the same as Multiple Target Deployment above, the only difference is that you have to specify the difference accoun in config json file and prepare assume-role. 708 | 709 | ```typescript 710 | { 711 | Name: 'TestDeployStacks', 712 | Stage: "TestStage", 713 | Kind: pipeline.ActionKind.BuildCodeBuild, 714 | Enable: true, 715 | Detail: { 716 | AppConfigFile: "config/app-config-sample3-test.json", 717 | BuildDeployStacks: { 718 | PreCommands: ['aws sts get-caller-identity'], 719 | StackNameList: ['Sample3Service1Stack'], 720 | } 721 | } 722 | }, 723 | { 724 | Name: 'ApproveManually', 725 | Stage: 'ApproveStage', 726 | Kind: pipeline.ActionKind.ApproveManual, 727 | Enable: true, 728 | Detail: { 729 | Description: 'Must check stacks before prod' 730 | } 731 | }, 732 | { 733 | Name: 'ProdDeployStacks', 734 | Stage: "ProdStage", 735 | Kind: pipeline.ActionKind.BuildCodeBuild, 736 | Enable: true, 737 | Detail: { 738 | AppConfigFile: "config/app-config-sample3-prod-cross.json", 739 | BuildDeployStacks: { 740 | PreCommands: ['aws sts get-caller-identity'], 741 | StackNameList: ['Sample3Service1Stack'], 742 | }, 743 | BuildAssumeRoleArn: 'arn:aws:iam::[your account number]:role/[your assume-role name]' 744 | } 745 | } 746 | ``` 747 | 748 | In here, ```app-config-sample3-test.json```'s destination is A-account, ```config/app-config-sample3-prod-cross.json```'s destination is ```B-account```. And ```BuildAssumeRoleArn``` option is added, where the ```assume-role``` must have a minimal policy for a target Stack deployment, and the role must be set to trust the account where the pipeline is ready. 749 | 750 | As shown in the following figure, temporary credentials are internally created using AWS STS to access the account. 751 | 752 | ![cross-account-pipeline](docs/asset/cross-account-pipeline.png) 753 | 754 | ### PrePost Build Commands Injection 755 | 756 | You can inject build commands before and after deploying the stacks. This allows you to set up the environment, build some modules, perform unit tests, and so on. 757 | 758 | ```typescript 759 | { 760 | Name: 'DeployStack1', 761 | Stage: "DevDeployStage", 762 | Kind: pipeline.ActionKind.BuildCodeBuild, 763 | Enable: false, 764 | Detail: { 765 | AppConfigFile: "config/app-config-sample1.json", 766 | BuildDeployStacks: { 767 | PreCommands: [ 768 | 'npm install --prefix code/lambda/api', 769 | 'pytest code/lambda/api/test' 770 | ], 771 | StackNameList: ['Sample1Service1Stack'], 772 | PostCommands: [ 773 | 'aws s3 sync code/lambda/api/report s3://aaa/bb/cc' 774 | ] 775 | } 776 | } 777 | } 778 | ``` 779 | 780 | ### Action Event Handling 781 | 782 | If you specify a lambda function as follows, the event is delivered at the time of each action change and the lambda is automatically called. 783 | 784 | ```typescript 785 | { 786 | Name: 'DeployStack1', 787 | Stage: "DevDeployStage", 788 | Kind: pipeline.ActionKind.BuildCodeBuild, 789 | Enable: false, 790 | EventStateLambda: { 791 | CodePath: 'code/lambda/cicd-event-state', 792 | Handler: 'handler.handle', 793 | Runtime: 'python3.7' 794 | }, 795 | Detail: { 796 | AppConfigFile: "config/app-config-sample1.json", 797 | BuildDeployStacks: { 798 | StackNameList: ['Sample1Service1Stack'], 799 | } 800 | } 801 | } 802 | ``` 803 | 804 | ### Temporary Deactivation 805 | 806 | The ```disable``` option allows you to temporarily disable certain Actions without removing the complex options. 807 | 808 | ```typescript 809 | { 810 | Name: 'DeployStack1', 811 | Stage: "DevDeployStage", 812 | Kind: pipeline.ActionKind.BuildCodeBuild, 813 | Enable: false, 814 | Detail: { 815 | AppConfigFile: "config/app-config-sample1.json", 816 | BuildDeployStacks: { 817 | StackNameList: ['Sample1Service1Stack'], 818 | } 819 | } 820 | }, 821 | { 822 | Name: 'DeployStack2', 823 | Stage: "DevDeployStage", 824 | Kind: pipeline.ActionKind.BuildCodeBuild, 825 | Enable: true, 826 | Detail: { 827 | AppConfigFile: "config/app-config-sample1.json", 828 | BuildDeployStacks: { 829 | StackNameList: ['Sample2Service1Stack'], 830 | } 831 | } 832 | } 833 | ``` 834 | 835 | ### Role Customizing 836 | 837 | If IAM Policies are not specified through the following method, ```AdministratorAccess``` permission is automatically granted. 838 | 839 | #### For Construct approach 840 | 841 | ```typescript 842 | const pipeline = new cicd.PipelineSimplePattern(this, 'Approach1', { 843 | projectPrefix: this.projectPrefix, 844 | stackConfig: this.stackConfig, 845 | stackName: this.stackName, 846 | env: this.commonProps.env!, 847 | pipelineName: 'Approach1Pipeline', 848 | actionFlow: [ 849 | ], 850 | buildPolicies: this.createCustomPolicies() 851 | }); 852 | 853 | private createCustomPolicies(): iam.PolicyStatement[] { 854 | const statement = new iam.PolicyStatement(); 855 | statement.addActions( 856 | "cognito:*", 857 | "dynamodb:*", 858 | "application-autoscaling:*", 859 | "elasticloadbalancingv2:*", 860 | "elasticloadbalancing:*", 861 | ); 862 | statement.addResources("*"); 863 | 864 | return [statement]; 865 | } 866 | ``` 867 | 868 | #### For BaseClass approach 869 | 870 | ```typescript 871 | @Override 872 | protected onBuildPolicies(): iam.PolicyStatement[] | undefined { 873 | const statement = new iam.PolicyStatement(); 874 | statement.addActions( 875 | "cognito:*", 876 | "dynamodb:*", 877 | "application-autoscaling:*", 878 | "elasticloadbalancingv2:*", 879 | "elasticloadbalancing:*", 880 | ); 881 | statement.addResources("*"); 882 | 883 | return [statement]; 884 | } 885 | ``` 886 | 887 | ### Build Project Customizing 888 | 889 | Because we provide the other options to execute AWS CodeBuild ```project```, you can customize the build project through the following two options. 890 | 891 | #### For Build-Spec 892 | 893 | ```typescript 894 | { 895 | Name: 'DeployAllStacks', 896 | Stage: "DevDeployStage", 897 | Kind: pipeline.ActionKind.BuildCodeBuild, 898 | Enable: true, 899 | Detail: { 900 | AppConfigFile: 'config/app-config-sample1.json', 901 | BuildSpecFile: 'script/cicd/buildspec_cdk_deploy.yaml' 902 | } 903 | } 904 | ``` 905 | 906 | #### For Shell-Script 907 | 908 | ```typescript 909 | { 910 | Name: 'DeployAllStacks', 911 | Stage: "DevDeployStage", 912 | Kind: pipeline.ActionKind.BuildCodeBuild, 913 | Enable: true, 914 | Detail: { 915 | AppConfigFile: 'config/app-config-sample1.json', 916 | BuildCommands: [ 917 | 'pwd', 918 | 'ls -l', 919 | 'script/cicd/install_dependencies.sh', 920 | 'script/cicd/unit_test.sh', 921 | 'script/cicd/deploy_stacks.sh', 922 | ] 923 | } 924 | } 925 | ``` 926 | 927 | ### CodePipeline Customizing 928 | 929 | Because we provide ```CodePipeline``` instance as a public member variable, you can customize anything using this object. 930 | 931 | #### For Construct approach 932 | 933 | ```typescript 934 | const pipeline = new cicd.PipelineSimplePattern(this, 'Approach1', { 935 | projectPrefix: this.projectPrefix, 936 | stackConfig: this.stackConfig, 937 | stackName: this.stackName, 938 | env: this.commonProps.env!, 939 | pipelineName: 'Approach1Pipeline', 940 | actionFlow: [ 941 | ] 942 | }) 943 | 944 | const codePipeline = pipeline.codePipeline; 945 | codePipeline.addStage(.....); 946 | ``` 947 | 948 | #### For BaseClass approach 949 | 950 | ```typescript 951 | @Override 952 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 953 | this.pipeline = pipeline; 954 | 955 | const codePipeline = pipeline.codePipeline; 956 | codePipeline.addStage(.....); 957 | } 958 | ``` 959 | 960 | ## Limitation 961 | 962 | Currently, the following limitations exist and will be improved soon. 963 | 964 | * cross-account Deployments: completed 965 | * AWS CodeBuild environment settings 966 | * self-mutating 967 | 968 | ## Security 969 | 970 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 971 | 972 | ## License 973 | 974 | This library is licensed under the MIT-0 License. See the LICENSE file. 975 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts infra/app-main", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, 21 | "@aws-cdk/core:enableStackNameDuplicates": true, 22 | "aws-cdk:enableDiffNoFail": true, 23 | "@aws-cdk/core:stackRelativeExports": true, 24 | "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, 25 | "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, 26 | "@aws-cdk/aws-kms:defaultKeyPolicies": true, 27 | "@aws-cdk/aws-s3:grantWriteWithoutAcl": true, 28 | "@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true, 29 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, 30 | "@aws-cdk/aws-efs:defaultEncryptionAtRest": true, 31 | "@aws-cdk/aws-lambda:recognizeVersionProps": true, 32 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, 33 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 34 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 35 | "@aws-cdk/aws-iam:minimizePolicies": true, 36 | "@aws-cdk/core:target-partitions": [ 37 | "aws", 38 | "aws-cn" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /codes/lambda/cicd-event-state/src/handler.py: -------------------------------------------------------------------------------- 1 | 2 | def handle(event, context): 3 | print('event--->', event) 4 | 5 | print('stage', event['detail']['stage']) 6 | print('action', event['detail']['action']) 7 | print('state', event['detail']['state']) 8 | 9 | return 'ok' -------------------------------------------------------------------------------- /codes/lambda/cicd-event-state/test/event_STARTED.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0", 3 | "id": "a88c9e57-54d0-56da-f578-c9267dce6ca0", 4 | "detail-type": "CodePipeline Action Execution State Change", 5 | "source": "aws.codepipeline", 6 | "account": "***********", 7 | "time": "2022-03-19T16:44:21Z", 8 | "region": "ap-northeast-2", 9 | "resources": [ 10 | "arn:aws:codepipeline:ap-northeast-2:***********:LiveProtoDev-AllStackDeploy" 11 | ], 12 | "detail": { 13 | "pipeline": "LiveProtoDev-AllStackDeploy", 14 | "execution-id": "b00f02d1-09ea-4afb-a7af-9359d305397b", 15 | "stage": "DevDeployStage2", 16 | "action": "ChannelBackend", 17 | "input-artifacts": [ 18 | { 19 | "name": "SourceOutput", 20 | "s3location": { 21 | "bucket": "liveprotodev-maincicdpip-simplepipelinecicdpipeli-15ripklll31ac", 22 | "key": "LiveProtoDev-AllStac/SourceOutp/vvsz3Pz" 23 | } 24 | } 25 | ], 26 | "state": "STARTED", 27 | "region": "ap-northeast-2", 28 | "type": { 29 | "owner": "AWS", 30 | "provider": "CodeBuild", 31 | "category": "Build", 32 | "version": "1" 33 | }, 34 | "version": 5.0 35 | } 36 | } -------------------------------------------------------------------------------- /codes/lambda/cicd-event-state/test/event_SUCCEEDED.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0", 3 | "id": "e75f110d-13c2-5780-d29b-6822d4ad4598", 4 | "detail-type": "CodePipeline Action Execution State Change", 5 | "source": "aws.codepipeline", 6 | "account": "***********", 7 | "time": "2022-03-19T16:47:28Z", 8 | "region": "ap-northeast-2", 9 | "resources": [ 10 | "arn:aws:codepipeline:ap-northeast-2:***********:LiveProtoDev-AllStackDeploy" 11 | ], 12 | "detail": { 13 | "pipeline": "LiveProtoDev-AllStackDeploy", 14 | "execution-id": "b00f02d1-09ea-4afb-a7af-9359d305397b", 15 | "stage": "DevDeployStage2", 16 | "execution-result": { 17 | "external-execution-url": "https://console.aws.amazon.com/codebuild/home?region=ap-northeast-2#/builds/SimplePipelineChannelBacken-4HYYzMl5gpfh:9776da58-f174-4e8d-9d35-02eb49d3a5f8/view/new", 18 | "external-execution-id": "SimplePipelineChannelBacken-4HYYzMl5gpfh:9776da58-f174-4e8d-9d35-02eb49d3a5f8" 19 | }, 20 | "output-artifacts": [ 21 | { 22 | "name": "ChannelBackendBuildOutput", 23 | "s3location": { 24 | "bucket": "liveprotodev-maincicdpip-simplepipelinecicdpipeli-15ripklll31ac", 25 | "key": "LiveProtoDev-AllStac/ChannelBac/e6b3vDU" 26 | } 27 | } 28 | ], 29 | "action": "ChannelBackend", 30 | "state": "SUCCEEDED", 31 | "region": "ap-northeast-2", 32 | "type": { 33 | "owner": "AWS", 34 | "provider": "CodeBuild", 35 | "category": "Build", 36 | "version": "1" 37 | }, 38 | "version": 5.0 39 | } 40 | } -------------------------------------------------------------------------------- /config/app-config-sample1.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "Name": "Pipeline", 4 | "Stage": "Sample1", 5 | "Account": "75157*******", 6 | "Region": "us-east-2", 7 | "Profile": "cdk-demo" 8 | }, 9 | 10 | "Stack": { 11 | "Approach1Pipeline": { 12 | "Name": "Approach1PipelineStack" 13 | }, 14 | "Approach2Pipeline": { 15 | "Name": "Approach2PipelineStack" 16 | }, 17 | "Approach3Pipeline": { 18 | "Name": "Approach3PipelineStack", 19 | 20 | "PipelineName": "Approach3Pipeline", 21 | 22 | "ActionFlow": [ 23 | { 24 | "Name": "GitClone", 25 | "Stage": "SourceStage", 26 | "Kind": "SourceCodeCommit", 27 | "Enable": true, 28 | 29 | "Detail": { 30 | "RepositoryName": "sample-repo", 31 | "BranchName": "release_cicd" 32 | } 33 | }, 34 | { 35 | "Name": "DeployAllStacks", 36 | "Stage": "DevDeployStage", 37 | "Kind": "BuildCodeBuild", 38 | "Enable": true, 39 | "Detail": { 40 | "AppConfigFile": "config/app-config-sample1.json", 41 | "BuildDeployStacks": { 42 | "StackNameList": ["Sample1Service1Stack"] 43 | } 44 | } 45 | } 46 | ] 47 | }, 48 | "Sample1Service1": { 49 | "Name": "Sample1Service1Stack" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /config/app-config-sample2.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "Name": "Pipeline", 4 | "Stage": "Sample2", 5 | "Account": "75157*******", 6 | "Region": "us-east-2", 7 | "Profile": "cdk-demo" 8 | }, 9 | 10 | "Stack": { 11 | "Sample2Service1": { 12 | "Name": "Sample2Service1Stack" 13 | }, 14 | "Sample2Service2": { 15 | "Name": "Sample2Service2Stack" 16 | }, 17 | "Sample2Service3": { 18 | "Name": "Sample2Service3Stack" 19 | }, 20 | "Sample2Pipeline": { 21 | "Name": "Sample2PipelineStack" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config/app-config-sample3-prod-cross.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "Name": "HelloWorld", 4 | "Stage": "Prod", 5 | "Account": "91708*******", 6 | "Region": "ap-northeast-2", 7 | "Profile": "cdk-demo" 8 | }, 9 | 10 | "Stack": { 11 | "Sample3Service1": { 12 | "Name": "Sample3Service1Stack" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/app-config-sample3-prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "Name": "HelloWorld", 4 | "Stage": "Prod", 5 | "Account": "75157*******", 6 | "Region": "ap-northeast-2", 7 | "Profile": "cdk-demo" 8 | }, 9 | 10 | "Stack": { 11 | "Sample3Service1": { 12 | "Name": "Sample3Service1Stack" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/app-config-sample3-test.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "Name": "HelloWorld", 4 | "Stage": "Test", 5 | "Account": "75157*******", 6 | "Region": "us-east-2", 7 | "Profile": "cdk-demo" 8 | }, 9 | 10 | "Stack": { 11 | "Sample3Service1": { 12 | "Name": "Sample3Service1Stack" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/app-config-sample3.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "Name": "Pipeline", 4 | "Stage": "Sample3", 5 | "Account": "75157*******", 6 | "Region": "us-east-2", 7 | "Profile": "cdk-demo" 8 | }, 9 | 10 | "Stack": { 11 | "Sample3Pipeline": { 12 | "Name": "Sample3PipelineStack" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/asset/cross-account-pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/cross-account-pipeline.png -------------------------------------------------------------------------------- /docs/asset/how-to-use-approach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/how-to-use-approach.png -------------------------------------------------------------------------------- /docs/asset/pipeline-usecase1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/pipeline-usecase1.png -------------------------------------------------------------------------------- /docs/asset/pipeline-usecase2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/pipeline-usecase2.png -------------------------------------------------------------------------------- /docs/asset/pipeline-usecase3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/pipeline-usecase3.png -------------------------------------------------------------------------------- /docs/asset/sample2-case1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/sample2-case1.png -------------------------------------------------------------------------------- /docs/asset/sample2-case2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/sample2-case2.png -------------------------------------------------------------------------------- /docs/asset/sample2-case3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/sample2-case3.png -------------------------------------------------------------------------------- /docs/asset/sample2-case4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/sample2-case4.png -------------------------------------------------------------------------------- /docs/asset/sample3-multiple-target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline/6f21d02907e2046df43bf601a91cad926c01a416/docs/asset/sample3-multiple-target.png -------------------------------------------------------------------------------- /infra/app-main.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { AppContext, AppContextError } from '../lib/template/app-context'; 3 | 4 | import { Approach1PipelineStack } from './stack/sample1/approach1-pipeline-stack' 5 | import { Approach2PipelineStack } from './stack/sample1/approach2-pipeline-stack' 6 | import { Approach3PipelineStack } from './stack/sample1/approach3-pipeline-stack' 7 | import { Sample1ServiceStack } from './stack/sample1/sample1-service-stack' 8 | 9 | import { Sample2ServiceStack } from './stack/sample2/sample2-service-stack' 10 | import { Sample2PipelineStack } from './stack/sample2/sample2-pipeline-stack' 11 | 12 | import { Sample3MultipleTargetStack } from './stack/sample3/sample3-multiple-target-stack' 13 | import { Sample3ServiceStack } from './stack/sample3/sample3-service-stack' 14 | 15 | 16 | try { 17 | const appContext = new AppContext({ 18 | appConfigFileKey: 'APP_CONFIG', 19 | }); 20 | 21 | // Sample1 22 | if (appContext.appConfig.Stack.Approach1Pipeline) { 23 | new Approach1PipelineStack(appContext, appContext.appConfig.Stack.Approach1Pipeline); 24 | } 25 | if (appContext.appConfig.Stack.Approach2Pipeline) { 26 | new Approach2PipelineStack(appContext, appContext.appConfig.Stack.Approach2Pipeline); 27 | } 28 | if (appContext.appConfig.Stack.Approach3Pipeline) { 29 | new Approach3PipelineStack(appContext, appContext.appConfig.Stack.Approach3Pipeline); 30 | } 31 | if (appContext.appConfig.Stack.Sample1Service1) { 32 | new Sample1ServiceStack(appContext, appContext.appConfig.Stack.Sample1Service1); 33 | } 34 | 35 | // Sample2 36 | if (appContext.appConfig.Stack.Sample2Service1) { 37 | new Sample2ServiceStack(appContext, appContext.appConfig.Stack.Sample2Service1); 38 | } 39 | if (appContext.appConfig.Stack.Sample2Service2) { 40 | new Sample2ServiceStack(appContext, appContext.appConfig.Stack.Sample2Service2); 41 | } 42 | if (appContext.appConfig.Stack.Sample2Service3) { 43 | new Sample2ServiceStack(appContext, appContext.appConfig.Stack.Sample2Service3); 44 | } 45 | if (appContext.appConfig.Stack.Sample2Pipeline) { 46 | new Sample2PipelineStack(appContext, appContext.appConfig.Stack.Sample2Pipeline); 47 | } 48 | 49 | // Sample3 50 | if (appContext.appConfig.Stack.Sample3Pipeline) { 51 | new Sample3MultipleTargetStack(appContext, appContext.appConfig.Stack.Sample3Pipeline); 52 | } 53 | if (appContext.appConfig.Stack.Sample3Service1) { 54 | new Sample3ServiceStack(appContext, appContext.appConfig.Stack.Sample3Service1); 55 | } 56 | 57 | } catch (error) { 58 | if (error instanceof AppContextError) { 59 | console.error('[AppContextError]:', error.message); 60 | } else { 61 | console.error('[Error]: not-handled-error', error); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /infra/stack/sample1/approach1-pipeline-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/base/base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | 4 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 5 | 6 | 7 | export class Approach1PipelineStack extends base.BaseStack { 8 | 9 | constructor(appContext: AppContext, stackConfig: any) { 10 | super(appContext, stackConfig); 11 | 12 | new pipeline.PipelineSimplePattern(this, 'Approach1', { 13 | projectPrefix: this.projectPrefix, 14 | stackConfig: this.stackConfig, 15 | stackName: this.stackName, 16 | env: this.commonProps.env!, 17 | pipelineName: 'Approach1Pipeline', 18 | actionFlow: [ 19 | { 20 | Name: 'GitClone', 21 | Stage: 'SourceStage', 22 | Kind: pipeline.ActionKind.SourceCodeCommit, 23 | Enable: true, 24 | Detail: { 25 | RepositoryName: 'sample-repo', 26 | BranchName: 'release_cicd' 27 | } 28 | }, 29 | { 30 | Name: 'DeployAllStacks', 31 | Stage: "DevDeployStage", 32 | Kind: pipeline.ActionKind.BuildCodeBuild, 33 | Enable: true, 34 | Detail: { 35 | AppConfigFile: "config/app-config-sample1.json", 36 | BuildDeployStacks: { 37 | StackNameList: ['Sample1Service1Stack'], 38 | } 39 | } 40 | } 41 | ] 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /infra/stack/sample1/approach2-pipeline-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Approach2PipelineStack extends base.PipelineBaseStack { 9 | private pipeline: pipeline.PipelineSimplePattern; 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | } 14 | 15 | @Override 16 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 17 | this.pipeline = pipeline; 18 | } 19 | 20 | @Override 21 | onPipelineName(): string { 22 | return 'Approach2Pipeline'; 23 | } 24 | 25 | @Override 26 | onActionFlow(): pipeline.ActionProps[] { 27 | return [ 28 | { 29 | Name: 'GitClone', 30 | Stage: 'SourceStage', 31 | Kind: pipeline.ActionKind.SourceCodeCommit, 32 | Enable: true, 33 | Detail: { 34 | RepositoryName: 'sample-repo', 35 | BranchName: 'release_cicd' 36 | } 37 | }, 38 | { 39 | Name: 'DeployAllStacks', 40 | Stage: "DevDeployStage", 41 | Kind: pipeline.ActionKind.BuildCodeBuild, 42 | Enable: true, 43 | Detail: { 44 | AppConfigFile: "config/app-config-sample1.json", 45 | BuildDeployStacks: { 46 | StackNameList: ['Sample1Service1Stack'], 47 | } 48 | } 49 | } 50 | ]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /infra/stack/sample1/approach3-pipeline-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as cicd from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Approach3PipelineStack extends base.PipelineBaseStack { 9 | private pipeline: cicd.PipelineSimplePattern; 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | } 14 | 15 | @Override 16 | onPostConstructor(pipeline: cicd.PipelineSimplePattern): void { 17 | this.pipeline = pipeline; 18 | } 19 | 20 | @Override 21 | onPipelineName(): string { 22 | return this.stackConfig.PipelineName; 23 | } 24 | 25 | @Override 26 | onActionFlow(): cicd.ActionProps[] { 27 | return this.stackConfig.ActionFlow; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /infra/stack/sample1/sample1-service-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/base/base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | 4 | 5 | export class Sample1ServiceStack extends base.BaseStack { 6 | 7 | constructor(appContext: AppContext, stackConfig: any) { 8 | super(appContext, stackConfig); 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /infra/stack/sample2/sample2-pipeline-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/base/base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | 4 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 5 | 6 | 7 | export class Sample2PipelineStack extends base.BaseStack { 8 | 9 | constructor(appContext: AppContext, stackConfig: any) { 10 | super(appContext, stackConfig); 11 | 12 | this.createCase1Pipeline(); 13 | this.createCase2Pipeline(); 14 | this.createCase3Pipeline(); 15 | this.createCase4Pipeline(); 16 | } 17 | 18 | private createCase1Pipeline() { 19 | new pipeline.PipelineSimplePattern(this, 'case1', { 20 | projectPrefix: this.projectPrefix, 21 | stackConfig: this.stackConfig, 22 | stackName: this.stackName, 23 | env: this.commonProps.env!, 24 | pipelineName: 'Case1Pipeline', 25 | actionFlow: [ 26 | { 27 | Name: 'GitClone', 28 | Stage: 'SourceStage', 29 | Kind: pipeline.ActionKind.SourceCodeCommit, 30 | Enable: true, 31 | Detail: { 32 | RepositoryName: 'sample-repo', 33 | BranchName: 'release_cicd' 34 | } 35 | }, 36 | { 37 | Name: 'DeployAllStacks', 38 | Stage: "DevDeployStage", 39 | Kind: pipeline.ActionKind.BuildCodeBuild, 40 | Enable: true, 41 | Detail: { 42 | AppConfigFile: "config/app-config-sample2.json", 43 | BuildDeployStacks: { 44 | StackNameList: ['Sample2Service1Stack', 'Sample2Service2Stack', 'Sample2Service3Stack'], 45 | } 46 | } 47 | } 48 | ] 49 | }) 50 | } 51 | 52 | private createCase2Pipeline() { 53 | new pipeline.PipelineSimplePattern(this, 'case2', { 54 | projectPrefix: this.projectPrefix, 55 | stackConfig: this.stackConfig, 56 | stackName: this.stackName, 57 | env: this.commonProps.env!, 58 | pipelineName: 'Case2Pipeline', 59 | actionFlow: [ 60 | { 61 | Name: 'GitClone', 62 | Stage: 'SourceStage', 63 | Kind: pipeline.ActionKind.SourceCodeCommit, 64 | Enable: true, 65 | Detail: { 66 | RepositoryName: 'sample-repo', 67 | BranchName: 'release_cicd' 68 | } 69 | }, 70 | { 71 | Name: 'DeployService1Stack', 72 | Stage: "DevDeployStage", 73 | Kind: pipeline.ActionKind.BuildCodeBuild, 74 | Enable: true, 75 | Order: 1, 76 | Detail: { 77 | AppConfigFile: "config/app-config-sample2.json", 78 | BuildDeployStacks: { 79 | StackNameList: ['Sample2Service1Stack'], 80 | } 81 | } 82 | }, 83 | { 84 | Name: 'DeployService2Stack', 85 | Stage: "DevDeployStage", 86 | Kind: pipeline.ActionKind.BuildCodeBuild, 87 | Enable: true, 88 | Order: 2, 89 | Detail: { 90 | AppConfigFile: "config/app-config-sample2.json", 91 | BuildDeployStacks: { 92 | StackNameList: ['Sample2Service2Stack'], 93 | } 94 | } 95 | }, 96 | { 97 | Name: 'DeployService3Stack', 98 | Stage: "DevDeployStage", 99 | Kind: pipeline.ActionKind.BuildCodeBuild, 100 | Enable: true, 101 | Order: 3, 102 | Detail: { 103 | AppConfigFile: "config/app-config-sample2.json", 104 | BuildDeployStacks: { 105 | StackNameList: ['Sample2Service3Stack'], 106 | } 107 | } 108 | } 109 | ] 110 | }) 111 | } 112 | 113 | private createCase3Pipeline() { 114 | new pipeline.PipelineSimplePattern(this, 'case3', { 115 | projectPrefix: this.projectPrefix, 116 | stackConfig: this.stackConfig, 117 | stackName: this.stackName, 118 | env: this.commonProps.env!, 119 | pipelineName: 'Case3Pipeline', 120 | actionFlow: [ 121 | { 122 | Name: 'GitClone', 123 | Stage: 'SourceStage', 124 | Kind: pipeline.ActionKind.SourceCodeCommit, 125 | Enable: true, 126 | Detail: { 127 | RepositoryName: 'sample-repo', 128 | BranchName: 'release_cicd' 129 | } 130 | }, 131 | { 132 | Name: 'DeployService1Stack', 133 | Stage: "DevDeployStage1", 134 | Kind: pipeline.ActionKind.BuildCodeBuild, 135 | Enable: true, 136 | Detail: { 137 | AppConfigFile: "config/app-config-sample2.json", 138 | BuildDeployStacks: { 139 | StackNameList: ['Sample2Service1Stack'], 140 | } 141 | } 142 | }, 143 | { 144 | Name: 'DeployService2Stack', 145 | Stage: "DevDeployStage2", 146 | Kind: pipeline.ActionKind.BuildCodeBuild, 147 | Enable: true, 148 | Detail: { 149 | AppConfigFile: "config/app-config-sample2.json", 150 | BuildDeployStacks: { 151 | StackNameList: ['Sample2Service2Stack'], 152 | } 153 | } 154 | }, 155 | { 156 | Name: 'DeployService3Stack', 157 | Stage: "DevDeployStage3", 158 | Kind: pipeline.ActionKind.BuildCodeBuild, 159 | Enable: true, 160 | Detail: { 161 | AppConfigFile: "config/app-config-sample2.json", 162 | BuildDeployStacks: { 163 | StackNameList: ['Sample2Service3Stack'], 164 | } 165 | } 166 | } 167 | ] 168 | }) 169 | } 170 | 171 | private createCase4Pipeline() { 172 | new pipeline.PipelineSimplePattern(this, 'case4', { 173 | projectPrefix: this.projectPrefix, 174 | stackConfig: this.stackConfig, 175 | stackName: this.stackName, 176 | env: this.commonProps.env!, 177 | pipelineName: 'Case4Pipeline', 178 | actionFlow: [ 179 | { 180 | Name: 'GitClone', 181 | Stage: 'SourceStage', 182 | Kind: pipeline.ActionKind.SourceCodeCommit, 183 | Enable: true, 184 | Detail: { 185 | RepositoryName: 'sample-repo', 186 | BranchName: 'release_cicd' 187 | } 188 | }, 189 | { 190 | Name: 'DeployService1Stack', 191 | Stage: "DevDeployStage", 192 | Kind: pipeline.ActionKind.BuildCodeBuild, 193 | Enable: true, 194 | Order: 1, 195 | Detail: { 196 | AppConfigFile: "config/app-config-sample2.json", 197 | BuildDeployStacks: { 198 | StackNameList: ['Sample2Service1Stack'], 199 | } 200 | } 201 | }, 202 | { 203 | Name: 'DeployService2Stack', 204 | Stage: "DevDeployStage", 205 | Kind: pipeline.ActionKind.BuildCodeBuild, 206 | Enable: true, 207 | Order: 1, 208 | Detail: { 209 | AppConfigFile: "config/app-config-sample2.json", 210 | BuildDeployStacks: { 211 | StackNameList: ['Sample2Service2Stack'], 212 | } 213 | } 214 | }, 215 | { 216 | Name: 'DeployService3Stack', 217 | Stage: "DevDeployStage", 218 | Kind: pipeline.ActionKind.BuildCodeBuild, 219 | Enable: true, 220 | Order: 1, 221 | Detail: { 222 | AppConfigFile: "config/app-config-sample2.json", 223 | BuildDeployStacks: { 224 | StackNameList: ['Sample2Service3Stack'], 225 | } 226 | } 227 | } 228 | ] 229 | }) 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /infra/stack/sample2/sample2-service-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/base/base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | 4 | 5 | export class Sample2ServiceStack extends base.BaseStack { 6 | 7 | constructor(appContext: AppContext, stackConfig: any) { 8 | super(appContext, stackConfig); 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-action-event-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Sample3ActionEventStack extends base.PipelineBaseStack { 9 | private pipeline: pipeline.PipelineSimplePattern; 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | } 14 | 15 | @Override 16 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 17 | this.pipeline = pipeline; 18 | } 19 | 20 | @Override 21 | onPipelineName(): string { 22 | return 'Approach2Pipeline'; 23 | } 24 | 25 | @Override 26 | onActionFlow(): pipeline.ActionProps[] { 27 | return [ 28 | { 29 | Name: 'GitClone', 30 | Stage: 'SourceStage', 31 | Kind: pipeline.ActionKind.SourceCodeCommit, 32 | Enable: true, 33 | Detail: { 34 | RepositoryName: 'sample-repo', 35 | BranchName: 'release_cicd' 36 | } 37 | }, 38 | { 39 | Name: 'DeployStack1', 40 | Stage: "DevDeployStage", 41 | Kind: pipeline.ActionKind.BuildCodeBuild, 42 | Enable: false, 43 | EventStateLambda: { 44 | CodePath: 'code/lambda/cicd-event-state', 45 | Handler: 'handler.handle', 46 | Runtime: 'python3.7' 47 | }, 48 | Detail: { 49 | AppConfigFile: "config/app-config-sample1.json", 50 | BuildDeployStacks: { 51 | StackNameList: ['Sample1Service1Stack'], 52 | } 53 | } 54 | } 55 | ]; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-buildproject-customizing1-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Sample3BuildProjectCustomizing1Stack extends base.PipelineBaseStack { 9 | private pipeline: pipeline.PipelineSimplePattern; 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | } 14 | 15 | @Override 16 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 17 | this.pipeline = pipeline; 18 | } 19 | 20 | @Override 21 | onPipelineName(): string { 22 | return 'Approach2Pipeline'; 23 | } 24 | 25 | @Override 26 | onActionFlow(): pipeline.ActionProps[] { 27 | return [ 28 | { 29 | Name: 'GitClone', 30 | Stage: 'SourceStage', 31 | Kind: pipeline.ActionKind.SourceCodeCommit, 32 | Enable: true, 33 | Detail: { 34 | RepositoryName: 'sample-repo', 35 | BranchName: 'release_cicd' 36 | } 37 | }, 38 | { 39 | Name: 'DeployAllStacks', 40 | Stage: "DevDeployStage", 41 | Kind: pipeline.ActionKind.BuildCodeBuild, 42 | Enable: true, 43 | Detail: { 44 | AppConfigFile: 'config/app-config-sample1.json', 45 | BuildSpecFile: 'script/cicd/buildspec_cdk_deploy.yaml' 46 | } 47 | } 48 | ]; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-buildproject-customizing2-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Sample3BuildProjectCustomizing2Stack extends base.PipelineBaseStack { 9 | private pipeline: pipeline.PipelineSimplePattern; 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | } 14 | 15 | @Override 16 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 17 | this.pipeline = pipeline; 18 | } 19 | 20 | @Override 21 | onPipelineName(): string { 22 | return 'Approach2Pipeline'; 23 | } 24 | 25 | @Override 26 | onActionFlow(): pipeline.ActionProps[] { 27 | return [ 28 | { 29 | Name: 'GitClone', 30 | Stage: 'SourceStage', 31 | Kind: pipeline.ActionKind.SourceCodeCommit, 32 | Enable: true, 33 | Detail: { 34 | RepositoryName: 'sample-repo', 35 | BranchName: 'release_cicd' 36 | } 37 | }, 38 | { 39 | Name: 'DeployAllStacks', 40 | Stage: "DevDeployStage", 41 | Kind: pipeline.ActionKind.BuildCodeBuild, 42 | Enable: true, 43 | Detail: { 44 | AppConfigFile: 'config/app-config-sample1.json', 45 | BuildCommands: [ 46 | 'pwd', 47 | 'ls -l', 48 | 'script/cicd/install_dependencies.sh', 49 | 'script/cicd/unit_test.sh', 50 | 'script/cicd/deploy_stacks.sh', 51 | ] 52 | } 53 | } 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-codepipeline-customizing1-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/base/base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | 4 | import * as cicd from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 5 | 6 | 7 | export class Sample3CodePipelineCustomizing1Stack extends base.BaseStack { 8 | 9 | constructor(appContext: AppContext, stackConfig: any) { 10 | super(appContext, stackConfig); 11 | 12 | const pipeline = new cicd.PipelineSimplePattern(this, 'Approach1', { 13 | projectPrefix: this.projectPrefix, 14 | stackConfig: this.stackConfig, 15 | stackName: this.stackName, 16 | env: this.commonProps.env!, 17 | pipelineName: 'Approach1Pipeline', 18 | actionFlow: [ 19 | ] 20 | }) 21 | 22 | const codePipeline = pipeline.codePipeline; 23 | codePipeline.addStage(.....); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-codepipeline-customizing2-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Sample3CodePipelineCustomizing2Stack extends base.PipelineBaseStack { 9 | private pipeline: pipeline.PipelineSimplePattern; 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | } 14 | 15 | @Override 16 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 17 | this.pipeline = pipeline; 18 | 19 | const codePipeline = pipeline.codePipeline; 20 | codePipeline.addStage(.....); 21 | } 22 | 23 | @Override 24 | onPipelineName(): string { 25 | return 'Approach2Pipeline'; 26 | } 27 | 28 | @Override 29 | onActionFlow(): pipeline.ActionProps[] { 30 | return [ 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-cross-account-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Sample3CrossAccountStack extends base.PipelineBaseStack { 9 | 10 | constructor(appContext: AppContext, stackConfig: any) { 11 | super(appContext, stackConfig); 12 | } 13 | 14 | @Override 15 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 16 | } 17 | 18 | @Override 19 | onPipelineName(): string { 20 | return 'MultiTargetPipeline'; 21 | } 22 | 23 | @Override 24 | onActionFlow(): pipeline.ActionProps[] { 25 | return [ 26 | { 27 | Name: 'GitClone', 28 | Stage: 'SourceStage', 29 | Kind: pipeline.ActionKind.SourceCodeCommit, 30 | Enable: true, 31 | Detail: { 32 | RepositoryName: 'sample-repo', 33 | BranchName: 'release_cicd' 34 | } 35 | }, 36 | { 37 | Name: 'TestDeployStacks', 38 | Stage: "TestStage", 39 | Kind: pipeline.ActionKind.BuildCodeBuild, 40 | Enable: true, 41 | Detail: { 42 | AppConfigFile: "config/app-config-sample3-test.json", 43 | BuildDeployStacks: { 44 | PreCommands: ['aws sts get-caller-identity'], 45 | StackNameList: ['Sample3Service1Stack'], 46 | } 47 | } 48 | }, 49 | { 50 | Name: 'ApproveManually', 51 | Stage: 'ApproveStage', 52 | Kind: pipeline.ActionKind.ApproveManual, 53 | Enable: true, 54 | Detail: { 55 | Description: 'Must check stacks before prod' 56 | } 57 | }, 58 | { 59 | Name: 'ProdDeployStacks', 60 | Stage: "ProdStage", 61 | Kind: pipeline.ActionKind.BuildCodeBuild, 62 | Enable: true, 63 | Detail: { 64 | AppConfigFile: "config/app-config-sample3-prod-cross.json", 65 | BuildDeployStacks: { 66 | PreCommands: ['aws sts get-caller-identity'], 67 | StackNameList: ['Sample3Service1Stack'], 68 | }, 69 | BuildAssumeRoleArn: 'arn:aws:iam::[your account number]:role/[your assume-role name]' 70 | } 71 | } 72 | ]; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-multiple-target-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Sample3MultipleTargetStack extends base.PipelineBaseStack { 9 | 10 | constructor(appContext: AppContext, stackConfig: any) { 11 | super(appContext, stackConfig); 12 | } 13 | 14 | @Override 15 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 16 | } 17 | 18 | @Override 19 | onPipelineName(): string { 20 | return 'MultiTargetPipeline'; 21 | } 22 | 23 | @Override 24 | onActionFlow(): pipeline.ActionProps[] { 25 | return [ 26 | { 27 | Name: "GitClone", 28 | Stage: "SourceStage", 29 | Kind: pipeline.ActionKind.SourceCodeCommit, 30 | Enable: true, 31 | Detail: { 32 | RepositoryName: "sample-repo", 33 | BranchName: "release_cicd" 34 | } 35 | }, 36 | { 37 | Name: "TestDeployStacks", 38 | Stage: "TestStage", 39 | Kind: pipeline.ActionKind.BuildCodeBuild, 40 | Enable: true, 41 | Detail: { 42 | AppConfigFile: "config/app-config-sample3-test.json", 43 | BuildDeployStacks: { 44 | StackNameList: ["Sample3Service1Stack"], 45 | } 46 | } 47 | }, 48 | { 49 | Name: "ApproveManually", 50 | Stage: "ApproveStage", 51 | Kind: pipeline.ActionKind.ApproveManual, 52 | Enable: true, 53 | Detail: { 54 | Description: "Must check stacks before prod" 55 | } 56 | }, 57 | { 58 | Name: "ProdDeployStacks", 59 | Stage: "ProdStage", 60 | Kind: pipeline.ActionKind.BuildCodeBuild, 61 | Enable: true, 62 | Detail: { 63 | AppConfigFile: "config/app-config-sample3-prod.json", 64 | BuildDeployStacks: { 65 | StackNameList: ["Sample3Service1Stack"], 66 | } 67 | } 68 | } 69 | ]; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-prepost-command-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Sample3PrePostCommandStack extends base.PipelineBaseStack { 9 | private pipeline: pipeline.PipelineSimplePattern; 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | } 14 | 15 | @Override 16 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 17 | this.pipeline = pipeline; 18 | } 19 | 20 | @Override 21 | onPipelineName(): string { 22 | return 'Approach2Pipeline'; 23 | } 24 | 25 | @Override 26 | onActionFlow(): pipeline.ActionProps[] { 27 | return [ 28 | { 29 | Name: 'GitClone', 30 | Stage: 'SourceStage', 31 | Kind: pipeline.ActionKind.SourceCodeCommit, 32 | Enable: true, 33 | Detail: { 34 | RepositoryName: 'sample-repo', 35 | BranchName: 'release_cicd' 36 | } 37 | }, 38 | { 39 | Name: 'DeployStack1', 40 | Stage: "DevDeployStage", 41 | Kind: pipeline.ActionKind.BuildCodeBuild, 42 | Enable: false, 43 | Detail: { 44 | AppConfigFile: "config/app-config-sample1.json", 45 | BuildDeployStacks: { 46 | PreCommands: [ 47 | 'npm install --prefix code/lambda/api', 48 | 'pytest code/lambda/api/test' 49 | ], 50 | StackNameList: ['Sample1Service1Stack'], 51 | PostCommands: [ 52 | 'aws s3 sync code/lambda/api/report s3://aaa/bb/cc' 53 | ] 54 | } 55 | } 56 | } 57 | ]; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-role-customizing2-stack.ts: -------------------------------------------------------------------------------- 1 | import * as iam from '@aws-cdk/aws-iam'; 2 | 3 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 4 | import { AppContext } from '../../../lib/template/app-context'; 5 | import { Override } from '../../../lib/template/stack/base/base-stack'; 6 | 7 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 8 | 9 | 10 | export class Sample3RoleCustomizing2Stack extends base.PipelineBaseStack { 11 | private pipeline: pipeline.PipelineSimplePattern; 12 | 13 | constructor(appContext: AppContext, stackConfig: any) { 14 | super(appContext, stackConfig); 15 | } 16 | 17 | @Override 18 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 19 | this.pipeline = pipeline; 20 | } 21 | 22 | @Override 23 | onPipelineName(): string { 24 | return 'Approach2Pipeline'; 25 | } 26 | 27 | @Override 28 | onActionFlow(): pipeline.ActionProps[] { 29 | return [ 30 | 31 | ]; 32 | } 33 | 34 | @Override 35 | protected onBuildPolicies(): iam.PolicyStatement[] | undefined { 36 | const statement = new iam.PolicyStatement(); 37 | statement.addActions( 38 | "cognito:*", 39 | "dynamodb:*", 40 | "application-autoscaling:*", 41 | "elasticloadbalancingv2:*", 42 | "elasticloadbalancing:*", 43 | ); 44 | statement.addResources("*"); 45 | 46 | return [statement]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-role-customzing1-stack.ts: -------------------------------------------------------------------------------- 1 | import * as iam from '@aws-cdk/aws-iam'; 2 | 3 | import * as base from '../../../lib/template/stack/base/base-stack'; 4 | import { AppContext } from '../../../lib/template/app-context'; 5 | 6 | import * as cicd from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 7 | 8 | 9 | export class Sample3RoleCustomizing1Stack extends base.BaseStack { 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | 14 | const pipeline = new cicd.PipelineSimplePattern(this, 'Approach1', { 15 | projectPrefix: this.projectPrefix, 16 | stackConfig: this.stackConfig, 17 | stackName: this.stackName, 18 | env: this.commonProps.env!, 19 | pipelineName: 'Approach1Pipeline', 20 | actionFlow: [ 21 | ], 22 | buildPolicies: this.createCustomPolicies() 23 | }); 24 | } 25 | 26 | private createCustomPolicies(): iam.PolicyStatement[] { 27 | const statement = new iam.PolicyStatement(); 28 | statement.addActions( 29 | "cognito:*", 30 | "dynamodb:*", 31 | "application-autoscaling:*", 32 | "elasticloadbalancingv2:*", 33 | "elasticloadbalancing:*", 34 | ); 35 | statement.addResources("*"); 36 | 37 | return [statement]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-service-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/base/base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | 4 | 5 | export class Sample3ServiceStack extends base.BaseStack { 6 | 7 | constructor(appContext: AppContext, stackConfig: any) { 8 | super(appContext, stackConfig); 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /infra/stack/sample3/sample3-temporary-disable-stack.ts: -------------------------------------------------------------------------------- 1 | import * as base from '../../../lib/template/stack/devops/pipeline-base-stack'; 2 | import { AppContext } from '../../../lib/template/app-context'; 3 | import { Override } from '../../../lib/template/stack/base/base-stack'; 4 | 5 | import * as pipeline from '../../../lib/template/construct/pattern/pipeline-simple-pattern'; 6 | 7 | 8 | export class Sample3TemporaryDisableStack extends base.PipelineBaseStack { 9 | private pipeline: pipeline.PipelineSimplePattern; 10 | 11 | constructor(appContext: AppContext, stackConfig: any) { 12 | super(appContext, stackConfig); 13 | } 14 | 15 | @Override 16 | onPostConstructor(pipeline: pipeline.PipelineSimplePattern): void { 17 | this.pipeline = pipeline; 18 | } 19 | 20 | @Override 21 | onPipelineName(): string { 22 | return 'Approach2Pipeline'; 23 | } 24 | 25 | @Override 26 | onActionFlow(): pipeline.ActionProps[] { 27 | return [ 28 | { 29 | Name: 'GitClone', 30 | Stage: 'SourceStage', 31 | Kind: pipeline.ActionKind.SourceCodeCommit, 32 | Enable: true, 33 | Detail: { 34 | RepositoryName: 'sample-repo', 35 | BranchName: 'release_cicd' 36 | } 37 | }, 38 | { 39 | Name: 'DeployStack1', 40 | Stage: "DevDeployStage", 41 | Kind: pipeline.ActionKind.BuildCodeBuild, 42 | Enable: false, 43 | Detail: { 44 | AppConfigFile: "config/app-config-sample1.json", 45 | BuildDeployStacks: { 46 | StackNameList: ['Sample1Service1Stack'], 47 | } 48 | } 49 | }, 50 | { 51 | Name: 'DeployStack2', 52 | Stage: "DevDeployStage", 53 | Kind: pipeline.ActionKind.BuildCodeBuild, 54 | Enable: true, 55 | Detail: { 56 | AppConfigFile: "config/app-config-sample1.json", 57 | BuildDeployStacks: { 58 | StackNameList: ['Sample2Service1Stack'], 59 | } 60 | } 61 | } 62 | ]; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@aws-samples/cdk-deploy-pipeline", 3 | "version": "0.1.0", 4 | "bin": { 5 | "cdk-deploy-pipeline": "infra/app-main.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@aws-cdk/assertions": "1.150.0", 15 | "@types/jest": "^26.0.10", 16 | "@types/node": "10.17.27", 17 | "jest": "^29.7.0", 18 | "ts-jest": "^26.2.0", 19 | "aws-cdk": "1.150.0", 20 | "ts-node": "^9.0.0", 21 | "typescript": "~3.9.7" 22 | }, 23 | "dependencies": { 24 | "@aws-cdk/aws-codecommit": "1.150.0", 25 | "@aws-cdk/aws-codebuild": "1.150.0", 26 | "@aws-cdk/aws-codepipeline": "1.150.0", 27 | "@aws-cdk/aws-codepipeline-actions": "1.150.0", 28 | "@aws-cdk/aws-ecs-patterns": "1.150.0", 29 | "@aws-cdk/cloudformation-include": "1.204.0", 30 | "@aws-cdk/aws-lambda-event-sources": "1.150.0", 31 | "@aws-cdk/aws-lambda": "1.150.0", 32 | "@aws-cdk/aws-iam": "1.150.0", 33 | "@aws-cdk/core": "1.150.0", 34 | "env-var": "6.3.0", 35 | "source-map-support": "^0.5.16" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/sample-stack.test.ts: -------------------------------------------------------------------------------- 1 | import { expect as expectCDK, matchTemplate, MatchStyle } from '@aws-cdk/assert'; 2 | import * as Sample from '../infra/stack/sample1/sample1-service-stack'; 3 | import { AppContext } from '../lib/template/app-context'; 4 | 5 | test('Empty Stack', () => { 6 | const appContext = new AppContext({ 7 | appConfigFileKey: 'APP_CONFIG' 8 | }) 9 | 10 | // WHEN 11 | const stack = new Sample.Sample1ServiceStack(appContext, {Name: 'SampleStack'}); 12 | 13 | // THEN 14 | expectCDK(stack).to(matchTemplate({ 15 | "Resources": {} 16 | }, MatchStyle.EXACT)) 17 | }); 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2018" 7 | ], 8 | "declaration": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "noImplicitThis": true, 13 | "alwaysStrict": true, 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": false, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "typeRoots": [ 23 | "./node_modules/@types" 24 | ] 25 | }, 26 | "exclude": [ 27 | "node_modules", 28 | "cdk.out" 29 | ] 30 | } 31 | --------------------------------------------------------------------------------