Skip to content

Commit fbd7728

Browse files
authored
feat(aws-lambda): add input and output Artifacts to the CodePipeline Action. (#1390)
Fixes #1384
1 parent 91ecdda commit fbd7728

File tree

4 files changed

+115
-14
lines changed

4 files changed

+115
-14
lines changed

packages/@aws-cdk/aws-codepipeline-api/lib/action.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ export abstract class Action extends cdk.Construct {
221221
public readonly owner: string;
222222
public readonly version: string;
223223

224-
private readonly inputArtifacts = new Array<Artifact>();
225-
private readonly outputArtifacts = new Array<Artifact>();
224+
private readonly _actionInputArtifacts = new Array<Artifact>();
225+
private readonly _actionOutputArtifacts = new Array<Artifact>();
226226
private readonly artifactBounds: ActionArtifactBounds;
227227
private readonly stage: IStage;
228228

@@ -245,9 +245,9 @@ export abstract class Action extends cdk.Construct {
245245
}
246246

247247
public validate(): string[] {
248-
return validation.validateArtifactBounds('input', this.inputArtifacts, this.artifactBounds.minInputs,
248+
return validation.validateArtifactBounds('input', this._actionInputArtifacts, this.artifactBounds.minInputs,
249249
this.artifactBounds.maxInputs, this.category, this.provider)
250-
.concat(validation.validateArtifactBounds('output', this.outputArtifacts, this.artifactBounds.minOutputs,
250+
.concat(validation.validateArtifactBounds('output', this._actionOutputArtifacts, this.artifactBounds.minOutputs,
251251
this.artifactBounds.maxOutputs, this.category, this.provider)
252252
);
253253
}
@@ -268,21 +268,21 @@ export abstract class Action extends cdk.Construct {
268268
}
269269

270270
public get _inputArtifacts(): Artifact[] {
271-
return this.inputArtifacts.slice();
271+
return this._actionInputArtifacts.slice();
272272
}
273273

274274
public get _outputArtifacts(): Artifact[] {
275-
return this.outputArtifacts.slice();
275+
return this._actionOutputArtifacts.slice();
276276
}
277277

278278
protected addOutputArtifact(name: string = this.stage._internal._generateOutputArtifactName(this)): Artifact {
279279
const artifact = new Artifact(this, name);
280-
this.outputArtifacts.push(artifact);
280+
this._actionOutputArtifacts.push(artifact);
281281
return artifact;
282282
}
283283

284284
protected addInputArtifact(artifact: Artifact = this.stage._internal._findInputArtifact(this)): Action {
285-
this.inputArtifacts.push(artifact);
285+
this._actionInputArtifacts.push(artifact);
286286
return this;
287287
}
288288
}

packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,34 @@ export = {
262262

263263
const pipeline = new codepipeline.Pipeline(stack, 'Pipeline');
264264

265-
// first stage must contain a Source action so we can't use it to test Lambda
265+
const bucket = new s3.Bucket(stack, 'Bucket');
266+
const sourceStage = pipeline.addStage('Source');
267+
const source1 = bucket.addToPipeline(sourceStage, 'SourceAction1', {
268+
bucketKey: 'some/key',
269+
outputArtifactName: 'sourceArtifact1',
270+
});
271+
const source2 = bucket.addToPipeline(sourceStage, 'SourceAction2', {
272+
bucketKey: 'another/key',
273+
outputArtifactName: 'sourceArtifact2',
274+
});
275+
266276
const stage = new codepipeline.Stage(stack, 'Stage', { pipeline });
267-
new lambda.PipelineInvokeAction(stack, 'InvokeAction', {
277+
const lambdaAction = new lambda.PipelineInvokeAction(stack, 'InvokeAction', {
268278
stage,
269279
lambda: lambdaFun,
270-
userParameters: 'foo-bar/42'
280+
userParameters: 'foo-bar/42',
281+
inputArtifacts: [
282+
source2.outputArtifact,
283+
source1.outputArtifact,
284+
],
285+
outputArtifactNames: [
286+
'lambdaOutput1',
287+
'lambdaOutput2',
288+
'lambdaOutput3',
289+
],
271290
});
272291

273-
expect(stack, /* skip validation */ true).to(haveResourceLike('AWS::CodePipeline::Pipeline', {
292+
expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', {
274293
"ArtifactStore": {
275294
"Location": {
276295
"Ref": "PipelineArtifactsBucket22248F97"
@@ -284,6 +303,9 @@ export = {
284303
]
285304
},
286305
"Stages": [
306+
{
307+
"Name": "Source",
308+
},
287309
{
288310
"Actions": [
289311
{
@@ -299,9 +321,16 @@ export = {
299321
},
300322
"UserParameters": "foo-bar/42"
301323
},
302-
"InputArtifacts": [],
324+
"InputArtifacts": [
325+
{ "Name": "sourceArtifact2" },
326+
{ "Name": "sourceArtifact1" },
327+
],
303328
"Name": "InvokeAction",
304-
"OutputArtifacts": [],
329+
"OutputArtifacts": [
330+
{ "Name": "lambdaOutput1" },
331+
{ "Name": "lambdaOutput2" },
332+
{ "Name": "lambdaOutput3" },
333+
],
305334
"RunOrder": 1
306335
}
307336
],
@@ -310,6 +339,9 @@ export = {
310339
]
311340
}));
312341

342+
test.equal(lambdaAction.outputArtifacts().length, 3);
343+
test.notEqual(lambdaAction.outputArtifact('lambdaOutput2'), undefined);
344+
313345
expect(stack, /* skip validation */ true).to(haveResource('AWS::IAM::Policy', {
314346
"PolicyDocument": {
315347
"Statement": [

packages/@aws-cdk/aws-lambda/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,25 @@ You can also add the Lambda to the Pipeline directly:
8787
fn.addToPipeline(lambdaStage, 'Lambda');
8888
```
8989

90+
The Lambda Action can have up to 5 inputs,
91+
and up to 5 outputs:
92+
93+
```typescript
94+
const lambdaAction = fn.addToPipeline(lambdaStage, 'Lambda', {
95+
inputArtifacts: [
96+
sourceAction.outputArtifact,
97+
buildAction.outputArtifact,
98+
],
99+
outputArtifactNames: [
100+
'Out1',
101+
'Out2',
102+
],
103+
});
104+
105+
lambdaAction.outputArtifacts(); // returns the list of output Artifacts
106+
lambdaAction.outputArtifact('Out2'); // returns the named output Artifact, or throws an exception if not found
107+
```
108+
90109
See [the AWS documentation](https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html)
91110
on how to write a Lambda function invoked from CodePipeline.
92111

packages/@aws-cdk/aws-lambda/lib/pipeline-action.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,33 @@ import { FunctionRef } from './lambda-ref';
99
* or through {@link FunctionRef#addToPipeline}.
1010
*/
1111
export interface CommonPipelineInvokeActionProps extends codepipeline.CommonActionProps {
12+
// because of @see links
13+
// tslint:disable:max-line-length
14+
15+
/**
16+
* The optional input Artifacts of the Action.
17+
* A Lambda Action can have up to 5 inputs.
18+
* The inputs will appear in the event passed to the Lambda,
19+
* under the `'CodePipeline.job'.data.inputArtifacts` path.
20+
*
21+
* @default the Action will not have any inputs
22+
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html#actions-invoke-lambda-function-json-event-example
23+
*/
24+
inputArtifacts?: codepipeline.Artifact[];
25+
26+
// tslint:enable:max-line-length
27+
28+
/**
29+
* The optional names of the output Artifacts of the Action.
30+
* A Lambda Action can have up to 5 outputs.
31+
* The outputs will appear in the event passed to the Lambda,
32+
* under the `'CodePipeline.job'.data.outputArtifacts` path.
33+
* It is the responsibility of the Lambda to upload ZIP files with the Artifact contents to the provided locations.
34+
*
35+
* @default the Action will not have any outputs
36+
*/
37+
outputArtifactNames?: string[];
38+
1239
/**
1340
* String to be used in the event data parameter passed to the Lambda
1441
* function
@@ -67,6 +94,16 @@ export class PipelineInvokeAction extends codepipeline.Action {
6794
}
6895
});
6996

97+
// handle input artifacts
98+
for (const inputArtifact of props.inputArtifacts || []) {
99+
this.addInputArtifact(inputArtifact);
100+
}
101+
102+
// handle output artifacts
103+
for (const outputArtifactName of props.outputArtifactNames || []) {
104+
this.addOutputArtifact(outputArtifactName);
105+
}
106+
70107
// allow pipeline to list functions
71108
props.stage.pipeline.role.addToPolicy(new iam.PolicyStatement()
72109
.addAction('lambda:ListFunctions')
@@ -86,4 +123,17 @@ export class PipelineInvokeAction extends codepipeline.Action {
86123
.addAction('codepipeline:PutJobFailureResult'));
87124
}
88125
}
126+
127+
public outputArtifacts(): codepipeline.Artifact[] {
128+
return this._outputArtifacts;
129+
}
130+
131+
public outputArtifact(artifactName: string): codepipeline.Artifact {
132+
const result = this._outputArtifacts.find(a => (a.name === artifactName));
133+
if (result === undefined) {
134+
throw new Error(`Could not find the output Artifact with name '${artifactName}'`);
135+
} else {
136+
return result;
137+
}
138+
}
89139
}

0 commit comments

Comments
 (0)