Skip to content

Commit

Permalink
feat(aws-codepipeline): make input and output artifact names optional…
Browse files Browse the repository at this point in the history
… when creating Actions.

BREAKING CHANGE: this commit contains the following breaking changes:
* Rename 'artifactName' in Action construction properties to 'outputArtifactName'
* Rename the 'artifact' property of Actions to 'outputArtifact'

Previously, we always required customers to explicitly name the output artifacts the Actions used in the Pipeline,
and to explicitly "wire together" the outputs of one Action as inputs to another.
With this change, the CodePipeline Construct generates artifact names,
if the customer didn't provide one explicitly,
and tries to find the first available output artifact to use as input to a newly created Action that needs it,
thus turning both the input and output artifacts from required to optional properties.
  • Loading branch information
skinny85 committed Oct 5, 2018
1 parent ed1e1e4 commit 5cc4f3c
Show file tree
Hide file tree
Showing 35 changed files with 303 additions and 158 deletions.
9 changes: 5 additions & 4 deletions packages/@aws-cdk/aws-cloudformation/lib/pipeline-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,25 @@ export interface PipelineCloudFormationActionProps extends codepipeline.CommonAc
/**
* Base class for Actions that execute CloudFormation
*/
export abstract class PipelineCloudFormationAction extends codepipeline.DeployAction {
export abstract class PipelineCloudFormationAction extends codepipeline.Action {
/**
* Output artifact containing the CloudFormation call response
*
* Only present if configured by passing `outputFileName`.
*/
public artifact?: codepipeline.Artifact;
public outputArtifact?: codepipeline.Artifact;

constructor(parent: cdk.Construct, id: string, props: PipelineCloudFormationActionProps, configuration?: any) {
super(parent, id, {
stage: props.stage,
artifactBounds: {
minInputs: 0,
maxInputs: 10,
maxInputs: 1,
minOutputs: 0,
maxOutputs: 1,
},
provider: 'CloudFormation',
category: codepipeline.ActionCategory.Deploy,
configuration: {
StackName: props.stackName,
OutputFileName: props.outputFileName,
Expand All @@ -63,7 +64,7 @@ export abstract class PipelineCloudFormationAction extends codepipeline.DeployAc
});

if (props.outputFileName) {
this.artifact = this.addOutputArtifact(props.outputArtifactName ||
this.outputArtifact = this.addOutputArtifact(props.outputArtifactName ||
(props.stage.name + this.id + 'Artifact'));
}
}
Expand Down
19 changes: 4 additions & 15 deletions packages/@aws-cdk/aws-codebuild/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,12 @@ const project = new codebuild.PipelineProject(this, 'MyProject');

const pipeline = new codepipeline.Pipeline(this, 'MyPipeline');

const sourceStage = new codepipeline.Stage(this, 'Source', {
pipeline,
});
const sourceAction = new codecommit.PipelineSourceAction(this, 'CodeCommit', {
stage: sourceStage,
artifactName: 'SourceOutput',
repository,
});
const sourceStage = pipeline.addStage('Source');
repository.addToPipeline(sourceStage, 'CodeCommit');

const buildStage = new codepipeline.Stage(this, 'Build', {
pipeline,
});
const buildStage = pipeline.addStage('Build');
new codebuild.PipelineBuildAction(this, 'CodeBuild', {
stage: buildStage,
inputArtifact: sourceAction.artifact,
project,
});
```
Expand All @@ -84,9 +75,7 @@ You can also add the Project to the Pipeline directly:
```ts
// equivalent to the code above:
project.addBuildToPipeline(buildStage, 'CodeBuild', {
inputArtifact: sourceAction.artifact,
})
project.addBuildToPipeline(buildStage, 'CodeBuild');
```
### Using Project as an event target
Expand Down
14 changes: 9 additions & 5 deletions packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import { ProjectRef } from './project';
*/
export interface CommonPipelineBuildActionProps {
/**
* The source to use as input for this build
* 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
* The name of the build's output artifact.
*
* @default an auto-generated name will be used
*/
artifactName?: string;
outputArtifactName?: string;
}

/**
Expand All @@ -41,7 +45,7 @@ export class PipelineBuildAction extends codepipeline.BuildAction {
stage: props.stage,
provider: 'CodeBuild',
inputArtifact: props.inputArtifact,
artifactName: props.artifactName,
outputArtifactName: props.outputArtifactName,
configuration: {
ProjectName: props.project.projectName
}
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 @@ -89,8 +89,8 @@ 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 addBuildToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineBuildActionProps): PipelineBuildAction {
return new PipelineBuildAction(this.parent!, name, {
public addBuildToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineBuildActionProps = {}): PipelineBuildAction {
return new PipelineBuildAction(this, name, {
stage,
project: this,
...props,
Expand Down
30 changes: 7 additions & 23 deletions packages/@aws-cdk/aws-codecommit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,41 @@ To add a CodeCommit Repository to your stack:
```ts
import codecommit = require('@aws-cdk/aws-codecommit');

const repository = new codecommit.Repository(this, 'Repository' ,{
repositoryName: 'MyRepositoryName'
const repo = new codecommit.Repository(this, 'Repository' ,{
repositoryName: 'MyRepositoryName',
description: 'Some description.', // optional property
});
```

To add an SNS trigger to your repository:

```ts
import codecommit = require('@aws-cdk/aws-codecommit');

const repository = new codecommit.Repository(this, 'Repository', {
repositoryName: 'MyRepositoryName'
});

// trigger is established for all repository actions on all branches by default.
repository.notify('arn:aws:sns:*:123456789012:my_topic');
repo.notify('arn:aws:sns:*:123456789012:my_topic');
```

### CodePipeline

To use a CodeCommit Repository in a CodePipeline:

```ts
import codecommit = require('@aws-cdk/aws-codecommit');
import codepipeline = require('@aws-cdk/aws-codepipeline');

// see above for the details...
const repository = new codecommit.Repository( // ...
);

const pipeline = new codepipeline.Pipeline(this, 'MyPipeline', {
pipelineName: 'MyPipeline',
});
const sourceStage = new codepipeline.Stage(this, 'Source', {
pipeline,
});
const sourceStage = pipeline.addStage('Source');
const sourceAction = new codecommit.PipelineSourceAction(this, 'CodeCommit', {
stage: sourceStage,
artifactName: 'SourceOutput', // name can be arbitrary
repository,
repository: repo,
});
// use sourceAction.artifact as the inputArtifact to later Actions...
```

You can also add the Repository to the Pipeline directly:

```ts
// equivalent to the code above:
const sourceAction = repository.addToPipeline(sourceStage, 'CodeCommit', {
artifactName: 'SourceOutput',
});
const sourceAction = repo.addToPipeline(sourceStage, 'CodeCommit');
```

### Events
Expand Down
6 changes: 4 additions & 2 deletions packages/@aws-cdk/aws-codecommit/lib/pipeline-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ export interface CommonPipelineSourceActionProps {
/**
* The name of the source's output artifact.
* Output artifacts are used by CodePipeline as inputs into other actions.
*
* @default a name will be auto-generated
*/
artifactName: string;
outputArtifactName?: string;

/**
* @default 'master'
Expand Down Expand Up @@ -51,7 +53,7 @@ export class PipelineSourceAction extends codepipeline.SourceAction {
BranchName: props.branch || 'master',
PollForSourceChanges: props.pollForSourceChanges !== undefined ? props.pollForSourceChanges : true
},
artifactName: props.artifactName
outputArtifactName: props.outputArtifactName
});

// https://docs.aws.amazon.com/codecommit/latest/userguide/auth-and-access-control-permissions-reference.html#aa-acp
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-codecommit/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ export abstract class RepositoryRef extends cdk.Construct {
* @param props the properties of the new Action
* @returns the newly created {@link PipelineSourceAction}
*/
public addToPipeline(stage: actions.IStage, name: string, props: CommonPipelineSourceActionProps): PipelineSourceAction {
return new PipelineSourceAction(this.parent!, name, {
public addToPipeline(stage: actions.IStage, name: string, props: CommonPipelineSourceActionProps = {}): PipelineSourceAction {
return new PipelineSourceAction(this, name, {
stage,
repository: this,
...props,
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-codecommit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
},
"nyc": {
"lines": 30,
"branches": 48
"branches": 40
},
"keywords": [
"aws",
Expand Down
5 changes: 1 addition & 4 deletions packages/@aws-cdk/aws-codedeploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,9 @@ const pipeline = new codepipeline.Pipeline(this, 'MyPipeline', {

// add the source and build Stages to the Pipeline...

const deployStage = new codepipeline.Stage(this, 'Deploy', {
pipeline,
}));
const deployStage = pipeline.addStage('Deploy');
new codedeploy.PipelineDeployAction(this, 'CodeDeploy', {
stage: deployStage,
inputArtifact: buildAction.artifact, // taken from a build Action in a previous Stage
applicationName: 'YourCodeDeployApplicationName',
deploymentGroupName: 'YourCodeDeployDeploymentGroupName',
});
Expand Down
4 changes: 3 additions & 1 deletion packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ export interface PipelineDeployActionProps extends actions.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: actions.Artifact;
inputArtifact?: actions.Artifact;
}

export class PipelineDeployAction extends actions.DeployAction {
Expand Down
53 changes: 40 additions & 13 deletions packages/@aws-cdk/aws-codepipeline-api/lib/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,37 @@ export function defaultBounds(): ActionArtifactBounds {
};
}

/**
* The API of Stage used internally by the CodePipeline Construct.
* You should never need to call any of the methods inside of it yourself.
*/
export interface IInternalStage {
/**
* Adds an Action to this Stage.
*
* @param action the Action to add to this Stage
*/
_attachAction(action: Action): void;

/**
* Generates a unique output artifact name for the given Action.
*
* @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;
}

/**
* The abstract interface of a Pipeline Stage that is used by Actions.
*/
Expand All @@ -56,21 +87,17 @@ export interface IStage {
readonly pipelineRole: iam.Role;

/**
* Grants read & write permissions to the Pipeline's S3 Bucket to the given Identity.
*
* @param identity the IAM Identity to grant the permissions to
* The API of Stage used internally by the CodePipeline Construct.
* You should never need to call any of the methods inside of it yourself.
*/
grantPipelineBucketReadWrite(identity: iam.IPrincipal): void;
readonly _internal: IInternalStage;

/**
* Adds an Action to this Stage.
* This is an internal operation -
* an Action is added to a Stage when it's constructed,
* so there's no need to call this method explicitly.
* Grants read & write permissions to the Pipeline's S3 Bucket to the given Identity.
*
* @param action the Action to add to this Stage
* @param identity the IAM Identity to grant the permissions to
*/
_attachAction(action: Action): void;
grantPipelineBucketReadWrite(identity: iam.IPrincipal): void;
}

/**
Expand Down Expand Up @@ -151,7 +178,7 @@ export abstract class Action extends cdk.Construct {
this.runOrder = 1;
this.stage = props.stage;

this.stage._attachAction(this);
this.stage._internal._attachAction(this);
}

public validate(): string[] {
Expand Down Expand Up @@ -192,12 +219,12 @@ export abstract class Action extends cdk.Construct {
}
}

protected addOutputArtifact(name: string): Artifact {
protected addOutputArtifact(name: string = this.stage._internal._generateOutputArtifactName(this)): Artifact {
const artifact = new Artifact(this, name);
return artifact;
}

protected addInputArtifact(artifact: Artifact): Action {
protected addInputArtifact(artifact: Artifact = this.stage._internal._findInputArtifact(this)): Action {
this._inputArtifacts.push(artifact);
return this;
}
Expand Down
10 changes: 4 additions & 6 deletions 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 {
/**
* 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 All @@ -19,7 +19,7 @@ export interface BuildActionProps extends CommonActionProps {
/**
* The name of the build's output artifact.
*/
artifactName?: string;
outputArtifactName?: string;

/**
* The action's configuration. These are key-value pairs that specify input values for an action.
Expand All @@ -36,7 +36,7 @@ export interface BuildActionProps extends CommonActionProps {
* such as {@link codebuild.PipelineBuildAction}.
*/
export abstract class BuildAction extends Action {
public readonly artifact?: Artifact;
public readonly outputArtifact: Artifact;

constructor(parent: cdk.Construct, name: string, props: BuildActionProps) {
super(parent, name, {
Expand All @@ -48,8 +48,6 @@ export abstract class BuildAction extends Action {
});

this.addInputArtifact(props.inputArtifact);
if (props.artifactName) {
this.artifact = this.addOutputArtifact(props.artifactName);
}
this.outputArtifact = this.addOutputArtifact(props.outputArtifactName);
}
}
4 changes: 1 addition & 3 deletions packages/@aws-cdk/aws-codepipeline-api/lib/deploy-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ export abstract class DeployAction extends Action {
configuration: props.configuration,
});

if (props.inputArtifact) {
this.addInputArtifact(props.inputArtifact);
}
this.addInputArtifact(props.inputArtifact);
}
}
Loading

0 comments on commit 5cc4f3c

Please sign in to comment.