Skip to content

Commit c99da16

Browse files
feat(codepipeline): variables for CodeStar Connections source Action (#18086)
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 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 93d39e4 commit c99da16

File tree

3 files changed

+188
-13
lines changed

3 files changed

+188
-13
lines changed

packages/@aws-cdk/aws-codepipeline-actions/README.md

+29
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,35 @@ const sourceAction = new codepipeline_actions.CodeStarConnectionsSourceAction({
198198
You can also use the `CodeStarConnectionsSourceAction` to connect to GitHub, in the same way
199199
(you just have to select GitHub as the source when creating the connection in the console).
200200

201+
Similarly to `GitHubSourceAction`, `CodeStarConnectionsSourceAction` also emits the variables:
202+
203+
```ts
204+
declare const project: codebuild.Project;
205+
206+
const sourceOutput = new codepipeline.Artifact();
207+
const sourceAction = new codepipeline_actions.CodeStarConnectionsSourceAction({
208+
actionName: 'BitBucket_Source',
209+
owner: 'aws',
210+
repo: 'aws-cdk',
211+
output: sourceOutput,
212+
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
213+
variablesNamespace: 'SomeSpace', // optional - by default, a name will be generated for you
214+
});
215+
216+
// later:
217+
218+
new codepipeline_actions.CodeBuildAction({
219+
actionName: 'CodeBuild',
220+
project,
221+
input: sourceOutput,
222+
environmentVariables: {
223+
COMMIT_ID: {
224+
value: sourceAction.variables.commitId,
225+
},
226+
},
227+
});
228+
```
229+
201230
### AWS S3 Source
202231

203232
To use an S3 Bucket as a source in CodePipeline:

packages/@aws-cdk/aws-codepipeline-actions/lib/codestar-connections/source-action.ts

+30
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,24 @@ import { sourceArtifactBounds } from '../common';
88
// eslint-disable-next-line no-duplicate-imports, import/order
99
import { Construct } from '@aws-cdk/core';
1010

11+
/**
12+
* The CodePipeline variables emitted by CodeStar source Action.
13+
*/
14+
export interface CodeStarSourceVariables {
15+
/** The name of the repository this action points to. */
16+
readonly fullRepositoryName: string;
17+
/** The name of the branch this action tracks. */
18+
readonly branchName: string;
19+
/** The date the currently last commit on the tracked branch was authored, in ISO-8601 format. */
20+
readonly authorDate: string;
21+
/** The SHA1 hash of the currently last commit on the tracked branch. */
22+
readonly commitId: string;
23+
/** The message of the currently last commit on the tracked branch. */
24+
readonly commitMessage: string;
25+
/** The connection ARN this source uses. */
26+
readonly connectionArn: string;
27+
}
28+
1129
/**
1230
* Construction properties for {@link CodeStarConnectionsSourceAction}.
1331
*/
@@ -101,6 +119,18 @@ export class CodeStarConnectionsSourceAction extends Action {
101119
this.props = props;
102120
}
103121

122+
/** The variables emitted by this action. */
123+
public get variables(): CodeStarSourceVariables {
124+
return {
125+
fullRepositoryName: this.variableExpression('FullRepositoryName'),
126+
branchName: this.variableExpression('BranchName'),
127+
authorDate: this.variableExpression('AuthorDate'),
128+
commitId: this.variableExpression('CommitId'),
129+
commitMessage: this.variableExpression('CommitMessage'),
130+
connectionArn: this.variableExpression('ConnectionArn'),
131+
};
132+
}
133+
104134
protected bound(_scope: Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig {
105135
// https://docs.aws.amazon.com/codepipeline/latest/userguide/security-iam.html#how-to-update-role-new-services
106136
options.role.addToPolicy(new iam.PolicyStatement({

packages/@aws-cdk/aws-codepipeline-actions/test/codestar-connections/codestar-connections-source-action.test.ts

+129-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import '@aws-cdk/assert-internal/jest';
2-
import { arrayWith, objectLike } from '@aws-cdk/assert-internal';
2+
import { arrayWith, objectLike, SynthUtils } from '@aws-cdk/assert-internal';
33
import * as codebuild from '@aws-cdk/aws-codebuild';
44
import * as codepipeline from '@aws-cdk/aws-codepipeline';
55
import { Stack } from '@aws-cdk/core';
@@ -148,26 +148,139 @@ describe('CodeStar Connections source Action', () => {
148148
],
149149
});
150150

151+
});
152+
153+
test('exposes variables', () => {
154+
const stack = new Stack();
155+
createBitBucketAndCodeBuildPipeline(stack);
156+
157+
expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', {
158+
'Stages': [
159+
{
160+
'Name': 'Source',
161+
},
162+
{
163+
'Name': 'Build',
164+
'Actions': [
165+
{
166+
'Name': 'CodeBuild',
167+
'Configuration': {
168+
'EnvironmentVariables': '[{"name":"CommitId","type":"PLAINTEXT","value":"#{Source_BitBucket_NS.CommitId}"}]',
169+
},
170+
},
171+
],
172+
},
173+
],
174+
});
175+
});
176+
177+
test('exposes variables with custom namespace', () => {
178+
const stack = new Stack();
179+
createBitBucketAndCodeBuildPipeline(stack, {
180+
variablesNamespace: 'kornicameister',
181+
});
182+
183+
expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', {
184+
'Stages': [
185+
{
186+
'Name': 'Source',
187+
'Actions': [
188+
{
189+
'Name': 'BitBucket',
190+
'Namespace': 'kornicameister',
191+
},
192+
],
193+
},
194+
{
195+
'Name': 'Build',
196+
'Actions': [
197+
{
198+
'Name': 'CodeBuild',
199+
'Configuration': {
200+
'EnvironmentVariables': '[{"name":"CommitId","type":"PLAINTEXT","value":"#{kornicameister.CommitId}"}]',
201+
},
202+
},
203+
],
204+
},
205+
],
206+
});
207+
});
208+
209+
test('fail if variable from unused action is referenced', () => {
210+
const stack = new Stack();
211+
const pipeline = createBitBucketAndCodeBuildPipeline(stack);
151212

213+
const unusedSourceOutput = new codepipeline.Artifact();
214+
const unusedSourceAction = new cpactions.CodeStarConnectionsSourceAction({
215+
actionName: 'UnusedBitBucket',
216+
owner: 'aws',
217+
repo: 'aws-cdk',
218+
output: unusedSourceOutput,
219+
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
220+
});
221+
const unusedBuildAction = new cpactions.CodeBuildAction({
222+
actionName: 'UnusedCodeBuild',
223+
project: new codebuild.PipelineProject(stack, 'UnusedMyProject'),
224+
input: unusedSourceOutput,
225+
environmentVariables: {
226+
CommitId: { value: unusedSourceAction.variables.commitId },
227+
},
228+
});
229+
pipeline.stage('Build').addAction(unusedBuildAction);
230+
231+
expect(() => {
232+
SynthUtils.synthesize(stack);
233+
}).toThrow(/Cannot reference variables of action 'UnusedBitBucket', as that action was never added to a pipeline/);
234+
});
235+
236+
test('fail if variable from unused action with custom namespace is referenced', () => {
237+
const stack = new Stack();
238+
const pipeline = createBitBucketAndCodeBuildPipeline(stack, {
239+
variablesNamespace: 'kornicameister',
240+
});
241+
const unusedSourceOutput = new codepipeline.Artifact();
242+
const unusedSourceAction = new cpactions.CodeStarConnectionsSourceAction({
243+
actionName: 'UnusedBitBucket',
244+
owner: 'aws',
245+
repo: 'aws-cdk',
246+
output: unusedSourceOutput,
247+
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
248+
variablesNamespace: 'kornicameister',
249+
});
250+
const unusedBuildAction = new cpactions.CodeBuildAction({
251+
actionName: 'UnusedCodeBuild',
252+
project: new codebuild.PipelineProject(stack, 'UnusedProject'),
253+
input: unusedSourceOutput,
254+
environmentVariables: {
255+
CommitId: { value: unusedSourceAction.variables.commitId },
256+
},
257+
});
258+
pipeline.stage('Build').addAction(unusedBuildAction);
259+
260+
expect(() => {
261+
SynthUtils.synthesize(stack);
262+
}).toThrow(/Cannot reference variables of action 'UnusedBitBucket', as that action was never added to a pipeline/);
152263
});
153264
});
154265

