-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
build-action.ts
162 lines (145 loc) · 5.33 KB
/
build-action.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import * as codebuild from '@aws-cdk/aws-codebuild';
import * as codepipeline from '@aws-cdk/aws-codepipeline';
import * as iam from '@aws-cdk/aws-iam';
import * as cdk from '@aws-cdk/core';
import { Action } from '../action';
/**
* The type of the CodeBuild action that determines its CodePipeline Category -
* Build, or Test.
* The default is Build.
*/
export enum CodeBuildActionType {
/**
* The action will have the Build Category.
* This is the default.
*/
BUILD,
/**
* The action will have the Test Category.
*/
TEST
}
/**
* Construction properties of the {@link CodeBuildAction CodeBuild build CodePipeline action}.
*/
export interface CodeBuildActionProps extends codepipeline.CommonAwsActionProps {
/**
* The source to use as input for this action.
*/
readonly input: codepipeline.Artifact;
/**
* The list of additional input Artifacts for this action.
*/
readonly extraInputs?: codepipeline.Artifact[];
/**
* The list of output Artifacts for this action.
* **Note**: if you specify more than one output Artifact here,
* you cannot use the primary 'artifacts' section of the buildspec;
* you have to use the 'secondary-artifacts' section instead.
* See https://docs.aws.amazon.com/codebuild/latest/userguide/sample-multi-in-out.html
* for details.
*
* @default the action will not have any outputs
*/
readonly outputs?: codepipeline.Artifact[];
/**
* The action's Project.
*/
readonly project: codebuild.IProject;
/**
* The type of the action that determines its CodePipeline Category -
* Build, or Test.
*
* @default CodeBuildActionType.BUILD
*/
readonly type?: CodeBuildActionType;
/**
* The environment variables to pass to the CodeBuild project when this action executes.
* If a variable with the same name was set both on the project level, and here,
* this value will take precedence.
*
* @default - No additional environment variables are specified.
*/
readonly environmentVariables?: { [name: string]: codebuild.BuildEnvironmentVariable };
}
/**
* CodePipeline build action that uses AWS CodeBuild.
*/
export class CodeBuildAction extends Action {
private readonly props: CodeBuildActionProps;
constructor(props: CodeBuildActionProps) {
super({
...props,
category: props.type === CodeBuildActionType.TEST
? codepipeline.ActionCategory.TEST
: codepipeline.ActionCategory.BUILD,
provider: 'CodeBuild',
artifactBounds: { minInputs: 1, maxInputs: 5, minOutputs: 0, maxOutputs: 5 },
inputs: [props.input, ...props.extraInputs || []],
resource: props.project,
});
this.props = props;
}
/**
* Reference a CodePipeline variable defined by the CodeBuild project this action points to.
* Variables in CodeBuild actions are defined using the 'exported-variables' subsection of the 'env'
* section of the buildspec.
*
* @param variableName the name of the variable to reference.
* A variable by this name must be present in the 'exported-variables' section of the buildspec
*
* @see https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-syntax
*/
public variable(variableName: string): string {
return this.variableExpression(variableName);
}
protected bound(scope: cdk.Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions):
codepipeline.ActionConfig {
// check for a cross-account action if there are any outputs
if ((this.actionProperties.outputs || []).length > 0) {
const pipelineStack = cdk.Stack.of(scope);
const projectStack = cdk.Stack.of(this.props.project);
if (pipelineStack.account !== projectStack.account) {
throw new Error('A cross-account CodeBuild action cannot have outputs. ' +
'This is a known CodeBuild limitation. ' +
'See https://github.com/aws/aws-cdk/issues/4169 for details');
}
}
// grant the Pipeline role the required permissions to this Project
options.role.addToPolicy(new iam.PolicyStatement({
resources: [this.props.project.projectArn],
actions: [
'codebuild:BatchGetBuilds',
'codebuild:StartBuild',
'codebuild:StopBuild',
]
}));
// allow the Project access to the Pipeline's artifact Bucket
// but only if the project is not imported
// (ie., has a role) - otherwise, the IAM library throws an error
if (this.props.project.role) {
if ((this.actionProperties.outputs || []).length > 0) {
options.bucket.grantReadWrite(this.props.project);
} else {
options.bucket.grantRead(this.props.project);
}
}
if (this.props.project instanceof codebuild.Project) {
this.props.project.bindToCodePipeline(scope, {
artifactBucket: options.bucket,
});
}
const configuration: any = {
ProjectName: this.props.project.projectName,
EnvironmentVariables: this.props.environmentVariables &&
cdk.Stack.of(scope).toJsonString(codebuild.Project.serializeEnvVariables(this.props.environmentVariables)),
};
if ((this.actionProperties.inputs || []).length > 1) {
// lazy, because the Artifact name might be generated lazily
configuration.PrimarySource = cdk.Lazy.stringValue({ produce: () => this.props.input.artifactName });
}
return {
configuration,
};
}
}