Skip to content

Commit cf90efa

Browse files
authored
feat(chartvalidator): api versions support (#11)
1 parent e1247b6 commit cf90efa

8 files changed

Lines changed: 176 additions & 136 deletions

chartvalidator/checker/appsets.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,4 @@ func str(v any) string {
170170
return s
171171
}
172172
return fmt.Sprintf("%v", v)
173-
}
173+
}

chartvalidator/checker/engine_app_checker.go

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"path/filepath"
67
"sync"
78
)
89

@@ -21,75 +22,84 @@ type AppCheckerEngine struct {
2122
resultChan chan AppCheckResult
2223
errorChan chan ErrorResult
2324

24-
ChartRenderingEngine *ChartRenderingEngine
25+
ChartRenderingEngine *ChartRenderingEngine
2526
ManifestValidationEngine *ManifestValidationEngine
26-
ImageExtractionEngine *ImageExtractionEngine
27+
ImageExtractionEngine *ImageExtractionEngine
2728
DockerValidationEngine *DockerImageValidationEngine
2829

29-
context context.Context
30-
executor CommandExecutor
30+
context context.Context
31+
executor CommandExecutor
3132

3233
workerWaitGroup sync.WaitGroup
3334

3435
name string
3536
}
3637

37-
func NewAppCheckerEngine(context context.Context, outputDir string) *AppCheckerEngine {
38+
func NewAppCheckerEngine(context context.Context, outputDir string, apiVersions []string) *AppCheckerEngine {
3839

3940
errorChan := make(chan ErrorResult)
4041

4142
cre := ChartRenderingEngine{
42-
inputChan: make(chan ChartRenderParams),
43-
resultChan: make(chan RenderResult),
44-
errorChan: errorChan,
45-
outputDir: outputDir,
46-
context: context,
47-
executor: &RealCommandExecutor{},
48-
name: "ChartRenderer",
43+
inputChan: make(chan ChartRenderParams),
44+
resultChan: make(chan RenderResult),
45+
errorChan: errorChan,
46+
outputDir: outputDir,
47+
context: context,
48+
executor: &RealCommandExecutor{},
49+
name: "ChartRenderer",
50+
apiVersions: apiVersions,
51+
}
52+
53+
// Construct absolute path to schemas directory
54+
schemasDir, err := filepath.Abs("schemas")
55+
if err != nil {
56+
// If we can't get the absolute path, use relative path as fallback
57+
schemasDir = "schemas"
4958
}
5059

5160
mve := ManifestValidationEngine{
52-
inputChan: cre.resultChan,
53-
resultChan: make(chan ManifestValidationResult),
54-
errorChan: errorChan,
55-
context: context,
56-
executor: &RealCommandExecutor{},
57-
name: "ManifestValidator",
61+
inputChan: cre.resultChan,
62+
resultChan: make(chan ManifestValidationResult),
63+
errorChan: errorChan,
64+
context: context,
65+
executor: &RealCommandExecutor{},
66+
name: "ManifestValidator",
67+
schemasDir: schemasDir,
5868
workerWaitGroup: sync.WaitGroup{},
5969
}
6070

6171
iee := ImageExtractionEngine{
62-
inputChan: mve.resultChan,
63-
outputChan: make(chan ImageExtractionResult),
64-
errorChan: errorChan,
65-
context: context,
66-
name: "ImageExtractor",
72+
inputChan: mve.resultChan,
73+
outputChan: make(chan ImageExtractionResult),
74+
errorChan: errorChan,
75+
context: context,
76+
name: "ImageExtractor",
6777
workerWaitGroup: sync.WaitGroup{},
6878
}
6979

7080
dve := DockerImageValidationEngine{
71-
inputChan: iee.outputChan,
72-
outputChan: make(chan DockerImageValidationResult),
73-
context: context,
74-
executor: &RealCommandExecutor{},
75-
name: "DockerValidator",
76-
cache: map[string]DockerImageValidationResult{},
77-
pending: map[string]*sync.WaitGroup{},
78-
cacheLock: sync.RWMutex{},
81+
inputChan: iee.outputChan,
82+
outputChan: make(chan DockerImageValidationResult),
83+
context: context,
84+
executor: &RealCommandExecutor{},
85+
name: "DockerValidator",
86+
cache: map[string]DockerImageValidationResult{},
87+
pending: map[string]*sync.WaitGroup{},
88+
cacheLock: sync.RWMutex{},
7989
workerWaitGroup: sync.WaitGroup{},
8090
}
81-
91+
8292
return &AppCheckerEngine{
8393
inputChan: make(chan AppCheckInstruction),
8494
resultChan: make(chan AppCheckResult),
8595
errorChan: make(chan ErrorResult),
8696

87-
context: context,
88-
executor: &RealCommandExecutor{},
97+
context: context,
98+
executor: &RealCommandExecutor{},
8999

90-
ChartRenderingEngine: &cre,
100+
ChartRenderingEngine: &cre,
91101
ManifestValidationEngine: &mve,
92-
ImageExtractionEngine: &iee,
102+
ImageExtractionEngine: &iee,
93103
DockerValidationEngine: &dve,
94104

95105
name: "AppChecker",
@@ -98,7 +108,7 @@ func NewAppCheckerEngine(context context.Context, outputDir string) *AppCheckerE
98108

99109
func (engine *AppCheckerEngine) allDoneWorker() {
100110
engine.workerWaitGroup.Wait()
101-
logEngineDebug(engine.name,-1,"all workers done, closing output channel")
111+
logEngineDebug(engine.name, -1, "all workers done, closing output channel")
102112
close(engine.resultChan)
103113
}
104114

@@ -113,7 +123,7 @@ func (engine *AppCheckerEngine) Start(workerCount int) {
113123
// Pour the input instructions into the chart renderer
114124
engine.workerWaitGroup.Add(1)
115125
go engine.pumpAppCheckInstructionsToChartRenderer()
116-
engine.workerWaitGroup.Add(1)
126+
engine.workerWaitGroup.Add(1)
117127
go engine.pumpOutputsToAppCheckResults()
118128

119129
go engine.allDoneWorker()
@@ -147,14 +157,7 @@ func (engine *AppCheckerEngine) pumpOutputsToAppCheckResults() {
147157
func (engine *AppCheckerEngine) pumpAppCheckInstructionsToChartRenderer() {
148158
defer engine.workerWaitGroup.Done()
149159
for instruction := range engine.inputChan {
150-
engine.ChartRenderingEngine.inputChan <- ChartRenderParams{
151-
Env: instruction.Chart.Env,
152-
ChartName: instruction.Chart.ChartName,
153-
RepoURL: instruction.Chart.RepoURL,
154-
ChartVersion: instruction.Chart.ChartVersion,
155-
BaseValuesFile: instruction.Chart.BaseValuesFile,
156-
ValuesOverride: instruction.Chart.ValuesOverride,
157-
}
160+
engine.ChartRenderingEngine.inputChan <- instruction.Chart
158161
}
159162
close(engine.ChartRenderingEngine.inputChan)
160-
}
163+
}

chartvalidator/checker/engine_chart_rendering.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,21 @@ import (
1010
"sync"
1111
)
1212

13-
1413
type ChartRenderingEngine struct {
1514
inputChan chan ChartRenderParams
1615
resultChan chan RenderResult
1716
errorChan chan ErrorResult
1817

19-
outputDir string
20-
context context.Context
21-
executor CommandExecutor
22-
name string
18+
outputDir string
19+
context context.Context
20+
executor CommandExecutor
21+
name string
2322
workerWaitGroup sync.WaitGroup
23+
apiVersions []string
2424
}
2525

2626
type RenderResult struct {
27-
Chart ChartRenderParams
27+
Chart ChartRenderParams
2828
ManifestPath string
2929
}
3030

@@ -36,7 +36,7 @@ func (engine *ChartRenderingEngine) Start(workerCount int) {
3636
}
3737

3838
for i := 0; i < workerCount; i++ {
39-
engine.workerWaitGroup.Add(1)
39+
engine.workerWaitGroup.Add(1)
4040
go func(workerId int) {
4141
engine.worker(workerId)
4242
}(i)
@@ -46,7 +46,7 @@ func (engine *ChartRenderingEngine) Start(workerCount int) {
4646

4747
func (engine *ChartRenderingEngine) allDoneWorker() {
4848
engine.workerWaitGroup.Wait()
49-
logEngineDebug(engine.name,-1,"all workers done, closing output channel")
49+
logEngineDebug(engine.name, -1, "all workers done, closing output channel")
5050
close(engine.resultChan)
5151
}
5252

@@ -74,7 +74,6 @@ func (engine *ChartRenderingEngine) worker(workerId int) {
7474
}
7575
}
7676

77-
7877
func (engine *ChartRenderingEngine) renderSingleChart(chart ChartRenderParams, workerId int) (*RenderResult, error) {
7978

8079
if !engine.executor.FileExists(chart.BaseValuesFile) {
@@ -96,16 +95,24 @@ func (engine *ChartRenderingEngine) renderSingleChart(chart ChartRenderParams, w
9695
"-f", chart.ValuesOverride,
9796
"--version", chart.ChartVersion,
9897
"--include-crds",
98+
"--kube-version", kubernetesVersion,
99+
}
100+
101+
// Add API versions if any
102+
for _, apiVer := range engine.apiVersions {
103+
if apiVer != "" {
104+
args = append(args, "--api-versions", apiVer)
105+
}
99106
}
100107

101108
logEngineDebug(engine.name, workerId, fmt.Sprintf("helm %s", strings.Join(args, " ")))
102109
cmd := engine.executor.CommandContext(engine.context, "helm", args...)
103-
110+
104111
// Set working directory to current directory so relative paths work
105112
if wd, err := os.Getwd(); err == nil {
106113
cmd.SetDir(wd)
107114
}
108-
115+
109116
output, err := cmd.CombinedOutput()
110117
if err != nil {
111118
msg := fmt.Sprintf("helm command failed: %s\nOutput: %s", err.Error(), string(output))
@@ -122,7 +129,7 @@ func (engine *ChartRenderingEngine) renderSingleChart(chart ChartRenderParams, w
122129
logEngineWarning(engine.name, workerId, msg)
123130
return nil, fmt.Errorf("failed to get absolute path for output dir: %w", err)
124131
}
125-
132+
126133
randStr := generateRandomString(6)
127134
filename := fmt.Sprintf("%s_%s.yaml", chart.ChartName, randStr)
128135
outputPath := filepath.Join(absOutputDir, filename)

chartvalidator/checker/engine_chart_rendering_test.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,18 @@ import (
1010
// Helper function to create and start a chart rendering engine
1111
func createEngine(mockExecutor *MockCommandExecutor, includeErrorChan bool) *ChartRenderingEngine {
1212
engine := &ChartRenderingEngine{
13-
inputChan: make(chan ChartRenderParams),
14-
resultChan: make(chan RenderResult),
15-
outputDir: "test_output",
16-
context: context.Background(),
17-
executor: mockExecutor,
13+
inputChan: make(chan ChartRenderParams),
14+
resultChan: make(chan RenderResult),
15+
outputDir: "test_output",
16+
context: context.Background(),
17+
executor: mockExecutor,
18+
apiVersions: []string{"something", "something-else"},
1819
}
19-
20+
2021
if includeErrorChan {
2122
engine.errorChan = make(chan ErrorResult)
2223
}
23-
24+
2425
engine.Start(1)
2526
return engine
2627
}
@@ -43,7 +44,7 @@ func TestRenderBasics(t *testing.T) {
4344
assertChartFieldsMatch(t, testChart, result.Chart)
4445

4546
// Verify the command that was executed
46-
expectedCommand := "helm template test-chart --release-name test-chart --repo https://example.com/charts -f values.yaml -f override.yaml --version 1.0.0 --include-crds"
47+
expectedCommand := "helm template test-chart --release-name test-chart --repo https://example.com/charts -f values.yaml -f override.yaml --version 1.0.0 --include-crds --kube-version 1.33.0 --api-versions something --api-versions something-else"
4748
actualCommand := mockExecutor.GetFullCommand()
4849
assert.Equal(t, expectedCommand, actualCommand)
4950
}
@@ -65,4 +66,4 @@ func TestRenderBaseFileNotExist(t *testing.T) {
6566
assert.Equal(t, errorResult.Chart.ChartName, testChart.ChartName)
6667
assert.NotNil(t, errorResult.Error)
6768
assert.Contains(t, errorResult.Error.Error(), "base values file does not exist")
68-
}
69+
}

0 commit comments

Comments
 (0)