Skip to content

Commit

Permalink
feat(aws-codepipeline): make input Artifacts explicit when creating A…
Browse files Browse the repository at this point in the history
…ctions.

BREAKING CHANGE: previously, the CodePipeline Construct would attempt
to wire the inputs of Actions implicitly, if they were not provided.
Now, this functionality has been removed, and we require specifying the
inputs for Build, Test and Deploy Actions explicitly.
  • Loading branch information
skinny85 committed Dec 19, 2018
1 parent 478a714 commit 0e2f1f1
Show file tree
Hide file tree
Showing 19 changed files with 45 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,6 @@ class StageDouble implements cpapi.IStage, cpapi.IInternalStage {
public _generateOutputArtifactName(): string {
throw new Error('Unsupported');
}

public _findInputArtifact(): cpapi.Artifact {
throw new Error('Unsupported');
}
}

class RoleDouble extends iam.Role {
Expand Down
16 changes: 11 additions & 5 deletions packages/@aws-cdk/aws-codebuild/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,15 @@ const project = new codebuild.PipelineProject(this, 'MyProject');
const pipeline = new codepipeline.Pipeline(this, 'MyPipeline');

const sourceStage = pipeline.addStage('Source');
repository.addToPipeline(sourceStage, 'CodeCommit');
const sourceAction = repository.addToPipeline(sourceStage, 'CodeCommit');

const buildStage = pipeline.addStage('Build');
new codebuild.PipelineBuildAction(this, 'CodeBuild', {
const buildAction = new codebuild.PipelineBuildAction(this, 'CodeBuild', {
stage: buildStage,
project,
inputArtifact: sourceAction.outputArtifact,
});
// use `buildAction.outputArtifact` as the `inputArtifact` to later Actions...
```

The `PipelineProject` utility class is a simple sugar around the `Project`
Expand All @@ -196,7 +198,9 @@ You can also add the Project to the Pipeline directly:
```ts
// equivalent to the code above:
const buildAction = project.addToPipeline(buildStage, 'CodeBuild');
const buildAction = project.addToPipeline(buildStage, 'CodeBuild', {
inputArtifact: sourceAction.outputArtifact,
});
```
In addition to the build Action, there is also a test Action. It works very
Expand All @@ -209,15 +213,17 @@ Examples:
new codebuild.PipelineTestAction(this, 'IntegrationTest', {
stage: buildStage,
project,
inputArtifact: sourceAction.outputArtifact,
// outputArtifactName is optional - if you don't specify it,
// the Action will have an undefined `outputArtifact` property
outputArtifactName: 'IntegrationTestOutput',
});

// equivalent to the code above:
project.addToPipelineAsTest(buildStage, 'IntegrationTest', {
// of course, this property is optional here as well
outputArtifactName: 'IntegrationTestOutput',
inputArtifact: sourceAction.outputArtifact,
// of course, this property is optional here as well
outputArtifactName: 'IntegrationTestOutput',
});
```
Expand Down
8 changes: 2 additions & 6 deletions packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ export interface CommonPipelineBuildActionProps extends CommonCodeBuildActionPro
codepipeline.CommonActionProps {
/**
* The source to use as input for this build.
*
* @default CodePipeline will use the output of the last Action from a previous Stage as input
*/
inputArtifact?: codepipeline.Artifact;
inputArtifact: codepipeline.Artifact;

/**
* The name of the build's output artifact.
Expand Down Expand Up @@ -115,10 +113,8 @@ export interface CommonPipelineTestActionProps extends CommonCodeBuildActionProp
codepipeline.CommonActionProps {
/**
* The source to use as input for this test.
*
* @default CodePipeline will use the output of the last Action from a previous Stage as input
*/
inputArtifact?: codepipeline.Artifact;
inputArtifact: codepipeline.Artifact;

/**
* The optional name of the primary output artifact.
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 @@ -94,7 +94,7 @@ export abstract class ProjectRef extends cdk.Construct implements events.IEventR
* @param props the properties of the new Action
* @returns the newly created {@link PipelineBuildAction} build Action
*/
public addToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineBuildActionProps = {}): PipelineBuildAction {
public addToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineBuildActionProps): PipelineBuildAction {
return new PipelineBuildAction(this, name, {
stage,
project: this,
Expand All @@ -111,7 +111,7 @@ export abstract class ProjectRef extends cdk.Construct implements events.IEventR
* @param props the properties of the new Action
* @returns the newly created {@link PipelineBuildAction} test Action
*/
public addToPipelineAsTest(stage: codepipeline.IStage, name: string, props: CommonPipelineTestActionProps = {}): PipelineTestAction {
public addToPipelineAsTest(stage: codepipeline.IStage, name: string, props: CommonPipelineTestActionProps): PipelineTestAction {
return new PipelineTestAction(this, name, {
stage,
project: this,
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-codecommit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ const sourceStage = pipeline.addStage('Source');
const sourceAction = new codecommit.PipelineSourceAction(this, 'CodeCommit', {
stage: sourceStage,
repository: repo,
outputArtifactName: 'SourceOutput', // optional - by default, a name will be auto-generated
});
// use `sourceAction.outputArtifact` as the `inputArtifact` to later Actions...
```

You can also add the Repository to the Pipeline directly:
Expand Down
5 changes: 4 additions & 1 deletion packages/@aws-cdk/aws-codedeploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,15 @@ const deployStage = pipeline.addStage('Deploy');
new codedeploy.PipelineDeployAction(this, 'CodeDeploy', {
stage: deployStage,
deploymentGroup,
inputArtifact: buildAction.outputArtifact,
});
```

You can also add the Deployment Group to the Pipeline directly:

```ts
// equivalent to the code above:
deploymentGroup.addToPipeline(deployStage, 'CodeDeploy');
deploymentGroup.addToPipeline(deployStage, 'CodeDeploy', {
inputArtifact: buildAction.outputArtifact,
});
```
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export abstract class ServerDeploymentGroupRef extends cdk.Construct {
* @param props the properties of the new Action
* @returns the newly created {@link PipelineDeployAction} deploy Action
*/
public addToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineDeployActionProps = {}):
public addToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineDeployActionProps):
PipelineDeployAction {
return new PipelineDeployAction(this, name, {
deploymentGroup: this,
Expand Down
4 changes: 1 addition & 3 deletions packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ import { ServerDeploymentGroupRef } from './deployment-group';
export interface CommonPipelineDeployActionProps extends codepipeline.CommonActionProps {
/**
* The source to use as input for deployment.
*
* @default CodePipeline will use the output of the last Action from a previous Stage as input
*/
inputArtifact?: codepipeline.Artifact;
inputArtifact: codepipeline.Artifact;
}

/**
Expand Down
13 changes: 1 addition & 12 deletions packages/@aws-cdk/aws-codepipeline-api/lib/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,6 @@ export interface IInternalStage {
* @param action the Action to generate the output artifact name for
*/
_generateOutputArtifactName(action: Action): string;

/**
* Finds an input artifact for the given Action.
* The chosen artifact will be the output artifact of the
* last Action in the Pipeline
* (up to the Stage this Action belongs to)
* with the highest runOrder that has an output artifact.
*
* @param action the Action to find the input artifact for
*/
_findInputArtifact(action: Action): Artifact;
}

/**
Expand Down Expand Up @@ -281,7 +270,7 @@ export abstract class Action extends cdk.Construct {
return artifact;
}

protected addInputArtifact(artifact: Artifact = this.stage._internal._findInputArtifact(this)): Action {
protected addInputArtifact(artifact: Artifact): Action {
this.inputArtifacts.push(artifact);
return this;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-codepipeline-api/lib/build-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface BuildActionProps extends CommonActionProps, CommonActionConstru
/**
* The source to use as input for this build.
*/
inputArtifact?: Artifact;
inputArtifact: Artifact;

/**
* The service provider that the action calls. For example, a valid provider for Source actions is CodeBuild.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface DeployActionProps extends CommonActionProps, CommonActionConstr

artifactBounds: ActionArtifactBounds;

inputArtifact?: Artifact;
inputArtifact: Artifact;

configuration?: any;
}
Expand Down
4 changes: 1 addition & 3 deletions packages/@aws-cdk/aws-codepipeline-api/lib/test-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import { Artifact } from "./artifact";
export interface TestActionProps extends CommonActionProps, CommonActionConstructProps {
/**
* The source to use as input for this test.
*
* @default CodePipeline will use the output of the last Action from a previous Stage as input
*/
inputArtifact?: Artifact;
inputArtifact: Artifact;

/**
* The optional name of the output artifact.
Expand Down
33 changes: 0 additions & 33 deletions packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,39 +333,6 @@ export class Pipeline extends cdk.Construct implements cpapi.IPipeline {
return 'Artifact_' + action.uniqueId;
}

/**
* Finds an input artifact for the given Action.
* The chosen artifact will be the output artifact of the
* last Action in the Pipeline
* (up to the Stage this Action belongs to),
* with the highest runOrder, that has an output artifact.
*
* @param stage the Stage `action` belongs to
* @param action the Action to find the input artifact for
*/
// ignore unused private method (it's actually used in Stage)
// @ts-ignore
private _findInputArtifact(stage: cpapi.IStage, action: cpapi.Action): cpapi.Artifact {
// search for the first Action that has an outputArtifact,
// and return that
const startIndex = this.stages.findIndex(s => s === stage);
for (let i = startIndex; i >= 0; i--) {
const currentStage = this.stages[i];

// get all of the Actions in the Stage, sorted by runOrder, descending
const currentActions = currentStage.actions.sort((a1, a2) => -(a1.runOrder - a2.runOrder));
for (const currentAction of currentActions) {
// for the first Stage (the one that `action` belongs to)
// we need to only take into account Actions with a smaller runOrder than `action`
if ((i !== startIndex || currentAction.runOrder < action.runOrder) && currentAction._outputArtifacts.length > 0) {
return currentAction._outputArtifacts[0];
}
}
}
throw new Error(`Could not determine the input artifact for Action with name '${action.id}'. ` +
'Please provide it explicitly with the inputArtifact property.');
}

private calculateInsertIndexFromPlacement(placement: StagePlacement): number {
// check if at most one placement property was provided
const providedPlacementProps = ['rightBefore', 'justAfter', 'atIndex']
Expand Down
4 changes: 0 additions & 4 deletions packages/@aws-cdk/aws-codepipeline/lib/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,6 @@ export class Stage extends cdk.Construct implements cpapi.IStage, cpapi.IInterna
return (this.pipeline as any)._generateOutputArtifactName(this, action);
}

public _findInputArtifact(action: cpapi.Action): cpapi.Artifact {
return (this.pipeline as any)._findInputArtifact(this, action);
}

private renderAction(action: cpapi.Action): CfnPipeline.ActionDeclarationProperty {
return {
name: action.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const repository = new codecommit.Repository(stack, 'MyRepo', {
const pipeline = new codepipeline.Pipeline(stack, 'Pipeline');

const sourceStage = new codepipeline.Stage(pipeline, 'source', { pipeline });
new codecommit.PipelineSourceAction(stack, 'source', {
const sourceAction = new codecommit.PipelineSourceAction(stack, 'source', {
stage: sourceStage,
outputArtifactName: 'SourceArtifact',
repository,
Expand All @@ -26,7 +26,11 @@ const project = new codebuild.Project(stack, 'MyBuildProject', {
});

const buildStage = new codepipeline.Stage(pipeline, 'build', { pipeline });
project.addToPipeline(buildStage, 'build');
project.addToPipelineAsTest(buildStage, 'test');
project.addToPipeline(buildStage, 'build', {
inputArtifact: sourceAction.outputArtifact,
});
project.addToPipelineAsTest(buildStage, 'test', {
inputArtifact: sourceAction.outputArtifact,
});

app.run();
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ const pipeline = new codepipeline.Pipeline(stack, 'Pipeline', {
});

const sourceStage = new codepipeline.Stage(stack, 'Source', { pipeline });
bucket.addToPipeline(sourceStage, 'S3Source', {
const sourceAction = bucket.addToPipeline(sourceStage, 'S3Source', {
bucketKey: 'application.zip',
outputArtifactName: 'SourceOutput',
});

const deployStage = new codepipeline.Stage(stack, 'Deploy', { pipeline });
deploymentGroup.addToPipeline(deployStage, 'CodeDeploy');
deploymentGroup.addToPipeline(deployStage, 'CodeDeploy', {
inputArtifact: sourceAction.outputArtifact,
});

app.run();
6 changes: 4 additions & 2 deletions packages/@aws-cdk/aws-codepipeline/test/test.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ export = {
repositoryName: 'Repo',
});
const sourceStage = pipeline.addStage('Source');
repo.addToPipeline(sourceStage, 'CodeCommit');
const sourceAction = repo.addToPipeline(sourceStage, 'CodeCommit');

const project = new codebuild.PipelineProject(stack, 'Project');
const buildStage = pipeline.addStage('Build');
project.addToPipeline(buildStage, 'CodeBuild');
project.addToPipeline(buildStage, 'CodeBuild', {
inputArtifact: sourceAction.outputArtifact,
});

expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', {
"Stages": [
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-ecr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const sourceAction = new ecr.PipelineSourceAction(this, 'ECR', {
imageTag: 'some-tag', // optional, default: 'latest'
outputArtifactName: 'SomeName', // optional
});
// use `sourceAction.outputArtifact` as the `inputArtifact` to later Actions...
```

You can also add the Repository to the Pipeline directly:
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-s3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ const sourceAction = new s3.PipelineSourceAction(this, 'S3Source', {
stage: sourceStage,
bucket: sourceBucket,
bucketKey: 'path/to/file.zip',
outputArtifactName: 'SourceOutput', // optional - by default, a name will be auto-generated
});
// use `sourceAction.outputArtifact` as the `inputArtifact` to later Actions...
```

You can also add the Bucket to the Pipeline directly:
Expand Down

0 comments on commit 0e2f1f1

Please sign in to comment.