From a536086d7929ae23892080fb89d4218d16464f66 Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Tue, 18 Dec 2018 12:53:45 -0800 Subject: [PATCH] feat(aws-codepipeline): make input Artifacts explicit when creating Actions. 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. --- .../test/test.pipeline-deploy-stack-action.ts | 6 ++-- .../test/test.pipeline-actions.ts | 4 --- packages/@aws-cdk/aws-codebuild/README.md | 16 ++++++--- .../aws-codebuild/lib/pipeline-actions.ts | 8 ++--- .../@aws-cdk/aws-codebuild/lib/project.ts | 4 +-- packages/@aws-cdk/aws-codecommit/README.md | 2 ++ packages/@aws-cdk/aws-codedeploy/README.md | 5 ++- .../aws-codedeploy/lib/deployment-group.ts | 2 +- .../aws-codedeploy/lib/pipeline-action.ts | 4 +-- .../aws-codepipeline-api/lib/action.ts | 13 +------- .../aws-codepipeline-api/lib/build-action.ts | 2 +- .../aws-codepipeline-api/lib/deploy-action.ts | 2 +- .../aws-codepipeline-api/lib/test-action.ts | 4 +-- .../@aws-cdk/aws-codepipeline/lib/pipeline.ts | 33 ------------------- .../@aws-cdk/aws-codepipeline/lib/stage.ts | 4 --- .../test/integ.pipeline-code-commit-build.ts | 10 ++++-- .../test/integ.pipeline-code-deploy.ts | 6 ++-- .../aws-codepipeline/test/test.action.ts | 6 ++-- packages/@aws-cdk/aws-ecr/README.md | 1 + packages/@aws-cdk/aws-s3/README.md | 2 ++ 20 files changed, 49 insertions(+), 85 deletions(-) diff --git a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts index 3c5876a60a894..78cca45e7bbc5 100644 --- a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts @@ -309,7 +309,7 @@ function createSelfUpdatingStack(pipelineStack: cdk.Stack): SelfUpdatingPipeline // simple source const bucket = s3.Bucket.import( pipeline, 'PatternBucket', { bucketArn: 'arn:aws:s3:::totally-fake-bucket' }); - new s3.PipelineSourceAction(pipeline, 'S3Source', { + const sourceAction = new s3.PipelineSourceAction(pipeline, 'S3Source', { bucket, bucketKey: 'the-great-key', stage: pipeline.addStage('source'), @@ -317,7 +317,9 @@ function createSelfUpdatingStack(pipelineStack: cdk.Stack): SelfUpdatingPipeline const project = new codebuild.PipelineProject(pipelineStack, 'CodeBuild'); const buildStage = pipeline.addStage('build'); - const buildAction = project.addToPipeline(buildStage, 'CodeBuild'); + const buildAction = project.addToPipeline(buildStage, 'CodeBuild', { + inputArtifact: sourceAction.outputArtifact, + }); const synthesizedApp = buildAction.outputArtifact; return {synthesizedApp, pipeline}; } diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.pipeline-actions.ts b/packages/@aws-cdk/aws-cloudformation/test/test.pipeline-actions.ts index 37da55382672f..c815250216ef2 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.pipeline-actions.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.pipeline-actions.ts @@ -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 { diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index 1edd0f58e6011..b13fc227e463e 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -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` @@ -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 @@ -209,6 +213,7 @@ 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', @@ -216,8 +221,9 @@ new codebuild.PipelineTestAction(this, 'IntegrationTest', { // 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', }); ``` diff --git a/packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts b/packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts index 368bb68eadcdc..276599d8889ab 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts @@ -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. @@ -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. diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index 12b72d3450aeb..90025d6cc1fe2 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -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, @@ -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, diff --git a/packages/@aws-cdk/aws-codecommit/README.md b/packages/@aws-cdk/aws-codecommit/README.md index b8b4753296a07..de0db57db133a 100644 --- a/packages/@aws-cdk/aws-codecommit/README.md +++ b/packages/@aws-cdk/aws-codecommit/README.md @@ -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: diff --git a/packages/@aws-cdk/aws-codedeploy/README.md b/packages/@aws-cdk/aws-codedeploy/README.md index 415024f7e7bc6..1d11290aa9700 100644 --- a/packages/@aws-cdk/aws-codedeploy/README.md +++ b/packages/@aws-cdk/aws-codedeploy/README.md @@ -175,6 +175,7 @@ const deployStage = pipeline.addStage('Deploy'); new codedeploy.PipelineDeployAction(this, 'CodeDeploy', { stage: deployStage, deploymentGroup, + inputArtifact: buildAction.outputArtifact, }); ``` @@ -182,5 +183,7 @@ 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, +}); ``` diff --git a/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts index 95b3557ad70c7..317263f9162f0 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts @@ -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, diff --git a/packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts b/packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts index 58985c522273d..69688d23c7c1e 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts @@ -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; } /** diff --git a/packages/@aws-cdk/aws-codepipeline-api/lib/action.ts b/packages/@aws-cdk/aws-codepipeline-api/lib/action.ts index c3ac1528f9448..5966ba7ddf95d 100644 --- a/packages/@aws-cdk/aws-codepipeline-api/lib/action.ts +++ b/packages/@aws-cdk/aws-codepipeline-api/lib/action.ts @@ -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; } /** @@ -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; } diff --git a/packages/@aws-cdk/aws-codepipeline-api/lib/build-action.ts b/packages/@aws-cdk/aws-codepipeline-api/lib/build-action.ts index da078f34a4bd1..097ddaa159406 100644 --- a/packages/@aws-cdk/aws-codepipeline-api/lib/build-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-api/lib/build-action.ts @@ -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. diff --git a/packages/@aws-cdk/aws-codepipeline-api/lib/deploy-action.ts b/packages/@aws-cdk/aws-codepipeline-api/lib/deploy-action.ts index 7e678020b9be0..c6d3ce88e4f4f 100644 --- a/packages/@aws-cdk/aws-codepipeline-api/lib/deploy-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-api/lib/deploy-action.ts @@ -9,7 +9,7 @@ export interface DeployActionProps extends CommonActionProps, CommonActionConstr artifactBounds: ActionArtifactBounds; - inputArtifact?: Artifact; + inputArtifact: Artifact; configuration?: any; } diff --git a/packages/@aws-cdk/aws-codepipeline-api/lib/test-action.ts b/packages/@aws-cdk/aws-codepipeline-api/lib/test-action.ts index 1d20efab9c9ac..58d8a192d4705 100644 --- a/packages/@aws-cdk/aws-codepipeline-api/lib/test-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-api/lib/test-action.ts @@ -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. diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 4baa3aff60dd7..6a8a6dae90f75 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -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'] diff --git a/packages/@aws-cdk/aws-codepipeline/lib/stage.ts b/packages/@aws-cdk/aws-codepipeline/lib/stage.ts index bd1faa6398c80..8fc109b86f723 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/stage.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/stage.ts @@ -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, diff --git a/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-commit-build.ts b/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-commit-build.ts index 47ee8fe3477a6..fde478478e9af 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-commit-build.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-commit-build.ts @@ -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, @@ -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(); diff --git a/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.ts b/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.ts index dfe6f662ba28e..2dc12120d9420 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.ts @@ -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(); diff --git a/packages/@aws-cdk/aws-codepipeline/test/test.action.ts b/packages/@aws-cdk/aws-codepipeline/test/test.action.ts index 33e2709e700e2..61859998ea7c4 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/test.action.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/test.action.ts @@ -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": [ diff --git a/packages/@aws-cdk/aws-ecr/README.md b/packages/@aws-cdk/aws-ecr/README.md index cefec43725fbb..948fb314cb03c 100644 --- a/packages/@aws-cdk/aws-ecr/README.md +++ b/packages/@aws-cdk/aws-ecr/README.md @@ -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: diff --git a/packages/@aws-cdk/aws-s3/README.md b/packages/@aws-cdk/aws-s3/README.md index 667b29e1c7444..7d037fee1542f 100644 --- a/packages/@aws-cdk/aws-s3/README.md +++ b/packages/@aws-cdk/aws-s3/README.md @@ -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: