Skip to content

Commit

Permalink
feat(pipelines): support timeout in CodeBuildStep (#17351)
Browse files Browse the repository at this point in the history
Make sure we can set timeout for those long running tests.

There's one thing I didn't get. In `_codebuild-factory.ts/produceAction()` I expected that this line:

```
    const projectOptions = mergeCodeBuildOptions(options.codeBuildDefaults, this.props.projectOptions);
```

would merge in the timeout if set. But it didn't do that. So that's why I pull the timeout in the later `codebuild.PipelineProject` explicitly via:

```
      timeout: this.props.projectOptions?.timeout,
```

Not sure why I had to do that. I noticed that `options.codeBuildDefaults` didn't have the timeout field, perhaps that's why the merge didn't work, or perhaps I don't understand this merge, and what I did was right :-)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
berenddeboer authored Jan 4, 2022
1 parent caa6788 commit 2aa3b8e
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/@aws-cdk/pipelines/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ new pipelines.CodeBuildStep('Synth', {
buildEnvironment: {
computeType: codebuild.ComputeType.LARGE,
},
timeout: Duration.minutes(90),

// Control Elastic Network Interface creation
vpc: vpc,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,16 @@ export class CodeBuildFactory implements ICodePipelineActionFactory {
const factory = CodeBuildFactory.fromShellStep(constructId, step, {
projectName: step.projectName,
role: step.role,
projectOptions: {
...additional,
projectOptions: mergeCodeBuildOptions(additional?.projectOptions, {
buildEnvironment: step.buildEnvironment,
rolePolicy: step.rolePolicyStatements,
securityGroups: step.securityGroups,
partialBuildSpec: step.partialBuildSpec,
vpc: step.vpc,
subnetSelection: step.subnetSelection,
...additional?.projectOptions,
},
...additional,
timeout: step.timeout,
}),
});

return {
Expand Down Expand Up @@ -279,6 +279,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory {
securityGroups: projectOptions.securityGroups,
buildSpec: projectBuildSpec,
role: this.props.role,
timeout: projectOptions.timeout,
});

if (this.props.additionalDependable) {
Expand Down Expand Up @@ -393,6 +394,7 @@ export function mergeCodeBuildOptions(...opts: Array<CodeBuildOptions | undefine
partialBuildSpec: mergeBuildSpecs(a.partialBuildSpec, b.partialBuildSpec),
vpc: b.vpc ?? a.vpc,
subnetSelection: b.subnetSelection ?? a.subnetSelection,
timeout: b.timeout ?? a.timeout,
};
}
}
Expand Down
20 changes: 20 additions & 0 deletions packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Duration } from '@aws-cdk/core';
import * as codebuild from '@aws-cdk/aws-codebuild';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
Expand Down Expand Up @@ -82,6 +83,15 @@ export interface CodeBuildStepProps extends ShellStepProps {
* @default - Security group will be automatically created.
*/
readonly securityGroups?: ec2.ISecurityGroup[];

/**
* The number of minutes after which AWS CodeBuild stops the build if it's
* not complete. For valid values, see the timeoutInMinutes field in the AWS
* CodeBuild User Guide.
*
* @default Duration.hours(1)
*/
readonly timeout?: Duration;
}

/**
Expand Down Expand Up @@ -144,6 +154,15 @@ export class CodeBuildStep extends ShellStep {
*/
readonly securityGroups?: ec2.ISecurityGroup[];

/**
* The number of minutes after which AWS CodeBuild stops the build if it's
* not complete. For valid values, see the timeoutInMinutes field in the AWS
* CodeBuild User Guide.
*
* @default Duration.hours(1)
*/
readonly timeout?: Duration;

private _project?: codebuild.IProject;

constructor(id: string, props: CodeBuildStepProps) {
Expand All @@ -157,6 +176,7 @@ export class CodeBuildStep extends ShellStep {
this.role = props.role;
this.rolePolicyStatements = props.rolePolicyStatements;
this.securityGroups = props.securityGroups;
this.timeout = props.timeout;
}

/**
Expand Down
11 changes: 10 additions & 1 deletion packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as cp from '@aws-cdk/aws-codepipeline';
import * as cpa from '@aws-cdk/aws-codepipeline-actions';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
import { Aws, CfnCapabilities, Fn, Lazy, PhysicalName, Stack } from '@aws-cdk/core';
import { Aws, CfnCapabilities, Duration, Fn, Lazy, PhysicalName, Stack } from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
import { Construct, Node } from 'constructs';
import { AssetType, FileSet, IFileSetProducer, ManualApprovalStep, ShellStep, StackAsset, StackDeployment, Step } from '../blueprint';
Expand Down Expand Up @@ -258,6 +258,15 @@ export interface CodeBuildOptions {
* @default - All private subnets.
*/
readonly subnetSelection?: ec2.SubnetSelection;

/**
* The number of minutes after which AWS CodeBuild stops the build if it's
* not complete. For valid values, see the timeoutInMinutes field in the AWS
* CodeBuild User Guide.
*
* @default Duration.hours(1)
*/
readonly timeout?: Duration;
}


Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/pipelines/rosetta/default.ts-fixture
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Fixture with packages imported, but nothing else
import { Construct } from 'constructs';
import { CfnOutput, Stage, Stack, StackProps, StageProps } from '@aws-cdk/core';
import { CfnOutput, Duration, Stage, Stack, StackProps, StageProps } from '@aws-cdk/core';
import cdk = require('@aws-cdk/core');
import codepipeline = require('@aws-cdk/aws-codepipeline');
import cpactions = require('@aws-cdk/aws-codepipeline-actions');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Template, Match } from '@aws-cdk/assertions';
import { Stack } from '@aws-cdk/core';
import { Duration, Stack } from '@aws-cdk/core';
import * as cdkp from '../../lib';
import { PIPELINE_ENV, TestApp, ModernTestGitHubNpmPipeline, AppWithOutput } from '../testhelpers';

Expand Down Expand Up @@ -43,6 +43,68 @@ test('additionalinputs creates the right commands', () => {
});
});

test('long duration steps are supported', () => {
// WHEN
new cdkp.CodePipeline(pipelineStack, 'Pipeline', {
synth: new cdkp.CodeBuildStep('Synth', {
commands: ['/bin/true'],
input: cdkp.CodePipelineSource.gitHub('test/test', 'main'),
additionalInputs: {
'some/deep/directory': cdkp.CodePipelineSource.gitHub('test2/test2', 'main'),
},
timeout: Duration.minutes(180),
}),
});

// THEN
Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodeBuild::Project', {
TimeoutInMinutes: 180,
});
});

test('timeout can be configured as part of defaults', () => {
// WHEN
new cdkp.CodePipeline(pipelineStack, 'Pipeline', {
synth: new cdkp.CodeBuildStep('Synth', {
commands: ['/bin/true'],
input: cdkp.CodePipelineSource.gitHub('test/test', 'main'),
additionalInputs: {
'some/deep/directory': cdkp.CodePipelineSource.gitHub('test2/test2', 'main'),
},
}),
codeBuildDefaults: {
timeout: Duration.minutes(180),
},
});

// THEN
Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodeBuild::Project', {
TimeoutInMinutes: 180,
});
});

test('timeout from defaults can be overridden', () => {
// WHEN
new cdkp.CodePipeline(pipelineStack, 'Pipeline', {
synth: new cdkp.CodeBuildStep('Synth', {
commands: ['/bin/true'],
input: cdkp.CodePipelineSource.gitHub('test/test', 'main'),
additionalInputs: {
'some/deep/directory': cdkp.CodePipelineSource.gitHub('test2/test2', 'main'),
},
timeout: Duration.minutes(888),
}),
codeBuildDefaults: {
timeout: Duration.minutes(180),
},
});

// THEN
Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodeBuild::Project', {
TimeoutInMinutes: 888,
});
});

test('envFromOutputs works even with very long stage and stack names', () => {
const pipeline = new ModernTestGitHubNpmPipeline(pipelineStack, 'Cdk');

Expand Down

0 comments on commit 2aa3b8e

Please sign in to comment.