Skip to content

Commit

Permalink
feat(code_pipeline_actions): variables for source action
Browse files Browse the repository at this point in the history
Adds `variables` method that allows to retrieve action's
[variables](https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-variables.html)
using type safe approach.
With that we can rely on compiler to pick up incorrect access instead
of hacking it with plain strings.

fixes: #17807
  • Loading branch information
kornicameister committed Dec 18, 2021
1 parent bdd91cb commit 891c647
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ import { sourceArtifactBounds } from '../common';
// eslint-disable-next-line no-duplicate-imports, import/order
import { Construct } from '@aws-cdk/core';

/**
* The CodePipeline variables emitted by CodeStar source Action.
*/
export interface CodeStarSourceVariables {
/** The name of the repository this action points to. */
readonly fullRepositoryName: string;
/** The name of the branch this action tracks. */
readonly branchName: string;
/** The date the currently last commit on the tracked branch was authored, in ISO-8601 format. */
readonly authorDate: string;
/** The SHA1 hash of the currently last commit on the tracked branch. */
readonly commitId: string;
/** The message of the currently last commit on the tracked branch. */
readonly commitMessage: string;
/** The connection ARN this source uses. */
readonly connectionArn: string;
}

/**
* Construction properties for {@link CodeStarConnectionsSourceAction}.
*/
Expand Down Expand Up @@ -101,6 +119,18 @@ export class CodeStarConnectionsSourceAction extends Action {
this.props = props;
}

/** The variables emitted by this action. */
public get variables(): CodeStarSourceVariables {
return {
fullRepositoryName: this.variableExpression('FullRepositoryName'),
branchName: this.variableExpression('BranchName'),
authorDate: this.variableExpression('AuthorDate'),
commitId: this.variableExpression('CommitId'),
commitMessage: this.variableExpression('CommitMessage'),
connectionArn: this.variableExpression('ConnectionArn'),
};
}

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({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '@aws-cdk/assert-internal/jest';
import { arrayWith, objectLike } from '@aws-cdk/assert-internal';
import { arrayWith, objectLike, SynthUtils } from '@aws-cdk/assert-internal';
import * as codebuild from '@aws-cdk/aws-codebuild';
import * as codepipeline from '@aws-cdk/aws-codepipeline';
import { Stack } from '@aws-cdk/core';
Expand Down Expand Up @@ -148,27 +148,155 @@ describe('CodeStar Connections source Action', () => {
],
});

});

test('exposes variables', () => {
const stack = new Stack();

createBitBucketAndCodeBuildPipeline(stack, {
triggerOnPush: false,
});

expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', {
'Stages': [
{
'Name': 'Source',
},
{
'Name': 'Build',
'Actions': [
{
'Name': 'CodeBuild',
'Configuration': {
'EnvironmentVariables': '[{"name":"CommitId","type":"PLAINTEXT","value":"#{Source_BitBucket_NS.CommitId}"}]',
},
},
],
},
],
});

});

test('exposes variables with custom namespace', () => {
const stack = new Stack();

createBitBucketAndCodeBuildPipeline(stack, {
triggerOnPush: false,
variablesNamespace: 'kornicameister',
});

expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', {
'Stages': [
{
'Name': 'Source',
'Actions': [
{
'Name': 'BitBucket',
'Namespace': 'kornicameister',
},
],
},
{
'Name': 'Build',
'Actions': [
{
'Name': 'CodeBuild',
'Configuration': {
'EnvironmentVariables': '[{"name":"CommitId","type":"PLAINTEXT","value":"#{kornicameister.CommitId}"}]',
},
},
],
},
],
});


});

test('fail if variable from unused action is referenced', () => {
const stack = new Stack();

createUnreferencedVariablePipeline(stack);

expect(() => {
SynthUtils.synthesize(stack);
}).toThrow(/Cannot reference variables of action 'BitBucketUnused', as that action was never added to a pipeline/);

});

test('fail if variable from unused action with custom namespace is referenced', () => {
const stack = new Stack();

createUnreferencedVariablePipeline(stack, 'kornicameister');

expect(() => {
SynthUtils.synthesize(stack);
}).toThrow(/Cannot reference variables of action 'BitBucketUnused', as that action was never added to a pipeline/);

});

});

function createBitBucketAndCodeBuildPipeline(stack: Stack, props: Partial<cpactions.BitBucketSourceActionProps>): void {
function createUnreferencedVariablePipeline(stack: Stack, variablesNamespace?: string) {
const sourceOutput = new codepipeline.Artifact();
const sourceAction = new cpactions.CodeStarConnectionsSourceAction({
actionName: 'BitBucketUsed',
owner: 'aws',
repo: 'aws-cdk',
output: sourceOutput,
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
});
const unusedSourceAction = new cpactions.CodeStarConnectionsSourceAction({
actionName: 'BitBucketUnused',
owner: 'aws',
repo: 'aws-cdk',
output: sourceOutput,
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
variablesNamespace: variablesNamespace,
});

new codepipeline.Pipeline(stack, 'Pipeline', {
stages: [
{
stageName: 'Source',
actions: [sourceAction],
},
{
stageName: 'Build',
actions: [
new cpactions.CodeStarConnectionsSourceAction({
actionName: 'BitBucket',
owner: 'aws',
repo: 'aws-cdk',
output: sourceOutput,
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
...props,
new cpactions.CodeBuildAction({
actionName: 'CodeBuild',
project: new codebuild.PipelineProject(stack, 'MyProject'),
input: sourceOutput,
outputs: [new codepipeline.Artifact()],
environmentVariables: {
CommitId: { value: unusedSourceAction.variables.commitId },
},
}),
],
},
],
});
}

function createBitBucketAndCodeBuildPipeline(stack: Stack, props: Partial<cpactions.BitBucketSourceActionProps>): void {
const sourceOutput = new codepipeline.Artifact();
const sourceAction = new cpactions.CodeStarConnectionsSourceAction({
actionName: 'BitBucket',
owner: 'aws',
repo: 'aws-cdk',
output: sourceOutput,
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
...props,
});

new codepipeline.Pipeline(stack, 'Pipeline', {
stages: [
{
stageName: 'Source',
actions: [sourceAction],
},
{
stageName: 'Build',
actions: [
Expand All @@ -177,6 +305,9 @@ function createBitBucketAndCodeBuildPipeline(stack: Stack, props: Partial<cpacti
project: new codebuild.PipelineProject(stack, 'MyProject'),
input: sourceOutput,
outputs: [new codepipeline.Artifact()],
environmentVariables: {
CommitId: { value: sourceAction.variables.commitId },
},
}),
],
},
Expand Down

0 comments on commit 891c647

Please sign in to comment.