diff --git a/cli/cmd/lint_test.go b/cli/cmd/lint_test.go index 13eaf2017..964e2ce93 100644 --- a/cli/cmd/lint_test.go +++ b/cli/cmd/lint_test.go @@ -16,90 +16,76 @@ import ( "github.com/spf13/cobra" ) -func TestLint_VerboseFlag(t *testing.T) { - // Create a temporary directory with a test chart - tmpDir := t.TempDir() - chartDir := filepath.Join(tmpDir, "test-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { - t.Fatal(err) +// getTestDataPath returns the absolute path to a test data file or directory. +// This helper is used to locate fixture files in the testdata/ directory. +func getTestDataPath(t *testing.T, relPath string) string { + t.Helper() + cwd, err := os.Getwd() + if err != nil { + t.Fatalf("failed to get working directory: %v", err) } - // Create Chart.yaml - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: test-chart -version: 1.0.0 -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { - t.Fatal(err) - } + // Navigate from cli/cmd/ to project root + projectRoot := filepath.Join(cwd, "..", "..") + absPath := filepath.Join(projectRoot, relPath) - // Create templates directory with a deployment - templatesDir := filepath.Join(chartDir, "templates") - if err := os.MkdirAll(templatesDir, 0755); err != nil { - t.Fatal(err) + // Verify the path exists + if _, err := os.Stat(absPath); err != nil { + t.Fatalf("test data path does not exist: %s (error: %v)", absPath, err) } - deploymentYaml := filepath.Join(templatesDir, "deployment.yaml") - deploymentContent := `apiVersion: apps/v1 -kind: Deployment -metadata: - name: test -spec: - template: - spec: - containers: - - name: nginx - image: nginx:1.21 -` - if err := os.WriteFile(deploymentYaml, []byte(deploymentContent), 0644); err != nil { - t.Fatal(err) - } + return absPath +} - // Create manifests directory with HelmChart - manifestsDir := filepath.Join(tmpDir, "manifests") - if err := os.MkdirAll(manifestsDir, 0755); err != nil { - t.Fatal(err) - } +// copyFixtureToTemp copies a fixture directory to a temporary directory for test isolation. +// This ensures tests can modify files without affecting the original fixtures. +func copyFixtureToTemp(t *testing.T, fixturePath string) string { + t.Helper() + tmpDir := t.TempDir() + destPath := filepath.Join(tmpDir, filepath.Base(fixturePath)) - helmChartManifest := filepath.Join(manifestsDir, "helmchart.yaml") - helmChartContent := `apiVersion: kots.io/v1beta2 -kind: HelmChart -metadata: - name: test-chart -spec: - chart: - name: test-chart - chartVersion: 1.0.0 - builder: {} -` - if err := os.WriteFile(helmChartManifest, []byte(helmChartContent), 0644); err != nil { - t.Fatal(err) - } + // Copy the fixture directory recursively + if err := filepath.Walk(fixturePath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } - // Create .replicated config - configPath := filepath.Join(tmpDir, ".replicated") - configContent := `charts: - - path: ` + chartDir + ` -manifests: - - ` + manifestsDir + `/*.yaml -repl-lint: - linters: - helm: {} - preflight: - disabled: true -` - if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { - t.Fatal(err) + // Calculate relative path from fixture root + relPath, err := filepath.Rel(fixturePath, path) + if err != nil { + return err + } + + destFilePath := filepath.Join(destPath, relPath) + + if info.IsDir() { + return os.MkdirAll(destFilePath, info.Mode()) + } + + // Copy file + data, err := os.ReadFile(path) + if err != nil { + return err + } + return os.WriteFile(destFilePath, data, info.Mode()) + }); err != nil { + t.Fatalf("failed to copy fixture from %s to %s: %v", fixturePath, destPath, err) } - // Change to temp directory for test + return destPath +} + +func TestLint_VerboseFlag(t *testing.T) { + fixturePath := getTestDataPath(t, "testdata/lint/simple-chart") + testDir := copyFixtureToTemp(t, fixturePath) + + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -190,7 +176,7 @@ repl-lint: func TestExtractAndDisplayImagesFromConfig_NoCharts(t *testing.T) { tmpDir := t.TempDir() - // Create .replicated config with no charts + // Create .replicated config with no charts section configPath := filepath.Join(tmpDir, ".replicated") configContent := `repl-lint: linters: @@ -200,7 +186,7 @@ func TestExtractAndDisplayImagesFromConfig_NoCharts(t *testing.T) { t.Fatal(err) } - // Change to temp directory + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) @@ -273,119 +259,16 @@ repl-lint: } func TestExtractAndDisplayImagesFromConfig_MultipleCharts(t *testing.T) { - // Create a temporary directory with multiple test charts - tmpDir := t.TempDir() - - // Create first chart - chart1Dir := filepath.Join(tmpDir, "chart1") - if err := os.MkdirAll(filepath.Join(chart1Dir, "templates"), 0755); err != nil { - t.Fatal(err) - } - chart1Yaml := filepath.Join(chart1Dir, "Chart.yaml") - if err := os.WriteFile(chart1Yaml, []byte("apiVersion: v2\nname: chart1\nversion: 1.0.0\n"), 0644); err != nil { - t.Fatal(err) - } - dep1Yaml := filepath.Join(chart1Dir, "templates", "deployment.yaml") - dep1Content := `apiVersion: apps/v1 -kind: Deployment -metadata: - name: test1 -spec: - template: - spec: - containers: - - name: nginx - image: nginx:1.21 -` - if err := os.WriteFile(dep1Yaml, []byte(dep1Content), 0644); err != nil { - t.Fatal(err) - } - - // Create second chart with different image - chart2Dir := filepath.Join(tmpDir, "chart2") - if err := os.MkdirAll(filepath.Join(chart2Dir, "templates"), 0755); err != nil { - t.Fatal(err) - } - chart2Yaml := filepath.Join(chart2Dir, "Chart.yaml") - if err := os.WriteFile(chart2Yaml, []byte("apiVersion: v2\nname: chart2\nversion: 1.0.0\n"), 0644); err != nil { - t.Fatal(err) - } - dep2Yaml := filepath.Join(chart2Dir, "templates", "deployment.yaml") - dep2Content := `apiVersion: apps/v1 -kind: Deployment -metadata: - name: test2 -spec: - template: - spec: - containers: - - name: redis - image: redis:7.0 -` - if err := os.WriteFile(dep2Yaml, []byte(dep2Content), 0644); err != nil { - t.Fatal(err) - } - - // Create manifests directory with HelmChart manifests for both charts - manifestsDir := filepath.Join(tmpDir, "manifests") - if err := os.MkdirAll(manifestsDir, 0755); err != nil { - t.Fatal(err) - } - - helmChart1 := filepath.Join(manifestsDir, "chart1-helmchart.yaml") - helmChart1Content := `apiVersion: kots.io/v1beta2 -kind: HelmChart -metadata: - name: chart1 -spec: - chart: - name: chart1 - chartVersion: 1.0.0 - builder: {} -` - if err := os.WriteFile(helmChart1, []byte(helmChart1Content), 0644); err != nil { - t.Fatal(err) - } - - helmChart2 := filepath.Join(manifestsDir, "chart2-helmchart.yaml") - helmChart2Content := `apiVersion: kots.io/v1beta2 -kind: HelmChart -metadata: - name: chart2 -spec: - chart: - name: chart2 - chartVersion: 1.0.0 - builder: {} -` - if err := os.WriteFile(helmChart2, []byte(helmChart2Content), 0644); err != nil { - t.Fatal(err) - } - - // Create .replicated config with both charts - configPath := filepath.Join(tmpDir, ".replicated") - configContent := `charts: - - path: ` + chart1Dir + ` - - path: ` + chart2Dir + ` -manifests: - - ` + manifestsDir + `/*.yaml -repl-lint: - linters: - helm: {} - preflight: - disabled: true -` - if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { - t.Fatal(err) - } + fixturePath := getTestDataPath(t, "testdata/lint/multi-chart-project") + testDir := copyFixtureToTemp(t, fixturePath) - // Change to temp directory + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -451,27 +334,13 @@ repl-lint: // TestJSONOutputContainsAllToolVersions tests that JSON output includes all tool versions func TestJSONOutputContainsAllToolVersions(t *testing.T) { - // Create a temporary directory with a test chart - tmpDir := t.TempDir() - chartDir := filepath.Join(tmpDir, "test-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { - t.Fatal(err) - } - - // Create minimal Chart.yaml - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: test-chart -version: 1.0.0 -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { - t.Fatal(err) - } + fixturePath := getTestDataPath(t, "testdata/lint/simple-chart") + testDir := copyFixtureToTemp(t, fixturePath) - // Create .replicated config with specific tool versions - configPath := filepath.Join(tmpDir, ".replicated") + // Update .replicated config to add tool versions and all linters + configPath := filepath.Join(testDir, ".replicated") configContent := `charts: - - path: ` + chartDir + ` + - path: chart repl-lint: version: 1 linters: @@ -487,13 +356,13 @@ repl-lint: t.Fatal(err) } - // Change to temp directory for test + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -673,27 +542,13 @@ repl-lint: // TestConfigMissingToolVersions tests that missing tool versions default to "latest" func TestConfigMissingToolVersions(t *testing.T) { - // Create a temporary directory with a test chart - tmpDir := t.TempDir() - chartDir := filepath.Join(tmpDir, "test-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { - t.Fatal(err) - } - - // Create minimal Chart.yaml - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: test-chart -version: 1.0.0 -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { - t.Fatal(err) - } + fixturePath := getTestDataPath(t, "testdata/lint/simple-chart") + testDir := copyFixtureToTemp(t, fixturePath) - // Create .replicated config WITHOUT tool versions - configPath := filepath.Join(tmpDir, ".replicated") + // Update .replicated config WITHOUT tool versions + configPath := filepath.Join(testDir, ".replicated") configContent := `charts: - - path: ` + chartDir + ` + - path: chart repl-lint: version: 1 linters: @@ -703,13 +558,13 @@ repl-lint: t.Fatal(err) } - // Change to temp directory for test + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -788,53 +643,16 @@ func isValidSemVer(version string) bool { // TestLint_ChartValidationError tests that lint fails when a chart is missing its HelmChart manifest func TestLint_ChartValidationError(t *testing.T) { - tmpDir := t.TempDir() - - // Create a chart - chartDir := filepath.Join(tmpDir, "test-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { - t.Fatal(err) - } - - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: test-app -version: 1.0.0 -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { - t.Fatal(err) - } - - // Create empty manifests directory (no HelmChart manifest) - manifestsDir := filepath.Join(tmpDir, "manifests") - if err := os.MkdirAll(manifestsDir, 0755); err != nil { - t.Fatal(err) - } - - // Create config with chart but no matching HelmChart manifest - configPath := filepath.Join(tmpDir, ".replicated") - configContent := `charts: - - path: ` + chartDir + ` -manifests: - - ` + manifestsDir + `/*.yaml -repl-lint: - linters: - helm: - disabled: true - preflight: - disabled: true -` - if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { - t.Fatal(err) - } + fixturePath := getTestDataPath(t, "testdata/lint/chart-missing-helmchart") + testDir := copyFixtureToTemp(t, fixturePath) - // Change to temp directory + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -878,103 +696,34 @@ repl-lint: // TestLint_ChartValidationWarning tests that lint succeeds but shows warning for orphaned HelmChart manifest func TestLint_ChartValidationWarning(t *testing.T) { - tmpDir := t.TempDir() + fixturePath := getTestDataPath(t, "testdata/lint/orphaned-helmchart") + testDir := copyFixtureToTemp(t, fixturePath) - // Create a chart - chartDir := filepath.Join(tmpDir, "test-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { + // Change to test directory + oldWd, err := os.Getwd() + if err != nil { t.Fatal(err) } - - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: current-app -version: 1.0.0 -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { + defer os.Chdir(oldWd) + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } - // Create manifests directory with matching HelmChart + orphaned one - manifestsDir := filepath.Join(tmpDir, "manifests") - if err := os.MkdirAll(manifestsDir, 0755); err != nil { - t.Fatal(err) - } + // Create output buffer + buf := new(bytes.Buffer) + w := tabwriter.NewWriter(buf, 0, 8, 4, ' ', 0) - // Matching HelmChart manifest - currentHelmChart := filepath.Join(manifestsDir, "current-app.yaml") - currentContent := `apiVersion: kots.io/v1beta2 -kind: HelmChart -metadata: - name: current-app -spec: - chart: - name: current-app - chartVersion: 1.0.0 - builder: {} -` - if err := os.WriteFile(currentHelmChart, []byte(currentContent), 0644); err != nil { - t.Fatal(err) + r := &runners{ + w: w, + outputFormat: "table", + args: runnerArgs{ + lintVerbose: false, + }, } - // Orphaned HelmChart manifest - oldHelmChart := filepath.Join(manifestsDir, "old-app.yaml") - oldContent := `apiVersion: kots.io/v1beta2 -kind: HelmChart -metadata: - name: old-app -spec: - chart: - name: old-app - chartVersion: 1.0.0 - builder: {} -` - if err := os.WriteFile(oldHelmChart, []byte(oldContent), 0644); err != nil { - t.Fatal(err) - } - - // Create config - configPath := filepath.Join(tmpDir, ".replicated") - configContent := `charts: - - path: ` + chartDir + ` -manifests: - - ` + manifestsDir + `/*.yaml -repl-lint: - linters: - helm: - disabled: true - preflight: - disabled: true -` - if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { - t.Fatal(err) - } - - // Change to temp directory - oldWd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { - t.Fatal(err) - } - - // Create output buffer - buf := new(bytes.Buffer) - w := tabwriter.NewWriter(buf, 0, 8, 4, ' ', 0) - - r := &runners{ - w: w, - outputFormat: "table", - args: runnerArgs{ - lintVerbose: false, - }, - } - - // Create a mock command with context - cmd := &cobra.Command{} - cmd.SetContext(context.Background()) + // Create a mock command with context + cmd := &cobra.Command{} + cmd.SetContext(context.Background()) // Run the lint command - should succeed err = r.runLint(cmd, []string{}) @@ -998,27 +747,13 @@ repl-lint: // TestLint_NoManifestsConfig tests error when charts configured but manifests section missing func TestLint_NoManifestsConfig(t *testing.T) { - tmpDir := t.TempDir() - - // Create a chart - chartDir := filepath.Join(tmpDir, "test-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { - t.Fatal(err) - } - - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: test-app -version: 1.0.0 -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { - t.Fatal(err) - } + fixturePath := getTestDataPath(t, "testdata/lint/chart-missing-helmchart") + testDir := copyFixtureToTemp(t, fixturePath) - // Create config WITHOUT manifests section - configPath := filepath.Join(tmpDir, ".replicated") + // Update config to remove manifests section + configPath := filepath.Join(testDir, ".replicated") configContent := `charts: - - path: ` + chartDir + ` + - path: chart repl-lint: linters: helm: @@ -1028,13 +763,13 @@ repl-lint: t.Fatal(err) } - // Change to temp directory + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -1079,96 +814,17 @@ repl-lint: // TestLint_AutodiscoveryWithMixedManifests tests that autodiscovery works // when manifests directory contains BOTH HelmChart manifests and Support Bundle specs, // and also includes Preflight specs. -// This is the bug we're fixing - autodiscovery currently stores explicit paths which -// causes strict validation to fail when processing mixed resource types. func TestLint_AutodiscoveryWithMixedManifests(t *testing.T) { - tmpDir := t.TempDir() - - // Create a chart - chartDir := filepath.Join(tmpDir, "charts", "my-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { - t.Fatal(err) - } - - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: my-app -version: 1.0.0 -description: Test chart for autodiscovery -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { - t.Fatal(err) - } - - valuesYaml := filepath.Join(chartDir, "values.yaml") - if err := os.WriteFile(valuesYaml, []byte("replicaCount: 1\n"), 0644); err != nil { - t.Fatal(err) - } - - // Create manifests directory with HelmChart, Support Bundle, and Preflight - manifestsDir := filepath.Join(tmpDir, "manifests") - if err := os.MkdirAll(manifestsDir, 0755); err != nil { - t.Fatal(err) - } - - // HelmChart manifest - helmChartFile := filepath.Join(manifestsDir, "helmchart.yaml") - helmChartContent := `apiVersion: kots.io/v1beta2 -kind: HelmChart -metadata: - name: my-app-chart -spec: - chart: - name: my-app - chartVersion: 1.0.0 - builder: {} -` - if err := os.WriteFile(helmChartFile, []byte(helmChartContent), 0644); err != nil { - t.Fatal(err) - } - - // Support Bundle spec - sbFile := filepath.Join(manifestsDir, "support-bundle.yaml") - sbContent := `apiVersion: troubleshoot.sh/v1beta2 -kind: SupportBundle -metadata: - name: my-support-bundle -spec: - collectors: - - logs: - selector: - - app=my-app -` - if err := os.WriteFile(sbFile, []byte(sbContent), 0644); err != nil { - t.Fatal(err) - } - - // Preflight spec - preflightFile := filepath.Join(manifestsDir, "preflight.yaml") - preflightContent := `apiVersion: troubleshoot.sh/v1beta2 -kind: Preflight -metadata: - name: my-preflight -spec: - analyzers: - - clusterVersion: - outcomes: - - pass: - message: Kubernetes version is valid -` - if err := os.WriteFile(preflightFile, []byte(preflightContent), 0644); err != nil { - t.Fatal(err) - } - - // NO .replicated config - trigger autodiscovery + fixturePath := getTestDataPath(t, "testdata/lint/mixed-manifests-autodiscovery") + testDir := copyFixtureToTemp(t, fixturePath) - // Change to temp directory + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -1469,30 +1125,11 @@ spec: // TestLint_AutodiscoveryHiddenDirectories tests that hidden directories (.git, .github) are ignored func TestLint_AutodiscoveryHiddenDirectories(t *testing.T) { - tmpDir := t.TempDir() - - // Create a real chart - chartDir := filepath.Join(tmpDir, "charts", "my-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { - t.Fatal(err) - } - - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: real-app -version: 1.0.0 -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { - t.Fatal(err) - } - - valuesYaml := filepath.Join(chartDir, "values.yaml") - if err := os.WriteFile(valuesYaml, []byte("replicaCount: 1\n"), 0644); err != nil { - t.Fatal(err) - } + fixturePath := getTestDataPath(t, "testdata/lint/hidden-dirs-test") + testDir := copyFixtureToTemp(t, fixturePath) - // Create fake charts in hidden directories (should be ignored) - gitDir := filepath.Join(tmpDir, ".git", "charts") + // Create .git directory with fake chart (can't commit .git dirs to git, so create at runtime) + gitDir := filepath.Join(testDir, ".git", "charts") if err := os.MkdirAll(gitDir, 0755); err != nil { t.Fatal(err) } @@ -1501,52 +1138,13 @@ version: 1.0.0 t.Fatal(err) } - githubDir := filepath.Join(tmpDir, ".github", "manifests") - if err := os.MkdirAll(githubDir, 0755); err != nil { - t.Fatal(err) - } - githubSB := filepath.Join(githubDir, "support-bundle.yaml") - sbContent := `apiVersion: troubleshoot.sh/v1beta2 -kind: SupportBundle -metadata: - name: fake-sb -spec: - collectors: [] -` - if err := os.WriteFile(githubSB, []byte(sbContent), 0644); err != nil { - t.Fatal(err) - } - - // Create real manifests - manifestsDir := filepath.Join(tmpDir, "manifests") - if err := os.MkdirAll(manifestsDir, 0755); err != nil { - t.Fatal(err) - } - - helmChartFile := filepath.Join(manifestsDir, "helmchart.yaml") - helmChartContent := `apiVersion: kots.io/v1beta2 -kind: HelmChart -metadata: - name: real-app-chart -spec: - chart: - name: real-app - chartVersion: 1.0.0 - builder: {} -` - if err := os.WriteFile(helmChartFile, []byte(helmChartContent), 0644); err != nil { - t.Fatal(err) - } - - // NO .replicated config - trigger autodiscovery - - // Change to temp directory + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -1574,13 +1172,15 @@ spec: // Verify only 1 chart discovered (hidden dirs ignored) output := buf.String() + t.Logf("Output:\n%s", output) if !strings.Contains(output, "1 Helm chart(s)") { t.Error("expected to discover exactly 1 chart (hidden dirs should be ignored)") } if !strings.Contains(output, "1 HelmChart manifest(s)") { t.Error("expected to discover exactly 1 HelmChart manifest") } - if strings.Contains(output, "2 ") { + // Check for multiple charts/manifests being discovered (would indicate hidden dirs not ignored) + if strings.Contains(output, "2 Helm chart(s)") || strings.Contains(output, "2 HelmChart manifest(s)") { t.Error("should not discover resources from hidden directories") } @@ -1589,93 +1189,16 @@ spec: // TestLint_AutodiscoveryBothYamlExtensions tests that both .yaml and .yml files are discovered func TestLint_AutodiscoveryBothYamlExtensions(t *testing.T) { - tmpDir := t.TempDir() - - // Create a chart - chartDir := filepath.Join(tmpDir, "charts", "my-chart") - if err := os.MkdirAll(chartDir, 0755); err != nil { - t.Fatal(err) - } - - // Helm requires Chart.yaml specifically (not .yml) - chartYaml := filepath.Join(chartDir, "Chart.yaml") - chartContent := `apiVersion: v2 -name: my-app -version: 1.0.0 -` - if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { - t.Fatal(err) - } - - valuesYaml := filepath.Join(chartDir, "values.yaml") - if err := os.WriteFile(valuesYaml, []byte("replicaCount: 1\n"), 0644); err != nil { - t.Fatal(err) - } + fixturePath := getTestDataPath(t, "testdata/lint/mixed-manifests-yaml-yml") + testDir := copyFixtureToTemp(t, fixturePath) - // Create manifests with mixed extensions - manifestsDir := filepath.Join(tmpDir, "manifests") - if err := os.MkdirAll(manifestsDir, 0755); err != nil { - t.Fatal(err) - } - - // HelmChart with .yaml - helmChartFile := filepath.Join(manifestsDir, "helmchart.yaml") - helmChartContent := `apiVersion: kots.io/v1beta2 -kind: HelmChart -metadata: - name: my-app-chart -spec: - chart: - name: my-app - chartVersion: 1.0.0 - builder: {} -` - if err := os.WriteFile(helmChartFile, []byte(helmChartContent), 0644); err != nil { - t.Fatal(err) - } - - // Support Bundle with .yml - sbFile := filepath.Join(manifestsDir, "support-bundle.yml") - sbContent := `apiVersion: troubleshoot.sh/v1beta2 -kind: SupportBundle -metadata: - name: my-support-bundle -spec: - collectors: - - logs: - selector: - - app=my-app -` - if err := os.WriteFile(sbFile, []byte(sbContent), 0644); err != nil { - t.Fatal(err) - } - - // Preflight with .yaml - preflightFile := filepath.Join(manifestsDir, "preflight.yaml") - preflightContent := `apiVersion: troubleshoot.sh/v1beta2 -kind: Preflight -metadata: - name: my-preflight -spec: - analyzers: - - clusterVersion: - outcomes: - - pass: - message: Valid -` - if err := os.WriteFile(preflightFile, []byte(preflightContent), 0644); err != nil { - t.Fatal(err) - } - - // NO .replicated config - trigger autodiscovery - - // Change to temp directory + // Change to test directory oldWd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(oldWd) - if err := os.Chdir(tmpDir); err != nil { + if err := os.Chdir(testDir); err != nil { t.Fatal(err) } @@ -1718,3 +1241,638 @@ spec: t.Log("SUCCESS: Autodiscovery correctly handled both .yaml and .yml extensions for manifests") } + +// Tests for config discovery vs autodiscovery behavior + +// TestLint_SubdirectoryWithParentConfig tests that running lint from a subdirectory +// uses the parent's .replicated config and does NOT trigger autodiscovery. +func TestLint_SubdirectoryWithParentConfig(t *testing.T) { + tmpDir := t.TempDir() + + // Create chart1 in parent directory + chart1Dir := filepath.Join(tmpDir, "chart1") + if err := os.MkdirAll(chart1Dir, 0755); err != nil { + t.Fatal(err) + } + + chart1Yaml := filepath.Join(chart1Dir, "Chart.yaml") + chart1Content := `apiVersion: v2 +name: app1 +version: 1.0.0 +description: Chart in parent config +` + if err := os.WriteFile(chart1Yaml, []byte(chart1Content), 0644); err != nil { + t.Fatal(err) + } + + valuesYaml := filepath.Join(chart1Dir, "values.yaml") + if err := os.WriteFile(valuesYaml, []byte("replicaCount: 1\n"), 0644); err != nil { + t.Fatal(err) + } + + // Create HelmChart manifest for chart1 + manifestsDir := filepath.Join(tmpDir, "manifests") + if err := os.MkdirAll(manifestsDir, 0755); err != nil { + t.Fatal(err) + } + + helmChartFile := filepath.Join(manifestsDir, "helmchart1.yaml") + helmChartContent := `apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: app1-chart +spec: + chart: + name: app1 + chartVersion: 1.0.0 + builder: {} +` + if err := os.WriteFile(helmChartFile, []byte(helmChartContent), 0644); err != nil { + t.Fatal(err) + } + + // Create .replicated config in parent with chart1 + configPath := filepath.Join(tmpDir, ".replicated") + configContent := `charts: + - path: ` + chart1Dir + ` +manifests: + - ` + manifestsDir + `/** +repl-lint: + linters: + helm: {} +` + if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { + t.Fatal(err) + } + + // Create subdirectory with chart2 (NOT in parent config) + subDir := filepath.Join(tmpDir, "subdir") + if err := os.MkdirAll(subDir, 0755); err != nil { + t.Fatal(err) + } + + chart2Dir := filepath.Join(subDir, "chart2") + if err := os.MkdirAll(chart2Dir, 0755); err != nil { + t.Fatal(err) + } + + chart2Yaml := filepath.Join(chart2Dir, "Chart.yaml") + chart2Content := `apiVersion: v2 +name: app2 +version: 1.0.0 +description: Chart NOT in parent config +` + if err := os.WriteFile(chart2Yaml, []byte(chart2Content), 0644); err != nil { + t.Fatal(err) + } + + chart2Values := filepath.Join(chart2Dir, "values.yaml") + if err := os.WriteFile(chart2Values, []byte("replicaCount: 1\n"), 0644); err != nil { + t.Fatal(err) + } + + // Change to subdirectory + oldWd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(oldWd) + if err := os.Chdir(subDir); err != nil { + t.Fatal(err) + } + + // Create output buffer + buf := new(bytes.Buffer) + w := tabwriter.NewWriter(buf, 0, 8, 4, ' ', 0) + + r := &runners{ + w: w, + outputFormat: "table", + args: runnerArgs{ + lintVerbose: false, + }, + } + + // Create a mock command with context + cmd := &cobra.Command{} + cmd.SetContext(context.Background()) + + // Run the lint command + err = r.runLint(cmd, []string{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Verify that autodiscovery did NOT trigger + output := buf.String() + if strings.Contains(output, "Auto-discovering lintable resources") { + t.Error("autodiscovery should NOT trigger when parent config exists with resources") + } + + // Verify chart1 from parent config was linted + if !strings.Contains(output, chart1Dir) { + t.Errorf("expected chart1 from parent config to be linted, got output:\n%s", output) + } + + // Verify chart2 was NOT linted (not in parent config) + if strings.Contains(output, "app2") { + t.Error("chart2 should NOT be linted (not in parent config)") + } + + t.Log("SUCCESS: Subdirectory correctly used parent config instead of autodiscovery") +} + +// TestLint_SubdirectoryWithEmptyParentConfig tests that running lint from a subdirectory +// with an empty parent config DOES trigger autodiscovery. +func TestLint_SubdirectoryWithEmptyParentConfig(t *testing.T) { + tmpDir := t.TempDir() + + // Create empty .replicated config in parent (no charts/preflights/manifests) + configPath := filepath.Join(tmpDir, ".replicated") + configContent := `repl-lint: + linters: + helm: {} + preflight: {} +` + if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { + t.Fatal(err) + } + + // Create subdirectory with resources + subDir := filepath.Join(tmpDir, "subdir") + if err := os.MkdirAll(subDir, 0755); err != nil { + t.Fatal(err) + } + + // Create chart in subdirectory + chartDir := filepath.Join(subDir, "my-chart") + if err := os.MkdirAll(chartDir, 0755); err != nil { + t.Fatal(err) + } + + chartYaml := filepath.Join(chartDir, "Chart.yaml") + chartContent := `apiVersion: v2 +name: discovered-app +version: 1.0.0 +description: Chart discovered by autodiscovery +` + if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { + t.Fatal(err) + } + + valuesYaml := filepath.Join(chartDir, "values.yaml") + if err := os.WriteFile(valuesYaml, []byte("replicaCount: 1\n"), 0644); err != nil { + t.Fatal(err) + } + + // Create HelmChart manifest for the discovered chart + helmChartFile := filepath.Join(subDir, "helmchart.yaml") + helmChartContent := `apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: discovered-app-chart +spec: + chart: + name: discovered-app + chartVersion: 1.0.0 + builder: {} +` + if err := os.WriteFile(helmChartFile, []byte(helmChartContent), 0644); err != nil { + t.Fatal(err) + } + + // Create preflight in subdirectory + preflightFile := filepath.Join(subDir, "preflight.yaml") + preflightContent := `apiVersion: troubleshoot.sh/v1beta2 +kind: Preflight +metadata: + name: discovered-preflight +spec: + analyzers: + - clusterVersion: + outcomes: + - pass: + message: Valid +` + if err := os.WriteFile(preflightFile, []byte(preflightContent), 0644); err != nil { + t.Fatal(err) + } + + // Change to subdirectory + oldWd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(oldWd) + if err := os.Chdir(subDir); err != nil { + t.Fatal(err) + } + + // Create output buffer + buf := new(bytes.Buffer) + w := tabwriter.NewWriter(buf, 0, 8, 4, ' ', 0) + + r := &runners{ + w: w, + outputFormat: "table", + args: runnerArgs{ + lintVerbose: false, + }, + } + + // Create a mock command with context + cmd := &cobra.Command{} + cmd.SetContext(context.Background()) + + // Run the lint command + err = r.runLint(cmd, []string{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Verify autodiscovery DID trigger + output := buf.String() + if !strings.Contains(output, "Auto-discovering lintable resources") { + t.Error("autodiscovery SHOULD trigger when parent config is empty") + } + + // Verify resources were discovered + if !strings.Contains(output, "1 Helm chart(s)") { + t.Error("expected to discover 1 chart") + } + if !strings.Contains(output, "1 Preflight spec(s)") { + t.Error("expected to discover 1 preflight") + } + + t.Log("SUCCESS: Empty parent config correctly triggered autodiscovery") +} + +// TestLint_MonorepoMultipleConfigs tests that multiple .replicated configs +// are merged correctly and autodiscovery does NOT trigger. +func TestLint_MonorepoMultipleConfigs(t *testing.T) { + tmpDir := t.TempDir() + + // Create app1 chart at grandparent level + app1Dir := filepath.Join(tmpDir, "app1") + if err := os.MkdirAll(app1Dir, 0755); err != nil { + t.Fatal(err) + } + + app1Chart := filepath.Join(app1Dir, "Chart.yaml") + app1Content := `apiVersion: v2 +name: app1 +version: 1.0.0 +description: Grandparent app +` + if err := os.WriteFile(app1Chart, []byte(app1Content), 0644); err != nil { + t.Fatal(err) + } + + if err := os.WriteFile(filepath.Join(app1Dir, "values.yaml"), []byte("replicaCount: 1\n"), 0644); err != nil { + t.Fatal(err) + } + + // Create HelmChart manifest for app1 + app1HelmChart := filepath.Join(tmpDir, "app1-helmchart.yaml") + app1HelmChartContent := `apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: app1-chart +spec: + chart: + name: app1 + chartVersion: 1.0.0 + builder: {} +` + if err := os.WriteFile(app1HelmChart, []byte(app1HelmChartContent), 0644); err != nil { + t.Fatal(err) + } + + // Create grandparent .replicated with app1 + grandparentConfig := filepath.Join(tmpDir, ".replicated") + grandparentContent := `charts: + - path: ` + app1Dir + ` +manifests: + - ` + tmpDir + `/*.yaml +repl-lint: + linters: + helm: {} +` + if err := os.WriteFile(grandparentConfig, []byte(grandparentContent), 0644); err != nil { + t.Fatal(err) + } + + // Create parent directory + parentDir := filepath.Join(tmpDir, "parent") + if err := os.MkdirAll(parentDir, 0755); err != nil { + t.Fatal(err) + } + + // Create app2 chart at parent level + app2Dir := filepath.Join(parentDir, "app2") + if err := os.MkdirAll(app2Dir, 0755); err != nil { + t.Fatal(err) + } + + app2Chart := filepath.Join(app2Dir, "Chart.yaml") + app2Content := `apiVersion: v2 +name: app2 +version: 1.0.0 +description: Parent app +` + if err := os.WriteFile(app2Chart, []byte(app2Content), 0644); err != nil { + t.Fatal(err) + } + + if err := os.WriteFile(filepath.Join(app2Dir, "values.yaml"), []byte("replicaCount: 1\n"), 0644); err != nil { + t.Fatal(err) + } + + // Create HelmChart manifest for app2 + app2HelmChart := filepath.Join(parentDir, "app2-helmchart.yaml") + app2HelmChartContent := `apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: app2-chart +spec: + chart: + name: app2 + chartVersion: 1.0.0 + builder: {} +` + if err := os.WriteFile(app2HelmChart, []byte(app2HelmChartContent), 0644); err != nil { + t.Fatal(err) + } + + // Create parent .replicated with app2 + parentConfig := filepath.Join(parentDir, ".replicated") + parentContent := `charts: + - path: ` + app2Dir + ` +manifests: + - ` + parentDir + `/*.yaml +` + if err := os.WriteFile(parentConfig, []byte(parentContent), 0644); err != nil { + t.Fatal(err) + } + + // Create child directory + childDir := filepath.Join(parentDir, "child") + if err := os.MkdirAll(childDir, 0755); err != nil { + t.Fatal(err) + } + + // Change to child directory + oldWd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(oldWd) + if err := os.Chdir(childDir); err != nil { + t.Fatal(err) + } + + // Create output buffer + buf := new(bytes.Buffer) + w := tabwriter.NewWriter(buf, 0, 8, 4, ' ', 0) + + r := &runners{ + w: w, + outputFormat: "table", + args: runnerArgs{ + lintVerbose: false, + }, + } + + // Create a mock command with context + cmd := &cobra.Command{} + cmd.SetContext(context.Background()) + + // Run the lint command + err = r.runLint(cmd, []string{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Verify autodiscovery did NOT trigger + output := buf.String() + if strings.Contains(output, "Auto-discovering lintable resources") { + t.Error("autodiscovery should NOT trigger when merged configs have resources") + } + + // Verify BOTH apps were linted (merged from grandparent and parent configs) + if !strings.Contains(output, "app1") { + t.Error("expected app1 from grandparent config to be linted") + } + if !strings.Contains(output, "app2") { + t.Error("expected app2 from parent config to be linted") + } + + t.Log("SUCCESS: Multiple configs correctly merged and both apps linted") +} + +// TestLint_AutodiscoveryOnlyWhenAllArraysEmpty tests that autodiscovery +// only triggers when ALL resource arrays are empty. +func TestLint_AutodiscoveryOnlyWhenAllArraysEmpty(t *testing.T) { + tmpDir := t.TempDir() + + // Create support bundle manifest + manifestsDir := filepath.Join(tmpDir, "manifests") + if err := os.MkdirAll(manifestsDir, 0755); err != nil { + t.Fatal(err) + } + + sbFile := filepath.Join(manifestsDir, "support-bundle.yaml") + sbContent := `apiVersion: troubleshoot.sh/v1beta2 +kind: SupportBundle +metadata: + name: configured-sb +spec: + collectors: + - logs: + selector: + - app=test +` + if err := os.WriteFile(sbFile, []byte(sbContent), 0644); err != nil { + t.Fatal(err) + } + + // Create .replicated config with ONLY manifests (no charts/preflights) + configPath := filepath.Join(tmpDir, ".replicated") + configContent := `manifests: + - ` + manifestsDir + `/** +repl-lint: + linters: + support-bundle: {} +` + if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { + t.Fatal(err) + } + + // Create subdirectory with a chart (NOT in config) + subDir := filepath.Join(tmpDir, "subdir") + if err := os.MkdirAll(subDir, 0755); err != nil { + t.Fatal(err) + } + + chartDir := filepath.Join(subDir, "chart1") + if err := os.MkdirAll(chartDir, 0755); err != nil { + t.Fatal(err) + } + + chartYaml := filepath.Join(chartDir, "Chart.yaml") + chartContent := `apiVersion: v2 +name: undiscovered-app +version: 1.0.0 +description: Should NOT be discovered +` + if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { + t.Fatal(err) + } + + if err := os.WriteFile(filepath.Join(chartDir, "values.yaml"), []byte("replicaCount: 1\n"), 0644); err != nil { + t.Fatal(err) + } + + // Change to subdirectory + oldWd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(oldWd) + if err := os.Chdir(subDir); err != nil { + t.Fatal(err) + } + + // Create output buffer + buf := new(bytes.Buffer) + w := tabwriter.NewWriter(buf, 0, 8, 4, ' ', 0) + + r := &runners{ + w: w, + outputFormat: "table", + args: runnerArgs{ + lintVerbose: false, + }, + } + + // Create a mock command with context + cmd := &cobra.Command{} + cmd.SetContext(context.Background()) + + // Run the lint command + err = r.runLint(cmd, []string{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Verify autodiscovery did NOT trigger + output := buf.String() + if strings.Contains(output, "Auto-discovering lintable resources") { + t.Error("autodiscovery should NOT trigger when manifests array is non-empty") + } + + // Verify chart was NOT discovered + if strings.Contains(output, "undiscovered-app") { + t.Error("chart should NOT be discovered when config has manifests") + } + + // Verify support bundle from config was used + if !strings.Contains(output, sbFile) { + t.Errorf("expected support bundle from parent config to be linted, got output:\n%s", output) + } + + t.Log("SUCCESS: Autodiscovery correctly did NOT trigger with non-empty manifests array") +} + +// TestLint_NoConfigAnywhere tests autodiscovery when no .replicated config +// exists anywhere in the directory tree. +func TestLint_NoConfigAnywhere(t *testing.T) { + tmpDir := t.TempDir() + + // Create deep nested directory structure with NO .replicated anywhere + deepDir := filepath.Join(tmpDir, "level1", "level2", "level3") + if err := os.MkdirAll(deepDir, 0755); err != nil { + t.Fatal(err) + } + + // Create chart in deep directory + chartDir := filepath.Join(deepDir, "my-chart") + if err := os.MkdirAll(chartDir, 0755); err != nil { + t.Fatal(err) + } + + chartYaml := filepath.Join(chartDir, "Chart.yaml") + chartContent := `apiVersion: v2 +name: deep-app +version: 1.0.0 +description: Chart in deep directory +` + if err := os.WriteFile(chartYaml, []byte(chartContent), 0644); err != nil { + t.Fatal(err) + } + + if err := os.WriteFile(filepath.Join(chartDir, "values.yaml"), []byte("replicaCount: 1\n"), 0644); err != nil { + t.Fatal(err) + } + + // Create HelmChart manifest + helmChartFile := filepath.Join(deepDir, "helmchart.yaml") + helmChartContent := `apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: deep-app-chart +spec: + chart: + name: deep-app + chartVersion: 1.0.0 + builder: {} +` + if err := os.WriteFile(helmChartFile, []byte(helmChartContent), 0644); err != nil { + t.Fatal(err) + } + + // Change to deep directory + oldWd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(oldWd) + if err := os.Chdir(deepDir); err != nil { + t.Fatal(err) + } + + // Create output buffer + buf := new(bytes.Buffer) + w := tabwriter.NewWriter(buf, 0, 8, 4, ' ', 0) + + r := &runners{ + w: w, + outputFormat: "table", + args: runnerArgs{ + lintVerbose: false, + }, + } + + // Create a mock command with context + cmd := &cobra.Command{} + cmd.SetContext(context.Background()) + + // Run the lint command + err = r.runLint(cmd, []string{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Verify autodiscovery triggered + output := buf.String() + if !strings.Contains(output, "Auto-discovering lintable resources") { + t.Error("autodiscovery SHOULD trigger when no config exists anywhere") + } + + // Verify chart was discovered + if !strings.Contains(output, "1 Helm chart(s)") { + t.Error("expected to discover 1 chart") + } + + t.Log("SUCCESS: Autodiscovery correctly triggered with no config in directory tree") +} diff --git a/testdata/lint/chart-missing-helmchart/.replicated b/testdata/lint/chart-missing-helmchart/.replicated new file mode 100644 index 000000000..f163d71d6 --- /dev/null +++ b/testdata/lint/chart-missing-helmchart/.replicated @@ -0,0 +1,10 @@ +charts: + - path: chart +manifests: + - manifests/*.yaml +repl-lint: + linters: + helm: + disabled: true + preflight: + disabled: true diff --git a/testdata/lint/chart-missing-helmchart/chart/Chart.yaml b/testdata/lint/chart-missing-helmchart/chart/Chart.yaml new file mode 100644 index 000000000..1f12b1d48 --- /dev/null +++ b/testdata/lint/chart-missing-helmchart/chart/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: test-app +version: 1.0.0 +description: Test chart without matching HelmChart manifest diff --git a/testdata/lint/chart-missing-helmchart/manifests/.gitkeep b/testdata/lint/chart-missing-helmchart/manifests/.gitkeep new file mode 100644 index 000000000..e5c70ee5a --- /dev/null +++ b/testdata/lint/chart-missing-helmchart/manifests/.gitkeep @@ -0,0 +1 @@ +# Empty manifests directory - no HelmChart manifest diff --git a/testdata/lint/configs/all-linters-enabled.yaml b/testdata/lint/configs/all-linters-enabled.yaml new file mode 100644 index 000000000..4db87984a --- /dev/null +++ b/testdata/lint/configs/all-linters-enabled.yaml @@ -0,0 +1,6 @@ +repl-lint: + version: 1 + linters: + helm: {} + preflight: {} + support-bundle: {} diff --git a/testdata/lint/configs/basic-helm-lint.yaml b/testdata/lint/configs/basic-helm-lint.yaml new file mode 100644 index 000000000..014270583 --- /dev/null +++ b/testdata/lint/configs/basic-helm-lint.yaml @@ -0,0 +1,5 @@ +repl-lint: + linters: + helm: {} + preflight: + disabled: true diff --git a/testdata/lint/configs/empty-config.yaml b/testdata/lint/configs/empty-config.yaml new file mode 100644 index 000000000..97e9e0516 --- /dev/null +++ b/testdata/lint/configs/empty-config.yaml @@ -0,0 +1,8 @@ +charts: [] +manifests: [] +preflights: [] +repl-lint: + linters: + helm: {} + preflight: + disabled: true diff --git a/testdata/lint/configs/helm-with-latest.yaml b/testdata/lint/configs/helm-with-latest.yaml new file mode 100644 index 000000000..97a0c2722 --- /dev/null +++ b/testdata/lint/configs/helm-with-latest.yaml @@ -0,0 +1,9 @@ +repl-lint: + tools: + helm: "latest" + preflight: "latest" + support-bundle: "latest" + linters: + helm: {} + preflight: + disabled: true diff --git a/testdata/lint/configs/helm-with-versions.yaml b/testdata/lint/configs/helm-with-versions.yaml new file mode 100644 index 000000000..780f66f76 --- /dev/null +++ b/testdata/lint/configs/helm-with-versions.yaml @@ -0,0 +1,9 @@ +repl-lint: + tools: + helm: "3.14.4" + preflight: "0.123.9" + support-bundle: "0.123.9" + linters: + helm: {} + preflight: + disabled: true diff --git a/testdata/lint/configs/manifests-only.yaml b/testdata/lint/configs/manifests-only.yaml new file mode 100644 index 000000000..72f43f297 --- /dev/null +++ b/testdata/lint/configs/manifests-only.yaml @@ -0,0 +1,6 @@ +manifests: + - manifests/*.yaml +repl-lint: + linters: + helm: {} + preflight: {} diff --git a/testdata/lint/hidden-dirs-test/.github/manifests/fake-sb.yaml b/testdata/lint/hidden-dirs-test/.github/manifests/fake-sb.yaml new file mode 100644 index 000000000..6f0c76360 --- /dev/null +++ b/testdata/lint/hidden-dirs-test/.github/manifests/fake-sb.yaml @@ -0,0 +1,7 @@ +# This should be ignored +apiVersion: troubleshoot.sh/v1beta2 +kind: SupportBundle +metadata: + name: fake +spec: + collectors: [] diff --git a/testdata/lint/hidden-dirs-test/charts/my-chart/Chart.yaml b/testdata/lint/hidden-dirs-test/charts/my-chart/Chart.yaml new file mode 100644 index 000000000..be9dd90ef --- /dev/null +++ b/testdata/lint/hidden-dirs-test/charts/my-chart/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: my-chart +version: 1.0.0 +description: Test chart for hidden directory autodiscovery diff --git a/testdata/lint/hidden-dirs-test/manifests/helmchart.yaml b/testdata/lint/hidden-dirs-test/manifests/helmchart.yaml new file mode 100644 index 000000000..000b9b78e --- /dev/null +++ b/testdata/lint/hidden-dirs-test/manifests/helmchart.yaml @@ -0,0 +1,9 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: my-chart +spec: + chart: + name: my-chart + chartVersion: 1.0.0 + weight: 1 diff --git a/testdata/lint/mixed-manifests-autodiscovery/charts/my-chart/Chart.yaml b/testdata/lint/mixed-manifests-autodiscovery/charts/my-chart/Chart.yaml new file mode 100644 index 000000000..5e6e5b0cf --- /dev/null +++ b/testdata/lint/mixed-manifests-autodiscovery/charts/my-chart/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: my-app +version: 1.0.0 +description: Test chart for autodiscovery with mixed manifests diff --git a/testdata/lint/mixed-manifests-autodiscovery/manifests/helmchart.yaml b/testdata/lint/mixed-manifests-autodiscovery/manifests/helmchart.yaml new file mode 100644 index 000000000..4561318f8 --- /dev/null +++ b/testdata/lint/mixed-manifests-autodiscovery/manifests/helmchart.yaml @@ -0,0 +1,9 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: my-app +spec: + chart: + name: my-app + chartVersion: 1.0.0 + weight: 1 diff --git a/testdata/lint/mixed-manifests-autodiscovery/manifests/preflight.yaml b/testdata/lint/mixed-manifests-autodiscovery/manifests/preflight.yaml new file mode 100644 index 000000000..90651afad --- /dev/null +++ b/testdata/lint/mixed-manifests-autodiscovery/manifests/preflight.yaml @@ -0,0 +1,13 @@ +apiVersion: troubleshoot.sh/v1beta2 +kind: Preflight +metadata: + name: my-app-preflight +spec: + analyzers: + - clusterVersion: + outcomes: + - fail: + when: "< 1.20.0" + message: Kubernetes version must be at least 1.20.0 + - pass: + message: Kubernetes version is supported diff --git a/testdata/lint/mixed-manifests-autodiscovery/manifests/support-bundle.yaml b/testdata/lint/mixed-manifests-autodiscovery/manifests/support-bundle.yaml new file mode 100644 index 000000000..d3ab3e781 --- /dev/null +++ b/testdata/lint/mixed-manifests-autodiscovery/manifests/support-bundle.yaml @@ -0,0 +1,10 @@ +apiVersion: troubleshoot.sh/v1beta2 +kind: SupportBundle +metadata: + name: my-app-support-bundle +spec: + collectors: + - logs: + selector: + - app=my-app + namespace: default diff --git a/testdata/lint/mixed-manifests-yaml-yml/charts/my-chart/Chart.yaml b/testdata/lint/mixed-manifests-yaml-yml/charts/my-chart/Chart.yaml new file mode 100644 index 000000000..5e6e5b0cf --- /dev/null +++ b/testdata/lint/mixed-manifests-yaml-yml/charts/my-chart/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: my-app +version: 1.0.0 +description: Test chart for autodiscovery with mixed manifests diff --git a/testdata/lint/mixed-manifests-yaml-yml/manifests/helmchart.yaml b/testdata/lint/mixed-manifests-yaml-yml/manifests/helmchart.yaml new file mode 100644 index 000000000..4561318f8 --- /dev/null +++ b/testdata/lint/mixed-manifests-yaml-yml/manifests/helmchart.yaml @@ -0,0 +1,9 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: my-app +spec: + chart: + name: my-app + chartVersion: 1.0.0 + weight: 1 diff --git a/testdata/lint/mixed-manifests-yaml-yml/manifests/preflight.yaml b/testdata/lint/mixed-manifests-yaml-yml/manifests/preflight.yaml new file mode 100644 index 000000000..90651afad --- /dev/null +++ b/testdata/lint/mixed-manifests-yaml-yml/manifests/preflight.yaml @@ -0,0 +1,13 @@ +apiVersion: troubleshoot.sh/v1beta2 +kind: Preflight +metadata: + name: my-app-preflight +spec: + analyzers: + - clusterVersion: + outcomes: + - fail: + when: "< 1.20.0" + message: Kubernetes version must be at least 1.20.0 + - pass: + message: Kubernetes version is supported diff --git a/testdata/lint/mixed-manifests-yaml-yml/manifests/support-bundle.yml b/testdata/lint/mixed-manifests-yaml-yml/manifests/support-bundle.yml new file mode 100644 index 000000000..d3ab3e781 --- /dev/null +++ b/testdata/lint/mixed-manifests-yaml-yml/manifests/support-bundle.yml @@ -0,0 +1,10 @@ +apiVersion: troubleshoot.sh/v1beta2 +kind: SupportBundle +metadata: + name: my-app-support-bundle +spec: + collectors: + - logs: + selector: + - app=my-app + namespace: default diff --git a/testdata/lint/multi-chart-project/.replicated b/testdata/lint/multi-chart-project/.replicated new file mode 100644 index 000000000..93e29cd5e --- /dev/null +++ b/testdata/lint/multi-chart-project/.replicated @@ -0,0 +1,10 @@ +charts: + - path: chart1 + - path: chart2 +manifests: + - manifests/*.yaml +repl-lint: + linters: + helm: {} + preflight: + disabled: true diff --git a/testdata/lint/multi-chart-project/chart1/Chart.yaml b/testdata/lint/multi-chart-project/chart1/Chart.yaml new file mode 100644 index 000000000..75e6b4f6f --- /dev/null +++ b/testdata/lint/multi-chart-project/chart1/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: chart1 +version: 1.0.0 +description: First chart for multi-chart testing diff --git a/testdata/lint/multi-chart-project/chart1/templates/deployment.yaml b/testdata/lint/multi-chart-project/chart1/templates/deployment.yaml new file mode 100644 index 000000000..1f352dd1d --- /dev/null +++ b/testdata/lint/multi-chart-project/chart1/templates/deployment.yaml @@ -0,0 +1,18 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + ports: + - containerPort: 80 diff --git a/testdata/lint/multi-chart-project/chart1/values.yaml b/testdata/lint/multi-chart-project/chart1/values.yaml new file mode 100644 index 000000000..0022858fb --- /dev/null +++ b/testdata/lint/multi-chart-project/chart1/values.yaml @@ -0,0 +1,3 @@ +image: + repository: nginx + tag: "1.21" diff --git a/testdata/lint/multi-chart-project/chart2/Chart.yaml b/testdata/lint/multi-chart-project/chart2/Chart.yaml new file mode 100644 index 000000000..24329c7d5 --- /dev/null +++ b/testdata/lint/multi-chart-project/chart2/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: chart2 +version: 1.0.0 +description: Second chart for multi-chart testing diff --git a/testdata/lint/multi-chart-project/chart2/templates/deployment.yaml b/testdata/lint/multi-chart-project/chart2/templates/deployment.yaml new file mode 100644 index 000000000..dea1e9bea --- /dev/null +++ b/testdata/lint/multi-chart-project/chart2/templates/deployment.yaml @@ -0,0 +1,18 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis +spec: + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - name: redis + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + ports: + - containerPort: 6379 diff --git a/testdata/lint/multi-chart-project/chart2/values.yaml b/testdata/lint/multi-chart-project/chart2/values.yaml new file mode 100644 index 000000000..7f1a50a8f --- /dev/null +++ b/testdata/lint/multi-chart-project/chart2/values.yaml @@ -0,0 +1,3 @@ +image: + repository: redis + tag: "7.0" diff --git a/testdata/lint/multi-chart-project/manifests/chart1-helmchart.yaml b/testdata/lint/multi-chart-project/manifests/chart1-helmchart.yaml new file mode 100644 index 000000000..80b500abf --- /dev/null +++ b/testdata/lint/multi-chart-project/manifests/chart1-helmchart.yaml @@ -0,0 +1,10 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: chart1 +spec: + chart: + name: chart1 + chartVersion: 1.0.0 + weight: 1 + builder: {} diff --git a/testdata/lint/multi-chart-project/manifests/chart2-helmchart.yaml b/testdata/lint/multi-chart-project/manifests/chart2-helmchart.yaml new file mode 100644 index 000000000..04e200f74 --- /dev/null +++ b/testdata/lint/multi-chart-project/manifests/chart2-helmchart.yaml @@ -0,0 +1,10 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: chart2 +spec: + chart: + name: chart2 + chartVersion: 1.0.0 + weight: 2 + builder: {} diff --git a/testdata/lint/orphaned-helmchart/.replicated b/testdata/lint/orphaned-helmchart/.replicated new file mode 100644 index 000000000..f163d71d6 --- /dev/null +++ b/testdata/lint/orphaned-helmchart/.replicated @@ -0,0 +1,10 @@ +charts: + - path: chart +manifests: + - manifests/*.yaml +repl-lint: + linters: + helm: + disabled: true + preflight: + disabled: true diff --git a/testdata/lint/orphaned-helmchart/chart/Chart.yaml b/testdata/lint/orphaned-helmchart/chart/Chart.yaml new file mode 100644 index 000000000..34886c6ab --- /dev/null +++ b/testdata/lint/orphaned-helmchart/chart/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: current-app +version: 1.0.0 +description: Current active chart diff --git a/testdata/lint/orphaned-helmchart/manifests/current-app-helmchart.yaml b/testdata/lint/orphaned-helmchart/manifests/current-app-helmchart.yaml new file mode 100644 index 000000000..63e01ec72 --- /dev/null +++ b/testdata/lint/orphaned-helmchart/manifests/current-app-helmchart.yaml @@ -0,0 +1,9 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: current-app +spec: + chart: + name: current-app + chartVersion: 1.0.0 + weight: 1 diff --git a/testdata/lint/orphaned-helmchart/manifests/old-app-helmchart.yaml b/testdata/lint/orphaned-helmchart/manifests/old-app-helmchart.yaml new file mode 100644 index 000000000..f474a62da --- /dev/null +++ b/testdata/lint/orphaned-helmchart/manifests/old-app-helmchart.yaml @@ -0,0 +1,9 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: old-app +spec: + chart: + name: old-app + chartVersion: 0.9.0 + weight: 2 diff --git a/testdata/lint/simple-chart/.replicated b/testdata/lint/simple-chart/.replicated new file mode 100644 index 000000000..b4975a7b2 --- /dev/null +++ b/testdata/lint/simple-chart/.replicated @@ -0,0 +1,9 @@ +charts: + - path: chart +manifests: + - manifests/*.yaml +repl-lint: + linters: + helm: {} + preflight: + disabled: true diff --git a/testdata/lint/simple-chart/chart/Chart.yaml b/testdata/lint/simple-chart/chart/Chart.yaml new file mode 100644 index 000000000..f4b224118 --- /dev/null +++ b/testdata/lint/simple-chart/chart/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: test-chart +version: 1.0.0 +description: A simple test chart for lint testing diff --git a/testdata/lint/simple-chart/chart/templates/deployment.yaml b/testdata/lint/simple-chart/chart/templates/deployment.yaml new file mode 100644 index 000000000..2ecaf9c3d --- /dev/null +++ b/testdata/lint/simple-chart/chart/templates/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: test-chart + template: + metadata: + labels: + app: test-chart + spec: + containers: + - name: nginx + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + ports: + - containerPort: 80 diff --git a/testdata/lint/simple-chart/chart/values.yaml b/testdata/lint/simple-chart/chart/values.yaml new file mode 100644 index 000000000..99bab5baf --- /dev/null +++ b/testdata/lint/simple-chart/chart/values.yaml @@ -0,0 +1,6 @@ +replicaCount: 1 + +image: + repository: nginx + tag: "1.21" + pullPolicy: IfNotPresent diff --git a/testdata/lint/simple-chart/manifests/helmchart.yaml b/testdata/lint/simple-chart/manifests/helmchart.yaml new file mode 100644 index 000000000..8ebd8f7f6 --- /dev/null +++ b/testdata/lint/simple-chart/manifests/helmchart.yaml @@ -0,0 +1,10 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: test-chart +spec: + chart: + name: test-chart + chartVersion: 1.0.0 + weight: 1 + builder: {}