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

kubernetes-sigs / kubebuilder / 20774603420

07 Jan 2026 07:55AM UTC coverage: 71.772% (-0.01%) from 71.782%
20774603420

Pull #5362

github

camilamacedo86
(helm/v2-alpha): Auto-detect and organize sample CRs in templates/samples/

Sample Custom Resources from config/samples/ are now automatically detected
and placed in templates/samples/ with conditional rendering via
.Values.samples.create (disabled by default). Detection uses CRD-based
matching to ensure only CR instances of defined CRDs are categorized as samples.

Assisted-by: Cursor
Pull Request #5362: WIP ✨ (helm/v2-alpha): Auto-detect and organize sample CRs in templates/samples/

81 of 91 new or added lines in 5 files covered. (89.01%)

41 existing lines in 2 files now uncovered.

6448 of 8984 relevant lines covered (71.77%)

32.11 hits per line

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

94.86
/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
}
48

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

59
        f.TemplateBody = f.generateBasicValues()
25✔
60

25✔
61
        if f.Force {
25✔
62
                f.IfExistsAction = machinery.OverwriteFile
×
63
        } else {
25✔
64
                f.IfExistsAction = machinery.SkipFile
25✔
65
        }
25✔
66

67
        return nil
25✔
68
}
69

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

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

92
        buf.WriteString(fmt.Sprintf(`## String to partially override chart.fullname template (will maintain the release name)
25✔
93
##
25✔
94
# nameOverride: ""
25✔
95

25✔
96
## String to fully override chart.fullname template
25✔
97
##
25✔
98
# fullnameOverride: ""
25✔
99

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

25✔
110
`, imageRepo, imageTag, imagePullPolicy))
25✔
111

25✔
112
        // Add extracted deployment configuration
25✔
113
        f.addDeploymentConfig(&buf)
25✔
114

25✔
115
        // RBAC configuration
25✔
116
        buf.WriteString(`## Helper RBAC roles for managing custom resources
25✔
117
##
25✔
118
rbacHelpers:
25✔
119
  # Install convenience admin/editor/viewer roles for CRDs
25✔
120
  enable: false
25✔
121

25✔
122
`)
25✔
123

25✔
124
        // CRD configuration
25✔
125
        buf.WriteString(`## Custom Resource Definitions
25✔
126
##
25✔
127
crd:
25✔
128
  # Install CRDs with the chart
25✔
129
  enable: true
25✔
130
  # Keep CRDs when uninstalling
25✔
131
  keep: true
25✔
132

25✔
133
`)
25✔
134

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

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

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

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

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

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

12✔
181
`)
12✔
182
        }
12✔
183

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

193
                buf.WriteString(fmt.Sprintf(`## Webhook server configuration
13✔
194
##
13✔
195
webhook:
13✔
196
  enable: true
13✔
197
  # Webhook server port
13✔
198
  port: %d
13✔
199

13✔
200
`, webhookPort))
13✔
201
        }
202

203
        // Samples configuration
204
        buf.WriteString(`## Sample Custom Resources
25✔
205
## Deploy example CR instances for testing and demonstration.
25✔
206
## These are the resources from config/samples/ directory.
25✔
207
##
25✔
208
samples:
25✔
209
  # Set to true to deploy sample CRs with the chart
25✔
210
  create: false
25✔
211

25✔
212
`)
25✔
213

25✔
214
        // Prometheus configuration
25✔
215
        buf.WriteString(`## Prometheus ServiceMonitor for metrics scraping.
25✔
216
## Requires prometheus-operator to be installed in the cluster.
25✔
217
##
25✔
218
prometheus:
25✔
219
  enable: false
