Skip to content

Commit

Permalink
feat(aws-codepipeline-actions): Add Full Clone support for CodeCommit (
Browse files Browse the repository at this point in the history
…#12558)

Add `codeBuildCloneOutput` property to the CodeCommit source action.

It automatically adds the `codecommit:GetRepository` permission to the CodeCommitSourceAction role.
It will also add the `codecommit:GitPull` permission to any CodeBuildAction using the artifact from CodeCommitSourceAction as input.

Closes #12236

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
DaWyz authored Jan 21, 2021
1 parent 6716181 commit d169688
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 5 deletions.
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-codepipeline-actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,26 @@ const sourceAction = new codepipeline_actions.CodeCommitSourceAction({
});
```

If you want to clone the entire CodeCommit repository (only available for CodeBuild actions),
you can set the `codeBuildCloneOutput` property to `true`:

```ts
const sourceOutput = new codepipeline.Artifact();
const sourceAction = new codepipeline_actions.CodeCommitSourceAction({
actionName: 'CodeCommit',
repository: repo,
output: sourceOutput,
codeBuildCloneOutput: true,
});

const buildAction = new codepipeline_actions.CodeBuildAction({
actionName: 'CodeBuild',
project,
input: sourceOutput, // The build action must use the CodeCommitSourceAction output as input.
outputs: [new codepipeline.Artifact()], // optional
});
```

The CodeCommit source action emits variables:

```ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as iam from '@aws-cdk/aws-iam';
import * as cdk from '@aws-cdk/core';
import { BitBucketSourceAction } from '..';
import { Action } from '../action';
import { CodeCommitSourceAction } from '../codecommit/source-action';

// keep this import separate from other imports to reduce chance for merge conflicts with v2-main
// eslint-disable-next-line no-duplicate-imports, import/order
Expand Down Expand Up @@ -176,17 +177,28 @@ export class CodeBuildAction extends Action {
});
}

// if any of the inputs come from the BitBucketSourceAction
// with codeBuildCloneOutput=true,
// grant the Project's Role to use the connection
for (const inputArtifact of this.actionProperties.inputs || []) {
// if any of the inputs come from the BitBucketSourceAction
// with codeBuildCloneOutput=true,
// grant the Project's Role to use the connection
const connectionArn = inputArtifact.getMetadata(BitBucketSourceAction._CONNECTION_ARN_PROPERTY);
if (connectionArn) {
this.props.project.addToRolePolicy(new iam.PolicyStatement({
actions: ['codestar-connections:UseConnection'],
resources: [connectionArn],
}));
}

// if any of the inputs come from the CodeCommitSourceAction
// with codeBuildCloneOutput=true,
// grant the Project's Role git pull access to the repository
const codecommitRepositoryArn = inputArtifact.getMetadata(CodeCommitSourceAction._FULL_CLONE_ARN_PROPERTY);
if (codecommitRepositoryArn) {
this.props.project.addToRolePolicy(new iam.PolicyStatement({
actions: ['codecommit:GitPull'],
resources: [codecommitRepositoryArn],
}));
}
}

const configuration: any = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,33 @@ export interface CodeCommitSourceActionProps extends codepipeline.CommonAwsActio
* @default a new role will be created.
*/
readonly eventRole?: iam.IRole;

/**
* 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-CodeCommit.html
*/
readonly codeBuildCloneOutput?: boolean;
}