155-
function createBitBucketAndCodeBuildPipeline(stack: Stack, props: Partial<cpactions.BitBucketSourceActionProps>): void {
266+
function createBitBucketAndCodeBuildPipeline(
267+
stack: Stack, props: Partial<cpactions.CodeStarConnectionsSourceActionProps> = {},
268+
): codepipeline.Pipeline {
156269
const sourceOutput = new codepipeline.Artifact();
157-
new codepipeline.Pipeline(stack, 'Pipeline', {
270+
const sourceAction = new cpactions.CodeStarConnectionsSourceAction({
271+
actionName: 'BitBucket',
272+
owner: 'aws',
273+
repo: 'aws-cdk',
274+
output: sourceOutput,
275+
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
276+
...props,
277+
});
278+
279+
return new codepipeline.Pipeline(stack, 'Pipeline', {
158280
stages: [
159281
{
160282
stageName: 'Source',
161-
actions: [
162-
new cpactions.CodeStarConnectionsSourceAction({
163-
actionName: 'BitBucket',
164-
owner: 'aws',
165-
repo: 'aws-cdk',
166-
output: sourceOutput,
167-
connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh',
168-
...props,
169-
}),
170-
],
283+
actions: [sourceAction],
171284
},
172285
{
173286
stageName: 'Build',
@@ -177,6 +290,9 @@ function createBitBucketAndCodeBuildPipeline(stack: Stack, props: Partial<cpacti
177290
project: new codebuild.PipelineProject(stack, 'MyProject'),
178291
input: sourceOutput,
179292
outputs: [new codepipeline.Artifact()],
293+
environmentVariables: {
294+
CommitId: { value: sourceAction.variables.commitId },
295+
},
180296
}),
181297
],
182298
},

0 commit comments

Comments
 (0)