Skip to content

Commit b0bc221

Browse files
authored
Merge pull request #44444 from hashicorp/f-codebuild-start-build
New action: `aws_codebuild_start_build`
2 parents 87fd5cf + dfb01c1 commit b0bc221

File tree

7 files changed

+596
-9
lines changed

7 files changed

+596
-9
lines changed

.changelog/44444.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-action
2+
aws_codebuild_start_build
3+
```

.github/workflows/semgrep-ci.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
name: Validate Code Quality Rules
2929
runs-on: ubuntu-latest
3030
container:
31-
image: "returntocorp/semgrep:1.52.0"
31+
image: "semgrep/semgrep:1.110.0"
3232
steps:
3333
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
3434
- run: |
@@ -43,7 +43,7 @@ jobs:
4343
needs: [semgrep-validate]
4444
runs-on: ubuntu-latest
4545
container:
46-
image: "returntocorp/semgrep:1.52.0"
46+
image: "semgrep/semgrep:1.110.0"
4747
steps:
4848
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
4949
- run: |
@@ -54,7 +54,7 @@ jobs:
5454
needs: [semgrep-test]
5555
runs-on: ubuntu-latest
5656
container:
57-
image: "returntocorp/semgrep:1.52.0"
57+
image: "semgrep/semgrep:1.110.0"
5858
steps:
5959
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
6060
- run: |
@@ -74,7 +74,7 @@ jobs:
7474
name: Naming Scan Caps/AWS/EC2
7575
runs-on: ubuntu-latest
7676
container:
77-
image: "returntocorp/semgrep:1.52.0"
77+
image: "semgrep/semgrep:1.110.0"
7878
if: (github.action != 'dependabot[bot]')
7979
steps:
8080
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -85,7 +85,7 @@ jobs:
8585
name: Test Configs Scan
8686
runs-on: ubuntu-latest
8787
container:
88-
image: "returntocorp/semgrep:1.52.0"
88+
image: "semgrep/semgrep:1.110.0"
8989
if: (github.action != 'dependabot[bot]')
9090
steps:
9191
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -96,7 +96,7 @@ jobs:
9696
name: Service Name Scan A-C
9797
runs-on: ubuntu-latest
9898
container:
99-
image: "returntocorp/semgrep:1.52.0"
99+
image: "semgrep/semgrep:1.110.0"
100100
if: (github.action != 'dependabot[bot]')
101101
steps:
102102
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -107,7 +107,7 @@ jobs:
107107
name: Service Name Scan C-I
108108
runs-on: ubuntu-latest
109109
container:
110-
image: "returntocorp/semgrep:1.52.0"
110+
image: "semgrep/semgrep:1.110.0"
111111
if: (github.action != 'dependabot[bot]')
112112
steps:
113113
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -118,7 +118,7 @@ jobs:
118118
name: Service Name Scan I-Q
119119
runs-on: ubuntu-latest
120120
container:
121-
image: "returntocorp/semgrep:1.52.0"
121+
image: "semgrep/semgrep:1.110.0"
122122
if: (github.action != 'dependabot[bot]')
123123
steps:
124124
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -129,7 +129,7 @@ jobs:
129129
name: Service Name Scan Q-Z
130130
runs-on: ubuntu-latest
131131
container:
132-
image: "returntocorp/semgrep:1.52.0"
132+
image: "semgrep/semgrep:1.110.0"
133133
if: (github.action != 'dependabot[bot]')
134134
steps:
135135
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

GNUmakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ provider-lint: ## [CI] ProviderLint Checks / providerlint
414414

415415
quick-fix-heading: ## Just a heading for quick-fix
416416
@echo "make: Quick fixes..."
417+
@echo "make: Multiple runs are needed if it finds errors (later targets not reached)"
417418

418419
quick-fix: quick-fix-heading fmt testacc-lint-fix fix-imports modern-fix semgrep-fix website-terrafmt-fix ## Some quick fixes
419420

internal/service/codebuild/service_package_gen.go

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package codebuild
5+
6+
import (
7+
"context"
8+
"time"
9+
10+
"github.com/aws/aws-sdk-go-v2/aws"
11+
"github.com/aws/aws-sdk-go-v2/service/codebuild"
12+
awstypes "github.com/aws/aws-sdk-go-v2/service/codebuild/types"
13+
"github.com/hashicorp/terraform-plugin-framework/action"
14+
"github.com/hashicorp/terraform-plugin-framework/action/schema"
15+
"github.com/hashicorp/terraform-plugin-framework/types"
16+
"github.com/hashicorp/terraform-plugin-log/tflog"
17+
"github.com/hashicorp/terraform-provider-aws/internal/framework"
18+
fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
19+
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
20+
"github.com/hashicorp/terraform-provider-aws/names"
21+
)
22+
23+
// @Action(aws_codebuild_start_build, name="CodeBuild Start Build")
24+
func newStartBuildAction(context.Context) (action.ActionWithConfigure, error) {
25+
return &startBuildAction{}, nil
26+
}
27+
28+
type startBuildAction struct {
29+
framework.ActionWithModel[startBuildActionModel]
30+
}
31+
32+
type startBuildActionModel struct {
33+
framework.WithRegionModel
34+
ProjectName types.String `tfsdk:"project_name"`
35+
SourceVersion types.String `tfsdk:"source_version"`
36+
Timeout types.Int64 `tfsdk:"timeout"`
37+
EnvironmentVariablesOverride fwtypes.ListNestedObjectValueOf[environmentVariableModel] `tfsdk:"environment_variables_override"`
38+
BuildID types.String `tfsdk:"build_id"`
39+
}
40+
41+
type environmentVariableModel struct {
42+
Name types.String `tfsdk:"name"`
43+
Value types.String `tfsdk:"value"`
44+
Type types.String `tfsdk:"type"`
45+
}
46+
47+
func (a *startBuildAction) Schema(ctx context.Context, req action.SchemaRequest, resp *action.SchemaResponse) {
48+
resp.Schema = schema.Schema{
49+
Description: "Starts a CodeBuild project build",
50+
Attributes: map[string]schema.Attribute{
51+
"project_name": schema.StringAttribute{
52+
Description: "Name of the CodeBuild project",
53+
Required: true,
54+
},
55+
"source_version": schema.StringAttribute{
56+
Description: "Version of the build input to be built",
57+
Optional: true,
58+
},
59+
names.AttrTimeout: schema.Int64Attribute{
60+
Description: "Timeout in seconds for the build operation",
61+
Optional: true,
62+
},
63+
"build_id": schema.StringAttribute{
64+
Description: "ID of the started build",
65+
Optional: true,
66+
},
67+
},
68+
Blocks: map[string]schema.Block{
69+
"environment_variables_override": schema.ListNestedBlock{
70+
CustomType: fwtypes.NewListNestedObjectTypeOf[environmentVariableModel](ctx),
71+
Description: "Environment variables to override for this build",
72+
NestedObject: schema.NestedBlockObject{
73+
Attributes: map[string]schema.Attribute{
74+
names.AttrName: schema.StringAttribute{
75+
Description: "Environment variable name",
76+
Required: true,
77+
},
78+
names.AttrValue: schema.StringAttribute{
79+
Description: "Environment variable value",
80+
Required: true,
81+
},
82+
names.AttrType: schema.StringAttribute{
83+
Description: "Environment variable type",
84+
Optional: true,
85+
},
86+
},
87+
},
88+
},
89+
},
90+
}
91+
}
92+
93+
func (a *startBuildAction) Invoke(ctx context.Context, req action.InvokeRequest, resp *action.InvokeResponse) {
94+
var model startBuildActionModel
95+
resp.Diagnostics.Append(req.Config.Get(ctx, &model)...)
96+
if resp.Diagnostics.HasError() {
97+
return
98+
}
99+
100+
conn := a.Meta().CodeBuildClient(ctx)
101+
102+
timeout := 30 * time.Minute
103+
if !model.Timeout.IsNull() {
104+
timeout = time.Duration(model.Timeout.ValueInt64()) * time.Second
105+
}
106+
107+
tflog.Info(ctx, "Starting CodeBuild project build", map[string]any{
108+
"project_name": model.ProjectName.ValueString(),
109+
})
110+
111+
resp.SendProgress(action.InvokeProgressEvent{
112+
Message: "Starting CodeBuild project build...",
113+
})
114+
115+
var input codebuild.StartBuildInput
116+
resp.Diagnostics.Append(fwflex.Expand(ctx, model, &input)...)
117+
if resp.Diagnostics.HasError() {
118+
return
119+
}
120+
121+
output, err := conn.StartBuild(ctx, &input)
122+
if err != nil {
123+
resp.Diagnostics.AddError("Starting CodeBuild project build", err.Error())
124+
return
125+
}
126+
127+
buildID := aws.ToString(output.Build.Id)
128+
model.BuildID = types.StringValue(buildID)
129+
130+
resp.SendProgress(action.InvokeProgressEvent{
131+
Message: "Build started, waiting for completion...",
132+
})
133+
134+
// Poll for build completion
135+
deadline := time.Now().Add(timeout)
136+
pollInterval := 30 * time.Second
137+
progressInterval := 2 * time.Minute
138+
lastProgressUpdate := time.Now()
139+
140+
for {
141+
select {
142+
case <-ctx.Done():
143+
resp.Diagnostics.AddError("Build monitoring cancelled", "Context was cancelled")
144+
return
145+
default:
146+
}
147+
148+
if time.Now().After(deadline) {
149+
resp.Diagnostics.AddError("Build timeout", "Build did not complete within the specified timeout")
150+
return
151+
}
152+
153+
input := codebuild.BatchGetBuildsInput{
154+
Ids: []string{buildID},
155+
}
156+
batchGetBuildsOutput, err := conn.BatchGetBuilds(ctx, &input)
157+
if err != nil {
158+
resp.Diagnostics.AddError("Getting build status", err.Error())
159+
return
160+
}
161+
162+
if len(batchGetBuildsOutput.Builds) == 0 {
163+
resp.Diagnostics.AddError("Build not found", "Build was not found in BatchGetBuilds response")
164+
return
165+
}
166+
167+
build := batchGetBuildsOutput.Builds[0]
168+
status := build.BuildStatus
169+
170+
if time.Since(lastProgressUpdate) >= progressInterval {
171+
resp.SendProgress(action.InvokeProgressEvent{
172+
Message: "Build currently in state: " + string(status),
173+
})
174+
lastProgressUpdate = time.Now()
175+
}
176+
177+
switch status {
178+
case awstypes.StatusTypeSucceeded:
179+
resp.SendProgress(action.InvokeProgressEvent{
180+
Message: "Build completed successfully",
181+
})
182+
return
183+
case awstypes.StatusTypeFailed, awstypes.StatusTypeFault, awstypes.StatusTypeStopped, awstypes.StatusTypeTimedOut:
184+
resp.Diagnostics.AddError("Build failed", "Build completed with status: "+string(status))
185+
return
186+
case awstypes.StatusTypeInProgress:
187+
// Continue polling
188+
default:
189+
resp.Diagnostics.AddError("Unexpected build status", "Received unexpected build status: "+string(status))
190+
return
191+
}
192+
193+
time.Sleep(pollInterval)
194+
}
195+
}

0 commit comments

Comments
 (0)