diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codestar-connections/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codestar-connections/source-action.ts index ca47af5c29c8e..71ff24eb35114 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codestar-connections/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codestar-connections/source-action.ts @@ -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}. */ @@ -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({ diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts index 75fe764109b25..97cc21cbb99ef 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts @@ -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'; @@ -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): 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): 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: [ @@ -177,6 +305,9 @@ function createBitBucketAndCodeBuildPipeline(stack: Stack, props: Partial