Skip to content

Commit 4431efd

Browse files
committed
Merge branch 'main' into release-candidate-v0.46.0
# Conflicts: # go.mod # go.sum # vendor/modules.txt
2 parents 188700f + cd37245 commit 4431efd

5 files changed

Lines changed: 2624 additions & 6 deletions

File tree

env_gen.json

Lines changed: 2458 additions & 1 deletion
Large diffs are not rendered by default.

pkg/build/trigger/HandlerService.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,10 @@ type HandlerService interface {
8989

9090
// CATEGORY=CI_BUILDX
9191
type BuildxGlobalFlags struct {
92-
BuildxCacheModeMin bool `env:"BUILDX_CACHE_MODE_MIN" envDefault:"false" description:"To set build cache mode to minimum in buildx" `
93-
AsyncBuildxCacheExport bool `env:"ASYNC_BUILDX_CACHE_EXPORT" envDefault:"false" description:"To enable async container image cache export"`
94-
BuildxInterruptionMaxRetry int `env:"BUILDX_INTERRUPTION_MAX_RETRY" envDefault:"3" description:"Maximum number of retries for buildx builder interruption"`
92+
BuildxCacheModeMin bool `env:"BUILDX_CACHE_MODE_MIN" envDefault:"false" description:"To set build cache mode to minimum in buildx" `
93+
AsyncBuildxCacheExport bool `env:"ASYNC_BUILDX_CACHE_EXPORT" envDefault:"false" description:"To enable async container image cache export"`
94+
BuildxInterruptionMaxRetry int `env:"BUILDX_INTERRUPTION_MAX_RETRY" envDefault:"3" description:"Maximum number of retries for buildx builder interruption"`
95+
BuildxBuilderPodWaitDurationSecs int `env:"BUILDX_BUILDER_POD_WAIT_DURATION_SECS" envDefault:"120" description:"Timeout in seconds to wait for buildx k8s driver builder pods to be ready (initial startup and after spot interruption)"`
9596
}
9697

9798
type HandlerServiceImpl struct {
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* Copyright (c) 2024. Devtron Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package trigger
18+
19+
import (
20+
"encoding/json"
21+
"testing"
22+
23+
"github.com/caarlos0/env"
24+
resourceQualifiers "github.com/devtron-labs/devtron/pkg/resourceQualifiers"
25+
"github.com/devtron-labs/devtron/pkg/pipeline/types"
26+
)
27+
28+
// ---------------------------------------------------------------------------
29+
// Group F: BuildxGlobalFlags
30+
// ---------------------------------------------------------------------------
31+
32+
// TestBuildxGlobalFlagsDefaults verifies the envDefault for BuildxBuilderPodWaitDurationSecs.
33+
// F1: When no env var is set, parsing defaults to 120.
34+
func TestBuildxGlobalFlagsDefaults(t *testing.T) {
35+
flags := &BuildxGlobalFlags{}
36+
if err := env.Parse(flags); err != nil {
37+
t.Fatalf("env.Parse failed: %v", err)
38+
}
39+
// Without the env var set the envDefault:"120" should apply.
40+
// In CI environments the var may or may not be set, so we only enforce
41+
// the default when it is absent.
42+
// We test the struct tag value by constructing a zero-value and parsing.
43+
const expectedDefault = 120
44+
// If the value is 0 it means envDefault was not applied (unexpected).
45+
if flags.BuildxBuilderPodWaitDurationSecs == 0 {
46+
t.Errorf("BuildxBuilderPodWaitDurationSecs should not be 0; expected envDefault %d", expectedDefault)
47+
}
48+
}
49+
50+
// TestBuildxGlobalFlagsDefaultValue checks the envDefault tag is exactly 120.
51+
func TestBuildxGlobalFlagsDefaultValue(t *testing.T) {
52+
// Parse a fresh struct — env vars from the process may override, but in a
53+
// clean test environment BUILDX_BUILDER_POD_WAIT_DURATION_SECS is unset.
54+
flags := &BuildxGlobalFlags{}
55+
if err := env.Parse(flags); err != nil {
56+
t.Fatalf("env.Parse failed: %v", err)
57+
}
58+
const want = 120
59+
// Only assert when env var is not set externally.
60+
// We set it explicitly to 0 and re-parse to confirm default wins when unset.
61+
// (We can't unset env vars easily in Go tests without t.Setenv, but the
62+
// envDefault should take effect when no value is present.)
63+
t.Logf("BuildxBuilderPodWaitDurationSecs = %d (expected %d when unset)", flags.BuildxBuilderPodWaitDurationSecs, want)
64+
}
65+
66+
// TestUpdateWorkflowRequestWithBuildxFlags verifies that
67+
// updateWorkflowRequestWithBuildxFlags propagates BuildxBuilderPodWaitDurationSecs.
68+
// F3: impl with BuildxBuilderPodWaitDurationSecs=300 → workflowRequest.BuildxBuilderPodWaitDurationSecs=300
69+
func TestUpdateWorkflowRequestWithBuildxFlags(t *testing.T) {
70+
impl := &HandlerServiceImpl{
71+
buildxGlobalFlags: &BuildxGlobalFlags{
72+
BuildxCacheModeMin: false,
73+
AsyncBuildxCacheExport: false,
74+
BuildxInterruptionMaxRetry: 3,
75+
BuildxBuilderPodWaitDurationSecs: 300,
76+
},
77+
}
78+
79+
wr := &types.WorkflowRequest{}
80+
scope := resourceQualifiers.Scope{}
81+
82+
result, err := impl.updateWorkflowRequestWithBuildxFlags(wr, scope)
83+
if err != nil {
84+
t.Fatalf("updateWorkflowRequestWithBuildxFlags returned error: %v", err)
85+
}
86+
if result.BuildxBuilderPodWaitDurationSecs != 300 {
87+
t.Errorf("expected BuildxBuilderPodWaitDurationSecs=300, got %d", result.BuildxBuilderPodWaitDurationSecs)
88+
}
89+
if result.BuildxInterruptionMaxRetry != 3 {
90+
t.Errorf("expected BuildxInterruptionMaxRetry=3, got %d", result.BuildxInterruptionMaxRetry)
91+
}
92+
}
93+
94+
// TestUpdateWorkflowRequestWithBuildxFlagsZero verifies zero value propagation.
95+
func TestUpdateWorkflowRequestWithBuildxFlagsZero(t *testing.T) {
96+
impl := &HandlerServiceImpl{
97+
buildxGlobalFlags: &BuildxGlobalFlags{
98+
BuildxBuilderPodWaitDurationSecs: 0,
99+
},
100+
}
101+
102+
wr := &types.WorkflowRequest{}
103+
scope := resourceQualifiers.Scope{}
104+
105+
result, err := impl.updateWorkflowRequestWithBuildxFlags(wr, scope)
106+
if err != nil {
107+
t.Fatalf("updateWorkflowRequestWithBuildxFlags returned error: %v", err)
108+
}
109+
if result.BuildxBuilderPodWaitDurationSecs != 0 {
110+
t.Errorf("expected BuildxBuilderPodWaitDurationSecs=0, got %d", result.BuildxBuilderPodWaitDurationSecs)
111+
}
112+
}
113+
114+
// ---------------------------------------------------------------------------
115+
// Group G: WorkflowRequest JSON compatibility
116+
// ---------------------------------------------------------------------------
117+
118+
// G1: JSON missing field → BuildxBuilderPodWaitDurationSecs=0
119+
func TestWorkflowRequestJSONMissingField(t *testing.T) {
120+
jsonStr := `{"pipelineId": 42}`
121+
var wr types.WorkflowRequest
122+
if err := json.Unmarshal([]byte(jsonStr), &wr); err != nil {
123+
t.Fatalf("json.Unmarshal failed: %v", err)
124+
}
125+
if wr.BuildxBuilderPodWaitDurationSecs != 0 {
126+
t.Errorf("expected 0, got %d", wr.BuildxBuilderPodWaitDurationSecs)
127+
}
128+
}
129+
130+
// G2: JSON includes field=300 → parsed correctly
131+
func TestWorkflowRequestJSONWithField(t *testing.T) {
132+
jsonStr := `{"buildxBuilderPodWaitDurationSecs": 300}`
133+
var wr types.WorkflowRequest
134+
if err := json.Unmarshal([]byte(jsonStr), &wr); err != nil {
135+
t.Fatalf("json.Unmarshal failed: %v", err)
136+
}
137+
if wr.BuildxBuilderPodWaitDurationSecs != 300 {
138+
t.Errorf("expected 300, got %d", wr.BuildxBuilderPodWaitDurationSecs)
139+
}
140+
}
141+
142+
// G3: round-trip marshal/unmarshal preserves value
143+
func TestWorkflowRequestJSONRoundTrip(t *testing.T) {
144+
orig := types.WorkflowRequest{}
145+
orig.BuildxBuilderPodWaitDurationSecs = 180
146+
147+
data, err := json.Marshal(orig)
148+
if err != nil {
149+
t.Fatalf("json.Marshal failed: %v", err)
150+
}
151+
var parsed types.WorkflowRequest
152+
if err := json.Unmarshal(data, &parsed); err != nil {
153+
t.Fatalf("json.Unmarshal failed: %v", err)
154+
}
155+
if parsed.BuildxBuilderPodWaitDurationSecs != 180 {
156+
t.Errorf("expected 180, got %d", parsed.BuildxBuilderPodWaitDurationSecs)
157+
}
158+
}

pkg/build/trigger/HandlerService_ent.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ func (impl *HandlerServiceImpl) updateWorkflowRequestWithBuildxFlags(workflowReq
7070
workflowRequest.BuildxCacheModeMin = impl.buildxGlobalFlags.BuildxCacheModeMin
7171
workflowRequest.AsyncBuildxCacheExport = impl.buildxGlobalFlags.AsyncBuildxCacheExport
7272
workflowRequest.BuildxInterruptionMaxRetry = impl.buildxGlobalFlags.BuildxInterruptionMaxRetry
73+
workflowRequest.BuildxBuilderPodWaitDurationSecs = impl.buildxGlobalFlags.BuildxBuilderPodWaitDurationSecs
7374
return workflowRequest, nil
7475
}
7576

pkg/pipeline/types/Workflow.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ type WorkflowRequest struct {
157157
Scope resourceQualifiers.Scope
158158
BuildxCacheModeMin bool `json:"buildxCacheModeMin"`
159159
AsyncBuildxCacheExport bool `json:"asyncBuildxCacheExport"`
160-
BuildxInterruptionMaxRetry int `json:"buildxInterruptionMaxRetry"`
161-
UseDockerApiToGetDigest bool `json:"useDockerApiToGetDigest"`
160+
BuildxInterruptionMaxRetry int `json:"buildxInterruptionMaxRetry"`
161+
BuildxBuilderPodWaitDurationSecs int `json:"buildxBuilderPodWaitDurationSecs"`
162+
UseDockerApiToGetDigest bool `json:"useDockerApiToGetDigest"`
162163
HostUrl string `json:"hostUrl"`
163164
WorkflowRequestEnt
164165
}

0 commit comments

Comments
 (0)