/**
* CodePipeline Source that is provided by an AWS CodeCommit repository.
*/
export class CodeCommitSourceAction extends Action {
/**
* The name of the property that holds the ARN of the CodeCommit Repository
* inside of the CodePipeline Artifact's metadata.
*
* @internal
*/
public static readonly _FULL_CLONE_ARN_PROPERTY = 'CodeCommitCloneRepositoryArn';

private readonly branch: string;
private readonly props: CodeCommitSourceActionProps;

Expand All @@ -100,6 +121,10 @@ export class CodeCommitSourceAction extends Action {
throw new Error("'branch' parameter cannot be an empty string");
}

if (props.codeBuildCloneOutput === true) {
props.output.setMetadata(CodeCommitSourceAction._FULL_CLONE_ARN_PROPERTY, props.repository.repositoryArn);
}

super({
...props,
resource: props.repository,
Expand Down Expand Up @@ -144,14 +169,15 @@ export class CodeCommitSourceAction extends Action {
options.bucket.grantReadWrite(options.role);

// https://docs.aws.amazon.com/codecommit/latest/userguide/auth-and-access-control-permissions-reference.html#aa-acp
options.role.addToPolicy(new iam.PolicyStatement({
options.role.addToPrincipalPolicy(new iam.PolicyStatement({
resources: [this.props.repository.repositoryArn],
actions: [
'codecommit:GetBranch',
'codecommit:GetCommit',
'codecommit:UploadArchive',
'codecommit:GetUploadArchiveStatus',
'codecommit:CancelUploadArchive',
...(this.props.codeBuildCloneOutput === true ? ['codecommit:GetRepository'] : []),
],
}));

Expand All @@ -160,6 +186,9 @@ export class CodeCommitSourceAction extends Action {
RepositoryName: this.props.repository.repositoryName,
BranchName: this.branch,
PollForSourceChanges: this.props.trigger === CodeCommitTrigger.POLL,
OutputArtifactFormat: this.props.codeBuildCloneOutput === true
? 'CODEBUILD_CLONE_REF'
: undefined,
},
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { countResources, expect, haveResourceLike, not } from '@aws-cdk/assert';
import { arrayWith, countResources, expect, haveResourceLike, not, objectLike } from '@aws-cdk/assert';
import * as codebuild from '@aws-cdk/aws-codebuild';
import * as codecommit from '@aws-cdk/aws-codecommit';
import * as codepipeline from '@aws-cdk/aws-codepipeline';
Expand Down Expand Up @@ -269,6 +269,111 @@ export = {
test.done();
},

'allows to enable full clone'(test: Test) {
const stack = new Stack();

const sourceOutput = new codepipeline.Artifact();
new codepipeline.Pipeline(stack, 'P', {
stages: [
{
stageName: 'Source',
actions: [
new cpactions.CodeCommitSourceAction({
actionName: 'CodeCommit',
repository: new codecommit.Repository(stack, 'R', {
repositoryName: 'repository',
}),
branch: Lazy.string({ produce: () => 'my-branch' }),
output: sourceOutput,
codeBuildCloneOutput: true,
}),
],
},
{
stageName: 'Build',
actions: [
new cpactions.CodeBuildAction({
actionName: 'Build',
project: new codebuild.PipelineProject(stack, 'CodeBuild'),
input: sourceOutput,
}),
],
},
],
});

expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', {
'Stages': [
{
'Name': 'Source',
'Actions': [{
'Configuration': {
'OutputArtifactFormat': 'CODEBUILD_CLONE_REF',
},
}],
},
{
'Name': 'Build',
'Actions': [
{
'Name': 'Build',
},
],
},
],
}));

expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
'PolicyDocument': {
'Statement': arrayWith(
objectLike({
'Action': [
'logs:CreateLogGroup',
'logs:CreateLogStream',
'logs:PutLogEvents',
],
}),
objectLike({
'Action': 'codecommit:GitPull',
'Effect': 'Allow',
'Resource': {
'Fn::GetAtt': [
'RC21A1702',
'Arn',
],
},
}),
),
},
}));

expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
'PolicyDocument': {
'Statement': arrayWith(
objectLike({
'Action': [
'codecommit:GetBranch',
'codecommit:GetCommit',
'codecommit:UploadArchive',
'codecommit:GetUploadArchiveStatus',
'codecommit:CancelUploadArchive',
'codecommit:GetRepository',
],
'Effect': 'Allow',
'Resource': {
'Fn::GetAtt': [
'RC21A1702',
'Arn',
],
},
}),
),
},
}));

test.done();
},

'uses the role when passed'(test: Test) {
const stack = new Stack();

Expand Down

0 comments on commit d169688

Please sign in to comment.