From 2d19f2dedae0acc321500b85b11d46d569fc1092 Mon Sep 17 00:00:00 2001 From: Giulio Calzolari <9049490+giuliocalzolari@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:36:52 +0100 Subject: [PATCH] fix: validate and generate with sub-chart dep (#46) Co-authored-by: Giulio --- .github/workflows/test.yml | 33 +++---------- Makefile | 8 +++- cmd/generate.go | 73 ++++++++++++---------------- cmd/generate_test.go | 17 ++++++- cmd/images_test.go | 2 +- cmd/load_test.go | 4 +- cmd/release_manifest_test.go | 8 ++-- cmd/root.go | 9 +++- cmd/save_test.go | 4 +- cmd/sync_test.go | 4 +- cmd/utils.go | 12 +++++ cmd/validate.go | 56 +++++++++------------- cmd/validate_test.go | 20 ++++++-- go.mod | 1 + go.sum | 2 + main_test.go | 32 ------------- pkg/render_helper/render_helper.go | 76 ++++++++++++++++++++++++++++++ testdata/test-chart1/values.yaml | 2 +- testdata/test-chart2/values.yaml | 2 +- testdata/test-chart3/Chart.yaml | 2 +- testdata/test-chart3/values.yaml | 2 +- 21 files changed, 212 insertions(+), 157 deletions(-) delete mode 100644 main_test.go create mode 100644 pkg/render_helper/render_helper.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 256d8c5..af4cf72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,10 +11,9 @@ on: - "plugin.yaml" permissions: - contents: write - pull-requests: write + contents: read + pull-requests: read actions: read - checks: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -34,22 +33,7 @@ jobs: - name: Set up Helm uses: azure/setup-helm@v4 with: - version: v3.12.1 - - - name: helm build dependency - run: | - # This step is needed to make HELM_DATAROBOT_TEST_SKIP_DEPENDENCY_UPDATE=true work in unit tests - helm dependency update testdata/test-chart3 - helm dependency update testdata/test-chart2 - helm dependency update testdata/test-chart1 - - - name: run unit test - run: | - export GOPROXY=https://proxy.golang.org - export HELM_DATAROBOT_TEST_SKIP_DEPENDENCY_UPDATE=true - go run gotest.tools/gotestsum@v1.12.0 --format short-verbose --junitfile testResult_unit.xml - ls -la . - cat testResult_unit.xml + version: v3.16.3 - name: Docs run: | @@ -60,11 +44,6 @@ jobs: exit 1 fi - - name: Report - uses: dorny/test-reporter@v1 - if: always() - with: - name: unit Tests - path: "testResult_unit.xml" - reporter: java-junit - fail-on-error: true + - name: run unit test + run: | + make test diff --git a/Makefile b/Makefile index e82f120..52d1020 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,13 @@ docs: build @mkdir ./docs @./$(APP_NAME) docs --path ./docs -test: +pre-test: + @echo "Pre tests..." + @helm dependency update testdata/test-chart3 + @helm dependency update testdata/test-chart2 + @helm dependency update testdata/test-chart1 + +test: pre-test @echo "Running tests..." $(GO) test ./... -v diff --git a/cmd/generate.go b/cmd/generate.go index 9e4497f..2e6c1d7 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -2,17 +2,16 @@ package cmd import ( "fmt" - "path" "path/filepath" "regexp" + "sort" "strings" + "github.com/datarobot-oss/helm-datarobot-plugin/pkg/chartutil" "github.com/datarobot-oss/helm-datarobot-plugin/pkg/image_uri" + "github.com/datarobot-oss/helm-datarobot-plugin/pkg/render_helper" "github.com/spf13/cobra" "gopkg.in/yaml.v2" - "helm.sh/helm/v3/pkg/chart/loader" - "helm.sh/helm/v3/pkg/chartutil" - "helm.sh/helm/v3/pkg/engine" ) var generateCmd = &cobra.Command{ @@ -32,55 +31,28 @@ $ helm datarobot generate chart.tgz Args: cobra.MinimumNArgs(1), // Requires at least one argument (file path) RunE: func(cmd *cobra.Command, args []string) error { chartPath := args[0] - chart, err := loader.Load(chartPath) + manifest, err := render_helper.NewRenderItems(chartPath) if err != nil { return fmt.Errorf("Error loading chart %s: %v", chartPath, err) } - options := chartutil.ReleaseOptions{ - Name: "test-release", - Namespace: "test", - } - values := map[string]interface{}{} - caps := chartutil.DefaultCapabilities.Copy() - - cvals, err := chartutil.CoalesceValues(chart, values) - if err != nil { - return fmt.Errorf("Error CoalesceValues chart %s: %v", chartPath, err) - } - - valuesToRender, err := chartutil.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, true) - if err != nil { - return fmt.Errorf("Error ToRenderValuesWithSchemaValidation chart %s: %v", chartPath, err) - } - var e engine.Engine - - renderedContentMap, err := e.Render(chart, valuesToRender) - if err != nil { - return fmt.Errorf("Error Render chart %s: %v", chartPath, err) - } - - var sb strings.Builder - uniqueEntries := make(map[string]struct{}) - for _, template := range chart.Templates { - fileName, _ := template.Name, template.Data - // We only apply the following lint rules to yaml files + uniqueEntries := make(map[string]string) + for fileName, template := range manifest { + // // We only apply the following lint rules to yaml files if filepath.Ext(fileName) != ".yaml" || filepath.Ext(fileName) == ".yml" { continue } - renderedContent := renderedContentMap[path.Join(chart.Name(), fileName)] if generateDebug { - fmt.Printf("---\n# Source: %s\n%s\n", fileName, renderedContent) + fmt.Printf("---\n# Source: %s\n%s\n", fileName, template) } - manifestImages, err := ExtractImagesFromManifest(renderedContent) + manifestImages, err := ExtractImagesFromManifest(template) if err != nil { - return fmt.Errorf("Error ExtractImagesFromManifest chart %s: %v", chartPath, err) + return fmt.Errorf("Error ExtractImagesFromManifest chart %s: %v", fileName, err) } re := regexp.MustCompile("[^a-zA-Z0-9]+") - for _, item := range manifestImages { iUri, err := image_uri.NewDockerUri(item) if err != nil { @@ -90,17 +62,34 @@ $ helm datarobot generate chart.tgz // Check if the item is already in the map if _, exists := uniqueEntries[uniqueKey]; !exists { // If not, add it to the map and the finalSlice - uniqueEntries[uniqueKey] = struct{}{} - sb.WriteString(fmt.Sprintf("- name: %s\n", uniqueKey)) - sb.WriteString(fmt.Sprintf(" image: %s\n", item)) + uniqueEntries[uniqueKey] = item } } } + var keys []string + for key := range uniqueEntries { + keys = append(keys, key) + } + + // Sort the keys + sort.Strings(keys) + + // Create a slice to hold the items + var items []chartutil.DatarobotImageDeclaration + for _, key := range keys { + items = append(items, chartutil.DatarobotImageDeclaration{Name: key, Image: uniqueEntries[key]}) + } + + yamlItems, err := yaml.Marshal(items) + if err != nil { + return fmt.Errorf("Error converting to YAML: %v\n", err) + } + output := map[string]interface{}{ "annotations": map[string]string{ - string(annotation): sb.String(), + string(annotation): string(yamlItems), }, } diff --git a/cmd/generate_test.go b/cmd/generate_test.go index eee026a..3e05d90 100644 --- a/cmd/generate_test.go +++ b/cmd/generate_test.go @@ -8,7 +8,7 @@ import ( func TestCommandGenerate(t *testing.T) { t.Run("test-chart5", func(t *testing.T) { - output, err := executeCommand(rootCmd, "generate", "../testdata/test-chart5") + output, err := executeCommand(rootCmd, "generate ../testdata/test-chart5") assert.NoError(t, err) expectedOutput := `annotations: datarobot.com/images: | @@ -18,4 +18,19 @@ func TestCommandGenerate(t *testing.T) { image: docker.io/alpine/curl:8.9.1` assert.Equal(t, expectedOutput, output) }) + + t.Run("test-chart1", func(t *testing.T) { + output, err := executeCommand(rootCmd, "generate ../testdata/test-chart1") + assert.NoError(t, err) + expectedOutput := `annotations: + datarobot.com/images: | + - name: test-image1_100 + image: docker.io/datarobotdev/test-image1:1.0.0 + - name: test-image2_200 + image: docker.io/datarobotdev/test-image2:2.0.0 + - name: test-image3_300 + image: docker.io/datarobotdev/test-image3:3.0.0` + assert.Equal(t, expectedOutput, output) + }) + } diff --git a/cmd/images_test.go b/cmd/images_test.go index 7a54cd6..c0a8843 100644 --- a/cmd/images_test.go +++ b/cmd/images_test.go @@ -7,7 +7,7 @@ import ( ) func TestCommandImages(t *testing.T) { - output, err := executeCommand(rootCmd, "image", "../testdata/test-chart1") + output, err := executeCommand(rootCmd, "image ../testdata/test-chart1") assert.NoError(t, err) expectedOutput := `- name: test-image1 image: docker.io/datarobotdev/test-image1:1.0.0 diff --git a/cmd/load_test.go b/cmd/load_test.go index 1085a4d..b6a45ab 100644 --- a/cmd/load_test.go +++ b/cmd/load_test.go @@ -11,7 +11,7 @@ func TestCommandLoad(t *testing.T) { t.Run("test-chart", func(t *testing.T) { filePath := "image-load.tgz" - output, err := executeCommand(rootCmd, "save", "../testdata/test-chart4", "-a", "custom/loadimages", "--output", filePath) + output, err := executeCommand(rootCmd, "save ../testdata/test-chart4 -a custom/loadimages --output "+filePath) assert.NoError(t, err) expectedSaveOutput := `Pulling image: docker.io/alpine/curl:8.9.1 Pulling image: docker.io/busybox:1.36.1 @@ -23,7 +23,7 @@ Tarball created successfully: image-load.tgz` t.Errorf("File was not created: %s", filePath) } - output, err = executeCommand(rootCmd, "load", filePath, "-r", "ttl.sh") + output, err = executeCommand(rootCmd, "load "+filePath+" -r ttl.sh") assert.NoError(t, err) expectedLoadOutput := `Successfully pushed image ttl.sh/curl:8.9.1 Successfully pushed image ttl.sh/busybox:1.36.1` diff --git a/cmd/release_manifest_test.go b/cmd/release_manifest_test.go index afb98d1..0f6062b 100644 --- a/cmd/release_manifest_test.go +++ b/cmd/release_manifest_test.go @@ -8,7 +8,7 @@ import ( func TestCommandReleaseManifest(t *testing.T) { t.Run("Test test-chart1", func(t *testing.T) { - output, err := executeCommand(rootCmd, "release-manifest", "../testdata/test-chart1", "-a", "datarobot.com/images") + output, err := executeCommand(rootCmd, "release-manifest ../testdata/test-chart1 -a \"datarobot.com/images\"") assert.NoError(t, err) // Expected output to compare expectedOutput := `images: @@ -29,7 +29,7 @@ func TestCommandReleaseManifest(t *testing.T) { }) t.Run("Test test-chart4", func(t *testing.T) { - output, err := executeCommand(rootCmd, "release-manifest", "../testdata/test-chart4", "-a", "custom/images") + output, err := executeCommand(rootCmd, "release-manifest ../testdata/test-chart4 -a \"custom/images\"") assert.NoError(t, err) expectedOutput := `images: test-image4.tar.zst: @@ -40,7 +40,7 @@ func TestCommandReleaseManifest(t *testing.T) { }) t.Run("Test test-chart4-datarobot", func(t *testing.T) { - output, err := executeCommand(rootCmd, "release-manifest", "../testdata/test-chart4", "-a", "datarobot.com/images") + output, err := executeCommand(rootCmd, "release-manifest ../testdata/test-chart4 -a \"datarobot.com/images\"") assert.NoError(t, err) expectedOutput := `images: test-image3.tar.zst: @@ -60,7 +60,7 @@ func TestCommandReleaseManifest(t *testing.T) { assert.Equal(t, expectedOutput, output) }) t.Run("Test test-chart4-duplicated", func(t *testing.T) { - output, err := executeCommand(rootCmd, "release-manifest", "../testdata/test-chart4", "-a", "custom/images-duplicated") + output, err := executeCommand(rootCmd, "release-manifest ../testdata/test-chart4 -a \"custom/images-duplicated\"") assert.NoError(t, err) // Expected output to compare expectedOutput := `images: diff --git a/cmd/root.go b/cmd/root.go index 530d42b..3c728cc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,6 +7,7 @@ import ( "regexp" "strings" + "github.com/mattn/go-shellwords" "github.com/spf13/cobra" ) @@ -36,8 +37,14 @@ func Execute() { } } -func executeCommand(root *cobra.Command, args ...string) (output string, err error) { +func executeCommand(root *cobra.Command, cmd string) (output string, err error) { buf := new(bytes.Buffer) + + args, err := shellwords.Parse(cmd) + if err != nil { + return "", err + } + root.SetOut(buf) root.SetErr(buf) root.SetArgs(args) diff --git a/cmd/save_test.go b/cmd/save_test.go index 6aba3e3..9d97715 100644 --- a/cmd/save_test.go +++ b/cmd/save_test.go @@ -11,7 +11,7 @@ func TestCommandSave(t *testing.T) { t.Run("test-chart4-dry-run", func(t *testing.T) { - output, err := executeCommand(rootCmd, "save", "../testdata/test-chart4", "-a", "custom/images-duplicated", "--dry-run", "--output", "test.tgz", "-a", "datarobot.com/images") + output, err := executeCommand(rootCmd, "save ../testdata/test-chart4 -a custom/images-duplicated --dry-run --output test.tgz -a \"datarobot.com/images\"") assert.NoError(t, err) expectedOutput := `[Dry-Run] Pulling image: docker.io/alpine/curl:8.9.1 [Dry-Run] ReTagging image: docker.io/alpine/curl:8.9.1 > docker.io/alpine/curl:stable @@ -28,7 +28,7 @@ func TestCommandSave(t *testing.T) { t.Run("test-chart4", func(t *testing.T) { filePath := "image-test.tgz" - output, err := executeCommand(rootCmd, "save", "../testdata/test-chart4", "--dry-run=false", "--output", filePath) + output, err := executeCommand(rootCmd, "save ../testdata/test-chart4 --dry-run=false --output "+filePath) assert.NoError(t, err) // Expected output to compare diff --git a/cmd/sync_test.go b/cmd/sync_test.go index c23e537..85f9f45 100644 --- a/cmd/sync_test.go +++ b/cmd/sync_test.go @@ -8,7 +8,7 @@ import ( func TestCommandSync(t *testing.T) { t.Run("test-chart4", func(t *testing.T) { - output, err := executeCommand(rootCmd, "sync", "../testdata/test-chart4", "-r", "registry.example.com", "-u", "testuser", "-p", "testpass", "--dry-run") + output, err := executeCommand(rootCmd, "sync ../testdata/test-chart4 -r registry.example.com -u testuser -p testpass --dry-run") assert.NoError(t, err) expectedOutput := `[Dry-Run] Pulling image: docker.io/alpine/curl:8.9.1 [Dry-Run] Pushing image: registry.example.com/alpine/curl:stable @@ -23,7 +23,7 @@ func TestCommandSync(t *testing.T) { } func TestCommandSyncLive(t *testing.T) { t.Run("test-chart4 ttl.sh", func(t *testing.T) { - output, err := executeCommand(rootCmd, "sync", "../testdata/test-chart4", "-r", "ttl.sh", "--dry-run=false") + output, err := executeCommand(rootCmd, "sync ../testdata/test-chart4 -r ttl.sh --dry-run=false") assert.NoError(t, err) // Expected output to compare expectedOutput := `Pulling image: docker.io/alpine/curl:8.9.1 diff --git a/cmd/utils.go b/cmd/utils.go index 9433f5c..1e35bb9 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "sort" "strings" dr_chartutil "github.com/datarobot-oss/helm-datarobot-plugin/pkg/chartutil" @@ -20,6 +21,15 @@ func isImageAllowed(image string, imageDoc []dr_chartutil.DatarobotImageDeclarat return false } +func SliceHas(slice []string, str string) bool { + for _, item := range slice { + if item == str { + return true + } + } + return false +} + func ExtractImagesFromManifest(manifest string) ([]string, error) { var manifestImages []string @@ -68,5 +78,7 @@ func ExtractImagesFromManifest(manifest string) ([]string, error) { for _, container := range cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers { manifestImages = append(manifestImages, container.Image) } + + sort.Strings(manifestImages) return manifestImages, nil } diff --git a/cmd/validate.go b/cmd/validate.go index 3336578..a597eb2 100644 --- a/cmd/validate.go +++ b/cmd/validate.go @@ -2,14 +2,12 @@ package cmd import ( "fmt" - "path" "path/filepath" + "sort" "strings" + "github.com/datarobot-oss/helm-datarobot-plugin/pkg/render_helper" "github.com/spf13/cobra" - "helm.sh/helm/v3/pkg/chart/loader" - "helm.sh/helm/v3/pkg/chartutil" - "helm.sh/helm/v3/pkg/engine" ) var validateCmd = &cobra.Command{ @@ -29,7 +27,7 @@ $ helm datarobot validate chart.tgz Args: cobra.MinimumNArgs(1), // Requires at least one argument (file path) RunE: func(cmd *cobra.Command, args []string) error { chartPath := args[0] - chart, err := loader.Load(chartPath) + manifest, err := render_helper.NewRenderItems(chartPath) if err != nil { return fmt.Errorf("Error loading chart %s: %v", chartPath, err) } @@ -38,56 +36,46 @@ $ helm datarobot validate chart.tgz if err != nil { return fmt.Errorf("Error ExtractImagesFromCharts: %v", err) } - - options := chartutil.ReleaseOptions{ - Name: "test-release", - Namespace: "test", + if validateDebug { + fmt.Printf("---\n# annotation: %s\n", annotation) + fmt.Printf("---\n# imageDoc: %s\n", imageDoc) } - values := map[string]interface{}{} - caps := chartutil.DefaultCapabilities.Copy() - cvals, err := chartutil.CoalesceValues(chart, values) - if err != nil { - return fmt.Errorf("Error CoalesceValues chart %s: %v", chartPath, err) - } - - valuesToRender, err := chartutil.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, true) - if err != nil { - return fmt.Errorf("Error ToRenderValuesWithSchemaValidation chart %s: %v", chartPath, err) + if len(imageDoc) == 0 { + return fmt.Errorf("imageDoc is empty") } - var e engine.Engine - - renderedContentMap, err := e.Render(chart, valuesToRender) - if err != nil { - return fmt.Errorf("Error Render chart %s: %v", chartPath, err) - } - for _, template := range chart.Templates { - fileName, _ := template.Name, template.Data + var errorImageAllowed []string + for fileName, template := range manifest { // We only apply the following lint rules to yaml files if filepath.Ext(fileName) != ".yaml" || filepath.Ext(fileName) == ".yml" { continue } - renderedContent := renderedContentMap[path.Join(chart.Name(), fileName)] if validateDebug { - fmt.Printf("---\n# Source: %s\n%s\n", fileName, renderedContent) + fmt.Printf("---\n# Source: %s\n%s\n", fileName, template) } - manifestImages, err := ExtractImagesFromManifest(renderedContent) + manifestImages, err := ExtractImagesFromManifest(template) if err != nil { - return fmt.Errorf("Error ExtractImagesFromManifest chart %s: %v", chartPath, err) + return fmt.Errorf("Error ExtractImagesFromManifest chart %s: %v", fileName, err) } // Validate manifestImages against the imageDoc for _, image := range manifestImages { - // fmt.Print(imageDoc) if !isImageAllowed(image, imageDoc) { - return fmt.Errorf("Image not defined in as imageDoc: %s\n", image) + if !SliceHas(errorImageAllowed, image) { + errorImageAllowed = append(errorImageAllowed, image) + } } } } - cmd.Print("Image Doc Valid") + if len(errorImageAllowed) > 0 { + sort.Strings(errorImageAllowed) + return fmt.Errorf("Images not declared as ImageDoc: %v", errorImageAllowed) + } else { + cmd.Print("Image Doc Valid") + } return nil }, diff --git a/cmd/validate_test.go b/cmd/validate_test.go index 2d17107..5df843f 100644 --- a/cmd/validate_test.go +++ b/cmd/validate_test.go @@ -7,17 +7,29 @@ import ( ) func TestCommandValidate(t *testing.T) { + t.Run("test-chart1", func(t *testing.T) { + output, err := executeCommand(rootCmd, "validate ../testdata/test-chart1 -a \"datarobot.com/images\"") + assert.NoError(t, err) + expectedOutput := `Image Doc Valid` + assert.Equal(t, expectedOutput, output) + }) t.Run("test-chart5", func(t *testing.T) { - - output, err := executeCommand(rootCmd, "validate", "../testdata/test-chart5") + output, err := executeCommand(rootCmd, "validate ../testdata/test-chart5") assert.NoError(t, err) expectedOutput := `Image Doc Valid` assert.Equal(t, expectedOutput, output) }) t.Run("test-chart5/error", func(t *testing.T) { - output, err := executeCommand(rootCmd, "validate", "../testdata/test-chart5", "-a", "'custom/images-wrong'") + output, err := executeCommand(rootCmd, "validate ../testdata/test-chart5 -a \"custom/images-wrong\"") assert.Error(t, err) - expectedOutput := `Error: Image not defined in as imageDoc: busybox:1.36.1` + expectedOutput := `Error: Images not declared as ImageDoc: [busybox:1.36.1 docker.io/alpine/curl:8.9.1]` assert.Equal(t, expectedOutput, output) }) + t.Run("test-chart5/empty", func(t *testing.T) { + output, err := executeCommand(rootCmd, "validate ../testdata/test-chart5 -a \"custom/non-existing\"") + assert.Error(t, err) + expectedOutput := `Error: imageDoc is empty` + assert.Equal(t, expectedOutput, output) + }) + } diff --git a/go.mod b/go.mod index ea10f64..12ba441 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.23.0 require ( github.com/google/go-containerregistry v0.20.2 + github.com/mattn/go-shellwords v1.0.12 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.10.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index eb3766a..c165e20 100644 --- a/go.sum +++ b/go.sum @@ -85,6 +85,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= diff --git a/main_test.go b/main_test.go deleted file mode 100644 index b6fb5bb..0000000 --- a/main_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "fmt" - "os" - "os/exec" - "strings" - "testing" -) - -func TestMain(m *testing.M) { - skipDepUpdate, _ := os.LookupEnv("HELM_DATAROBOT_TEST_SKIP_DEPENDENCY_UPDATE") - if strings.ToLower(skipDepUpdate) != "true" { - charts := []string{ - "testdata/test-chart3", - "testdata/test-chart2", - "testdata/test-chart1", - } - for _, chart := range charts { - fmt.Printf("Running `helm dependency update %s`", chart) - cmd := exec.Command("helm", "dependency", "update", chart) - err := cmd.Run() - if err != nil { - fmt.Printf("Failed to run `helm dependency update %s`", chart) - os.Exit(1) - } - } - } - - // Now run the tests - os.Exit(m.Run()) -} diff --git a/pkg/render_helper/render_helper.go b/pkg/render_helper/render_helper.go new file mode 100644 index 0000000..46a64a0 --- /dev/null +++ b/pkg/render_helper/render_helper.go @@ -0,0 +1,76 @@ +package render_helper + +import ( + "fmt" + "maps" + "sort" + + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chartutil" + "helm.sh/helm/v3/pkg/engine" +) + +func NewRenderItems(chartPath string) (map[string]string, error) { + renderItems := make(map[string]string) + chart, err := loader.Load(chartPath) + if err != nil { + return nil, fmt.Errorf("Error loading chart %s: %v", chartPath, err) + } + + options := chartutil.ReleaseOptions{ + Name: "test-release", + Namespace: "test", + } + values := map[string]interface{}{} + caps := chartutil.DefaultCapabilities.Copy() + + cvals, err := chartutil.CoalesceValues(chart, values) + if err != nil { + return nil, fmt.Errorf("Error CoalesceValues chart %s: %v", chartPath, err) + } + + valuesToRender, err := chartutil.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, true) + if err != nil { + return nil, fmt.Errorf("Error ToRenderValuesWithSchemaValidation chart %s: %v", chartPath, err) + } + var e engine.Engine + + renderedContentMap, err := e.Render(chart, valuesToRender) + if err != nil { + return nil, fmt.Errorf("Error Render chart %s: %v", chartPath, err) + } + maps.Copy(renderItems, renderedContentMap) + + for _, child := range chart.Dependencies() { + // fmt.Print(child) + renderedContentMapChild, err := e.Render(child, valuesToRender) + if err != nil { + return nil, fmt.Errorf("Error Render chart %s: %v", chartPath, err) + } + + maps.Copy(renderItems, renderedContentMapChild) + } + + return SortMap(renderItems), nil +} + +// SortMap takes a map[string]string and returns a new map[string]string +// with the key-value pairs sorted by keys. +func SortMap(m map[string]string) map[string]string { + // Step 1: Extract keys + keys := make([]string, 0, len(m)) + for key := range m { + keys = append(keys, key) + } + + // Step 2: Sort keys + sort.Strings(keys) + + // Step 3: Create a new map to hold the sorted key-value pairs + sortedMap := make(map[string]string) + for _, key := range keys { + sortedMap[key] = m[key] + } + + return sortedMap +} diff --git a/testdata/test-chart1/values.yaml b/testdata/test-chart1/values.yaml index 770da98..b331367 100644 --- a/testdata/test-chart1/values.yaml +++ b/testdata/test-chart1/values.yaml @@ -5,7 +5,7 @@ replicaCount: 1 image: - repository: nginx + repository: docker.io/datarobotdev/test-image1 pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. tag: "" diff --git a/testdata/test-chart2/values.yaml b/testdata/test-chart2/values.yaml index 5757116..73b56b8 100644 --- a/testdata/test-chart2/values.yaml +++ b/testdata/test-chart2/values.yaml @@ -5,7 +5,7 @@ replicaCount: 1 image: - repository: nginx + repository: docker.io/datarobotdev/test-image2 pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. tag: "" diff --git a/testdata/test-chart3/Chart.yaml b/testdata/test-chart3/Chart.yaml index 8c285cb..777296b 100644 --- a/testdata/test-chart3/Chart.yaml +++ b/testdata/test-chart3/Chart.yaml @@ -21,7 +21,7 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.0.0" +appVersion: "3.0.0" annotations: diff --git a/testdata/test-chart3/values.yaml b/testdata/test-chart3/values.yaml index b8fe4e8..23774cb 100644 --- a/testdata/test-chart3/values.yaml +++ b/testdata/test-chart3/values.yaml @@ -5,7 +5,7 @@ replicaCount: 1 image: - repository: nginx + repository: docker.io/datarobotdev/test-image3 pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. tag: ""