25✔
220
`)
25✔
221

25✔
222
        buf.WriteString("\n")
25✔
223
        return buf.String()
25✔
224
}
225

226
// addDeploymentConfig adds extracted deployment configuration to the values
227
func (f *HelmValuesBasic) addDeploymentConfig(buf *bytes.Buffer) {
25✔
228
        f.addArgsSection(buf)
25✔
229

25✔
230
        if f.DeploymentConfig == nil {
29✔
231
                // Add default sections with examples
4✔
232
                f.addDefaultDeploymentSections(buf)
4✔
233
                return
4✔
234
        }
4✔
235

236
        // Add environment variables if they exist
237
        if env, exists := f.DeploymentConfig["env"]; exists && env != nil {
23✔
238
                buf.WriteString("  ## Environment variables\n")
2✔
239
                buf.WriteString("  ##\n")
2✔
240
                buf.WriteString("  env:\n")
2✔
241
                if envYaml, err := yaml.Marshal(env); err == nil {
4✔
242
                        f.IndentYamlProperly(buf, envYaml)
2✔
243
                } else {
2✔
UNCOV
244
                        buf.WriteString("    []\n")
×
UNCOV
245
                }
×
246
                buf.WriteString("\n")
2✔
247
        } else {
19✔
248
                buf.WriteString("  ## Environment variables\n")
19✔
249
                buf.WriteString("  ##\n")
19✔
250
                buf.WriteString("  env: []\n\n")
19✔
251
        }
19✔
252

253
        // Add image pull secrets
254
        if imagePullSecrets, exists := f.DeploymentConfig["imagePullSecrets"]; exists && imagePullSecrets != nil {
22✔
255
                buf.WriteString("  ## Image pull secrets\n")
1✔
256
                buf.WriteString("  ##\n")
1✔
257
                buf.WriteString("  imagePullSecrets:\n")
1✔
258
                if imagePullSecretsYaml, err := yaml.Marshal(imagePullSecrets); err == nil {
2✔
259
                        lines := bytes.SplitSeq(imagePullSecretsYaml, []byte("\n"))
1✔
260
                        for line := range lines {
4✔
261
                                if len(line) > 0 {
5✔
262
                                        buf.WriteString("    ")
2✔
263
                                        buf.Write(line)
2✔
264
                                        buf.WriteString("\n")
2✔
265
                                }
2✔
266
                        }
267
                }
268
                buf.WriteString("\n")
1✔
269
        } else {
20✔
270
                f.addDefaultImagePullSecrets(buf)
20✔
271
        }
20✔
272

273
        // Add podSecurityContext
274
        if podSecCtx, exists := f.DeploymentConfig["podSecurityContext"]; exists && podSecCtx != nil {
21✔
275
                buf.WriteString("  ## Pod-level security settings\n")
×
276
                buf.WriteString("  ##\n")
×
277
                buf.WriteString("  podSecurityContext:\n")
×
UNCOV
278
                if secYaml, err := yaml.Marshal(podSecCtx); err == nil {
×
UNCOV
279
                        f.IndentYamlProperly(buf, secYaml)
×
UNCOV
280
                }
×
UNCOV
281
                buf.WriteString("\n")
×
282
        } else {
21✔
283
                f.addDefaultPodSecurityContext(buf)
21✔
284
        }
21✔
285

286
        // Add securityContext
287
        if secCtx, exists := f.DeploymentConfig["securityContext"]; exists && secCtx != nil {
21✔
288
                buf.WriteString("  ## Container-level security settings\n")
×
289
                buf.WriteString("  ##\n")
×
290
                buf.WriteString("  securityContext:\n")
×
UNCOV
291
                if secYaml, err := yaml.Marshal(secCtx); err == nil {
×
UNCOV
292
                        f.IndentYamlProperly(buf, secYaml)
×
UNCOV
293
                }
×
UNCOV
294
                buf.WriteString("\n")
×
295
        } else {
21✔
296
                f.addDefaultSecurityContext(buf)
21✔
297
        }
21✔
298

299
        // Add resources
300
        if resources, exists := f.DeploymentConfig["resources"]; exists && resources != nil {
22✔
301
                buf.WriteString("  ## Resource limits and requests\n")
1✔
302
                buf.WriteString("  ##\n")
1✔
303
                buf.WriteString("  resources:\n")
1✔
304
                if resYaml, err := yaml.Marshal(resources); err == nil {
2✔
305
                        f.IndentYamlProperly(buf, resYaml)
1✔
306
                }
1✔
307
                buf.WriteString("\n")
1✔
308
        } else {
20✔
309
                f.addDefaultResources(buf)
20✔
310
        }
20✔
311

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

325
        buf.WriteString("  ## Manager pod's node selector\n")
21✔
326
        buf.WriteString("  ##\n")
21✔
327
        if nodeSelector, exists := f.DeploymentConfig["podNodeSelector"]; exists && nodeSelector != nil {
22✔
328
                buf.WriteString("  nodeSelector:\n")
1✔
329
                if nodYaml, err := yaml.Marshal(nodeSelector); err == nil {
2✔
330
                        f.IndentYamlProperly(buf, nodYaml)
1✔
331
                }
1✔
332
                buf.WriteString("\n")
1✔
333
        } else {
20✔
334
                buf.WriteString("  nodeSelector: {}\n")
20✔
335
                buf.WriteString("\n")
20✔
336
        }
20✔
337

338
        buf.WriteString("  ## Manager pod's tolerations\n")
21✔
339
        buf.WriteString("  ##\n")
21✔
340
        if tolerations, exists := f.DeploymentConfig["podTolerations"]; exists && tolerations != nil {
22✔
341
                buf.WriteString("  tolerations:\n")
1✔
342
                if tolYaml, err := yaml.Marshal(tolerations); err == nil {
2✔
343
                        f.IndentYamlProperly(buf, tolYaml)
1✔
344
                }
1✔
345
                buf.WriteString("\n")
1✔
346
        } else {
20✔
347
                buf.WriteString("  tolerations: []\n")
20✔
348
                buf.WriteString("\n")
20✔
349
        }
20✔
350
}
351

352
func (f *HelmValuesBasic) IndentYamlProperly(buf *bytes.Buffer, envYaml []byte) {
6✔
353
        lines := bytes.SplitSeq(envYaml, []byte("\n"))
6✔
354
        for line := range lines {
34✔
355
                if len(line) > 0 {
50✔
356
                        buf.WriteString("    ")
22✔
357
                        buf.Write(line)
22✔
358
                        buf.WriteString("\n")
22✔
359
                }
22✔
360
        }
361
}
362

363
// addDefaultDeploymentSections adds default sections when no deployment config is available
364
func (f *HelmValuesBasic) addDefaultDeploymentSections(buf *bytes.Buffer) {
4✔
365
        buf.WriteString("  ## Environment variables\n")
4✔
366
        buf.WriteString("  ##\n")
4✔
367
        buf.WriteString("  env: []\n\n")
4✔
368

4✔
369
        f.addDefaultImagePullSecrets(buf)
4✔
370
        f.addDefaultPodSecurityContext(buf)
4✔
371
        f.addDefaultSecurityContext(buf)
4✔
372
        f.addDefaultResources(buf)
4✔
373
}
4✔
374

375
// addArgsSection adds controller manager args section to the values file
376
func (f *HelmValuesBasic) addArgsSection(buf *bytes.Buffer) {
25✔
377
        buf.WriteString("  ## Arguments\n  ##\n")
25✔
378

25✔
379
        if f.DeploymentConfig != nil {
46✔
380
                if args, exists := f.DeploymentConfig["args"]; exists && args != nil {
22✔
381
                        if argsYaml, err := yaml.Marshal(args); err == nil {
2✔
382
                                if trimmed := strings.TrimSpace(string(argsYaml)); trimmed != "" && trimmed != "[]" {
2✔
383
                                        lines := bytes.Split(argsYaml, []byte("\n"))
1✔
384
                                        buf.WriteString("  args:\n")
1✔
385
                                        for _, line := range lines {
3✔
386
                                                if len(line) > 0 {
3✔
387
                                                        buf.WriteString("    ")
1✔
388
                                                        buf.Write(line)
1✔
389
                                                        buf.WriteString("\n")
1✔
390
                                                }
1✔
391
                                        }
392
                                        buf.WriteString("\n")
1✔
393
                                        return
1✔
394
                                }
395
                        }
396
                }
397
        }
398

399
        buf.WriteString("  args: []\n\n")
24✔
400
}
401

402
// addDefaultImagePullSecrets adds default imagePullSecrets section
403
func (f *HelmValuesBasic) addDefaultImagePullSecrets(buf *bytes.Buffer) {
24✔
404
        buf.WriteString("  ## Image pull secrets\n")
24✔
405
        buf.WriteString("  ##\n")
24✔
406
        buf.WriteString("  imagePullSecrets: []\n\n")
24✔
407
}
24✔
408

409
// addDefaultPodSecurityContext adds default podSecurityContext section
410
func (f *HelmValuesBasic) addDefaultPodSecurityContext(buf *bytes.Buffer) {
25✔
411
        buf.WriteString("  ## Pod-level security settings\n")
25✔
412
        buf.WriteString("  ##\n")
25✔
413
        buf.WriteString("  podSecurityContext: {}\n")
25✔
414
        buf.WriteString("    # fsGroup: 2000\n\n")
25✔
415
}
25✔
416

417
// addDefaultSecurityContext adds default securityContext section
418
func (f *HelmValuesBasic) addDefaultSecurityContext(buf *bytes.Buffer) {
25✔
419
        buf.WriteString("  ## Container-level security settings\n")
25✔
420
        buf.WriteString("  ##\n")
25✔
421
        buf.WriteString("  securityContext: {}\n")
25✔
422
        buf.WriteString("    # capabilities:\n")
25✔
423
        buf.WriteString("    #   drop:\n")
25✔
424
        buf.WriteString("    #   - ALL\n")
25✔
425
        buf.WriteString("    # readOnlyRootFilesystem: true\n")
25✔
426
        buf.WriteString("    # runAsNonRoot: true\n")
25✔
427
        buf.WriteString("    # runAsUser: 1000\n\n")
25✔
428
}
25✔
429

430
// addDefaultResources adds default resources section
431
func (f *HelmValuesBasic) addDefaultResources(buf *bytes.Buffer) {
24✔
432
        buf.WriteString("  ## Resource limits and requests\n")
24✔
433
        buf.WriteString("  ##\n")
24✔
434
        buf.WriteString("  resources: {}\n")
24✔
435
        buf.WriteString("    # limits:\n")
24✔
436
        buf.WriteString("    #   cpu: 100m\n")
24✔
437
        buf.WriteString("    #   memory: 128Mi\n")
24✔
438
        buf.WriteString("    # requests:\n")
24✔
439
        buf.WriteString("    #   cpu: 100m\n")
24✔
440
        buf.WriteString("    #   memory: 128Mi\n\n")
24✔
441
}
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