Created
December 11, 2024 16:13
-
-
Save matheus1lva/e3830702351c85ac5c5db8acb4a98c0b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { CfnOutput } from 'aws-cdk-lib' | |
import * as codebuild from 'aws-cdk-lib/aws-codebuild' | |
import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions' | |
import { StackContext } from 'sst/constructs' | |
import { BasePipeline } from './base-pipeline' | |
export interface PipelineStackConfig { | |
readonly bitbucketOwner: string | |
readonly bitbucketRepo: string | |
readonly bitbucketConnectionArn?: string | |
} | |
export function BranchPipeline({ stack, app }: StackContext) { | |
const { pipeline, buildRole, sourceOutput, pipelineRole } = new BasePipeline(stack, 'MainPipeline', { | |
app, | |
stack, | |
baseName: 'branch-pipeline', | |
pullRequests: true, | |
}) | |
const testProject = new codebuild.PipelineProject(stack, `BranchPipelineTestProject`, { | |
buildSpec: codebuild.BuildSpec.fromObject({ | |
version: '0.2', | |
phases: { | |
install: { | |
'runtime-versions': { | |
nodejs: '20', | |
}, | |
commands: ['npm install -g pnpm', 'pnpm install --frozen-lockfile --store-dir=/root/.pnpm-store'], | |
}, | |
build: { | |
commands: ['pnpm test'], | |
}, | |
}, | |
cache: { | |
paths: ['node_modules/**/*', '**/node_modules/**/*', 'web/.next/cache/**/*', '/root/.pnpm-store/**/*'], | |
}, | |
}), | |
environment: { | |
buildImage: codebuild.LinuxBuildImage.STANDARD_7_0, | |
privileged: true, | |
environmentVariables: { | |
DOCKER: { value: 'true' }, | |
NODE_OPTIONS: { value: '--max_old_space_size=8192' }, | |
}, | |
}, | |
role: buildRole, | |
}) | |
pipeline.addStage({ | |
stageName: 'Test', | |
actions: [ | |
new codepipeline_actions.CodeBuildAction({ | |
actionName: 'Test', | |
project: testProject, | |
input: sourceOutput, | |
role: pipelineRole, | |
}), | |
], | |
}) | |
// Add outputs | |
new CfnOutput(stack, 'PipelineURL', { | |
value: `https://${stack.region}.console.aws.amazon.com/codepipeline/home?region=${stack.region}#/view/${pipeline.pipelineName}`, | |
description: 'Pipeline URL', | |
}) | |
return { | |
pipeline, | |
} | |
} | |
import { CfnOutput, RemovalPolicy } from 'aws-cdk-lib' | |
import * as codebuild from 'aws-cdk-lib/aws-codebuild' | |
import * as codepipeline from 'aws-cdk-lib/aws-codepipeline' | |
import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions' | |
import * as iam from 'aws-cdk-lib/aws-iam' | |
import * as s3 from 'aws-cdk-lib/aws-s3' | |
import { Construct } from 'constructs' | |
import { StackContext, use } from 'sst/constructs' | |
import { BITBUCKET_BRANCH, BITBUCKET_OWNER, BITBUCKET_REPO } from './config' | |
import { Connections } from './connections' | |
export interface BasePipelineProps { | |
app: StackContext['app'] | |
stack: StackContext['stack'] | |
baseName: string | |
pullRequests?: boolean | |
branch?: string | |
triggerOnPush?: boolean | |
} | |
export class BasePipeline extends Construct { | |
pipeline: codepipeline.Pipeline | |
buildRole: iam.Role | |
sourceOutput: codepipeline.Artifact | |
sourceAction: codepipeline_actions.CodeStarConnectionsSourceAction | |
pipelineRole: iam.Role | |
constructor(scope: Construct, id: string, props: BasePipelineProps) { | |
super(scope, id) | |
const { app, stack, triggerOnPush = true } = props | |
const baseName = app.logicalPrefixedName(props.baseName) | |
this.sourceOutput = new codepipeline.Artifact(`${baseName}SourceOutput`) | |
const branch = props.branch ?? BITBUCKET_BRANCH | |
this.buildRole = new iam.Role(stack, `${baseName}CodeBuildRole`, { | |
assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), | |
}) | |
const { connectionArn, connectionPolicy } = use(Connections) | |
this.buildRole.addToPolicy( | |
new iam.PolicyStatement({ | |
effect: iam.Effect.ALLOW, | |
actions: [ | |
'logs:CreateLogGroup', | |
'logs:CreateLogStream', | |
'logs:PutLogEvents', | |
's3:GetBucketAcl', | |
's3:GetBucketLocation', | |
's3:GetObject', | |
's3:GetObjectVersion', | |
's3:PutObject', | |
'sts:AssumeRole', | |
], | |
resources: ['*'], | |
}), | |
) | |
// Grant permissions to the build role | |
this.buildRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess')) | |
// Create Pipeline role | |
this.pipelineRole = new iam.Role(stack, `${baseName}CodePipelineRole`, { | |
assumedBy: new iam.ServicePrincipal('codepipeline.amazonaws.com'), | |
}) | |
this.pipelineRole.addToPolicy( | |
new iam.PolicyStatement({ | |
effect: iam.Effect.ALLOW, | |
actions: [ | |
'logs:CreateLogGroup', | |
'logs:CreateLogStream', | |
'logs:PutLogEvents', | |
's3:GetObject', | |
's3:GetObjectVersion', | |
's3:GetBucketVersioning', | |
's3:PutObject', | |
'codebuild:BatchGetBuilds', | |
'codebuild:StartBuild', | |
'codebuild:StopBuild', | |
'codestar-connections:UseConnection', | |
'codestar-connections:GetConnection', | |
'codestar-connections:PassConnection', | |
], | |
resources: ['*'], | |
}), | |
) | |
this.pipelineRole.addManagedPolicy(connectionPolicy) | |
this.sourceAction = new codepipeline_actions.CodeStarConnectionsSourceAction({ | |
actionName: 'Source', | |
owner: BITBUCKET_OWNER, | |
repo: BITBUCKET_REPO, | |
branch: branch, | |
output: this.sourceOutput, | |
connectionArn: connectionArn, | |
triggerOnPush, | |
variablesNamespace: 'pipeVariables', | |
codeBuildCloneOutput: true, | |
role: this.pipelineRole, | |
}) | |
// create the artifact bucket | |
const artifactBucket = new s3.Bucket(stack, `${baseName}ArtifactBucket`, { | |
versioned: true, | |
removalPolicy: RemovalPolicy.DESTROY, | |
autoDeleteObjects: true, | |
}) | |
// Create Pipeline | |
this.pipeline = new codepipeline.Pipeline(stack, `${baseName}Pipeline`, { | |
pipelineType: codepipeline.PipelineType.V2, | |
pipelineName: `${baseName}-pipeline`, | |
crossAccountKeys: true, | |
restartExecutionOnUpdate: true, | |
executionMode: codepipeline.ExecutionMode.PARALLEL, | |
role: this.pipelineRole, | |
artifactBucket, | |
...(props.pullRequests && { | |
triggers: [ | |
{ | |
providerType: codepipeline.ProviderType.CODE_STAR_SOURCE_CONNECTION, | |
gitConfiguration: { | |
sourceAction: this.sourceAction, | |
pullRequestFilter: [ | |
{ | |
events: [codepipeline.GitPullRequestEvent.OPEN, codepipeline.GitPullRequestEvent.UPDATED], | |
branchesIncludes: [branch], | |
}, | |
], | |
}, | |
}, | |
], | |
}), | |
}) | |
// Create Lint Project | |
const lintProject = new codebuild.PipelineProject(stack, `${baseName}LintProject`, { | |
buildSpec: codebuild.BuildSpec.fromObject({ | |
version: '0.2', | |
phases: { | |
install: { | |
'runtime-versions': { | |
nodejs: '20', | |
}, | |
commands: ['npm install -g pnpm', 'pnpm install --store-dir=/root/.pnpm-store'], | |
}, | |
build: { | |
commands: ['pnpm lint'], | |
}, | |
}, | |
cache: { | |
paths: ['node_modules/**/*', '**/node_modules/**/*', 'web/.next/cache/**/*', '/root/.pnpm-store/**/*'], | |
}, | |
}), | |
environment: { | |
buildImage: codebuild.LinuxBuildImage.STANDARD_7_0, | |
privileged: true, | |
environmentVariables: { | |
DOCKER: { value: 'true' }, | |
NODE_OPTIONS: { value: '--max_old_space_size=8192' }, | |
}, | |
}, | |
role: this.buildRole, | |
}) | |
this.pipeline.addStage({ | |
stageName: 'Source', | |
actions: [this.sourceAction], | |
}) | |
this.pipeline.addStage({ | |
stageName: 'Lint', | |
actions: [ | |
new codepipeline_actions.CodeBuildAction({ | |
actionName: 'Lint', | |
project: lintProject, | |
input: this.sourceOutput, | |
role: this.pipelineRole, | |
}), | |
], | |
}) | |
new CfnOutput(stack, `${baseName}PipelineURL`, { | |
value: `https://${stack.region}.console.aws.amazon.com/codepipeline/home?region=${stack.region}#/view/${this.pipeline.pipelineName}`, | |
description: 'Pipeline URL', | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment