in lib/pipelines/simple-cicd-pipeline.ts [56:275]
constructor(scope: Construct, id: string, props: SimpleCicdPipelineProps) {
const {
artifactsBucket,
prefix,
ssmRoot,
repo,
pipelineName,
modulePipelineRole,
emailHandler,
semverHandler,
...rest
} = props
super(scope, id, {
pipelineName,
artifactBucket: artifactsBucket,
role: modulePipelineRole,
...rest
})
let repoName = repo.repository
let repoBranch = repo.branch
// Provision SNS Topic for notifications
const notificationTopic = new sns.Topic(this, 'Topic', {
displayName: `${pipelineName}-cicd-topic` ,
topicName: `${pipelineName}-cicd-topic`
})
new ssm.StringParameter(this, 'SnsTopicArn', {
description: 'CICD SNS Topic Arn',
parameterName: `${ssmRoot}/sns-topic/${repoName}-${repoBranch}-arn`,
stringValue: notificationTopic.topicArn
})
// Source Control Stage (CodeCommit)
const sourceOutputArtifact = new Artifact('SourceArtifact')
switch (repo.type) {
case TriggerType.CodeCommit: {
const codeCommitRepo = Repository.fromRepositoryName(
scope,
`${repoName}${repoBranch}CodeCommitRepo`,
repoName
)
codeCommitRepo.onCommit('OnCommit', {
target: new targets.CodePipeline(this),
branches: [`${repoBranch}`]
})
const sourceAction = new CodeCommitSourceAction({
repository: codeCommitRepo,
branch: repoBranch,
output: sourceOutputArtifact,
actionName: 'Source'
})
this.addStage({
stageName: 'Source',
actions: [sourceAction]
})
break
}
case TriggerType.GitHub: {
const oauth = SecretValue.secretsManager(config.deployment['githubSecret'])
const sourceAction = new GitHubSourceAction({
actionName: 'Source',
oauthToken: oauth,
owner: repo.owner,
repo: repoName,
branch: repoBranch,
output: sourceOutputArtifact,
})
this.addStage({
stageName: 'Source',
actions: [sourceAction]
})
break
}
}
// Building Stage
const buildOutputArtifact = new Artifact('BuildArtifact')
const buildRole = new CodeBuildRole(this, 'buildRole')
const buildProject = new BuildProject(this, `${pipelineName}-build`, {
repoName: repoName,
role: buildRole,
bucketArn: artifactsBucket.bucketArn,
bucketName: artifactsBucket.bucketName
})
buildProject.onStateChange('build', {
target: new targets.LambdaFunction(emailHandler)
})
const buildAction = new CodeBuildAction ({
actionName: 'Build',
outputs: [buildOutputArtifact],
input: sourceOutputArtifact,
project: buildProject
})
const semverAction = new LambdaInvokeAction({
actionName: 'SemverLambda',
lambda: semverHandler,
userParameters: {
'repo': repoName,
'branch': repoBranch
},
runOrder: 20
});
this.addStage({
stageName: 'Build',
actions: [buildAction, semverAction]
})
// Push SemVer to Parameter Store
let semverParam = `${ssmRoot}/simple-cicd/${repoName}/${repoBranch}/version`
new ssm.StringParameter(this, `${repoName}${repoBranch}Version`, {
description: `Version number of ${repoName}/${repoBranch}`,
parameterName: semverParam,
stringValue: '0.1.0'
})
// Testing Stage
const testOutputArtifact = new Artifact('TestArtifact')
const testRole = new CodeBuildRole(this, 'testRole')
const testProject = new TestProject(this, `${pipelineName}-test`, {
repoName: repoName,
role: testRole,
bucketArn: artifactsBucket.bucketArn,
bucketName: artifactsBucket.bucketName,
semverParameter: semverParam
})
testProject.onStateChange('test', {
target: new targets.LambdaFunction(emailHandler)
})
const testAction = new CodeBuildAction ({
actionName: 'Test',
outputs: [testOutputArtifact],
input: buildOutputArtifact,
project: testProject
})
this.addStage({
stageName: 'Test',
actions: [testAction]
})
// Target defaults
// TODO: Make this user configurable
let targetEnvs = [StageName.dev, StageName.test, StageName.prod]
if (repo.targets) {
targetEnvs = repo.targets
}
// Deploying Stage (One stage per target environment)
targetEnvs.forEach((stageName: StageName) => {
// Only add stage if accountId is set
if (config.accountIds[stageName]) {
const deployRole = new CodeBuildRole(this, `${stageName}DeployRole`, { stageName })
const deployProject = new DeployProject(
this,
`${pipelineName}-${stageName}-deploy`,
{
repoName: repoName,
stageName: stageName,
role: deployRole,
bucketArn: artifactsBucket.bucketArn,
bucketName: artifactsBucket.bucketName,
semverParameter: semverParam
}
)
deployProject.onStateChange('deploy', {
target: new targets.LambdaFunction(emailHandler)
})
if (stageName == 'prod') {
this.addStage({
stageName: 'prod-approval',
actions: [new ManualApprovalAction({
actionName: 'Promote'
})]
})
}
const moduleDeployOutputArtifact = new Artifact()
const moduleDeployAction = new CodeBuildAction({
actionName: 'Deploy',
input: testOutputArtifact,
outputs: [moduleDeployOutputArtifact],
project: deployProject,
role: modulePipelineRole
})
this.addStage({
stageName: `Deploy-to-${stageName}-environment`,
actions: [moduleDeployAction]
})
}
})
if (repo.cron) {
const cwRule = new Rule(this, `${pipelineName}-cronTrigger`, {
ruleName: `${pipelineName}-trigger`,
enabled: true,
schedule: Schedule.expression(`cron(${repo.cron})`)
})
cwRule.addTarget(new targets.CodePipeline(this))
}
}