Skip to content
This repository was archived by the owner on Feb 15, 2024. It is now read-only.

Commit 5bf6154

Browse files
srijitmSrijit Mitra
andauthored
Feature/test stage (#21)
* Adding a test stage to the pipeline, cleaning up CodeBuild environment properties * Renaming stages for more clarity * Documentation updates Co-authored-by: Srijit Mitra <srijit@amazon.com>
1 parent bbcf5ad commit 5bf6154

File tree

8 files changed

+193
-49
lines changed

8 files changed

+193
-49
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ This project provides a serverless CI/CD platform leveraging native AWS services
44

55
This CI/CD platform is in use at a variety of AWS clients where the development teams are leveraging CloudFormation, Serverless Framework, AWS CDK and Terraform.
66

7+
## Getting started
8+
9+
- [Pre-Requisites](docs/prereq.md)
10+
- [Administrator Guide](docs/admin.md)
11+
- [Developer Guide](docs/developer.md)
12+
713
## Goals
814

915
- Pipelines as code.
@@ -39,9 +45,3 @@ The number of stages and their function is fully customizable e.g. adding a stag
3945
- AWS CloudWatch
4046
- AWS Systems Manager: Parameter Store
4147
- AWS CloudFormation
42-
43-
## Getting started
44-
45-
- [Pre-Requisites](docs/prereq.md)
46-
- [Administrator Guide](docs/admin.md)
47-
- [Developer Guide](docs/developer.md)

docs/developer.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@ As the developer you are responsible for maintaining a scripts folder with three
77
```text
88
scripts/build.sh
99
10+
scripts/test.sh
11+
1012
scripts/deploy.sh
1113
```
1214

13-
The build and deploy scripts must contain all the commands required to build your application, including the installation of any dependencies. The pipeline will execute the build script once. The deploy script will be executed once per target environment i.e dev, test and prod.
15+
The build,test and deploy scripts must contain all the commands required to build your application, including the installation of any dependencies. The pipeline will execute the build and test scripts once per run. The deploy script will be executed once per target environment i.e dev, test and prod.
1416

1517
This enforces the *"build once, deploy many"* paradigm and also ensures that your deployment script is environment agnostic.
1618

17-
Finally, you as the developer are now in complete control of how your applications gets deployed to your AWS accounts.
19+
Finally, you as the developer are now in complete control of how your applications get deployed to your AWS accounts.
1820

1921
## Detailed Instructions
2022

21-
Create a directory called scripts in the root of the application source code repository called ***scripts*** with 2 files:
23+
Create a directory called scripts in the root of the application source code repository called ***scripts*** with 3 files:
2224

2325
1. build.sh
2426

@@ -58,6 +60,20 @@ Create a directory called scripts in the root of the application source code rep
5860
echo "Nothing to build!"
5961
```
6062
63+
1. test.sh
64+
65+
Sample build script for a project which doesn't require a build
66+
67+
```bash
68+
#! /bin/bash
69+
70+
set -e
71+
set -u
72+
set -o pipefail
73+
74+
echo "Nothing to test. Tests executed as part of build."
75+
```
76+
6177
1. deploy.sh - A bash script which deploys the application. The shell script can trigger Terraform/Cloudformation/AWS CDK etc. Since the shell script will run in the AWS CodeBuild docker environment, as long as the binaries are available CodeBuild will be able to execute it.
6278

6379
Sample deployment script which installs AWS CDK and triggers the deployment

lib/pipelines/codecommit-pipeline.ts

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { Role } from '@aws-cdk/aws-iam'
3434
import { IFunction } from '@aws-cdk/aws-lambda'
3535
import { Repository } from '@aws-cdk/aws-codecommit'
3636
import { BuildProject } from '../projects/build-project'
37-
import { BuildEnvironmentVariableType } from '@aws-cdk/aws-codebuild'
37+
import { TestProject } from '../projects/test-project'
3838
import { Rule, Schedule } from '@aws-cdk/aws-events'
3939
import ssm = require('@aws-cdk/aws-ssm');
4040
import sns = require('@aws-cdk/aws-sns');
@@ -88,22 +88,19 @@ export class CodeCommitPipeline extends Pipeline {
8888
stringValue: notificationTopic.topicArn
8989
})
9090

91+
// Source Control Stage (CodeCommit)
9192
const sourceOutputArtifact = new Artifact('SourceArtifact')
92-
const buildOutputArtifact = new Artifact('BuildArtifact')
93-
9493
const codeCommitRepo = Repository.fromRepositoryName(
9594
scope,
9695
`${repoName}${repoBranch}CodeCommitRepo`,
9796
repoName
9897
)
9998

100-
// CodeCommit Repo Target
10199
codeCommitRepo.onCommit('OnCommit', {
102100
target: new targets.CodePipeline(this),
103101
branches: [`${repoBranch}`]
104102
})
105103

106-
// SourceAction
107104
const sourceAction = new CodeCommitSourceAction({
108105
repository: codeCommitRepo,
109106
branch: repoBranch,
@@ -116,29 +113,18 @@ export class CodeCommitPipeline extends Pipeline {
116113
actions: [sourceAction]
117114
})
118115

119-
// Build
120-
const sourceCodeBuildRole = new CodeBuildRole(this, 'sourceCodeBuildRole')
121-
122-
const buildProject = new BuildProject(this, 'sourceProject', {
123-
projectName: `${prefix}-${repoName}-${repoBranch}-build`,
124-
role: sourceCodeBuildRole,
125-
environmentVariables: {
126-
ARTIFACTS_BUCKET_NAME: {
127-
type: BuildEnvironmentVariableType.PLAINTEXT,
128-
value: artifactsBucket.bucketName
129-
},
130-
ARTIFACTS_BUCKET_ARN: {
131-
type: BuildEnvironmentVariableType.PLAINTEXT,
132-
value: artifactsBucket.bucketArn
133-
},
134-
REPO_NAME: {
135-
type: BuildEnvironmentVariableType.PLAINTEXT,
136-
value: repoName
137-
}
138-
}
116+
// Building Stage
117+
const buildOutputArtifact = new Artifact('BuildArtifact')
118+
const buildRole = new CodeBuildRole(this, 'buildRole')
119+
120+
const buildProject = new BuildProject(this, `${prefix}-${repoName}-${repoBranch}-build`, {
121+
repoName: repoName,
122+
role: buildRole,
123+
bucketArn: artifactsBucket.bucketArn,
124+
bucketName: artifactsBucket.bucketName
139125
})
140126

141-
buildProject.onStateChange('deploymentStatus', {
127+
buildProject.onStateChange('buildStatus', {
142128
target: new targets.LambdaFunction(emailHandler)
143129
})
144130

@@ -164,7 +150,34 @@ export class CodeCommitPipeline extends Pipeline {
164150
actions: [buildAction, semverAction]
165151
})
166152

167-
// Deploy
153+
// Testing Stage
154+
const testOutputArtifact = new Artifact('TestArtifact')
155+
const testRole = new CodeBuildRole(this, 'testRole')
156+
157+
const testProject = new TestProject(this, `${prefix}-${repoName}-${repoBranch}-test`, {
158+
repoName: repoName,
159+
role: testRole,
160+
bucketArn: artifactsBucket.bucketArn,
161+
bucketName: artifactsBucket.bucketName
162+
})
163+
164+
testProject.onStateChange('testStatus', {
165+
target: new targets.LambdaFunction(emailHandler)
166+
})
167+
168+
const testAction = new CodeBuildAction ({
169+
actionName: 'Test',
170+
outputs: [testOutputArtifact],
171+
input: buildOutputArtifact,
172+
project: testProject
173+
})
174+
175+
this.addStage({
176+
stageName: 'Test',
177+
actions: [testAction]
178+
})
179+
180+
// Deploying Stage (One stage per target environment)
168181
;[StageName.dev, StageName.test, StageName.prod].forEach((stageName: StageName) => {
169182

170183
if (config.accountIds[stageName]) {
@@ -196,13 +209,13 @@ export class CodeCommitPipeline extends Pipeline {
196209
const moduleDeployOutputArtifact = new Artifact()
197210
const moduleDeployAction = new CodeBuildAction({
198211
actionName: 'Deploy',
199-
input: buildOutputArtifact,
212+
input: testOutputArtifact,
200213
outputs: [moduleDeployOutputArtifact],
201214
project: deployProject,
202215
role: modulePipelineRole
203216
})
204217
this.addStage({
205-
stageName: `${stageName}-deploy`,
218+
stageName: `Deploy-to-${stageName}-environment`,
206219
actions: [moduleDeployAction]
207220
})
208221
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: MIT-0
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
6+
* software and associated documentation files (the "Software"), to deal in the Software
7+
* without restriction, including without limitation the rights to use, copy, modify,
8+
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9+
* permit persons to whom the Software is furnished to do so.
10+
*
11+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13+
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17+
*/
18+
19+
import { BuildEnvironmentVariableType, ComputeType,
20+
LinuxBuildImage } from '@aws-cdk/aws-codebuild'
21+
22+
export const defaultEnvironment = {
23+
buildImage: LinuxBuildImage.STANDARD_4_0,
24+
computeType: ComputeType.SMALL,
25+
privileged: true
26+
}
27+
28+
export function projectEnvironmentVars(props: {
29+
repoName: string
30+
bucketName: string
31+
bucketArn: string
32+
}) {
33+
const siteVars: any = {}
34+
35+
return {
36+
ARTIFACTS_BUCKET_NAME: {
37+
type: BuildEnvironmentVariableType.PLAINTEXT,
38+
value: props.bucketName
39+
},
40+
ARTIFACTS_BUCKET_ARN: {
41+
type: BuildEnvironmentVariableType.PLAINTEXT,
42+
value: props.bucketArn
43+
},
44+
REPO_NAME: {
45+
type: BuildEnvironmentVariableType.PLAINTEXT,
46+
value: props.repoName
47+
},
48+
...siteVars
49+
}
50+
}

lib/projects/build-project.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,25 @@
1919

2020
import { Construct } from '@aws-cdk/core'
2121
import { PipelineProject, ProjectProps, BuildSpec} from '@aws-cdk/aws-codebuild'
22-
import { defaultEnvironment } from './project-environment'
22+
import { defaultEnvironment } from './build-project-environment'
23+
import { projectEnvironmentVars } from './build-project-environment'
24+
import { Role } from '@aws-cdk/aws-iam'
2325

2426
export interface BuildProjectProps extends ProjectProps {
27+
repoName: string
28+
bucketName: string
29+
bucketArn: string
30+
role: Role
2531
}
2632

2733
export class BuildProject extends PipelineProject {
2834
constructor(scope: Construct, id: string, props: BuildProjectProps) {
29-
const { ...rest } = props
35+
const { repoName, bucketName, bucketArn } = props
3036
super(scope, id, {
37+
projectName: id,
38+
role: props.role,
39+
environment: defaultEnvironment,
40+
environmentVariables: projectEnvironmentVars({ repoName, bucketName, bucketArn }),
3141
buildSpec: BuildSpec.fromObject({
3242
version: '0.2',
3343
phases: {
@@ -40,18 +50,12 @@ export class BuildProject extends PipelineProject {
4050
commands: [
4151
'bash ${CODEBUILD_SRC_DIR}/scripts/build.sh'
4252
]
43-
},
44-
post_build: {
45-
commands: [
46-
]
4753
}
4854
},
4955
artifacts: {
5056
files: '**/*'
5157
}
52-
}),
53-
environment: defaultEnvironment,
54-
...rest
58+
})
5559
})
5660
}
5761
}

lib/projects/deploy-project.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
import { PipelineProject, BuildSpec } from '@aws-cdk/aws-codebuild'
2121
import { Construct } from '@aws-cdk/core'
22-
import { defaultEnvironment } from './project-environment'
23-
import { projectEnvironmentVars } from './project-environment'
22+
import { defaultEnvironment } from './deploy-project-environment'
23+
import { projectEnvironmentVars } from './deploy-project-environment'
2424
import { Role } from '@aws-cdk/aws-iam'
2525
import { StageName } from '../../config/config';
2626

lib/projects/test-project.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: MIT-0
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
6+
* software and associated documentation files (the "Software"), to deal in the Software
7+
* without restriction, including without limitation the rights to use, copy, modify,
8+
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9+
* permit persons to whom the Software is furnished to do so.
10+
*
11+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13+
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17+
*/
18+
19+
20+
import { Construct } from '@aws-cdk/core'
21+
import { PipelineProject, ProjectProps, BuildSpec} from '@aws-cdk/aws-codebuild'
22+
import { defaultEnvironment } from './build-project-environment'
23+
import { projectEnvironmentVars } from './build-project-environment'
24+
import { Role } from '@aws-cdk/aws-iam'
25+
26+
export interface BuildProjectProps extends ProjectProps {
27+
repoName: string
28+
bucketName: string
29+
bucketArn: string
30+
role: Role
31+
}
32+
33+
export class TestProject extends PipelineProject {
34+
constructor(scope: Construct, id: string, props: BuildProjectProps) {
35+
const { repoName, bucketName, bucketArn } = props
36+
super(scope, id, {
37+
projectName: id,
38+
role: props.role,
39+
environment: defaultEnvironment,
40+
environmentVariables: projectEnvironmentVars({ repoName, bucketName, bucketArn }),
41+
buildSpec: BuildSpec.fromObject({
42+
version: '0.2',
43+
phases: {
44+
install: {
45+
'runtime-versions': {
46+
nodejs: '10'
47+
}
48+
},
49+
build: {
50+
commands: [
51+
'bash ${CODEBUILD_SRC_DIR}/scripts/test.sh'
52+
]
53+
}
54+
},
55+
artifacts: {
56+
files: '**/*'
57+
}
58+
})
59+
})
60+
}
61+
}

0 commit comments

Comments
 (0)