• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubernetes-sigs / kubebuilder / 20684073393

03 Jan 2026 10:54PM UTC coverage: 61.607% (+0.4%) from 61.226%
20684073393

Pull #5339

github

camilamacedo86
(helm/v2-alpha): add custom resources to templates/extras

Manual resources not matching the standard layout now go to
templates/extras/ with proper templating applied.

Assisted-by: Cursor
Pull Request #5339: (Blocked by #5294) ✨ (helm/v2-alpha): add custom resources to templates/extras

103 of 107 new or added lines in 7 files covered. (96.26%)

183 existing lines in 5 files now uncovered.

5990 of 9723 relevant lines covered (61.61%)

26.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.93
/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/templates/values_basic.go
1
/*
2
Copyright 2025 The Kubernetes Authors.
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 templates
18

19
import (
20
        "bytes"
21
        "fmt"
22
        "path/filepath"
23
        "strings"
24

25
        "go.yaml.in/yaml/v3"
26

27
        "sigs.k8s.io/kubebuilder/v4/pkg/machinery"
28
)
29

30
var _ machinery.Template = &HelmValuesBasic{}
31

32
// HelmValuesBasic scaffolds a basic values.yaml based on detected features
33
type HelmValuesBasic struct {
34
        machinery.TemplateMixin
35
        machinery.ProjectNameMixin
36

37
        // DeploymentConfig stores extracted deployment configuration (env, resources, security contexts)
38
        DeploymentConfig map[string]any
39
        // OutputDir specifies the output directory for the chart
40
        OutputDir string
41
        // Force if true allows overwriting the scaffolded file
42
        Force bool
43
        // HasWebhooks is true when webhooks were found in the config
44
        HasWebhooks bool
45
        // HasMetrics is true when metrics service/monitor were found in the config
46
        HasMetrics bool
47
        // NamePrefix is the detected kustomize namePrefix used for resource names
48
        NamePrefix string
49
}
50

51
// SetTemplateDefaults implements machinery.Template
52
func (f *HelmValuesBasic) SetTemplateDefaults() error {
25✔
53
        if f.Path == "" {
50✔
54
                outputDir := f.OutputDir
25✔
55
                if outputDir == "" {
47✔
56
                        outputDir = "dist"
22✔
57
                }
22✔
58
                f.Path = filepath.Join(outputDir, "chart", "values.yaml")
25✔
59
        }
60

61
        f.TemplateBody = f.generateBasicValues()
25✔
62

25✔
63
        if f.Force {
25✔
UNCOV
64
                f.IfExistsAction = machinery.OverwriteFile
×
65
        } else {
25✔
66
                f.IfExistsAction = machinery.SkipFile
25✔
67
        }
25✔
68

69
        return nil
25✔
70
}
71

72
// generateBasicValues creates a basic values.yaml based on detected features
73
func (f *HelmValuesBasic) generateBasicValues() string {
25✔
74
        var buf bytes.Buffer
25✔
75

25✔
76
        // Controller Manager configuration
25✔
77
        imageRepo := "controller"
25✔
78
        imageTag := "latest"
25✔
79
        imagePullPolicy := "IfNotPresent"
25✔
80
        if f.DeploymentConfig != nil {
46✔
81
                if imgCfg, ok := f.DeploymentConfig["image"].(map[string]any); ok {
22✔
82
                        if repo, ok := imgCfg["repository"].(string); ok && repo != "" {
2✔
83
                                imageRepo = repo
1✔
84
                        }
1✔
85
                        if tag, ok := imgCfg["tag"].(string); ok && tag != "" {
2✔
86
                                imageTag = tag
1✔
87
                        }
1✔
88
                        if policy, ok := imgCfg["pullPolicy"].(string); ok && policy != "" {
2✔
89
                                imagePullPolicy = policy
1✔
90
                        }
1✔
91
                }
92
        }
93

94
        // Add namePrefix at the top (detected from kustomize)
95
        namePrefix := f.NamePrefix
25✔
96
        if namePrefix == "" {
50✔
97
                namePrefix = f.ProjectName
25✔
98
        }
25✔
99

100
        buf.WriteString(fmt.Sprintf(`# Prefix for all resource names
25✔
101
namePrefix: %s
25✔
102

25✔
103
# Configure the controller manager deployment
25✔
104
manager:
25✔
105
  replicas: 1
25✔
106
  
25✔
107
  image:
25✔
108
    repository: %s
25✔
109
    tag: %s
25✔
110
    pullPolicy: %s
25✔
111

25✔
112
`, namePrefix, imageRepo, imageTag, imagePullPolicy))
25✔
113

25✔
114
        // Add extracted deployment configuration
25✔
115
        f.addDeploymentConfig(&buf)
25✔
116

25✔
117
        // RBAC configuration
25✔
118
        buf.WriteString(`# Essential RBAC permissions (required for controller operation)
25✔
119
# These include ServiceAccount, controller permissions, leader election, and metrics access
25✔
120
# Note: Essential RBAC is always enabled as it's required for the controller to function
25✔
121

25✔
122
# Helper RBAC roles for managing custom resources
25✔
123
# These provide convenient admin/editor/viewer roles for each CRD type
25✔
124
# Useful for giving users different levels of access to your custom resources
25✔
125
rbacHelpers:
25✔
126
  enable: false  # Install convenience admin/editor/viewer roles for CRDs
25✔
127

25✔
128
`)
25✔
129

25✔
130
        // CRD configuration
25✔
131
        buf.WriteString(`# Custom Resource Definitions
25✔
132
crd:
25✔
133
  enable: true  # Install CRDs with the chart
25✔
134
  keep: true    # Keep CRDs when uninstalling
25✔
135

25✔
136
`)
25✔
137

25✔
138
        // Metrics configuration (enable if metrics artifacts detected in kustomize output)
25✔
139
        metricsPort := 8443
25✔
140
        if f.DeploymentConfig != nil {
46✔
141
                if mp, ok := f.DeploymentConfig["metricsPort"].(int); ok && mp > 0 {
26✔
142
                        metricsPort = mp
5✔
143
                }
5✔
144
        }
145

146
        if f.HasMetrics {
38✔
147
                buf.WriteString(fmt.Sprintf(`# Controller metrics endpoint.
13✔
148
# Enable to expose /metrics endpoint with RBAC protection.
13✔
149
metrics:
13✔
150
  enable: true
13✔
151
  port: %d  # Metrics server port
13✔
152

13✔
153
`, metricsPort))
13✔
154
        } else {
25✔
155
                buf.WriteString(fmt.Sprintf(`# Controller metrics endpoint.
12✔
156
# Enable to expose /metrics endpoint with RBAC protection.
12✔
157
metrics:
12✔
158
  enable: false
12✔
159
  port: %d  # Metrics server port
12✔
160

12✔
161
`, metricsPort))
12✔
162
        }
12✔
163

164
        // Cert-manager configuration (always present, enabled based on webhooks)
165
        if f.HasWebhooks {
38✔
166
                buf.WriteString(`# Cert-manager integration for TLS certificates.
13✔
167
# Required for webhook certificates and metrics endpoint certificates.
13✔
168
certManager:
13✔
169
  enable: true
13✔
170

13✔
171
`)
13✔
172
        } else {
25✔
173
                buf.WriteString(`# Cert-manager integration for TLS certificates.
12✔
174
# Required for webhook certificates and metrics endpoint certificates.
12✔
175
certManager:
12✔
176
  enable: false
12✔
177

12✔
178
`)
12✔
179
        }
12✔
180

181
        // Webhook configuration - only if webhooks are present
182
        if f.HasWebhooks {
38✔
183
                webhookPort := 9443
13✔
184
                if f.DeploymentConfig != nil {
26✔
185
                        if wp, ok := f.DeploymentConfig["webhookPort"].(int); ok && wp > 0 {
16✔
186
                                webhookPort = wp
3✔
187
                        }
3✔
188
                }
189

190
                buf.WriteString(fmt.Sprintf(`# Webhook server configuration
13✔
191
webhook:
13✔
192
  enable: true
13✔
193
  port: %d  # Webhook server port
13✔
194

13✔
195
`, webhookPort))
13✔
196
        }
197

198
        // Prometheus configuration
199
        buf.WriteString(`# Prometheus ServiceMonitor for metrics scraping.
25✔
200
# Requires prometheus-operator to be installed in the cluster.
25✔
201
prometheus:
25✔
202
  enable: false
25✔
203
`)
25✔
204

25✔
205
        buf.WriteString("\n")
25✔
206
        return buf.String()
25✔
207
}
208

209
// addDeploymentConfig adds extracted deployment configuration to the values
210
func (f *HelmValuesBasic) addDeploymentConfig(buf *bytes.Buffer) {
25✔
211
        f.addArgsSection(buf)
25✔
212

25✔
213
        if f.DeploymentConfig == nil {
29✔
214
                // Add default sections with examples
4✔
215
                f.addDefaultDeploymentSections(buf)
4✔
216
                return
4✔
217
        }
4✔
218

219
        // Add environment variables if they exist
220
        if env, exists := f.DeploymentConfig["env"]; exists && env != nil {
23✔
221
                buf.WriteString("  # Environment variables\n")
2✔
222
                buf.WriteString("  env:\n")
2✔
223
                if envYaml, err := yaml.Marshal(env); err == nil {
4✔
224
                        f.IndentYamlProperly(buf, envYaml)
2✔
225
                } else {
2✔
UNCOV
226
                        buf.WriteString("    []\n")
×
UNCOV
227
                }
×
228
                buf.WriteString("\n")
2✔
229
        } else {
19✔
230
                buf.WriteString("  # Environment variables\n")
19✔
231
                buf.WriteString("  env: []\n\n")
19✔
232
        }
19✔
233

234
        // Add image pull secrets
235
        if imagePullSecrets, exists := f.DeploymentConfig["imagePullSecrets"]; exists && imagePullSecrets != nil {
22✔
236
                buf.WriteString("  # Image pull secrets\n")
1✔
237
                buf.WriteString("  imagePullSecrets:\n")
1✔
238
                if imagePullSecretsYaml, err := yaml.Marshal(imagePullSecrets); err == nil {
2✔
239
                        lines := bytes.SplitSeq(imagePullSecretsYaml, []byte("\n"))
1✔
240
                        for line := range lines {
4✔
241
                                if len(line) > 0 {
5✔
242
                                        buf.WriteString("    ")
2✔
243
                                        buf.Write(line)
2✔
244
                                        buf.WriteString("\n")
2✔
245
                                }
2✔
246
                        }
247
                }
248
                buf.WriteString("\n")
1✔
249
        } else {
20✔
250
                f.addDefaultImagePullSecrets(buf)
20✔
251
        }
20✔
252

253
        // Add podSecurityContext
254
        if podSecCtx, exists := f.DeploymentConfig["podSecurityContext"]; exists && podSecCtx != nil {
21✔
UNCOV
255
                buf.WriteString("  # Pod-level security settings\n")
×
256
                buf.WriteString("  podSecurityContext:\n")
×
257
                if secYaml, err := yaml.Marshal(podSecCtx); err == nil {
×
258
                        f.IndentYamlProperly(buf, secYaml)
×
259
                }
×
260
                buf.WriteString("\n")
×
261
        } else {
21✔
262
                f.addDefaultPodSecurityContext(buf)
21✔
263
        }
21✔
264

265
        // Add securityContext
266
        if secCtx, exists := f.DeploymentConfig["securityContext"]; exists && secCtx != nil {
21✔
UNCOV
267
                buf.WriteString("  # Container-level security settings\n")
×
UNCOV
268
                buf.WriteString("  securityContext:\n")
×
UNCOV
269
                if secYaml, err := yaml.Marshal(secCtx); err == nil {
×
UNCOV
270
                        f.IndentYamlProperly(buf, secYaml)
×
UNCOV
271
                }
×
UNCOV
272
                buf.WriteString("\n")
×
273
        } else {
21✔
274
                f.addDefaultSecurityContext(buf)
21✔
275
        }
21✔
276

277
        // Add resources
278
        if resources, exists := f.DeploymentConfig["resources"]; exists && resources != nil {
22✔
279
                buf.WriteString("  # Resource limits and requests\n")
1✔
280
                buf.WriteString("  resources:\n")
1✔
281
                if resYaml, err := yaml.Marshal(resources); err == nil {
2✔
282
                        f.IndentYamlProperly(buf, resYaml)
1✔
283
                }
1✔
284
                buf.WriteString("\n")
1✔
285
        } else {
20✔
286
                f.addDefaultResources(buf)
20✔
287
        }
20✔
288

289
        buf.WriteString("  # Manager pod's affinity\n")
21✔
290
        if affinity, exists := f.DeploymentConfig["podAffinity"]; exists && affinity != nil {
22✔
291
                buf.WriteString("  affinity:\n")
1✔
292
                if affYaml, err := yaml.Marshal(affinity); err == nil {
2✔
293
                        f.IndentYamlProperly(buf, affYaml)
1✔
294
                }
1✔
295
                buf.WriteString("\n")
1✔
296
        } else {
20✔
297
                buf.WriteString("  affinity: {}\n")
20✔
298
                buf.WriteString("\n")
20✔
299
        }
20✔
300

301
        buf.WriteString("  # Manager pod's node selector\n")
21✔
302
        if nodeSelector, exists := f.DeploymentConfig["podNodeSelector"]; exists && nodeSelector != nil {
22✔
303
                buf.WriteString("  nodeSelector:\n")
1✔
304
                if nodYaml, err := yaml.Marshal(nodeSelector); err == nil {
2✔
305
                        f.IndentYamlProperly(buf, nodYaml)
1✔
306
                }
1✔
307
                buf.WriteString("\n")
1✔
308
        } else {
20✔
309
                buf.WriteString("  nodeSelector: {}\n")
20✔
310
                buf.WriteString("\n")
20✔
311
        }
20✔
312

313
        buf.WriteString("  # Manager pod's tolerations\n")
21✔
314
        if tolerations, exists := f.DeploymentConfig["podTolerations"]; exists && tolerations != nil {
22✔
315
                buf.WriteString("  tolerations:\n")
1✔
316
                if tolYaml, err := yaml.Marshal(tolerations); err == nil {
2✔
317
                        f.IndentYamlProperly(buf, tolYaml)
1✔
318
                }
1✔
319
                buf.WriteString("\n")
1✔
320
        } else {
20✔
321
                buf.WriteString("  tolerations: []\n")
20✔
322
                buf.WriteString("\n")
20✔
323
        }
20✔
324
}
325

326
func (f *HelmValuesBasic) IndentYamlProperly(buf *bytes.Buffer, envYaml []byte) {
6✔
327
        lines := bytes.SplitSeq(envYaml, []byte("\n"))
6✔
328
        for line := range lines {
34✔
329
                if len(line) > 0 {
50✔
330
                        buf.WriteString("    ")
22✔
331
                        buf.Write(line)
22✔
332
                        buf.WriteString("\n")
22✔
333
                }
22✔
334
        }
335
}
336

337
// addDefaultDeploymentSections adds default sections when no deployment config is available
338
func (f *HelmValuesBasic) addDefaultDeploymentSections(buf *bytes.Buffer) {
4✔
339
        buf.WriteString("  # Environment variables\n")
4✔
340
        buf.WriteString("  env: []\n\n")
4✔
341

4✔
342
        f.addDefaultImagePullSecrets(buf)
4✔
343
        f.addDefaultPodSecurityContext(buf)
4✔
344
        f.addDefaultSecurityContext(buf)
4✔
345
        f.addDefaultResources(buf)
4✔
346
}
4✔
347

348
// addArgsSection adds controller manager args section to the values file
349
func (f *HelmValuesBasic) addArgsSection(buf *bytes.Buffer) {
25✔
350
        buf.WriteString("  # Arguments\n")
25✔
351

25✔
352
        if f.DeploymentConfig != nil {
46✔
353
                if args, exists := f.DeploymentConfig["args"]; exists && args != nil {
22✔
354
                        if argsYaml, err := yaml.Marshal(args); err == nil {
2✔
355
                                if trimmed := strings.TrimSpace(string(argsYaml)); trimmed != "" && trimmed != "[]" {
2✔
356
                                        lines := bytes.Split(argsYaml, []byte("\n"))
1✔
357
                                        buf.WriteString("  args:\n")
1✔
358
                                        for _, line := range lines {
3✔
359
                                                if len(line) > 0 {
3✔
360
                                                        buf.WriteString("    ")
1✔
361
                                                        buf.Write(line)
1✔
362
                                                        buf.WriteString("\n")
1✔
363
                                                }
1✔
364
                                        }
365
                                        buf.WriteString("\n")
1✔
366
                                        return
1✔
367
                                }
368
                        }
369
                }
370
        }
371

372
        buf.WriteString("  args: []\n\n")
24✔
373
}
374

375
// addDefaultImagePullSecrets adds default imagePullSecrets section
376
func (f *HelmValuesBasic) addDefaultImagePullSecrets(buf *bytes.Buffer) {
24✔
377
        buf.WriteString("  # Image pull secrets\n")
24✔
378
        buf.WriteString("  imagePullSecrets: []\n\n")
24✔
379
}
24✔
380

381
// addDefaultPodSecurityContext adds default podSecurityContext section
382
func (f *HelmValuesBasic) addDefaultPodSecurityContext(buf *bytes.Buffer) {
25✔
383
        buf.WriteString("  # Pod-level security settings\n")
25✔
384
        buf.WriteString("  podSecurityContext: {}\n")
25✔
385
        buf.WriteString("    # fsGroup: 2000\n\n")
25✔
386
}
25✔
387

388
// addDefaultSecurityContext adds default securityContext section
389
func (f *HelmValuesBasic) addDefaultSecurityContext(buf *bytes.Buffer) {
25✔
390
        buf.WriteString("  # Container-level security settings\n")
25✔
391
        buf.WriteString("  securityContext: {}\n")
25✔
392
        buf.WriteString("    # capabilities:\n")
25✔
393
        buf.WriteString("    #   drop:\n")
25✔
394
        buf.WriteString("    #   - ALL\n")
25✔
395
        buf.WriteString("    # readOnlyRootFilesystem: true\n")
25✔
396
        buf.WriteString("    # runAsNonRoot: true\n")
25✔
397
        buf.WriteString("    # runAsUser: 1000\n\n")
25✔
398
}
25✔
399

400
// addDefaultResources adds default resources section
401
func (f *HelmValuesBasic) addDefaultResources(buf *bytes.Buffer) {
24✔
402
        buf.WriteString("  # Resource limits and requests\n")
24✔
403
        buf.WriteString("  resources: {}\n")
24✔
404
        buf.WriteString("    # limits:\n")
24✔
405
        buf.WriteString("    #   cpu: 100m\n")
24✔
406
        buf.WriteString("    #   memory: 128Mi\n")
24✔
407
        buf.WriteString("    # requests:\n")
24✔
408
        buf.WriteString("    #   cpu: 100m\n")
24✔
409
        buf.WriteString("    #   memory: 128Mi\n\n")
24✔
410
}
24✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc