From 95bb1ad60e600007421acd6d160e0d7fb9bc0389 Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Thu, 19 Mar 2020 08:20:34 -0700 Subject: [PATCH] feat(codepipeline): add experimental support for the BitBucket source action (#6756) Fixes #6710 Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .../aws-codepipeline-actions/README.md | 31 +++++ .../lib/bitbucket/source-action.ts | 112 ++++++++++++++++++ .../aws-codepipeline-actions/lib/index.ts | 1 + .../bitbucket/test.bitbucket-source-action.ts | 76 ++++++++++++ 4 files changed, 220 insertions(+) create mode 100644 packages/@aws-cdk/aws-codepipeline-actions/lib/bitbucket/source-action.ts create mode 100644 packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/test.bitbucket-source-action.ts diff --git a/packages/@aws-cdk/aws-codepipeline-actions/README.md b/packages/@aws-cdk/aws-codepipeline-actions/README.md index 92102fc07e18a..8429662b69fd8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/README.md +++ b/packages/@aws-cdk/aws-codepipeline-actions/README.md @@ -106,6 +106,37 @@ new codepipeline_actions.CodeBuildAction({ }); ``` +#### BitBucket + +CodePipeline can use a BitBucket Git repository as a source: + +**Note**: you have to manually connect CodePipeline through the AWS Console with your BitBucket account. +This is a one-time operation for a given AWS account in a given region. +The simplest way to do that is to either start creating a new CodePipeline, +or edit na existing one, while being logged in to BitBucket. +Choose BitBucket as the source, +and grant CodePipeline permissions to your BitBucket account. +Copy & paste the Connection ARN that you get in the console, +or use the [`codestar-connections list-connections` AWS CLI operation](https://docs.aws.amazon.com/cli/latest/reference/codestar-connections/list-connections.html) +to find it. +After that, you can safely abort creating or editing the pipeline - +the connection has already been created. + +```typescript +const sourceOutput = new codepipeline.Artifact(); +const sourceAction = new codepipeline_actions.BitBucketSourceAction({ + actionName: 'BitBucket_Source', + owner: 'aws', + repo: 'aws-cdk', + output: sourceOutput, + connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh', +}); +``` + +**Note**: as this feature is still in Beta in CodePipeline, +the above class `BitBucketSourceAction` is experimental - +we reserve the right to make breaking changes to it. + #### AWS S3 To use an S3 Bucket as a source in CodePipeline: diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/bitbucket/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/bitbucket/source-action.ts new file mode 100644 index 0000000000000..9c005cc849edc --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/bitbucket/source-action.ts @@ -0,0 +1,112 @@ +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as iam from '@aws-cdk/aws-iam'; +import { Construct } from '@aws-cdk/core'; +import { Action } from '../action'; +import { sourceArtifactBounds } from '../common'; + +/** + * Construction properties for {@link BitBucketSourceAction}. + * + * @experimental + */ +export interface BitBucketSourceActionProps extends codepipeline.CommonAwsActionProps { + /** + * The output artifact that this action produces. + * Can be used as input for further pipeline actions. + */ + readonly output: codepipeline.Artifact; + + /** + * The ARN of the CodeStar Connection created in the AWS console + * that has permissions to access this BitBucket repository. + * + * @example 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh' + * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-create.html + */ + readonly connectionArn: string; + + /** + * The owning user or organization of the repository. + * + * @example 'aws' + */ + readonly owner: string; + + /** + * The name of the repository. + * + * @example 'aws-cdk' + */ + readonly repo: string; + + /** + * The branch to build. + * + * @default 'master' + */ + readonly branch?: string; + + // long URL in @see + // tslint:disable:max-line-length + /** + * Whether the output should be the contents of the repository + * (which is the default), + * or a link that allows CodeBuild to clone the repository before building. + * + * **Note**: if this option is true, + * then only CodeBuild actions can use the resulting {@link output}. + * + * @default false + * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodestarConnectionSource.html#action-reference-CodestarConnectionSource-config + */ + readonly codeBuildCloneOutput?: boolean; + // tslint:enable:max-line-length +} + +/** + * A CodePipeline source action for BitBucket. + * + * @experimental + */ +export class BitBucketSourceAction extends Action { + private readonly props: BitBucketSourceActionProps; + + constructor(props: BitBucketSourceActionProps) { + super({ + ...props, + category: codepipeline.ActionCategory.SOURCE, + owner: 'AWS', // because props also has a (different!) owner property! + provider: 'CodeStarSourceConnection', + artifactBounds: sourceArtifactBounds(), + outputs: [props.output], + }); + + this.props = props; + } + + protected bound(_scope: Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { + // https://docs.aws.amazon.com/codepipeline/latest/userguide/security-iam.html#how-to-update-role-new-services + options.role.addToPolicy(new iam.PolicyStatement({ + actions: [ + 'codestar-connections:UseConnection', + ], + resources: [ + this.props.connectionArn, + ], + })); + + // the action needs to write the output to the pipeline bucket + options.bucket.grantReadWrite(options.role); + + return { + configuration: { + ConnectionArn: this.props.connectionArn, + FullRepositoryId: `${this.props.owner}/${this.props.repo}`, + BranchName: this.props.branch ?? 'master', + OutputArtifactFormat: this.props.codeBuildCloneOutput === true + ? 'CODEBUILD_CLONE_REF' + : undefined, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts index d27a31e802791..b57acaec03b0d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/index.ts @@ -1,4 +1,5 @@ export * from './alexa-ask/deploy-action'; +export * from './bitbucket/source-action'; export * from './cloudformation/pipeline-actions'; export * from './codebuild/build-action'; export * from './codecommit/source-action'; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/test.bitbucket-source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/test.bitbucket-source-action.ts new file mode 100644 index 0000000000000..f26a2816945eb --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/bitbucket/test.bitbucket-source-action.ts @@ -0,0 +1,76 @@ +import { expect, haveResourceLike } from "@aws-cdk/assert"; +import * as codebuild from '@aws-cdk/aws-codebuild'; +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import { Stack } from "@aws-cdk/core"; +import { Test } from 'nodeunit'; +import * as cpactions from '../../lib'; + +// tslint:disable:object-literal-key-quotes + +export = { + 'BitBucket source Action': { + 'produces the correct configuration when added to a pipeline'(test: Test) { + const stack = new Stack(); + + const sourceOutput = new codepipeline.Artifact(); + new codepipeline.Pipeline(stack, 'Pipeline', { + stages: [ + { + stageName: 'Source', + actions: [ + new cpactions.BitBucketSourceAction({ + actionName: 'BitBucket', + owner: 'aws', + repo: 'aws-cdk', + output: sourceOutput, + connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh', + }), + ], + }, + { + stageName: 'Build', + actions: [ + new cpactions.CodeBuildAction({ + actionName: 'CodeBuild', + project: new codebuild.PipelineProject(stack, 'MyProject'), + input: sourceOutput, + }), + ], + }, + ], + }); + + expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + "Stages": [ + { + "Name": "Source", + "Actions": [ + { + "Name": "BitBucket", + "ActionTypeId": { + "Owner": "AWS", + "Provider": "CodeStarSourceConnection", + }, + "Configuration": { + "ConnectionArn": "arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh", + "FullRepositoryId": "aws/aws-cdk", + "BranchName": "master", + }, + }, + ], + }, + { + "Name": "Build", + "Actions": [ + { + "Name": "CodeBuild", + }, + ], + }, + ], + })); + + test.done(); + }, + }, +};