Skip to content

Commit

Permalink
feat(codepipeline): change to stand-alone Artifacts. (#2338)
Browse files Browse the repository at this point in the history
This commit changes the way Artifacts are used in CodePipeline.
Instead of being properties on the Actions,
they are now stand-alone objects,
created independently of the Actions,
and referenced when instantiating them.
This is to not force users to assign Actions to intermediate variables
when defining a Pipeline.

This change had a few interesting consequences:
* We no longer needed the abstract subclasses of Action like SourceAction,
  DeployAction, etc., and so they were removed.
* The old naming convention of `inputArtifacts` and `outputArtifactNames`
  was shortened to be simply `inputs` and `outputs`.
* There was no longer any need to differentiate Build and Test Actions,
  and so the two CodeBuild and Jenkins Actions were merged into one.

BREAKING CHANGE: CodePipeline Actions no longer have the `outputArtifact`
and `outputArtifacts` properties.
* `inputArtifact(s)` and `additionalInputArtifacts` properties were renamed
  to `input(s)` and `extraInputs`.
* `outputArtifactName(s)` and `additionalOutputArtifactNames` properties
  were renamed to `output(s)` and `extraOutputs`.
* The classes `CodeBuildBuildAction` and `CodeBuildTestAction` were merged
  into one class `CodeBuildAction`.
* The classes `JenkinsBuildAction` and `JenkinsTestAction` were merged
  into one class `JenkinsAction`.
  • Loading branch information
skinny85 authored Apr 22, 2019
1 parent 486a7a8 commit b778e10
Show file tree
Hide file tree
Showing 73 changed files with 1,465 additions and 1,237 deletions.
17 changes: 10 additions & 7 deletions packages/@aws-cdk/app-delivery/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ const pipeline = new codepipeline.Pipeline(pipelineStack, 'CodePipeline', {
});

// Configure the CodePipeline source - where your CDK App's source code is hosted
const sourceOutput = new codepipeline.Artifact();
const source = new codepipeline_actions.GitHubSourceAction({
actionName: 'GitHub',
output: sourceOutput,
/* ... */
});
pipeline.addStage({
Expand All @@ -69,23 +71,24 @@ const project = new codebuild.PipelineProject(pipelineStack, 'CodeBuild', {
* },
*/
});
const buildAction = new codepipeline_actions.CodeBuildBuildAction({
const synthesizedApp = new codepipeline.Artifact();
const buildAction = new codepipeline_actions.CodeBuildAction({
actionName: 'CodeBuild',
project,
inputArtifact: source.outputArtifact,
input: sourceOutput,
output: synthesizedApp,
});
pipeline.addStage({
name: 'build',
actions: [buildAction],
});
const synthesizedApp = buildAction.outputArtifact;

// Optionally, self-update the pipeline stack
const selfUpdateStage = pipeline.addStage({ name: 'SelfUpdate' });
new cicd.PipelineDeployStackAction(pipelineStack, 'SelfUpdatePipeline', {
stage: selfUpdateStage,
stack: pipelineStack,
inputArtifact: synthesizedApp,
input: synthesizedApp,
});

// Now add our service stacks
Expand All @@ -95,7 +98,7 @@ const serviceStackA = new MyServiceStackA(app, 'ServiceStackA', { /* ... */ });
const deployServiceAAction = new cicd.PipelineDeployStackAction(pipelineStack, 'DeployServiceStackA', {
stage: deployStage,
stack: serviceStackA,
inputArtifact: synthesizedApp,
input: synthesizedApp,
// See the note below for details about this option.
adminPermissions: false,
});
Expand All @@ -114,7 +117,7 @@ const serviceStackB = new MyServiceStackB(app, 'ServiceStackB', { /* ... */ });
new cicd.PipelineDeployStackAction(pipelineStack, 'DeployServiceStackB', {
stage: deployStage,
stack: serviceStackB,
inputArtifact: synthesizedApp,
input: synthesizedApp,
createChangeSetRunOrder: 998,
adminPermissions: true, // no need to modify the role with admin
});
Expand Down Expand Up @@ -148,7 +151,7 @@ artifacts:
files: '**/*'
```
The `PipelineDeployStackAction` expects it's `inputArtifact` to contain the result of
The `PipelineDeployStackAction` expects it's `input` to contain the result of
synthesizing a CDK App using the `cdk synth -o <directory>`.


Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface PipelineDeployStackActionProps {
* The CodePipeline artifact that holds the synthesized app, which is the
* contents of the ``<directory>`` when running ``cdk synth -o <directory>``.
*/
readonly inputArtifact: codepipeline.Artifact;
readonly input: codepipeline.Artifact;

/**
* The name to use when creating a ChangeSet for the stack.
Expand Down Expand Up @@ -126,7 +126,7 @@ export class PipelineDeployStackAction extends cdk.Construct {
changeSetName,
runOrder: createChangeSetRunOrder,
stackName: props.stack.name,
templatePath: props.inputArtifact.atPath(`${props.stack.name}.template.yaml`),
templatePath: props.input.atPath(`${props.stack.name}.template.yaml`),
adminPermissions: props.adminPermissions,
deploymentRole: props.role,
capabilities,
Expand Down
5 changes: 3 additions & 2 deletions packages/@aws-cdk/app-delivery/test/integ.cicd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ const pipeline = new codepipeline.Pipeline(stack, 'CodePipeline', {
removalPolicy: cdk.RemovalPolicy.Destroy
})
});
const sourceOutput = new codepipeline.Artifact('Artifact_CICDGitHubF8BA7ADD');
const source = new cpactions.GitHubSourceAction({
actionName: 'GitHub',
owner: 'awslabs',
repo: 'aws-cdk',
oauthToken: cdk.SecretValue.plainText('DummyToken'),
pollForSourceChanges: true,
outputArtifactName: 'Artifact_CICDGitHubF8BA7ADD',
output: sourceOutput,
});
pipeline.addStage({
name: 'Source',
Expand All @@ -32,7 +33,7 @@ new cicd.PipelineDeployStackAction(stack, 'DeployStack', {
changeSetName: 'CICD-ChangeSet',
createChangeSetRunOrder: 10,
executeChangeSetRunOrder: 999,
inputArtifact: source.outputArtifact,
input: sourceOutput,
adminPermissions: false,
capabilities: cfn.CloudFormationCapabilities.None,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { countResources, expect, haveResource, isSuperObject } from '@aws-cdk/assert';
import cfn = require('@aws-cdk/aws-cloudformation');
import codebuild = require('@aws-cdk/aws-codebuild');
import codepipeline = require('@aws-cdk/aws-codepipeline');
Expand All @@ -8,8 +9,6 @@ import cdk = require('@aws-cdk/cdk');
import cxapi = require('@aws-cdk/cx-api');
import fc = require('fast-check');
import nodeunit = require('nodeunit');

import { countResources, expect, haveResource, isSuperObject } from '@aws-cdk/assert';
import { PipelineDeployStackAction } from '../lib/pipeline-deploy-stack-action';

interface SelfUpdatingPipeline {
Expand All @@ -36,7 +35,7 @@ export = nodeunit.testCase({
});
new PipelineDeployStackAction(stack, 'Action', {
changeSetName: 'ChangeSet',
inputArtifact: fakeAction.outputArtifact,
input: fakeAction.outputArtifact,
stack: new cdk.Stack(app, 'DeployedStack', { env: { account: stackAccount } }),
stage: pipeline.addStage({ name: 'DeployStage' }),
adminPermissions: false,
Expand Down Expand Up @@ -67,7 +66,7 @@ export = nodeunit.testCase({
changeSetName: 'ChangeSet',
createChangeSetRunOrder: createRunOrder,
executeChangeSetRunOrder: executeRunOrder,
inputArtifact: fakeAction.outputArtifact,
input: fakeAction.outputArtifact,
stack: new cdk.Stack(app, 'DeployedStack'),
stage: pipeline.addStage({ name: 'DeployStage' }),
adminPermissions: false,
Expand Down Expand Up @@ -96,21 +95,21 @@ export = nodeunit.testCase({
new PipelineDeployStackAction(pipelineStack, 'SelfUpdatePipeline', {
stage: selfUpdateStage1,
stack: pipelineStack,
inputArtifact: selfUpdatingStack.synthesizedApp,
input: selfUpdatingStack.synthesizedApp,
capabilities: cfn.CloudFormationCapabilities.NamedIAM,
adminPermissions: false,
});
new PipelineDeployStackAction(pipelineStack, 'DeployStack', {
stage: selfUpdateStage2,
stack: stackWithNoCapability,
inputArtifact: selfUpdatingStack.synthesizedApp,
input: selfUpdatingStack.synthesizedApp,
capabilities: cfn.CloudFormationCapabilities.None,
adminPermissions: false,
});
new PipelineDeployStackAction(pipelineStack, 'DeployStack2', {
stage: selfUpdateStage3,
stack: stackWithAnonymousCapability,
inputArtifact: selfUpdatingStack.synthesizedApp,
input: selfUpdatingStack.synthesizedApp,
capabilities: cfn.CloudFormationCapabilities.AnonymousIAM,
adminPermissions: false,
});
Expand Down Expand Up @@ -159,7 +158,7 @@ export = nodeunit.testCase({
new PipelineDeployStackAction(pipelineStack, 'SelfUpdatePipeline', {
stage: selfUpdateStage,
stack: pipelineStack,
inputArtifact: selfUpdatingStack.synthesizedApp,
input: selfUpdatingStack.synthesizedApp,
adminPermissions: true,
});
expect(pipelineStack).to(haveResource('AWS::IAM::Policy', {
Expand Down Expand Up @@ -195,7 +194,7 @@ export = nodeunit.testCase({
const deployAction = new PipelineDeployStackAction(pipelineStack, 'SelfUpdatePipeline', {
stage: selfUpdateStage,
stack: pipelineStack,
inputArtifact: selfUpdatingStack.synthesizedApp,
input: selfUpdatingStack.synthesizedApp,
adminPermissions: false,
role
});
Expand All @@ -218,7 +217,7 @@ export = nodeunit.testCase({
const deployAction = new PipelineDeployStackAction(pipelineStack, 'DeployServiceStackA', {
stage: deployStage,
stack: emptyStack,
inputArtifact: selfUpdatingStack.synthesizedApp,
input: selfUpdatingStack.synthesizedApp,
adminPermissions: false,
});
// we might need to add permissions
Expand Down Expand Up @@ -282,7 +281,7 @@ export = nodeunit.testCase({
const deployStage = pipeline.addStage({ name: 'DeployStage' });
const action = new PipelineDeployStackAction(stack, 'Action', {
changeSetName: 'ChangeSet',
inputArtifact: fakeAction.outputArtifact,
input: fakeAction.outputArtifact,
stack: deployedStack,
stage: deployStage,
adminPermissions: false,
Expand All @@ -305,7 +304,7 @@ class FakeAction extends codepipeline.Action {
constructor(actionName: string) {
super({
actionName,
artifactBounds: codepipeline.defaultBounds(),
artifactBounds: { minInputs: 0, maxInputs: 5, minOutputs: 0, maxOutputs: 5 },
category: codepipeline.ActionCategory.Test,
provider: 'Test',
});
Expand All @@ -329,28 +328,31 @@ function createSelfUpdatingStack(pipelineStack: cdk.Stack): SelfUpdatingPipeline

// simple source
const bucket = s3.Bucket.import( pipeline, 'PatternBucket', { bucketArn: 'arn:aws:s3:::totally-fake-bucket' });
const sourceOutput = new codepipeline.Artifact('SourceOutput');
const sourceAction = new cpactions.S3SourceAction({
actionName: 'S3Source',
bucket,
bucketKey: 'the-great-key',
output: sourceOutput,
});
pipeline.addStage({
name: 'source',
actions: [sourceAction],
});

const project = new codebuild.PipelineProject(pipelineStack, 'CodeBuild');
const buildAction = new cpactions.CodeBuildBuildAction({
const buildOutput = new codepipeline.Artifact('BuildOutput');
const buildAction = new cpactions.CodeBuildAction({
actionName: 'CodeBuild',
project,
inputArtifact: sourceAction.outputArtifact,
input: sourceOutput,
output: buildOutput,
});
pipeline.addStage({
name: 'build',
actions: [buildAction],
});
const synthesizedApp = buildAction.outputArtifact;
return {synthesizedApp, pipeline};
return {synthesizedApp: buildOutput, pipeline};
}

function hasPipelineAction(expectedAction: any): (props: any) => boolean {
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-codebuild/lib/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -753,11 +753,11 @@ export class Project extends ProjectBase {
if (this.source.type === SourceType.CodePipeline) {
if (this._secondarySources.length > 0) {
ret.push('A Project with a CodePipeline Source cannot have secondary sources. ' +
"Use the CodeBuild Pipeline Actions' `additionalInputArtifacts` property instead");
"Use the CodeBuild Pipeline Actions' `extraInputs` property instead");
}
if (this._secondaryArtifacts.length > 0) {
ret.push('A Project with a CodePipeline Source cannot have secondary artifacts. ' +
"Use the CodeBuild Pipeline Actions' `additionalOutputArtifactNames` property instead");
"Use the CodeBuild Pipeline Actions' `extraOutputs` property instead");
}
}
return ret;
Expand Down
Loading

0 comments on commit b778e10

Please sign in to comment.