From c3667d7aba4b7f50e5d69c1228f12bb55196f75b Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Tue, 18 Jun 2019 00:07:29 -0700 Subject: [PATCH] fix(codebuild): API cleanup. (#2745) Change the names of the source classes to be more consistent with other integrations. Make the abstract Source classes package-private. Add static factory methods to Source. Change the names of artifacts classes to be more consistent with other integrations. Add static factory methods to Artifacts. Make CodePipelineSource, CodePipelineArtifacts, NoSource, and NoArtifacts package-private. Get rid of the SourceType enum. BREAKING CHANGE: * codebuild: rename BuildSource to Source, S3BucketSource to S3Source, BuildArtifacts to Artifacts, S3BucketBuildArtifacts to S3Artifacts * codebuild: the classes CodePipelineBuildSource, CodePipelineBuildArtifacts, NoBuildSource, and NoBuildArtifacts have been removed * codebuild: rename buildScriptAsset and buildScriptAssetEntrypoint to buildScript and buildScriptEntrypoint, respectively --- packages/@aws-cdk/aws-codebuild/README.md | 49 ++-- .../@aws-cdk/aws-codebuild/lib/artifacts.ts | 131 +++++---- .../lib/codepipeline-artifacts.ts | 14 + .../aws-codebuild/lib/codepipeline-source.ts | 15 + .../aws-codebuild/lib/no-artifacts.ts | 19 ++ .../@aws-cdk/aws-codebuild/lib/no-source.ts | 19 ++ .../aws-codebuild/lib/pipeline-project.ts | 6 +- .../@aws-cdk/aws-codebuild/lib/project.ts | 199 ++++++------- .../aws-codebuild/lib/source-types.ts | 7 + packages/@aws-cdk/aws-codebuild/lib/source.ts | 267 +++++++++--------- .../aws-codebuild/test/integ.github.ts | 2 +- .../test/integ.project-bucket.ts | 2 +- ...teg.project-secondary-sources-artifacts.ts | 4 +- .../test/integ.project-shell.expected.json | 243 ---------------- .../aws-codebuild/test/integ.project-shell.ts | 14 - .../test/integ.project-vpc.expected.json | 119 +------- .../aws-codebuild/test/integ.project-vpc.ts | 14 +- .../aws-codebuild/test/test.codebuild.ts | 164 +++++------ .../aws-codebuild/test/test.project.ts | 78 ++--- .../aws-codepipeline-actions/README.md | 11 - .../test.cloudformation-pipeline-actions.ts | 8 +- .../test/integ.pipeline-code-commit-build.ts | 4 +- .../test/test.pipeline.ts | 4 +- .../test/codebuild/codebuild.test.ts | 2 +- .../test/codebuild/integ.project-events.ts | 2 +- 25 files changed, 499 insertions(+), 898 deletions(-) create mode 100644 packages/@aws-cdk/aws-codebuild/lib/codepipeline-artifacts.ts create mode 100644 packages/@aws-cdk/aws-codebuild/lib/codepipeline-source.ts create mode 100644 packages/@aws-cdk/aws-codebuild/lib/no-artifacts.ts create mode 100644 packages/@aws-cdk/aws-codebuild/lib/no-source.ts create mode 100644 packages/@aws-cdk/aws-codebuild/lib/source-types.ts delete mode 100644 packages/@aws-cdk/aws-codebuild/test/integ.project-shell.expected.json delete mode 100644 packages/@aws-cdk/aws-codebuild/test/integ.project-shell.ts diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index 8bb4d088a57bb..4899ba712181e 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -42,15 +42,10 @@ methods and attributes. ## Source Build projects are usually associated with a _source_, which is specified via -the `source` property which accepts a class that extends the `BuildSource` -abstract base class. The supported sources are: - -### `NoSource` - -This is the default and implies that no source is associated with this -build project. - -The `buildSpec` option is required in this case. +the `source` property which accepts a class that extends the `Source` +abstract base class. +The default is to have no source associated with the build project; +the `buildSpec` option is required in that case. Here's a CodeBuild project with no source which simply prints `Hello, CodeBuild!`: @@ -67,11 +62,11 @@ import codecommit = require('@aws-cdk/aws-codecommit'); const repository = new codecommit.Repository(this, 'MyRepo', { repositoryName: 'foo' }); new codebuild.Project(this, 'MyFirstCodeCommitProject', { - source: new codebuild.CodeCommitSource({ repository }), + source: codebuild.Source.codeCommit({ repository }), }); ``` -### `S3BucketSource` +### `S3Source` Create a CodeBuild project with an S3 bucket as the source: @@ -81,25 +76,20 @@ import s3 = require('@aws-cdk/aws-s3'); const bucket = new s3.Bucket(this, 'MyBucket'); new codebuild.Project(this, 'MyProject', { - source: new codebuild.S3BucketSource({ + source: codebuild.Source.s3({ bucket: bucket, path: 'path/to/file.zip', }), }); ``` -### `CodePipelineSource` - -Used as a special source type when a CodeBuild project is used as a -CodePipeline action. - ### `GitHubSource` and `GitHubEnterpriseSource` These source types can be used to build code from a GitHub repository. Example: ```typescript -const gitHubSource = new codebuild.GitHubSource({ +const gitHubSource = codebuild.Source.gitHub({ owner: 'awslabs', repo: 'aws-cdk', webhook: true, // optional, default: true if `webhookFilteres` were provided, false otherwise @@ -121,6 +111,23 @@ aws codebuild import-source-credentials --server-type GITHUB --auth-type PERSONA This source type can be used to build code from a BitBucket repository. +## CodePipeline + +To add a CodeBuild Project as an Action to CodePipeline, +use the `PipelineProject` class instead of `Project`. +It's a simple class that doesn't allow you to specify `sources`, +`secondarySources`, `artifacts` or `secondaryArtifacts`, +as these are handled by setting input and output CodePipeline `Artifact` instances on the Action, +instead of setting them on the Project. + +```typescript +const project = new codebuild.PipelineProject(this, 'Project', { + // properties as above... +}) +``` + +For more details, see the readme of the `@aws-cdk/@aws-codepipeline` package. + ## Caching You can save time when your project builds by using a cache. A cache can store reusable pieces of your build environment and use them across multiple builds. Your build project can use one of two types of caching: Amazon S3 or local. In general, S3 caching is a good option for small and intermediate build artifacts that are more expensive to build than to download. Local caching is a good option for large intermediate build artifacts because the cache is immediately available on the build host. @@ -225,13 +232,13 @@ multiple outputs. For example: ```ts const project = new codebuild.Project(this, 'MyProject', { secondarySources: [ - new codebuild.CodeCommitSource({ + codebuild.Source.codeCommit({ identifier: 'source2', repository: repo, }), ], secondaryArtifacts: [ - new codebuild.S3BucketBuildArtifacts({ + codebuild.Artifacts.s3({ identifier: 'artifact2', bucket: bucket, path: 'some/path', @@ -324,7 +331,7 @@ const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { vpc: vpc, }); new Project(stack, 'MyProject', { - buildScriptAsset: new assets.ZipDirectoryAsset(stack, 'Bundle', { path: 'script_bundle' }), + buildScript: new assets.ZipDirectoryAsset(stack, 'Bundle', { path: 'script_bundle' }), securityGroups: [securityGroup], vpc: vpc }); diff --git a/packages/@aws-cdk/aws-codebuild/lib/artifacts.ts b/packages/@aws-cdk/aws-codebuild/lib/artifacts.ts index 53c9e835a2766..0e314f8ae5eba 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/artifacts.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/artifacts.ts @@ -1,84 +1,83 @@ import s3 = require('@aws-cdk/aws-s3'); +import { Construct } from '@aws-cdk/cdk'; import { CfnProject } from './codebuild.generated'; -import { Project } from './project'; +import { IProject } from './project'; /** - * Properties common to all Artifacts classes. + * The type returned from {@link IArtifacts#bind}. */ -export interface BuildArtifactsProps { +export interface ArtifactsConfig { /** - * The artifact identifier. - * This property is required on secondary artifacts. + * The low-level CloudFormation artifacts property. */ - readonly identifier?: string; + readonly artifactsProperty: CfnProject.ArtifactsProperty; } /** - * Artifacts definition for a CodeBuild Project. + * The abstract interface of a CodeBuild build output. + * Implemented by {@link Artifacts}. */ -export abstract class BuildArtifacts { - public readonly identifier?: string; - protected abstract readonly type: string; - - constructor(props: BuildArtifactsProps) { - this.identifier = props.identifier; - } - +export interface IArtifacts { /** - * @internal + * The artifact identifier. + * This property is required on secondary artifacts. */ - public _bind(_project: Project) { - return; - } + readonly identifier?: string; - public toArtifactsJSON(): CfnProject.ArtifactsProperty { - const artifactsProp = this.toArtifactsProperty(); - return { - artifactIdentifier: this.identifier, - type: this.type, - ...artifactsProp, - }; - } + /** + * The CodeBuild type of this artifact. + */ + readonly type: string; - protected toArtifactsProperty(): any { - return { - }; - } + /** + * Callback when an Artifacts class is used in a CodeBuild Project. + * + * @param scope a root Construct that allows creating new Constructs + * @param project the Project this Artifacts is used in + */ + bind(scope: Construct, project: IProject): ArtifactsConfig; } /** - * A `NO_ARTIFACTS` CodeBuild Project Artifact definition. - * This is the default artifact type, - * if none was specified when creating the Project - * (and the source was not specified to be CodePipeline). - * *Note*: the `NO_ARTIFACTS` type cannot be used as a secondary artifact, - * and because of that, you're not allowed to specify an identifier for it. + * Properties common to all Artifacts classes. */ -export class NoBuildArtifacts extends BuildArtifacts { - protected readonly type = 'NO_ARTIFACTS'; - - constructor() { - super({}); - } +export interface ArtifactsProps { + /** + * The artifact identifier. + * This property is required on secondary artifacts. + */ + readonly identifier?: string; } /** - * CodePipeline Artifact definition for a CodeBuild Project. - * *Note*: this type cannot be used as a secondary artifact, - * and because of that, you're not allowed to specify an identifier for it. + * Artifacts definition for a CodeBuild Project. */ -export class CodePipelineBuildArtifacts extends BuildArtifacts { - protected readonly type = 'CODEPIPELINE'; +export abstract class Artifacts implements IArtifacts { + public static s3(props: S3ArtifactsProps): Artifacts { + return new S3Artifacts(props); + } - constructor() { - super({}); + public readonly identifier?: string; + public abstract readonly type: string; + + protected constructor(props: ArtifactsProps) { + this.identifier = props.identifier; + } + + public bind(_scope: Construct, _project: IProject): ArtifactsConfig { + return { + artifactsProperty: { + artifactIdentifier: this.identifier, + type: this.type, + }, + }; } } /** - * Construction properties for {@link S3BucketBuildArtifacts}. + * Construction properties for {@link S3Artifacts}. */ -export interface S3BucketBuildArtifactsProps extends BuildArtifactsProps { +export interface S3ArtifactsProps extends ArtifactsProps { /** * The name of the output bucket. */ @@ -119,27 +118,25 @@ export interface S3BucketBuildArtifactsProps extends BuildArtifactsProps { /** * S3 Artifact definition for a CodeBuild Project. */ -export class S3BucketBuildArtifacts extends BuildArtifacts { - protected readonly type = 'S3'; +class S3Artifacts extends Artifacts { + public readonly type = 'S3'; - constructor(private readonly props: S3BucketBuildArtifactsProps) { + constructor(private readonly props: S3ArtifactsProps) { super(props); } - /** - * @internal - */ - public _bind(project: Project) { + public bind(_scope: Construct, project: IProject): ArtifactsConfig { this.props.bucket.grantReadWrite(project); - } - - protected toArtifactsProperty(): any { + const superConfig = super.bind(_scope, project); return { - location: this.props.bucket.bucketName, - path: this.props.path, - namespaceType: this.props.includeBuildId === false ? 'NONE' : 'BUILD_ID', - name: this.props.name, - packaging: this.props.packageZip === false ? 'NONE' : 'ZIP', + artifactsProperty: { + ...superConfig.artifactsProperty, + location: this.props.bucket.bucketName, + path: this.props.path, + namespaceType: this.props.includeBuildId === false ? 'NONE' : 'BUILD_ID', + name: this.props.name, + packaging: this.props.packageZip === false ? 'NONE' : 'ZIP', + } }; } } diff --git a/packages/@aws-cdk/aws-codebuild/lib/codepipeline-artifacts.ts b/packages/@aws-cdk/aws-codebuild/lib/codepipeline-artifacts.ts new file mode 100644 index 0000000000000..8b8d72e6c2cc7 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/codepipeline-artifacts.ts @@ -0,0 +1,14 @@ +import { Artifacts } from './artifacts'; + +/** + * CodePipeline Artifact definition for a CodeBuild Project. + * *Note*: this type cannot be used as a secondary artifact, + * and because of that, you're not allowed to specify an identifier for it. + */ +export class CodePipelineArtifacts extends Artifacts { + public readonly type = 'CODEPIPELINE'; + + constructor() { + super({}); + } +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/codepipeline-source.ts b/packages/@aws-cdk/aws-codebuild/lib/codepipeline-source.ts new file mode 100644 index 0000000000000..fb72a6b605a4a --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/codepipeline-source.ts @@ -0,0 +1,15 @@ +import { Source } from './source'; +import { CODEPIPELINE_SOURCE_ARTIFACTS_TYPE } from './source-types'; + +/** + * CodePipeline Source definition for a CodeBuild Project. + * *Note*: this type cannot be used as a secondary source, + * and because of that, you're not allowed to specify an identifier for it. + */ +export class CodePipelineSource extends Source { + public readonly type = CODEPIPELINE_SOURCE_ARTIFACTS_TYPE; + + constructor() { + super({}); + } +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/no-artifacts.ts b/packages/@aws-cdk/aws-codebuild/lib/no-artifacts.ts new file mode 100644 index 0000000000000..72bbbd07b9f71 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/no-artifacts.ts @@ -0,0 +1,19 @@ +import { Artifacts } from './artifacts'; + +/** + * A `NO_ARTIFACTS` CodeBuild Project Artifact definition. + * This is the default artifact type, + * if none was specified when creating the Project + * (and the source was not specified to be CodePipeline). + * *Note*: the `NO_ARTIFACTS` type cannot be used as a secondary artifact, + * and because of that, you're not allowed to specify an identifier for it. + * + * This class is private to the @aws-codebuild package. + */ +export class NoArtifacts extends Artifacts { + public readonly type = 'NO_ARTIFACTS'; + + constructor() { + super({}); + } +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/no-source.ts b/packages/@aws-cdk/aws-codebuild/lib/no-source.ts new file mode 100644 index 0000000000000..eb45884c6f1e7 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/no-source.ts @@ -0,0 +1,19 @@ +import { Source } from './source'; +import { NO_SOURCE_TYPE } from './source-types'; + +/** + * A `NO_SOURCE` CodeBuild Project Source definition. + * This is the default source type, + * if none was specified when creating the Project. + * *Note*: the `NO_SOURCE` type cannot be used as a secondary source, + * and because of that, you're not allowed to specify an identifier for it. + * + * This class is private to the aws-codebuild package. + */ +export class NoSource extends Source { + public readonly type = NO_SOURCE_TYPE; + + constructor() { + super({}); + } +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/pipeline-project.ts b/packages/@aws-cdk/aws-codebuild/lib/pipeline-project.ts index 7d6e4e4193e09..979850701a862 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/pipeline-project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/pipeline-project.ts @@ -1,7 +1,7 @@ import cdk = require('@aws-cdk/cdk'); -import { CodePipelineBuildArtifacts } from './artifacts'; +import { CodePipelineArtifacts } from './codepipeline-artifacts'; +import { CodePipelineSource } from './codepipeline-source'; import { CommonProjectProps, Project } from './project'; -import { CodePipelineSource } from './source'; // tslint:disable-next-line:no-empty-interface export interface PipelineProjectProps extends CommonProjectProps { @@ -14,7 +14,7 @@ export class PipelineProject extends Project { constructor(scope: cdk.Construct, id: string, props?: PipelineProjectProps) { super(scope, id, { source: new CodePipelineSource(), - artifacts: new CodePipelineBuildArtifacts(), + artifacts: new CodePipelineArtifacts(), ...props }); } diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index 96f411214d662..053ed6c824fed 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -1,4 +1,3 @@ -import assets = require('@aws-cdk/assets'); import { DockerImageAsset, DockerImageAssetProps } from '@aws-cdk/assets-docker'; import cloudwatch = require('@aws-cdk/aws-cloudwatch'); import ec2 = require('@aws-cdk/aws-ec2'); @@ -7,17 +6,20 @@ import events = require('@aws-cdk/aws-events'); import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); import { Aws, Construct, IResource, Lazy, PhysicalName, Resource, ResourceIdentifiers, Stack } from '@aws-cdk/cdk'; -import { BuildArtifacts, CodePipelineBuildArtifacts, NoBuildArtifacts } from './artifacts'; -import { BuildSpec, mergeBuildSpecs } from './build-spec'; +import { IArtifacts } from './artifacts'; +import { BuildSpec } from './build-spec'; import { Cache } from './cache'; import { CfnProject } from './codebuild.generated'; -import { BuildSource, NoSource, SourceType } from './source'; +import { CodePipelineArtifacts } from './codepipeline-artifacts'; +import { NoArtifacts } from './no-artifacts'; +import { NoSource } from './no-source'; +import { ISource } from './source'; +import { CODEPIPELINE_SOURCE_ARTIFACTS_TYPE, NO_SOURCE_TYPE } from './source-types'; -const CODEPIPELINE_TYPE = 'CODEPIPELINE'; const S3_BUCKET_ENV = 'SCRIPT_S3_BUCKET'; const S3_KEY_ENV = 'SCRIPT_S3_KEY'; -export interface IProject extends IResource, iam.IGrantable { +export interface IProject extends IResource, iam.IGrantable, ec2.IConnectable { /** * The ARN of this Project. * @attribute @@ -33,6 +35,8 @@ export interface IProject extends IResource, iam.IGrantable { /** The IAM service Role of this Project. Undefined for imported Projects. */ readonly role?: iam.IRole; + addToRolePolicy(policyStatement: iam.PolicyStatement): void; + /** * Defines a CloudWatch event rule triggered when something happens with this project. * @@ -165,6 +169,34 @@ abstract class ProjectBase extends Resource implements IProject { /** The IAM service Role of this Project. */ public abstract readonly role?: iam.IRole; + /** + * Actual connections object for this Project. + * May be unset, in which case this Project is not configured to use a VPC. + * @internal + */ + protected _connections: ec2.Connections; + + /** + * Access the Connections object. + * Will fail if this Project does not have a VPC set. + */ + public get connections(): ec2.Connections { + if (!this._connections) { + throw new Error('Only VPC-associated Projects have security groups to manage. Supply the "vpc" parameter when creating the Project'); + } + return this._connections; + } + + /** + * Add a permission only if there's a policy attached. + * @param statement The permissions statement to add + */ + public addToRolePolicy(statement: iam.PolicyStatement) { + if (this.role) { + this.role.addToPolicy(statement); + } + } + /** * Defines a CloudWatch event rule triggered when something happens with this project. * @@ -374,26 +406,6 @@ export interface CommonProjectProps { */ readonly buildSpec?: BuildSpec; - /** - * Run a script from an asset as build script - * - * If supplied together with buildSpec, the asset script will be run - * _after_ the existing commands in buildspec. - * - * This feature can also be used without a source, to simply run an - * arbitrary script in a serverless way. - * - * @default - No asset build script. - */ - readonly buildScriptAsset?: assets.Asset; - - /** - * The script in the asset to run. - * - * @default build.sh - */ - readonly buildScriptAssetEntrypoint?: string; - /** * Service Role to assume while running the build. * @@ -504,15 +516,15 @@ export interface ProjectProps extends CommonProjectProps { * * @default - NoSource */ - readonly source?: BuildSource; + readonly source?: ISource; /** * Defines where build artifacts will be stored. - * Could be: PipelineBuildArtifacts, NoBuildArtifacts and S3BucketBuildArtifacts. + * Could be: PipelineBuildArtifacts, NoArtifacts and S3Artifacts. * - * @default NoBuildArtifacts + * @default NoArtifacts */ - readonly artifacts?: BuildArtifacts; + readonly artifacts?: IArtifacts; /** * The secondary sources for the Project. @@ -521,7 +533,7 @@ export interface ProjectProps extends CommonProjectProps { * @default - No secondary sources. * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-multi-in-out.html */ - readonly secondarySources?: BuildSource[]; + readonly secondarySources?: ISource[]; /** * The secondary artifacts for the Project. @@ -530,7 +542,7 @@ export interface ProjectProps extends CommonProjectProps { * @default - No secondary artifacts. * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-multi-in-out.html */ - readonly secondaryArtifacts?: BuildArtifacts[]; + readonly secondaryArtifacts?: IArtifacts[]; } /** @@ -610,21 +622,16 @@ export class Project extends ProjectBase { */ public readonly projectName: string; - private readonly source: BuildSource; + private readonly source: ISource; private readonly buildImage: IBuildImage; - private readonly _secondarySources: BuildSource[]; - private readonly _secondaryArtifacts: BuildArtifacts[]; - private _securityGroups: ec2.ISecurityGroup[] = []; + private readonly _secondarySources: CfnProject.SourceProperty[]; + private readonly _secondaryArtifacts: CfnProject.ArtifactsProperty[]; constructor(scope: Construct, id: string, props: ProjectProps) { super(scope, id, { physicalName: props.projectName, }); - if (props.buildScriptAssetEntrypoint && !props.buildScriptAsset) { - throw new Error('To use buildScriptAssetEntrypoint, supply buildScriptAsset as well.'); - } - this.role = props.role || new iam.Role(this, 'Role', { roleName: PhysicalName.auto({ crossEnvironment: true }), assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com') @@ -636,10 +643,17 @@ export class Project extends ProjectBase { // let source "bind" to the project. this usually involves granting permissions // for the code build role to interact with the source. this.source = props.source || new NoSource(); - this.source._bind(this); + const sourceConfig = this.source.bind(this, this); + if (props.badge && !this.source.badgeSupported) { + throw new Error(`Badge is not supported for source type ${this.source.type}`); + } - const artifacts = this.parseArtifacts(props); - artifacts._bind(this); + const artifacts = props.artifacts + ? props.artifacts + : (this.source.type === CODEPIPELINE_SOURCE_ARTIFACTS_TYPE + ? new CodePipelineArtifacts() + : new NoArtifacts()); + const artifactsConfig = artifacts.bind(this, this); const cache = props.cache || Cache.none(); @@ -648,34 +662,11 @@ export class Project extends ProjectBase { // Inject download commands for asset if requested const environmentVariables = props.environmentVariables || {}; - let buildSpec = props.buildSpec; - - if (props.buildScriptAsset) { - environmentVariables[S3_BUCKET_ENV] = { value: props.buildScriptAsset.s3BucketName }; - environmentVariables[S3_KEY_ENV] = { value: props.buildScriptAsset.s3ObjectKey }; - - const runScript = this.buildImage.runScriptBuildspec(props.buildScriptAssetEntrypoint || 'build.sh'); - buildSpec = buildSpec ? mergeBuildSpecs(buildSpec, runScript) : runScript; - props.buildScriptAsset.grantRead(this.role); + const buildSpec = props.buildSpec; + if (this.source.type === NO_SOURCE_TYPE && (buildSpec === undefined || !buildSpec.isImmediate)) { + throw new Error("If the Project's source is NoSource, you need to provide a concrete buildSpec"); } - // Render the source and add in the buildspec - const renderSource = () => { - if (props.badge && !this.source.badgeSupported) { - throw new Error(`Badge is not supported for source type ${this.source.type}`); - } - - if (this.source.type === SourceType.None && (buildSpec === undefined || !buildSpec.isImmediate)) { - throw new Error("If the Project's source is NoSource, you need to provide a concrete buildSpec"); - } - - const sourceJson = this.source._toSourceJSON(); - return { - ...sourceJson, - buildSpec: buildSpec && buildSpec.toBuildSpec() - }; - }; - this._secondarySources = []; for (const secondarySource of props.secondarySources || []) { this.addSecondarySource(secondarySource); @@ -690,8 +681,11 @@ export class Project extends ProjectBase { const resource = new CfnProject(this, 'Resource', { description: props.description, - source: renderSource(), - artifacts: artifacts.toArtifactsJSON(), + source: { + ...sourceConfig.sourceProperty, + buildSpec: buildSpec && buildSpec.toBuildSpec() + }, + artifacts: artifactsConfig.artifactsProperty, serviceRole: this.role.roleArn, environment: this.renderEnvironment(props.environment, environmentVariables), encryptionKey: props.encryptionKey && props.encryptionKey.keyArn, @@ -701,7 +695,7 @@ export class Project extends ProjectBase { timeoutInMinutes: props.timeout, secondarySources: Lazy.anyValue({ produce: () => this.renderSecondarySources() }), secondaryArtifacts: Lazy.anyValue({ produce: () => this.renderSecondaryArtifacts() }), - triggers: this.source._buildTriggers(), + triggers: sourceConfig.buildTriggers, vpcConfig: this.configureVpc(props), }); @@ -724,20 +718,6 @@ export class Project extends ProjectBase { } } - public get securityGroups(): ec2.ISecurityGroup[] { - return this._securityGroups.slice(); - } - - /** - * Add a permission only if there's a policy attached. - * @param statement The permissions statement to add - */ - public addToRolePolicy(statement: iam.PolicyStatement) { - if (this.role) { - this.role.addToPolicy(statement); - } - } - /** * Add a permission only if there's a policy attached. * @param statement The permissions statement to add @@ -758,12 +738,11 @@ export class Project extends ProjectBase { * @param secondarySource the source to add as a secondary source * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-multi-in-out.html */ - public addSecondarySource(secondarySource: BuildSource): void { + public addSecondarySource(secondarySource: ISource): void { if (!secondarySource.identifier) { throw new Error('The identifier attribute is mandatory for secondary sources'); } - secondarySource._bind(this); - this._secondarySources.push(secondarySource); + this._secondarySources.push(secondarySource.bind(this, this).sourceProperty); } /** @@ -772,12 +751,11 @@ export class Project extends ProjectBase { * @param secondaryArtifact the artifact to add as a secondary artifact * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-multi-in-out.html */ - public addSecondaryArtifact(secondaryArtifact: BuildArtifacts): any { + public addSecondaryArtifact(secondaryArtifact: IArtifacts): any { if (!secondaryArtifact.identifier) { throw new Error("The identifier attribute is mandatory for secondary artifacts"); } - secondaryArtifact._bind(this); - this._secondaryArtifacts.push(secondaryArtifact); + this._secondaryArtifacts.push(secondaryArtifact.bind(this, this).artifactsProperty); } /** @@ -785,7 +763,7 @@ export class Project extends ProjectBase { */ protected validate(): string[] { const ret = new Array(); - if (this.source.type === SourceType.CodePipeline) { + if (this.source.type === CODEPIPELINE_SOURCE_ARTIFACTS_TYPE) { if (this._secondarySources.length > 0) { ret.push('A Project with a CodePipeline Source cannot have secondary sources. ' + "Use the CodeBuild Pipeline Actions' `extraInputs` property instead"); @@ -852,13 +830,13 @@ export class Project extends ProjectBase { private renderSecondarySources(): CfnProject.SourceProperty[] | undefined { return this._secondarySources.length === 0 ? undefined - : this._secondarySources.map((secondarySource) => secondarySource._toSourceJSON()); + : this._secondarySources; } private renderSecondaryArtifacts(): CfnProject.ArtifactsProperty[] | undefined { return this._secondaryArtifacts.length === 0 ? undefined - : this._secondaryArtifacts.map((secondaryArtifact) => secondaryArtifact.toArtifactsJSON()); + : this._secondaryArtifacts; } /** @@ -878,16 +856,19 @@ export class Project extends ProjectBase { throw new Error(`Configure 'allowAllOutbound' directly on the supplied SecurityGroup.`); } + let securityGroups: ec2.ISecurityGroup[]; if (props.securityGroups && props.securityGroups.length > 0) { - this._securityGroups = props.securityGroups.slice(); + securityGroups = props.securityGroups; } else { const securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, description: 'Automatic generated security group for CodeBuild ' + this.node.uniqueId, allowAllOutbound: props.allowAllOutbound }); - this._securityGroups = [securityGroup]; + securityGroups = [securityGroup]; } + this._connections = new ec2.Connections({ securityGroups }); + this.addToRoleInlinePolicy(new iam.PolicyStatement({ resources: ['*'], actions: [ @@ -911,27 +892,17 @@ export class Project extends ProjectBase { return { vpcId: props.vpc.vpcId, subnets: props.vpc.selectSubnets(props.subnetSelection).subnetIds, - securityGroupIds: this._securityGroups.map(s => s.securityGroupId) + securityGroupIds: this.connections.securityGroups.map(s => s.securityGroupId) }; } - private parseArtifacts(props: ProjectProps) { - if (props.artifacts) { - return props.artifacts; - } - if (this.source._toSourceJSON().type === CODEPIPELINE_TYPE) { - return new CodePipelineBuildArtifacts(); - } else { - return new NoBuildArtifacts(); - } - } - - private validateCodePipelineSettings(artifacts: BuildArtifacts) { - const sourceType = this.source._toSourceJSON().type; - const artifactsType = artifacts.toArtifactsJSON().type; + private validateCodePipelineSettings(artifacts: IArtifacts) { + const sourceType = this.source.type; + const artifactsType = artifacts.type; - if ((sourceType === CODEPIPELINE_TYPE || artifactsType === CODEPIPELINE_TYPE) && - (sourceType !== artifactsType)) { + if ((sourceType === CODEPIPELINE_SOURCE_ARTIFACTS_TYPE || + artifactsType === CODEPIPELINE_SOURCE_ARTIFACTS_TYPE) && + (sourceType !== artifactsType)) { throw new Error('Both source and artifacts must be set to CodePipeline'); } } diff --git a/packages/@aws-cdk/aws-codebuild/lib/source-types.ts b/packages/@aws-cdk/aws-codebuild/lib/source-types.ts new file mode 100644 index 0000000000000..fb9137ec66e8c --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/source-types.ts @@ -0,0 +1,7 @@ +export const NO_SOURCE_TYPE = 'NO_SOURCE'; +export const CODEPIPELINE_SOURCE_ARTIFACTS_TYPE = 'CODEPIPELINE'; +export const S3_SOURCE_TYPE = 'S3'; +export const CODECOMMIT_SOURCE_TYPE = 'CODECOMMIT'; +export const GITHUB_SOURCE_TYPE = 'GITHUB'; +export const GITHUB_ENTERPRISE_SOURCE_TYPE = 'GITHUB_ENTERPRISE'; +export const BITBUCKET_SOURCE_TYPE = 'BITBUCKET'; diff --git a/packages/@aws-cdk/aws-codebuild/lib/source.ts b/packages/@aws-cdk/aws-codebuild/lib/source.ts index 9bd734fad4faa..671a3cf1ba947 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/source.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/source.ts @@ -1,13 +1,44 @@ import codecommit = require('@aws-cdk/aws-codecommit'); import iam = require('@aws-cdk/aws-iam'); import s3 = require('@aws-cdk/aws-s3'); +import { Construct } from '@aws-cdk/cdk'; import { CfnProject } from './codebuild.generated'; -import { Project } from './project'; +import { IProject } from './project'; +import { + BITBUCKET_SOURCE_TYPE, + CODECOMMIT_SOURCE_TYPE, + GITHUB_ENTERPRISE_SOURCE_TYPE, + GITHUB_SOURCE_TYPE, + S3_SOURCE_TYPE +} from './source-types'; + +/** + * The type returned from {@link ISource#bind}. + */ +export interface SourceConfig { + readonly sourceProperty: CfnProject.SourceProperty; + + readonly buildTriggers?: CfnProject.ProjectTriggersProperty; +} + +/** + * The abstract interface of a CodeBuild source. + * Implemented by {@link Source}. + */ +export interface ISource { + readonly identifier?: string; + + readonly type: string; + + readonly badgeSupported: boolean; + + bind(scope: Construct, project: IProject): SourceConfig; +} /** * Properties common to all Source classes. */ -export interface BuildSourceProps { +export interface SourceProps { /** * The source identifier. * This property is required on secondary sources. @@ -18,12 +49,32 @@ export interface BuildSourceProps { /** * Source provider definition for a CodeBuild Project. */ -export abstract class BuildSource { +export abstract class Source implements ISource { + public static s3(props: S3SourceProps): Source { + return new S3Source(props); + } + + public static codeCommit(props: CodeCommitSourceProps): Source { + return new CodeCommitSource(props); + } + + public static gitHub(props: GitHubSourceProps): Source { + return new GitHubSource(props); + } + + public static gitHubEnterprise(props: GitHubEnterpriseSourceProps): Source { + return new GitHubEnterpriseSource(props); + } + + public static bitBucket(props: BitBucketSourceProps): Source { + return new BitBucketSource(props); + } + public readonly identifier?: string; - public abstract readonly type: SourceType; + public abstract readonly type: string; public readonly badgeSupported: boolean = false; - constructor(props: BuildSourceProps) { + protected constructor(props: SourceProps) { this.identifier = props.identifier; } @@ -31,54 +82,21 @@ export abstract class BuildSource { * Called by the project when the source is added so that the source can perform * binding operations on the source. For example, it can grant permissions to the * code build project to read from the S3 bucket. - * - * @internal */ - public _bind(_project: Project) { - // by default, do nothing - return; - } - - /** @internal */ - public _toSourceJSON(): CfnProject.SourceProperty { - const sourceProp = this.toSourceProperty(); - return { - sourceIdentifier: this.identifier, - type: this.type, - ...sourceProp, - }; - } - - /** @internal */ - public _buildTriggers(): CfnProject.ProjectTriggersProperty | undefined { - return undefined; - } - - protected toSourceProperty(): any { + public bind(_scope: Construct, _project: IProject): SourceConfig { return { + sourceProperty: { + sourceIdentifier: this.identifier, + type: this.type, + } }; } } -/** - * A `NO_SOURCE` CodeBuild Project Source definition. - * This is the default source type, - * if none was specified when creating the Project. - * *Note*: the `NO_SOURCE` type cannot be used as a secondary source, - * and because of that, you're not allowed to specify an identifier for it. - */ -export class NoSource extends BuildSource { - public readonly type: SourceType = SourceType.None; - - constructor() { - super({}); - } -} - /** * The construction properties common to all build sources that are backed by Git. */ -export interface GitBuildSourceProps extends BuildSourceProps { +interface GitSourceProps extends SourceProps { /** * The depth of history to download. Minimum value is 0. * If this value is 0, greater than 25, or not provided, @@ -90,20 +108,22 @@ export interface GitBuildSourceProps extends BuildSourceProps { /** * A common superclass of all build sources that are backed by Git. */ -export abstract class GitBuildSource extends BuildSource { +abstract class GitSource extends Source { private readonly cloneDepth?: number; - protected constructor(props: GitBuildSourceProps) { + protected constructor(props: GitSourceProps) { super(props); this.cloneDepth = props.cloneDepth; } - /** @internal */ - public _toSourceJSON(): CfnProject.SourceProperty { + public bind(_scope: Construct, _project: IProject): SourceConfig { + const superConfig = super.bind(_scope, _project); return { - ...super._toSourceJSON(), - gitCloneDepth: this.cloneDepth + sourceProperty: { + ...superConfig.sourceProperty, + gitCloneDepth: this.cloneDepth, + }, }; } } @@ -381,7 +401,7 @@ export class FilterGroup { /** * The construction properties common to all third-party build sources that are backed by Git. */ -export interface ThirdPartyGitBuildSourceProps extends GitBuildSourceProps { +interface ThirdPartyGitSourceProps extends GitSourceProps { /** * Whether to send notifications on your build's start and end. * @@ -409,13 +429,13 @@ export interface ThirdPartyGitBuildSourceProps extends GitBuildSourceProps { /** * A common superclass of all third-party build sources that are backed by Git. */ -export abstract class ThirdPartyGitBuildSource extends GitBuildSource { +abstract class ThirdPartyGitSource extends GitSource { public readonly badgeSupported: boolean = true; protected readonly webhookFilters: FilterGroup[]; private readonly reportBuildStatus: boolean; private readonly webhook?: boolean; - protected constructor(props: ThirdPartyGitBuildSourceProps) { + protected constructor(props: ThirdPartyGitSourceProps) { super(props); this.webhook = props.webhook; @@ -423,21 +443,20 @@ export abstract class ThirdPartyGitBuildSource extends GitBuildSource { this.webhookFilters = props.webhookFilters || []; } - /** @internal */ - public _buildTriggers(): CfnProject.ProjectTriggersProperty | undefined { + public bind(_scope: Construct, _project: IProject): SourceConfig { const anyFilterGroupsProvided = this.webhookFilters.length > 0; const webhook = this.webhook === undefined ? (anyFilterGroupsProvided ? true : undefined) : this.webhook; - return webhook === undefined ? undefined : { - webhook, - filterGroups: anyFilterGroupsProvided ? this.webhookFilters.map(fg => fg._toJson()) : undefined, - }; - } - /** @internal */ - public _toSourceJSON(): CfnProject.SourceProperty { + const superConfig = super.bind(_scope, _project); return { - ...super._toSourceJSON(), - reportBuildStatus: this.reportBuildStatus, + sourceProperty: { + ...superConfig.sourceProperty, + reportBuildStatus: this.reportBuildStatus, + }, + buildTriggers: webhook === undefined ? undefined : { + webhook, + filterGroups: anyFilterGroupsProvided ? this.webhookFilters.map(fg => fg._toJson()) : undefined, + } }; } } @@ -445,15 +464,15 @@ export abstract class ThirdPartyGitBuildSource extends GitBuildSource { /** * Construction properties for {@link CodeCommitSource}. */ -export interface CodeCommitSourceProps extends GitBuildSourceProps { +export interface CodeCommitSourceProps extends GitSourceProps { readonly repository: codecommit.IRepository; } /** * CodeCommit Source definition for a CodeBuild project. */ -export class CodeCommitSource extends GitBuildSource { - public readonly type: SourceType = SourceType.CodeCommit; +class CodeCommitSource extends GitSource { + public readonly type = CODECOMMIT_SOURCE_TYPE; private readonly repo: codecommit.IRepository; constructor(props: CodeCommitSourceProps) { @@ -461,28 +480,27 @@ export class CodeCommitSource extends GitBuildSource { this.repo = props.repository; } - /** - * @internal - */ - public _bind(project: Project) { + public bind(_scope: Construct, project: IProject): SourceConfig { // https://docs.aws.amazon.com/codebuild/latest/userguide/setting-up.html project.addToRolePolicy(new iam.PolicyStatement({ actions: ['codecommit:GitPull'], resources: [this.repo.repositoryArn] })); - } - protected toSourceProperty(): any { + const superConfig = super.bind(_scope, project); return { - location: this.repo.repositoryCloneUrlHttp + sourceProperty: { + ...superConfig.sourceProperty, + location: this.repo.repositoryCloneUrlHttp, + }, }; } } /** - * Construction properties for {@link S3BucketSource}. + * Construction properties for {@link S3Source}. */ -export interface S3BucketSourceProps extends BuildSourceProps { +export interface S3SourceProps extends SourceProps { readonly bucket: s3.IBucket; readonly path: string; } @@ -490,48 +508,34 @@ export interface S3BucketSourceProps extends BuildSourceProps { /** * S3 bucket definition for a CodeBuild project. */ -export class S3BucketSource extends BuildSource { - public readonly type: SourceType = SourceType.S3; +class S3Source extends Source { + public readonly type = S3_SOURCE_TYPE; private readonly bucket: s3.IBucket; private readonly path: string; - constructor(props: S3BucketSourceProps) { + constructor(props: S3SourceProps) { super(props); this.bucket = props.bucket; this.path = props.path; } - /** - * @internal - */ - public _bind(project: Project) { + public bind(_scope: Construct, project: IProject): SourceConfig { this.bucket.grantRead(project); - } - protected toSourceProperty(): any { + const superConfig = super.bind(_scope, project); return { - location: `${this.bucket.bucketName}/${this.path}`, + sourceProperty: { + ...superConfig.sourceProperty, + location: `${this.bucket.bucketName}/${this.path}`, + }, }; } } -/** - * CodePipeline Source definition for a CodeBuild Project. - * *Note*: this type cannot be used as a secondary source, - * and because of that, you're not allowed to specify an identifier for it. - */ -export class CodePipelineSource extends BuildSource { - public readonly type: SourceType = SourceType.CodePipeline; - - constructor() { - super({}); - } -} - /** * Construction properties for {@link GitHubSource} and {@link GitHubEnterpriseSource}. */ -export interface GitHubSourceProps extends ThirdPartyGitBuildSourceProps { +export interface GitHubSourceProps extends ThirdPartyGitSourceProps { /** * The GitHub account/user that owns the repo. * @@ -550,8 +554,8 @@ export interface GitHubSourceProps extends ThirdPartyGitBuildSourceProps { /** * GitHub Source definition for a CodeBuild project. */ -export class GitHubSource extends ThirdPartyGitBuildSource { - public readonly type: SourceType = SourceType.GitHub; +class GitHubSource extends ThirdPartyGitSource { + public readonly type = GITHUB_SOURCE_TYPE; private readonly httpsCloneUrl: string; constructor(props: GitHubSourceProps) { @@ -559,9 +563,14 @@ export class GitHubSource extends ThirdPartyGitBuildSource { this.httpsCloneUrl = `https://github.com/${props.owner}/${props.repo}.git`; } - protected toSourceProperty(): any { + public bind(_scope: Construct, project: IProject): SourceConfig { + const superConfig = super.bind(_scope, project); return { - location: this.httpsCloneUrl, + sourceProperty: { + ...superConfig.sourceProperty, + location: this.httpsCloneUrl, + }, + buildTriggers: superConfig.buildTriggers, }; } } @@ -569,7 +578,7 @@ export class GitHubSource extends ThirdPartyGitBuildSource { /** * Construction properties for {@link GitHubEnterpriseSource}. */ -export interface GitHubEnterpriseSourceProps extends ThirdPartyGitBuildSourceProps { +export interface GitHubEnterpriseSourceProps extends ThirdPartyGitSourceProps { /** * The HTTPS URL of the repository in your GitHub Enterprise installation. */ @@ -586,8 +595,8 @@ export interface GitHubEnterpriseSourceProps extends ThirdPartyGitBuildSourcePro /** * GitHub Enterprise Source definition for a CodeBuild project. */ -export class GitHubEnterpriseSource extends ThirdPartyGitBuildSource { - public readonly type: SourceType = SourceType.GitHubEnterprise; +class GitHubEnterpriseSource extends ThirdPartyGitSource { + public readonly type = GITHUB_ENTERPRISE_SOURCE_TYPE; private readonly httpsCloneUrl: string; private readonly ignoreSslErrors?: boolean; @@ -597,10 +606,15 @@ export class GitHubEnterpriseSource extends ThirdPartyGitBuildSource { this.ignoreSslErrors = props.ignoreSslErrors; } - protected toSourceProperty(): any { + public bind(_scope: Construct, _project: IProject): SourceConfig { + const superConfig = super.bind(_scope, _project); return { - location: this.httpsCloneUrl, - insecureSsl: this.ignoreSslErrors, + sourceProperty: { + ...superConfig.sourceProperty, + location: this.httpsCloneUrl, + insecureSsl: this.ignoreSslErrors, + }, + buildTriggers: superConfig.buildTriggers, }; } } @@ -608,7 +622,7 @@ export class GitHubEnterpriseSource extends ThirdPartyGitBuildSource { /** * Construction properties for {@link BitBucketSource}. */ -export interface BitBucketSourceProps extends ThirdPartyGitBuildSourceProps { +export interface BitBucketSourceProps extends ThirdPartyGitSourceProps { /** * The BitBucket account/user that owns the repo. * @@ -627,8 +641,8 @@ export interface BitBucketSourceProps extends ThirdPartyGitBuildSourceProps { /** * BitBucket Source definition for a CodeBuild project. */ -export class BitBucketSource extends ThirdPartyGitBuildSource { - public readonly type: SourceType = SourceType.BitBucket; +class BitBucketSource extends ThirdPartyGitSource { + public readonly type = BITBUCKET_SOURCE_TYPE; private readonly httpsCloneUrl: any; constructor(props: BitBucketSourceProps) { @@ -636,8 +650,7 @@ export class BitBucketSource extends ThirdPartyGitBuildSource { this.httpsCloneUrl = `https://bitbucket.org/${props.owner}/${props.repo}.git`; } - /** @internal */ - public _buildTriggers(): CfnProject.ProjectTriggersProperty | undefined { + public bind(_scope: Construct, _project: IProject): SourceConfig { // BitBucket sources don't support the PULL_REQUEST_REOPENED event action if (this.anyWebhookFilterContainsPrReopenedEventAction()) { throw new Error('BitBucket sources do not support the PULL_REQUEST_REOPENED webhook event action'); @@ -648,12 +661,13 @@ export class BitBucketSource extends ThirdPartyGitBuildSource { throw new Error('BitBucket sources do not support file path conditions for webhook filters'); } - return super._buildTriggers(); - } - - protected toSourceProperty(): any { + const superConfig = super.bind(_scope, _project); return { - location: this.httpsCloneUrl + sourceProperty: { + ...superConfig.sourceProperty, + location: this.httpsCloneUrl, + }, + buildTriggers: superConfig.buildTriggers, }; } @@ -670,19 +684,6 @@ export class BitBucketSource extends ThirdPartyGitBuildSource { } } -/** - * Source types for CodeBuild Project - */ -export enum SourceType { - None = 'NO_SOURCE', - CodeCommit = 'CODECOMMIT', - CodePipeline = 'CODEPIPELINE', - GitHub = 'GITHUB', - GitHubEnterprise = 'GITHUB_ENTERPRISE', - BitBucket = 'BITBUCKET', - S3 = 'S3', -} - function set2Array(set: Set): T[] { const ret: T[] = []; set.forEach(el => ret.push(el)); diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.github.ts b/packages/@aws-cdk/aws-codebuild/test/integ.github.ts index 955f88bbf1a54..2db2ae3344434 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.github.ts +++ b/packages/@aws-cdk/aws-codebuild/test/integ.github.ts @@ -5,7 +5,7 @@ class TestStack extends cdk.Stack { constructor(scope: cdk.App, id: string) { super(scope, id); - const source = new codebuild.GitHubSource({ + const source = codebuild.Source.gitHub({ owner: 'awslabs', repo: 'aws-cdk', reportBuildStatus: false, diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-bucket.ts b/packages/@aws-cdk/aws-codebuild/test/integ.project-bucket.ts index 93383eb9eef38..12626a39514d0 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-bucket.ts +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-bucket.ts @@ -12,7 +12,7 @@ const bucket = new s3.Bucket(stack, 'MyBucket', { }); new codebuild.Project(stack, 'MyProject', { - source: new codebuild.S3BucketSource({ + source: codebuild.Source.s3({ bucket, path: 'path/to/my/source.zip', }), diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.ts b/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.ts index 8f33a229d4561..c407760563df1 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.ts +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-secondary-sources-artifacts.ts @@ -15,14 +15,14 @@ new codebuild.Project(stack, 'MyProject', { version: '0.2', }), secondarySources: [ - new codebuild.S3BucketSource({ + codebuild.Source.s3({ bucket, path: 'some/path', identifier: 'AddSource1', }), ], secondaryArtifacts: [ - new codebuild.S3BucketBuildArtifacts({ + codebuild.Artifacts.s3({ bucket, path: 'another/path', name: 'name', diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-shell.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-shell.expected.json deleted file mode 100644 index 23577c4af4fa8..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-shell.expected.json +++ /dev/null @@ -1,243 +0,0 @@ -{ - "Parameters": { - "BundleS3Bucket0EFC11B0": { - "Type": "String", - "Description": "S3 bucket for asset \"aws-cdk-codebuild-project-shell/Bundle\"" - }, - "BundleS3VersionKey720F2199": { - "Type": "String", - "Description": "S3 key for asset version \"aws-cdk-codebuild-project-shell/Bundle\"" - }, - "BundleArtifactHashEA214C27": { - "Type": "String", - "Description": "Artifact hash for asset \"aws-cdk-codebuild-project-shell/Bundle\"" - } - }, - "Resources": { - "MyProjectRole9BBE5233": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "codebuild.", - { - "Ref": "AWS::URLSuffix" - } - ] - ] - } - } - } - ], - "Version": "2012-10-17" - } - } - }, - "MyProjectRoleDefaultPolicyB19B7C29": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":s3:::", - { - "Ref": "BundleS3Bucket0EFC11B0" - } - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":s3:::", - { - "Ref": "BundleS3Bucket0EFC11B0" - }, - "/", - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "BundleS3VersionKey720F2199" - } - ] - } - ] - }, - "*" - ] - ] - } - ] - }, - { - "Action": [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/codebuild/", - { - "Ref": "MyProject39F7B0AE" - } - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/codebuild/", - { - "Ref": "MyProject39F7B0AE" - }, - ":*" - ] - ] - } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "MyProjectRoleDefaultPolicyB19B7C29", - "Roles": [ - { - "Ref": "MyProjectRole9BBE5233" - } - ] - } - }, - "MyProject39F7B0AE": { - "Type": "AWS::CodeBuild::Project", - "Properties": { - "Artifacts": { - "Type": "NO_ARTIFACTS" - }, - "Environment": { - "ComputeType": "BUILD_GENERAL1_SMALL", - "EnvironmentVariables": [ - { - "Name": "SCRIPT_S3_BUCKET", - "Type": "PLAINTEXT", - "Value": { - "Ref": "BundleS3Bucket0EFC11B0" - } - }, - { - "Name": "SCRIPT_S3_KEY", - "Type": "PLAINTEXT", - "Value": { - "Fn::Join": [ - "", - [ - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "BundleS3VersionKey720F2199" - } - ] - } - ] - }, - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "||", - { - "Ref": "BundleS3VersionKey720F2199" - } - ] - } - ] - } - ] - ] - } - } - ], - "Image": "aws/codebuild/standard:1.0", - "PrivilegedMode": false, - "Type": "LINUX_CONTAINER" - }, - "ServiceRole": { - "Fn::GetAtt": [ - "MyProjectRole9BBE5233", - "Arn" - ] - }, - "Source": { - "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"pre_build\": {\n \"commands\": [\n \"echo \\\"Downloading scripts from s3://${SCRIPT_S3_BUCKET}/${SCRIPT_S3_KEY}\\\"\",\n \"aws s3 cp s3://${SCRIPT_S3_BUCKET}/${SCRIPT_S3_KEY} /tmp\",\n \"mkdir -p /tmp/scriptdir\",\n \"unzip /tmp/$(basename $SCRIPT_S3_KEY) -d /tmp/scriptdir\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"export SCRIPT_DIR=/tmp/scriptdir\",\n \"echo \\\"Running build.sh\\\"\",\n \"chmod +x /tmp/scriptdir/build.sh\",\n \"/tmp/scriptdir/build.sh\"\n ]\n }\n }\n}", - "Type": "NO_SOURCE" - } - } - } - } -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-shell.ts b/packages/@aws-cdk/aws-codebuild/test/integ.project-shell.ts deleted file mode 100644 index 1f00f2953829a..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-shell.ts +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env node -import assets = require('@aws-cdk/assets'); -import cdk = require('@aws-cdk/cdk'); -import { Project } from '../lib'; - -const app = new cdk.App(); - -const stack = new cdk.Stack(app, 'aws-cdk-codebuild-project-shell'); - -new Project(stack, 'MyProject', { - buildScriptAsset: new assets.ZipDirectoryAsset(stack, 'Bundle', { path: 'script_bundle' }) -}); - -app.synth(); diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json index 35f355bfeb053..55fbb665cbe1b 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.expected.json @@ -240,61 +240,6 @@ "Properties": { "PolicyDocument": { "Statement": [ - { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":s3:::", - { - "Ref": "BundleS3Bucket0EFC11B0" - } - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":s3:::", - { - "Ref": "BundleS3Bucket0EFC11B0" - }, - "/", - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "BundleS3VersionKey720F2199" - } - ] - } - ] - }, - "*" - ] - ] - } - ] - }, { "Action": "ec2:CreateNetworkInterfacePermission", "Condition": { @@ -446,52 +391,6 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "EnvironmentVariables": [ - { - "Name": "SCRIPT_S3_BUCKET", - "Type": "PLAINTEXT", - "Value": { - "Ref": "BundleS3Bucket0EFC11B0" - } - }, - { - "Name": "SCRIPT_S3_KEY", - "Type": "PLAINTEXT", - "Value": { - "Fn::Join": [ - "", - [ - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "BundleS3VersionKey720F2199" - } - ] - } - ] - }, - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "||", - { - "Ref": "BundleS3VersionKey720F2199" - } - ] - } - ] - } - ] - ] - } - } - ], "Image": "aws/codebuild/standard:1.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -503,7 +402,7 @@ ] }, "Source": { - "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"pre_build\": {\n \"commands\": [\n \"echo \\\"Downloading scripts from s3://${SCRIPT_S3_BUCKET}/${SCRIPT_S3_KEY}\\\"\",\n \"aws s3 cp s3://${SCRIPT_S3_BUCKET}/${SCRIPT_S3_KEY} /tmp\",\n \"mkdir -p /tmp/scriptdir\",\n \"unzip /tmp/$(basename $SCRIPT_S3_KEY) -d /tmp/scriptdir\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"export SCRIPT_DIR=/tmp/scriptdir\",\n \"echo \\\"Running build.sh\\\"\",\n \"chmod +x /tmp/scriptdir/build.sh\",\n \"/tmp/scriptdir/build.sh\"\n ]\n }\n }\n}", + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"echo \\\"Nothing to do!\\\"\"\n ]\n }\n }\n}", "Type": "NO_SOURCE" }, "VpcConfig": { @@ -526,19 +425,5 @@ } } } - }, - "Parameters": { - "BundleS3Bucket0EFC11B0": { - "Type": "String", - "Description": "S3 bucket for asset \"aws-cdk-codebuild-project-vpc/Bundle\"" - }, - "BundleS3VersionKey720F2199": { - "Type": "String", - "Description": "S3 key for asset version \"aws-cdk-codebuild-project-vpc/Bundle\"" - }, - "BundleArtifactHashEA214C27": { - "Type": "String", - "Description": "Artifact hash for asset \"aws-cdk-codebuild-project-vpc/Bundle\"" - } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.ts b/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.ts index 9d118d04ed81b..dd53529eb9748 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.ts +++ b/packages/@aws-cdk/aws-codebuild/test/integ.project-vpc.ts @@ -1,8 +1,7 @@ #!/usr/bin/env node -import assets = require('@aws-cdk/assets'); import ec2 = require('@aws-cdk/aws-ec2'); import cdk = require('@aws-cdk/cdk'); -import { Project } from '../lib'; +import codebuild = require('../lib'); const app = new cdk.App(); @@ -17,8 +16,15 @@ const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { groupName: 'Bob', vpc, }); -new Project(stack, 'MyProject', { - buildScriptAsset: new assets.ZipDirectoryAsset(stack, 'Bundle', { path: 'script_bundle' }), +new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { + commands: ['echo "Nothing to do!"'], + }, + }, + }), securityGroups: [securityGroup], vpc }); diff --git a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts index c71fc625ac0b0..ac25c92d3279a 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts @@ -6,6 +6,8 @@ import s3 = require('@aws-cdk/aws-s3'); import cdk = require('@aws-cdk/cdk'); import { Test } from 'nodeunit'; import codebuild = require('../lib'); +import { CodePipelineSource } from '../lib/codepipeline-source'; +import { NoSource } from '../lib/no-source'; // tslint:disable:object-literal-key-quotes @@ -14,10 +16,7 @@ export = { 'with CodePipeline source'(test: Test) { const stack = new cdk.Stack(); - const source = new codebuild.CodePipelineSource(); - new codebuild.Project(stack, 'MyProject', { - source - }); + new codebuild.PipelineProject(stack, 'MyProject'); expect(stack).toMatch({ "Resources": { @@ -144,7 +143,7 @@ export = { const repo = new codecommit.Repository(stack, 'MyRepo', { repositoryName: 'hello-cdk' }); - const source = new codebuild.CodeCommitSource({ repository: repo, cloneDepth: 2 }); + const source = codebuild.Source.codeCommit({ repository: repo, cloneDepth: 2 }); new codebuild.Project(stack, 'MyProject', { source @@ -298,7 +297,7 @@ export = { const bucket = new s3.Bucket(stack, 'MyBucket'); new codebuild.Project(stack, 'MyProject', { - source: new codebuild.S3BucketSource({ + source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip', }), @@ -475,7 +474,7 @@ export = { const stack = new cdk.Stack(); new codebuild.Project(stack, 'Project', { - source: new codebuild.GitHubSource({ + source: codebuild.Source.gitHub({ owner: 'testowner', repo: 'testrepo', cloneDepth: 3, @@ -520,7 +519,7 @@ export = { const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); new codebuild.Project(stack, 'MyProject', { - source: new codebuild.GitHubEnterpriseSource({ + source: codebuild.Source.gitHubEnterprise({ httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', ignoreSslErrors: true, cloneDepth: 4, @@ -570,7 +569,7 @@ export = { const stack = new cdk.Stack(); new codebuild.Project(stack, 'Project', { - source: new codebuild.BitBucketSource({ + source: codebuild.Source.bitBucket({ owner: 'testowner', repo: 'testrepo', cloneDepth: 5, @@ -634,8 +633,8 @@ export = { allowAllOutbound: true, description: 'Example', }); - new codebuild.Project(stack, 'MyProject', { - source: new codebuild.S3BucketSource({ + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip', }), @@ -668,6 +667,9 @@ export = { } } })); + + test.notEqual(project.connections, undefined); + test.done(); }, 'without VPC configuration but security group identified'(test: Test) { @@ -684,7 +686,7 @@ export = { test.throws(() => new codebuild.Project(stack, 'MyProject', { - source: new codebuild.S3BucketSource({ + source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip', }), @@ -705,7 +707,7 @@ export = { }); test.throws(() => new codebuild.Project(stack, 'MyProject', { - source: new codebuild.S3BucketSource({ + source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip', }), @@ -717,6 +719,17 @@ export = { test.done(); }, + 'without passing a VPC cannot access the connections property'(test: Test) { + const stack = new cdk.Stack(); + + const project = new codebuild.PipelineProject(stack, 'MyProject'); + + test.throws(() => project.connections, + /Only VPC-associated Projects have security groups to manage. Supply the "vpc" parameter when creating the Project/); + + test.done(); + }, + 'with a KMS Key adds decrypt permissions to the CodeBuild Role'(test: Test) { const stack = new cdk.Stack(); @@ -765,7 +778,7 @@ export = { buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', }), - artifacts: new codebuild.S3BucketBuildArtifacts({ + artifacts: codebuild.Artifacts.s3({ path: 'some/path', name: 'some_name', bucket, @@ -795,7 +808,10 @@ export = { version: '0.2', }), secondarySources: [ - new codebuild.CodePipelineSource(), + codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), ], }); }, /identifier/); @@ -805,11 +821,9 @@ export = { 'are not allowed for a Project with CodePipeline as Source'(test: Test) { const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyProject', { - source: new codebuild.CodePipelineSource(), - }); + const project = new codebuild.PipelineProject(stack, 'MyProject'); - project.addSecondarySource(new codebuild.S3BucketSource({ + project.addSecondarySource(codebuild.Source.s3({ bucket: new s3.Bucket(stack, 'MyBucket'), path: 'some/path', identifier: 'id', @@ -826,13 +840,13 @@ export = { const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'MyBucket'); const project = new codebuild.Project(stack, 'MyProject', { - source: new codebuild.S3BucketSource({ + source: codebuild.Source.s3({ bucket, path: 'some/path', }), }); - project.addSecondarySource(new codebuild.S3BucketSource({ + project.addSecondarySource(codebuild.Source.s3({ bucket, path: 'another/path', identifier: 'source1', @@ -861,7 +875,7 @@ export = { version: '0.2', }), secondaryArtifacts: [ - new codebuild.S3BucketBuildArtifacts({ + codebuild.Artifacts.s3({ bucket: new s3.Bucket(stack, 'MyBucket'), path: 'some/path', name: 'name', @@ -875,11 +889,9 @@ export = { 'are not allowed for a Project with CodePipeline as Source'(test: Test) { const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyProject', { - source: new codebuild.CodePipelineSource(), - }); + const project = new codebuild.PipelineProject(stack, 'MyProject'); - project.addSecondaryArtifact(new codebuild.S3BucketBuildArtifacts({ + project.addSecondaryArtifact(codebuild.Artifacts.s3({ bucket: new s3.Bucket(stack, 'MyBucket'), path: 'some/path', name: 'name', @@ -897,13 +909,13 @@ export = { const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'MyBucket'); const project = new codebuild.Project(stack, 'MyProject', { - source: new codebuild.S3BucketSource({ + source: codebuild.Source.s3({ bucket, path: 'some/path', }), }); - project.addSecondaryArtifact(new codebuild.S3BucketBuildArtifacts({ + project.addSecondaryArtifact(codebuild.Artifacts.s3({ bucket, path: 'another/path', name: 'name', @@ -928,41 +940,7 @@ export = { 'both source and artifacs are set to CodePipeline'(test: Test) { const stack = new cdk.Stack(); - new codebuild.Project(stack, 'MyProject', { - source: new codebuild.CodePipelineSource(), - artifacts: new codebuild.CodePipelineBuildArtifacts() - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - "Source": { - "Type": "CODEPIPELINE" - }, - "Artifacts": { - "Type": "CODEPIPELINE" - }, - "ServiceRole": { - "Fn::GetAtt": [ - "MyProjectRole9BBE5233", - "Arn" - ] - }, - "Environment": { - "Type": "LINUX_CONTAINER", - "PrivilegedMode": false, - "Image": "aws/codebuild/standard:1.0", - "ComputeType": "BUILD_GENERAL1_SMALL" - } - })); - - test.done(); - }, - - 'if source is set to CodePipeline, and artifacts are not set, they are defaulted to CodePipeline'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'MyProject', { - source: new codebuild.CodePipelineSource() - }); + new codebuild.PipelineProject(stack, 'MyProject'); expect(stack).to(haveResource('AWS::CodeBuild::Project', { "Source": { @@ -987,31 +965,16 @@ export = { test.done(); }, - - 'fails if one of source/artifacts is set to CodePipeline and the other isn\'t'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => new codebuild.Project(stack, 'MyProject', { - source: new codebuild.CodePipelineSource(), - artifacts: new codebuild.NoBuildArtifacts() - }), /Both source and artifacts must be set to CodePipeline/); - - test.throws(() => new codebuild.Project(stack, 'YourProject', { - source: new codebuild.CodeCommitSource({ - repository: new codecommit.Repository(stack, 'MyRepo', { repositoryName: 'boo' }) - }), - artifacts: new codebuild.CodePipelineBuildArtifacts() - }), /Both source and artifacts must be set to CodePipeline/); - - test.done(); - } - } + }, }, 'events'(test: Test) { const stack = new cdk.Stack(); const project = new codebuild.Project(stack, 'MyProject', { - source: new codebuild.CodePipelineSource() + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), }); project.onBuildFailed('OnBuildFailed', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) }}); @@ -1130,8 +1093,7 @@ export = { 'environment variables can be overridden at the project level'(test: Test) { const stack = new cdk.Stack(); - new codebuild.Project(stack, 'Project', { - source: new codebuild.CodePipelineSource(), + new codebuild.PipelineProject(stack, 'Project', { environment: { environmentVariables: { FOO: { value: '1234' }, @@ -1196,7 +1158,12 @@ export = { '.metricXxx() methods can be used to obtain Metrics for CodeBuild projects'(test: Test) { const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyBuildProject', { source: new codebuild.CodePipelineSource() }); + const project = new codebuild.Project(stack, 'MyBuildProject', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + }); const metricBuilds = project.metricBuilds(); test.same(metricBuilds.dimensions!.ProjectName, project.projectName); @@ -1224,7 +1191,10 @@ export = { test.throws(() => { new codebuild.Project(stack, 'MyProject', { - source: new codebuild.CodePipelineSource(), + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), environment: invalidEnvironment, }); }, /Windows images do not support the Small ComputeType/); @@ -1236,7 +1206,7 @@ export = { const stack = new cdk.Stack(); interface BadgeValidationTestCase { - source: codebuild.BuildSource, + source: codebuild.Source, shouldPassValidation: boolean } @@ -1244,13 +1214,13 @@ export = { const bucket = new s3.Bucket(stack, 'MyBucket'); const cases: BadgeValidationTestCase[] = [ - { source: new codebuild.NoSource(), shouldPassValidation: false }, - { source: new codebuild.CodePipelineSource(), shouldPassValidation: false }, - { source: new codebuild.CodeCommitSource({ repository: repo }), shouldPassValidation: false }, - { source: new codebuild.S3BucketSource({ bucket, path: 'path/to/source.zip' }), shouldPassValidation: false }, - { source: new codebuild.GitHubSource({ owner: 'awslabs', repo: 'aws-cdk' }), shouldPassValidation: true }, - { source: new codebuild.GitHubEnterpriseSource({ httpsCloneUrl: 'url' }), shouldPassValidation: true }, - { source: new codebuild.BitBucketSource({ owner: 'awslabs', repo: 'aws-cdk' }), shouldPassValidation: true } + { source: new NoSource(), shouldPassValidation: false }, + { source: new CodePipelineSource(), shouldPassValidation: false }, + { source: codebuild.Source.codeCommit({ repository: repo }), shouldPassValidation: false }, + { source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip' }), shouldPassValidation: false }, + { source: codebuild.Source.gitHub({ owner: 'awslabs', repo: 'aws-cdk' }), shouldPassValidation: true }, + { source: codebuild.Source.gitHubEnterprise({ httpsCloneUrl: 'url' }), shouldPassValidation: true }, + { source: codebuild.Source.bitBucket({ owner: 'awslabs', repo: 'aws-cdk' }), shouldPassValidation: true } ]; cases.forEach(testCase => { @@ -1302,7 +1272,7 @@ export = { test.throws(() => { new codebuild.Project(stack, 'Project', { - source: new codebuild.BitBucketSource({ + source: codebuild.Source.bitBucket({ owner: 'owner', repo: 'repo', webhookFilters: [ @@ -1321,7 +1291,7 @@ export = { test.throws(() => { new codebuild.Project(stack, 'Project', { - source: new codebuild.BitBucketSource({ + source: codebuild.Source.bitBucket({ owner: 'owner', repo: 'repo', webhookFilters: [filterGroup], diff --git a/packages/@aws-cdk/aws-codebuild/test/test.project.ts b/packages/@aws-cdk/aws-codebuild/test/test.project.ts index 8f7372d58b471..6d87439a9e2e6 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.project.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.project.ts @@ -1,11 +1,8 @@ import { expect, haveResource, haveResourceLike, not } from '@aws-cdk/assert'; -import assets = require('@aws-cdk/assets'); import { Bucket } from '@aws-cdk/aws-s3'; import cdk = require('@aws-cdk/cdk'); import { Test } from 'nodeunit'; -import path = require('path'); import codebuild = require('../lib'); -import { Cache, LocalCacheMode } from '../lib/cache'; // tslint:disable:object-literal-key-quotes @@ -16,7 +13,10 @@ export = { // WHEN new codebuild.Project(stack, 'Project', { - source: new codebuild.CodePipelineSource(), + source: codebuild.Source.s3({ + bucket: new Bucket(stack, 'Bucket'), + path: 'path', + }), buildSpec: codebuild.BuildSpec.fromSourceFilename('hello.yml'), }); @@ -36,7 +36,6 @@ export = { // WHEN new codebuild.Project(stack, 'Project', { - source: new codebuild.CodePipelineSource(), buildSpec: codebuild.BuildSpec.fromObject({ phases: ['say hi'] }) }); @@ -56,7 +55,6 @@ export = { test.throws(() => { new codebuild.Project(stack, 'Project', { - source: new codebuild.NoSource(), }); }, /you need to provide a concrete buildSpec/); @@ -69,7 +67,6 @@ export = { test.throws(() => { new codebuild.Project(stack, 'Project', { - source: new codebuild.NoSource(), buildSpec: codebuild.BuildSpec.fromSourceFilename('bla.yml'), }); }, /you need to provide a concrete buildSpec/); @@ -84,7 +81,7 @@ export = { // WHEN new codebuild.Project(stack, 'Project', { - source: new codebuild.GitHubSource({ + source: codebuild.Source.gitHub({ owner: 'testowner', repo: 'testrepo', cloneDepth: 3, @@ -110,7 +107,7 @@ export = { // WHEN new codebuild.Project(stack, 'Project', { - source: new codebuild.GitHubSource({ + source: codebuild.Source.gitHub({ owner: 'testowner', repo: 'testrepo', reportBuildStatus: false, @@ -133,7 +130,7 @@ export = { // WHEN new codebuild.Project(stack, 'Project', { - source: new codebuild.GitHubSource({ + source: codebuild.Source.gitHub({ owner: 'testowner', repo: 'testrepo', webhook: true, @@ -151,55 +148,17 @@ export = { }, }, - 'construct from asset'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - buildScriptAsset: new assets.ZipDirectoryAsset(stack, 'Asset', { path: path.join(__dirname, 'script_bundle') }), - buildScriptAssetEntrypoint: 'build.sh', - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: { - ComputeType: "BUILD_GENERAL1_SMALL", - EnvironmentVariables: [ - { - Name: "SCRIPT_S3_BUCKET", - Type: "PLAINTEXT", - Value: { Ref: "AssetS3Bucket235698C0" } - }, - { - Name: "SCRIPT_S3_KEY", - Type: "PLAINTEXT", - Value: { - "Fn::Join": ["", [ - { "Fn::Select": [0, { "Fn::Split": ["||", { Ref: "AssetS3VersionKeyA852DDAE" }] }] }, - { "Fn::Select": [1, { "Fn::Split": ["||", { Ref: "AssetS3VersionKeyA852DDAE" }] }] } - ]] - } - } - ], - }, - Source: { - // Not testing BuildSpec, it's too big and finicky - Type: "NO_SOURCE" - } - })); - - test.done(); - }, - 'project with s3 cache bucket'(test: Test) { // GIVEN const stack = new cdk.Stack(); // WHEN new codebuild.Project(stack, 'Project', { - source: new codebuild.CodePipelineSource(), - cache: Cache.bucket(new Bucket(stack, 'Bucket'), { + source: codebuild.Source.s3({ + bucket: new Bucket(stack, 'SourceBucket'), + path: 'path', + }), + cache: codebuild.Cache.bucket(new Bucket(stack, 'Bucket'), { prefix: "cache-prefix" }) }); @@ -231,8 +190,12 @@ export = { // WHEN new codebuild.Project(stack, 'Project', { - source: new codebuild.CodePipelineSource(), - cache: Cache.local(LocalCacheMode.Custom, LocalCacheMode.DockerLayer, LocalCacheMode.Source) + source: codebuild.Source.s3({ + bucket: new Bucket(stack, 'Bucket'), + path: 'path', + }), + cache: codebuild.Cache.local(codebuild.LocalCacheMode.Custom, codebuild.LocalCacheMode.DockerLayer, + codebuild.LocalCacheMode.Source) }); // THEN @@ -256,7 +219,10 @@ export = { // WHEN new codebuild.Project(stack, 'Project', { - source: new codebuild.CodePipelineSource() + source: codebuild.Source.s3({ + bucket: new Bucket(stack, 'Bucket'), + path: 'path', + }), }); // THEN diff --git a/packages/@aws-cdk/aws-codepipeline-actions/README.md b/packages/@aws-cdk/aws-codepipeline-actions/README.md index dcabfc3deae42..22b8240bfaa19 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/README.md +++ b/packages/@aws-cdk/aws-codepipeline-actions/README.md @@ -183,17 +183,6 @@ new codepipeline.Pipeline(this, 'MyPipeline', { }); ``` -The `PipelineProject` utility class is a simple sugar around the `Project` -class, it's equivalent to: - -```ts -const project = new codebuild.Project(this, 'MyProject', { - source: new codebuild.CodePipelineSource(), - artifacts: new codebuild.CodePipelineBuildArtifacts(), - // rest of the properties from PipelineProject are passed unchanged... -} -``` - The default category of the CodeBuild Action is `Build`; if you want a `Test` Action instead, override the `type` property: diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts index d0719607d51a7..e9a19f3a8216b 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts @@ -1,5 +1,5 @@ import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; -import { CodePipelineBuildArtifacts, CodePipelineSource, Project } from '@aws-cdk/aws-codebuild'; +import codebuild = require('@aws-cdk/aws-codebuild'); import { Repository } from '@aws-cdk/aws-codecommit'; import codepipeline = require('@aws-cdk/aws-codepipeline'); import { Role } from '@aws-cdk/aws-iam'; @@ -37,11 +37,7 @@ export = { /** Build! */ - const buildArtifacts = new CodePipelineBuildArtifacts(); - const project = new Project(stack, 'MyBuildProject', { - source: new CodePipelineSource(), - artifacts: buildArtifacts, - }); + const project = new codebuild.PipelineProject(stack, 'MyBuildProject'); const buildOutput = new codepipeline.Artifact('OutputYo'); const buildAction = new cpactions.CodeBuildAction({ diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.ts index 81b3c0a5733a1..42e64c80c0688 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.ts @@ -19,9 +19,7 @@ const sourceAction = new cpactions.CodeCommitSourceAction({ pollForSourceChanges: true, }); -const project = new codebuild.Project(stack, 'MyBuildProject', { - source: new codebuild.CodePipelineSource(), -}); +const project = new codebuild.PipelineProject(stack, 'MyBuildProject'); const buildAction = new cpactions.CodeBuildAction({ actionName: 'build', project, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts index 26a4a702b6432..b4534a812c748 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts @@ -33,9 +33,7 @@ export = { actions: [source], }); - const project = new codebuild.Project(stack, 'MyBuildProject', { - source: new codebuild.CodePipelineSource() - }); + const project = new codebuild.PipelineProject(stack, 'MyBuildProject'); pipeline.addStage({ stageName: 'build', actions: [ diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts b/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts index adc6bade85faa..cfe94306d06d3 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts @@ -7,7 +7,7 @@ import targets = require('../../lib'); test('use codebuild project as an eventrule target', () => { // GIVEN const stack = new Stack(); - const project = new codebuild.Project(stack, 'MyProject', { source: new codebuild.CodePipelineSource() }); + const project = new codebuild.PipelineProject(stack, 'MyProject'); const rule = new events.Rule(stack, 'Rule', { scheduleExpression: 'rate(1 min)' }); // WHEN diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts index e1b4f6d24ec91..a8e6f35f86dcb 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts @@ -14,7 +14,7 @@ const stack = new cdk.Stack(app, 'aws-cdk-codebuild-events'); const repo = new codecommit.Repository(stack, 'MyRepo', { repositoryName: 'aws-cdk-codebuild-events' }); const project = new codebuild.Project(stack, 'MyProject', { - source: new codebuild.CodeCommitSource({ repository: repo }), + source: codebuild.Source.codeCommit({ repository: repo }), }); const queue = new sqs.Queue(stack, 'MyQueue');