From def5d097a49c08d81a31dfa725eb5f49ee03d0df Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Wed, 4 Jun 2025 14:29:13 +0200 Subject: [PATCH 1/4] feat(tests): Fixing linter problems Using golangci-lint --- .golangci.yml | 26 +++++++++++++ cmd/katenary/main.go | 24 +++++++----- generator/chart.go | 11 ++++-- generator/configMap.go | 8 ++-- generator/converter.go | 16 ++++++-- generator/deployment.go | 9 ++--- generator/extrafiles/readme.go | 5 ++- generator/generator.go | 11 ++++-- generator/katenaryfile/main.go | 40 +++++++++++--------- generator/labels/katenaryLabels.go | 17 +++++++-- parser/main_test.go | 60 ++++++++++++++++++++++++++++++ utils/hash_test.go | 13 +++++++ utils/utils.go | 4 +- 13 files changed, 195 insertions(+), 49 deletions(-) create mode 100644 .golangci.yml create mode 100644 parser/main_test.go create mode 100644 utils/hash_test.go diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..55a37d4 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,26 @@ +version: "2" +run: + issues-exit-code: 1 +linters: + enabled: + - unused + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ + - "(.+)_test.go" +formatters: + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ + - "(.+)_test.go" diff --git a/cmd/katenary/main.go b/cmd/katenary/main.go index 8a88969..3276d31 100644 --- a/cmd/katenary/main.go +++ b/cmd/katenary/main.go @@ -10,6 +10,7 @@ import ( "katenary/generator/katenaryfile" "katenary/generator/labels" "katenary/utils" + "log" "os" "strings" @@ -24,7 +25,10 @@ Each [command] and subcommand has got an "help" and "--help" flag to show more i func main() { rootCmd := buildRootCmd() - rootCmd.Execute() + + if err := rootCmd.Execute(); err != nil { + log.Fatal(err) + } } func buildRootCmd() *cobra.Command { @@ -97,26 +101,26 @@ func generateCompletionCommand(name string) *cobra.Command { Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), Short: "Generates completion scripts", Long: fmt.Sprintf(completionHelp, name), - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { - cmd.Help() - return + return cmd.Help() } switch args[0] { case "bash": // get the bash version if cmd.Flags().Changed("bash-v1") { - cmd.Root().GenBashCompletion(os.Stdout) - return + return cmd.Root().GenBashCompletion(os.Stdout) } - cmd.Root().GenBashCompletionV2(os.Stdout, true) + return cmd.Root().GenBashCompletionV2(os.Stdout, true) case "zsh": - cmd.Root().GenZshCompletion(os.Stdout) + return cmd.Root().GenZshCompletion(os.Stdout) case "fish": - cmd.Root().GenFishCompletion(os.Stdout, true) + return cmd.Root().GenFishCompletion(os.Stdout, true) case "powershell": - cmd.Root().GenPowerShellCompletion(os.Stdout) + return cmd.Root().GenPowerShellCompletion(os.Stdout) } + + return fmt.Errorf("unknown completion type: %s", args[0]) }, } diff --git a/generator/chart.go b/generator/chart.go index 9d4c564..cb7af79 100644 --- a/generator/chart.go +++ b/generator/chart.go @@ -117,8 +117,13 @@ func (chart *HelmChart) SaveTemplates(templateDir string) { os.Exit(1) } - f.Write(t) - f.Close() + if _, err := f.Write(t); err != nil { + log.Fatal("error writing template file:", err) + } + + if err := f.Close(); err != nil { + log.Fatal("error closing template file:", err) + } } } @@ -126,7 +131,7 @@ func (chart *HelmChart) SaveTemplates(templateDir string) { func (chart *HelmChart) generateConfigMapsAndSecrets(project *types.Project) error { appName := chart.Name for _, s := range project.Services { - if s.Environment == nil || len(s.Environment) == 0 { + if len(s.Environment) == 0 { continue } diff --git a/generator/configMap.go b/generator/configMap.go index 5d79449..777ed82 100644 --- a/generator/configMap.go +++ b/generator/configMap.go @@ -142,7 +142,9 @@ func NewConfigMapFromDirectory(service types.ServiceConfig, appName, path string // cumulate the path to the WorkingDir path = filepath.Join(service.WorkingDir, path) path = filepath.Clean(path) - cm.AppendDir(path) + if err := cm.AppendDir(path); err != nil { + log.Fatal("Error adding files to configmap:", err) + } return cm } @@ -165,7 +167,7 @@ func (c *ConfigMap) AppendDir(path string) error { // read all files in the path and add them to the configmap stat, err := os.Stat(path) if err != nil { - return fmt.Errorf("Path %s does not exist, %w\n", path, err) + return fmt.Errorf("path %s does not exist, %w", path, err) } // recursively read all files in the path and add them to the configmap if stat.IsDir() { @@ -212,7 +214,7 @@ func (c *ConfigMap) AppendFile(path string) error { // read all files in the path and add them to the configmap stat, err := os.Stat(path) if err != nil { - return fmt.Errorf("Path %s doesn not exists, %w", path, err) + return fmt.Errorf("path %s doesn not exists, %w", path, err) } // recursively read all files in the path and add them to the configmap if !stat.IsDir() { diff --git a/generator/converter.go b/generator/converter.go index 2d12c18..24e2481 100644 --- a/generator/converter.go +++ b/generator/converter.go @@ -113,7 +113,11 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) error { fmt.Println(utils.IconFailure, err) return err } - defer os.Chdir(currentDir) // after the generation, go back to the original directory + defer func() { + if err := os.Chdir(currentDir); err != nil { // after the generation, go back to the original directory + log.Fatal(err) + } + }() // repove the directory part of the docker-compose files for i, f := range dockerComposeFile { @@ -626,8 +630,14 @@ func writeContent(path string, content []byte) { fmt.Println(utils.IconFailure, err) os.Exit(1) } - defer f.Close() - f.Write(content) + defer func() { + if err := f.Close(); err != nil { + log.Fatal(err) + } + if _, err := f.Write(content); err != nil { + log.Fatal(err) + } + }() } // helmLint runs "helm lint" on the output directory. diff --git a/generator/deployment.go b/generator/deployment.go index c05de83..6421f66 100644 --- a/generator/deployment.go +++ b/generator/deployment.go @@ -305,10 +305,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, sam if len(service.Environment) == 0 { return } - inSamePod := false - if len(samePod) > 0 && samePod[0] { - inSamePod = true - } + inSamePod := len(samePod) > 0 && samePod[0] drop := []string{} secrets := []string{} @@ -660,7 +657,9 @@ func (d *Deployment) appendFileToConfigMap(service types.ServiceConfig, appName d.configMaps[pathname].mountPath = mp } - cm.AppendFile(volume.Source) + if err := cm.AppendFile(volume.Source); err != nil { + log.Fatal("Error adding file to configmap:", err) + } } func (d *Deployment) bindVolumes(volume types.ServiceVolumeConfig, isSamePod bool, tobind map[string]bool, service types.ServiceConfig, appName string) { diff --git a/generator/extrafiles/readme.go b/generator/extrafiles/readme.go index b3201fe..d328d33 100644 --- a/generator/extrafiles/readme.go +++ b/generator/extrafiles/readme.go @@ -4,6 +4,7 @@ import ( "bytes" _ "embed" "fmt" + "log" "sort" "strings" "text/template" @@ -48,7 +49,9 @@ func ReadMeFile(charname, description string, values map[string]any) string { vv := map[string]any{} out, _ := yaml.Marshal(values) - yaml.Unmarshal(out, &vv) + if err := yaml.Unmarshal(out, &vv); err != nil { + log.Printf("Error parsing values: %s", err) + } result := make(map[string]string) parseValues("", vv, result) diff --git a/generator/generator.go b/generator/generator.go index cb8d5ee..d3a5113 100644 --- a/generator/generator.go +++ b/generator/generator.go @@ -117,7 +117,10 @@ func Generate(project *types.Project) (*HelmChart, error) { for _, s := range project.Services { for _, d := range s.GetDependencies() { if dep, ok := deployments[d]; ok { - deployments[s.Name].DependsOn(dep, d) + err := deployments[s.Name].DependsOn(dep, d) + if err != nil { + log.Printf("error creating init container for service %[1]s: %[2]s", s.Name, err) + } } else { log.Printf("service %[1]s depends on %[2]s, but %[2]s is not defined", s.Name, d) } @@ -129,7 +132,9 @@ func Generate(project *types.Project) (*HelmChart, error) { } // generate configmaps with environment variables - chart.generateConfigMapsAndSecrets(project) + if err := chart.generateConfigMapsAndSecrets(project); err != nil { + log.Fatalf("error generating configmaps and secrets: %s", err) + } // if the env-from label is set, we need to add the env vars from the configmap // to the environment of the service @@ -385,7 +390,7 @@ func samePodVolume(service types.ServiceConfig, v types.ServiceVolumeConfig, dep return false } - if service.Volumes == nil || len(service.Volumes) == 0 { + if len(service.Volumes) == 0 { return false } diff --git a/generator/katenaryfile/main.go b/generator/katenaryfile/main.go index 312d747..b9b938d 100644 --- a/generator/katenaryfile/main.go +++ b/generator/katenaryfile/main.go @@ -75,24 +75,30 @@ func OverrideWithConfig(project *types.Project) { if project.Services[i].Labels == nil { project.Services[i].Labels = make(map[string]string) } + mustGetLabelContent := func(o any, s *types.ServiceConfig, labelName string) { + err := getLabelContent(o, s, labelName) + if err != nil { + log.Fatal(err) + } + } if s, ok := services[name]; ok { - getLabelContent(s.MainApp, &project.Services[i], labels.LabelMainApp) - getLabelContent(s.Values, &project.Services[i], labels.LabelValues) - getLabelContent(s.Secrets, &project.Services[i], labels.LabelSecrets) - getLabelContent(s.Ports, &project.Services[i], labels.LabelPorts) - getLabelContent(s.Ingress, &project.Services[i], labels.LabelIngress) - getLabelContent(s.HealthCheck, &project.Services[i], labels.LabelHealthCheck) - getLabelContent(s.SamePod, &project.Services[i], labels.LabelSamePod) - getLabelContent(s.Description, &project.Services[i], labels.LabelDescription) - getLabelContent(s.Ignore, &project.Services[i], labels.LabelIgnore) - getLabelContent(s.Dependencies, &project.Services[i], labels.LabelDependencies) - getLabelContent(s.ConfigMapFile, &project.Services[i], labels.LabelConfigMapFiles) - getLabelContent(s.MapEnv, &project.Services[i], labels.LabelMapEnv) - getLabelContent(s.CronJob, &project.Services[i], labels.LabelCronJob) - getLabelContent(s.EnvFrom, &project.Services[i], labels.LabelEnvFrom) - getLabelContent(s.ExchangeVolumes, &project.Services[i], labels.LabelExchangeVolume) - getLabelContent(s.ValuesFrom, &project.Services[i], labels.LabelValueFrom) + mustGetLabelContent(s.MainApp, &project.Services[i], labels.LabelMainApp) + mustGetLabelContent(s.Values, &project.Services[i], labels.LabelValues) + mustGetLabelContent(s.Secrets, &project.Services[i], labels.LabelSecrets) + mustGetLabelContent(s.Ports, &project.Services[i], labels.LabelPorts) + mustGetLabelContent(s.Ingress, &project.Services[i], labels.LabelIngress) + mustGetLabelContent(s.HealthCheck, &project.Services[i], labels.LabelHealthCheck) + mustGetLabelContent(s.SamePod, &project.Services[i], labels.LabelSamePod) + mustGetLabelContent(s.Description, &project.Services[i], labels.LabelDescription) + mustGetLabelContent(s.Ignore, &project.Services[i], labels.LabelIgnore) + mustGetLabelContent(s.Dependencies, &project.Services[i], labels.LabelDependencies) + mustGetLabelContent(s.ConfigMapFile, &project.Services[i], labels.LabelConfigMapFiles) + mustGetLabelContent(s.MapEnv, &project.Services[i], labels.LabelMapEnv) + mustGetLabelContent(s.CronJob, &project.Services[i], labels.LabelCronJob) + mustGetLabelContent(s.EnvFrom, &project.Services[i], labels.LabelEnvFrom) + mustGetLabelContent(s.ExchangeVolumes, &project.Services[i], labels.LabelExchangeVolume) + mustGetLabelContent(s.ValuesFrom, &project.Services[i], labels.LabelValueFrom) } } fmt.Println(utils.IconInfo, "Katenary file loaded successfully, the services are now configured.") @@ -155,5 +161,5 @@ func GenerateSchema() string { return err.Error() } - return string(out.Bytes()) + return out.String() } diff --git a/generator/labels/katenaryLabels.go b/generator/labels/katenaryLabels.go index 54c9e38..5c2ea33 100644 --- a/generator/labels/katenaryLabels.go +++ b/generator/labels/katenaryLabels.go @@ -5,6 +5,7 @@ import ( _ "embed" "fmt" "katenary/utils" + "log" "regexp" "sort" "strings" @@ -125,23 +126,30 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string { } var buf bytes.Buffer - template.Must(template.New("shorthelp").Parse(help.Long)).Execute(&buf, struct { + var err error + err = template.Must(template.New("shorthelp").Parse(help.Long)).Execute(&buf, struct { KatenaryPrefix string }{ KatenaryPrefix: KatenaryLabelPrefix, }) + if err != nil { + log.Fatalf("Error executing template: %v", err) + } help.Long = buf.String() buf.Reset() - template.Must(template.New("example").Parse(help.Example)).Execute(&buf, struct { + err = template.Must(template.New("example").Parse(help.Example)).Execute(&buf, struct { KatenaryPrefix string }{ KatenaryPrefix: KatenaryLabelPrefix, }) + if err != nil { + log.Fatalf("Error executing template: %v", err) + } help.Example = buf.String() buf.Reset() - template.Must(template.New("complete").Parse(helpTemplate)).Execute(&buf, struct { + err = template.Must(template.New("complete").Parse(helpTemplate)).Execute(&buf, struct { Name string Help Help KatenaryPrefix string @@ -150,6 +158,9 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string { Help: help, KatenaryPrefix: KatenaryLabelPrefix, }) + if err != nil { + log.Fatalf("Error executing template: %v", err) + } return buf.String() } diff --git a/parser/main_test.go b/parser/main_test.go new file mode 100644 index 0000000..bba0511 --- /dev/null +++ b/parser/main_test.go @@ -0,0 +1,60 @@ +package parser + +import ( + "log" + "os" + "path/filepath" + "testing" +) + +const composeFile = ` +services: + app: + image: nginx:latest +` + +func setupTest() (string, error) { + // write the composeFile to a temporary file + tmpDir, err := os.MkdirTemp("", "katenary-test-parse") + if err != nil { + return "", err + } + writeFile := filepath.Join(tmpDir, "compose.yaml") + writeErr := os.WriteFile(writeFile, []byte(composeFile), 0644) + return writeFile, writeErr +} + +func tearDownTest(tmpDir string) { + if tmpDir != "" { + if err := os.RemoveAll(tmpDir); err != nil { + log.Fatalf("Failed to remove temporary directory %s: %s", tmpDir, err.Error()) + } + } +} + +func TestParse(t *testing.T) { + file, err := setupTest() + dirname := filepath.Dir(file) + currentDir, _ := os.Getwd() + if err := os.Chdir(dirname); err != nil { + t.Fatalf("Failed to change directory to %s: %s", dirname, err.Error()) + } + defer func() { + tearDownTest(dirname) + if err := os.Chdir(currentDir); err != nil { + t.Fatalf("Failed to change back to original directory %s: %s", currentDir, err.Error()) + } + }() + + if err != nil { + t.Fatalf("Failed to setup test: %s", err.Error()) + } + + Project, err := Parse(nil, nil) + if err != nil { + t.Fatalf("Failed to parse compose file: %s", err.Error()) + } + if Project == nil { + t.Fatal("Expected project to be not nil") + } +} diff --git a/utils/hash_test.go b/utils/hash_test.go new file mode 100644 index 0000000..90fe6e2 --- /dev/null +++ b/utils/hash_test.go @@ -0,0 +1,13 @@ +package utils + +import "testing" + +func TestHash(t *testing.T) { + h, err := HashComposefiles([]string{"./hash.go"}) + if err != nil { + t.Fatalf("failed to hash compose files: %v", err) + } + if len(h) == 0 { + t.Fatal("hash should not be empty") + } +} diff --git a/utils/utils.go b/utils/utils.go index 244a589..b9910c8 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -165,7 +165,9 @@ func Confirm(question string, icon ...Icon) bool { fmt.Print(question + " [y/N] ") } var response string - fmt.Scanln(&response) + if _, err := fmt.Scanln(&response); err != nil { + log.Fatalf("Error parsing response: %s", err.Error()) + } return strings.ToLower(response) == "y" } From a8341a9b442f59285398f10ea66c614390d17e7b Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Wed, 4 Jun 2025 14:41:53 +0200 Subject: [PATCH 2/4] feat(tests): .Close() can be "unchecked" --- generator/chart.go | 5 +---- generator/converter.go | 4 +--- generator/tools_test.go | 1 + 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/generator/chart.go b/generator/chart.go index cb7af79..d8bc0bf 100644 --- a/generator/chart.go +++ b/generator/chart.go @@ -116,14 +116,11 @@ func (chart *HelmChart) SaveTemplates(templateDir string) { fmt.Println(utils.IconFailure, err) os.Exit(1) } - + defer f.Close() if _, err := f.Write(t); err != nil { log.Fatal("error writing template file:", err) } - if err := f.Close(); err != nil { - log.Fatal("error closing template file:", err) - } } } diff --git a/generator/converter.go b/generator/converter.go index 24e2481..77ceb73 100644 --- a/generator/converter.go +++ b/generator/converter.go @@ -630,10 +630,8 @@ func writeContent(path string, content []byte) { fmt.Println(utils.IconFailure, err) os.Exit(1) } + defer f.Close() defer func() { - if err := f.Close(); err != nil { - log.Fatal(err) - } if _, err := f.Write(content); err != nil { log.Fatal(err) } diff --git a/generator/tools_test.go b/generator/tools_test.go index 2395411..66d586e 100644 --- a/generator/tools_test.go +++ b/generator/tools_test.go @@ -49,6 +49,7 @@ func internalCompileTest(t *testing.T, options ...string) string { ChartVersion: chartVersion, } if err := Convert(convertOptions, "compose.yml"); err != nil { + log.Printf("Failed to convert: %s", err) return err.Error() } From b143f743efe9d8b827baa8e272d5ce45215b2965 Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Wed, 4 Jun 2025 15:17:26 +0200 Subject: [PATCH 3/4] feat(chore): Add tests and use "any" instead of "inteface" --- generator/extrafiles/notes_test.go | 40 +++++++++++++++++++++++++++++ generator/extrafiles/readme.go | 8 +++--- generator/extrafiles/readme_test.go | 33 ++++++++++++++++++++++++ generator/utils.go | 2 +- utils/icons.go | 2 +- utils/utils.go | 8 +++--- 6 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 generator/extrafiles/notes_test.go create mode 100644 generator/extrafiles/readme_test.go diff --git a/generator/extrafiles/notes_test.go b/generator/extrafiles/notes_test.go new file mode 100644 index 0000000..656aecd --- /dev/null +++ b/generator/extrafiles/notes_test.go @@ -0,0 +1,40 @@ +package extrafiles + +import ( + "strings" + "testing" +) + +// override the embedded template for testing +var testTemplate = ` +Some header +{{ ingress_list }} +Some footer +` + +func init() { + notesTemplate = testTemplate +} + +func TestNotesFile_NoServices(t *testing.T) { + result := NotesFile([]string{}) + if !strings.Contains(result, "Some header") || !strings.Contains(result, "Some footer") { + t.Errorf("Expected template header/footer in output, got: %s", result) + } +} + +func TestNotesFile_WithServices(t *testing.T) { + services := []string{"svc1", "svc2"} + result := NotesFile(services) + + for _, svc := range services { + cond := "{{- if and .Values." + svc + ".ingress .Values." + svc + ".ingress.enabled }}" + line := "{{- $count = add1 $count -}}{{- $listOfURL = printf \"%s\\n- http://%s\" $listOfURL (tpl .Values." + svc + ".ingress.host .) -}}" + if !strings.Contains(result, cond) { + t.Errorf("Expected condition for service %s in output", svc) + } + if !strings.Contains(result, line) { + t.Errorf("Expected line for service %s in output", svc) + } + } +} diff --git a/generator/extrafiles/readme.go b/generator/extrafiles/readme.go index d328d33..8fba0c8 100644 --- a/generator/extrafiles/readme.go +++ b/generator/extrafiles/readme.go @@ -21,7 +21,7 @@ type chart struct { Values []string } -func parseValues(prefix string, values map[string]interface{}, result map[string]string) { +func parseValues(prefix string, values map[string]any, result map[string]string) { for key, value := range values { path := key if prefix != "" { @@ -29,11 +29,11 @@ func parseValues(prefix string, values map[string]interface{}, result map[string } switch v := value.(type) { - case []interface{}: + case []any: for i, u := range v { - parseValues(fmt.Sprintf("%s[%d]", path, i), map[string]interface{}{"value": u}, result) + parseValues(fmt.Sprintf("%s[%d]", path, i), map[string]any{"value": u}, result) } - case map[string]interface{}: + case map[string]any: parseValues(path, v, result) default: strValue := fmt.Sprintf("`%v`", value) diff --git a/generator/extrafiles/readme_test.go b/generator/extrafiles/readme_test.go new file mode 100644 index 0000000..e819872 --- /dev/null +++ b/generator/extrafiles/readme_test.go @@ -0,0 +1,33 @@ +package extrafiles + +import ( + "regexp" + "testing" +) + +func TestReadMeFile_Basic(t *testing.T) { + values := map[string]any{ + "replicas": 2, + "image": map[string]any{ + "repository": "nginx", + "tag": "latest", + }, + } + + result := ReadMeFile("testchart", "A test chart", values) + t.Logf("Generated README content:\n%s", result) + paramerRegExp := regexp.MustCompile(`\|\s+` + "`" + `(.*?)` + "`" + `\s+\|\s+` + "`" + `(.*?)` + "`" + `\s+\|`) + matches := paramerRegExp.FindAllStringSubmatch(result, -1) + if len(matches) != 3 { + t.Errorf("Expected 5 lines in the table for headers and parameters, got %d", len(matches)) + } + if matches[0][1] != "image.repository" || matches[0][2] != "nginx" { + t.Errorf("Expected third line to be image.repository, got %s", matches[1]) + } + if matches[1][1] != "image.tag" || matches[1][2] != "latest" { + t.Errorf("Expected fourth line to be image.tag, got %s", matches[2]) + } + if matches[2][1] != "replicas" || matches[2][2] != "2" { + t.Errorf("Expected second line to be replicas, got %s", matches[0]) + } +} diff --git a/generator/utils.go b/generator/utils.go index 539f07d..c10cd15 100644 --- a/generator/utils.go +++ b/generator/utils.go @@ -87,7 +87,7 @@ func UnWrapTPL(in []byte) []byte { return regexpLineWrap.ReplaceAll(in, []byte(" }}")) } -func ToK8SYaml(obj interface{}) ([]byte, error) { +func ToK8SYaml(obj any) ([]byte, error) { if o, err := yaml.Marshal(obj); err != nil { return nil, nil } else { diff --git a/utils/icons.go b/utils/icons.go index 5028c24..2a2a38d 100644 --- a/utils/icons.go +++ b/utils/icons.go @@ -22,7 +22,7 @@ const ( ) // Warn prints a warning message -func Warn(msg ...interface{}) { +func Warn(msg ...any) { orange := "\033[38;5;214m" reset := "\033[0m" fmt.Print(IconWarning, orange, " ") diff --git a/utils/utils.go b/utils/utils.go index b9910c8..ab4ba59 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -136,12 +136,12 @@ func GetValuesFromLabel(service types.ServiceConfig, LabelValues string) map[str switch val := value.(type) { case string: descriptions[val] = nil - case map[string]interface{}: - for k, v := range value.(map[string]interface{}) { + case map[string]any: + for k, v := range value.(map[string]any) { descriptions[k] = &EnvConfig{Service: service, Description: v.(string)} } - case map[interface{}]interface{}: - for k, v := range value.(map[interface{}]interface{}) { + case map[any]any: + for k, v := range value.(map[any]any) { descriptions[k.(string)] = &EnvConfig{Service: service, Description: v.(string)} } default: From d94bb8ac32c3bd79a417dfaef36c84e60ecc3bab Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Wed, 4 Jun 2025 15:18:11 +0200 Subject: [PATCH 4/4] feat(doc): regenerate documentation --- doc/docs/.markdownlint.yaml | 5 ++ doc/docs/labels.md | 72 +++++++++------------ doc/docs/packages/generator.md | 51 ++++++++------- doc/docs/packages/generator/extrafiles.md | 2 +- doc/docs/packages/generator/katenaryfile.md | 2 +- doc/docs/packages/generator/labels.md | 14 ++-- doc/docs/packages/update.md | 60 ----------------- doc/docs/packages/utils.md | 8 +-- doc/mkdocs.yml | 1 - 9 files changed, 73 insertions(+), 142 deletions(-) create mode 100644 doc/docs/.markdownlint.yaml delete mode 100644 doc/docs/packages/update.md diff --git a/doc/docs/.markdownlint.yaml b/doc/docs/.markdownlint.yaml new file mode 100644 index 0000000..f6df9d2 --- /dev/null +++ b/doc/docs/.markdownlint.yaml @@ -0,0 +1,5 @@ +MD012: false +MD013: false +MD022: false +MD033: false +MD046: false diff --git a/doc/docs/labels.md b/doc/docs/labels.md index 637db16..e70fefb 100644 --- a/doc/docs/labels.md +++ b/doc/docs/labels.md @@ -37,8 +37,8 @@ Add files to the configmap. **Type**: `[]string` -It makes a file or directory to be converted to one or more ConfigMaps -and mounted in the pod. The file or directory is relative to the +It makes a file or directory to be converted to one or more ConfigMaps +and mounted in the pod. The file or directory is relative to the service directory. If it is a directory, all files inside it are added to the ConfigMap. @@ -47,7 +47,7 @@ If the directory as subdirectories, so one configmap per subpath are created. !!! Warning It is not intended to be used to store an entire project in configmaps. - It is intended to be used to store configuration files that are not managed + It is intended to be used to store configuration files that are not managed by the application, like nginx configuration files. Keep in mind that your project sources should be stored in an application image or in a storage. @@ -61,7 +61,6 @@ labels: - ./conf.d ``` - ### katenary.v3/cronjob Create a cronjob from the service. @@ -71,8 +70,9 @@ Create a cronjob from the service. This adds a cronjob to the chart. The label value is a YAML object with the following attributes: -- command: the command to be executed -- schedule: the cron schedule (cron format or @every where "every" is a + +- command: the command to be executed +- schedule: the cron schedule (cron format or @every where "every" is a duration like 1h30m, daily, hourly...) - rbac: false (optionnal), if true, it will create a role, a rolebinding and a serviceaccount to make your cronjob able to connect the Kubernetes API @@ -86,15 +86,14 @@ labels: schedule: "* */1 * * *" # or @hourly for example ``` - ### katenary.v3/dependencies Add Helm dependencies to the service. **Type**: `[]object` -Set the service to be, actually, a Helm dependency. This means that the -service will not be exported as template. The dependencies are added to +Set the service to be, actually, a Helm dependency. This means that the +service will not be exported as template. The dependencies are added to the Chart.yaml file and the values are added to the values.yaml file. It's a list of objects with the following attributes: @@ -106,12 +105,12 @@ It's a list of objects with the following attributes: !!! Info Katenary doesn't update the helm depenedencies by default. - + Use `--helm-update` (or `-u`) flag to update the dependencies. example: katenary convert -u -By setting an alias, it is possible to change the name of the dependency +By setting an alias, it is possible to change the name of the dependency in values.yaml. **Example:** @@ -133,14 +132,13 @@ labels: password: the secret password ``` - ### katenary.v3/description Description of the service **Type**: `string` -This replaces the default comment in values.yaml file to the given description. +This replaces the default comment in values.yaml file to the given description. It is useful to document the service and configuration. The value can be set with a documentation in multiline format. @@ -154,7 +152,6 @@ labels: It can be multiline. ``` - ### katenary.v3/env-from Add environment variables from antoher service. @@ -180,14 +177,13 @@ service2: - myservice1 ``` - ### katenary.v3/exchange-volumes Add exchange volumes (empty directory on the node) to share data **Type**: `[]object` -This label allows sharing data between containres. The volume is created in +This label allows sharing data between containres. The volume is created in the node and mounted in the pod. It is useful to share data between containers in a "same pod" logic. For example to let PHP-FPM and Nginx share the same direcotory. @@ -198,9 +194,10 @@ This will create: - a `initContainer` for each definition Fields: - - name: the name of the volume (manadatory) - - mountPath: the path where the volume is mounted in the pod (optional, default is `/opt`) - - init: a command to run to initialize the volume with data (optional) + +- name: the name of the volume (manadatory) +- mountPath: the path where the volume is mounted in the pod (optional, default is `/opt`) +- init: a command to run to initialize the volume with data (optional) !!! Warning This is highly experimental. This is mainly useful when using the "same-pod" label. @@ -223,7 +220,6 @@ php: init: cp -ra /var/www/html/* /opt ``` - ### katenary.v3/health-check Health check to be added to the deployment. @@ -243,7 +239,6 @@ labels: port: 8080 ``` - ### katenary.v3/ignore Ignore the service @@ -259,14 +254,13 @@ labels: katenary.v3/ignore: "true" ``` - ### katenary.v3/ingress Ingress rules to be added to the service. **Type**: `object` -Declare an ingress rule for the service. The port should be exposed or +Declare an ingress rule for the service. The port should be exposed or declared with `katenary.v3/ports`. **Example:** @@ -278,14 +272,13 @@ labels: hostname: mywebsite.com (optional) ``` - ### katenary.v3/main-app Mark the service as the main app. **Type**: `bool` -This makes the service to be the main application. Its image tag is +This makes the service to be the main application. Its image tag is considered to be the Chart appVersion and to be the defaultvalue in Pod container image attribute. @@ -305,7 +298,6 @@ ghost: katenary.v3/main-app: true ``` - ### katenary.v3/map-env Map env vars from the service to the deployment. @@ -313,8 +305,8 @@ Map env vars from the service to the deployment. **Type**: `map[string]string` Because you may need to change the variable for Kubernetes, this label -forces the value to another. It is also particullary helpful to use a template -value instead. For example, you could bind the value to a service name +forces the value to another. It is also particullary helpful to use a template +value instead. For example, you could bind the value to a service name with Helm attributes: `{{ tpl .Release.Name . }}`. @@ -333,14 +325,13 @@ labels: DB_HOST: '{{ include "__APP__.fullname" . }}-database' ``` - ### katenary.v3/ports Ports to be added to the service. **Type**: `[]uint32` -Only useful for services without exposed port. It is mandatory if the +Only useful for services without exposed port. It is mandatory if the service is a dependency of another service. **Example:** @@ -352,17 +343,16 @@ labels: - 8081 ``` - ### katenary.v3/same-pod Move the same-pod deployment to the target deployment. **Type**: `string` -This will make the service to be included in another service pod. Some services +This will make the service to be included in another service pod. Some services must work together in the same pod, like a sidecar or a proxy or nginx + php-fpm. -Note that volume and VolumeMount are copied from the source to the target +Note that volume and VolumeMount are copied from the source to the target deployment. **Example:** @@ -377,14 +367,13 @@ php: katenary.v3/same-pod: web ``` - ### katenary.v3/secrets Env vars to be set as secrets. **Type**: `[]string` -This label allows setting the environment variables as secrets. The variable +This label allows setting the environment variables as secrets. The variable is removed from the environment and added to a secret object. The variable can be set to the `katenary.v3/values` too, @@ -401,7 +390,6 @@ labels: - PASSWORD ``` - ### katenary.v3/values Environment variables to be added to the values.yaml @@ -412,11 +400,11 @@ By default, all environment variables in the "env" and environment files are added to configmaps with the static values set. This label allows adding environment variables to the values.yaml file. -Note that the value inside the configmap is `{{ tpl vaname . }}`, so -you can set the value to a template that will be rendered with the +Note that the value inside the configmap is `{{ tpl vaname . }}`, so +you can set the value to a template that will be rendered with the values.yaml file. -The value can be set with a documentation. This may help to understand +The value can be set with a documentation. This may help to understand the purpose of the variable. **Example:** @@ -438,7 +426,6 @@ labels: It can be, of course, a multiline text. ``` - ### katenary.v3/values-from Add values from another service. @@ -460,9 +447,9 @@ database: MARIADB_USER: myuser MARIADB_PASSWORD: mypassword labels: - # it can be a secret + # we can declare secrets katenary.v3/secrets: |- - - DB_PASSWORD + - MARIADB_PASSWORD php: image: php:7.4-fpm environment: @@ -476,5 +463,4 @@ php: DB_PASSWORD: database.MARIADB_PASSWORD ``` - diff --git a/doc/docs/packages/generator.md b/doc/docs/packages/generator.md index 1e681b2..0283f52 100644 --- a/doc/docs/packages/generator.md +++ b/doc/docs/packages/generator.md @@ -35,7 +35,7 @@ var Version = "master" // changed at compile time ``` -## func [Convert]() +## func [Convert]() ```go func Convert(config ConvertOptions, dockerComposeFile ...string) error @@ -92,7 +92,7 @@ NewCronJob creates a new CronJob from a compose service. The appName is the name ## func [ToK8SYaml]() ```go -func ToK8SYaml(obj interface{}) ([]byte, error) +func ToK8SYaml(obj any) ([]byte, error) ``` @@ -149,7 +149,7 @@ func NewConfigMapFromDirectory(service types.ServiceConfig, appName, path string NewConfigMapFromDirectory creates a new ConfigMap from a compose service. This path is the path to the file or directory. If the path is a directory, all files in the directory are added to the ConfigMap. Each subdirectory are ignored. Note that the Generate\(\) function will create the subdirectories ConfigMaps. -### func \(\*ConfigMap\) [AddBinaryData]() +### func \(\*ConfigMap\) [AddBinaryData]() ```go func (c *ConfigMap) AddBinaryData(key string, value []byte) @@ -158,7 +158,7 @@ func (c *ConfigMap) AddBinaryData(key string, value []byte) AddBinaryData adds binary data to the configmap. Append or overwrite the value if the key already exists. -### func \(\*ConfigMap\) [AddData]() +### func \(\*ConfigMap\) [AddData]() ```go func (c *ConfigMap) AddData(key, value string) @@ -167,7 +167,7 @@ func (c *ConfigMap) AddData(key, value string) AddData adds a key value pair to the configmap. Append or overwrite the value if the key already exists. -### func \(\*ConfigMap\) [AppendDir]() +### func \(\*ConfigMap\) [AppendDir]() ```go func (c *ConfigMap) AppendDir(path string) error @@ -176,7 +176,7 @@ func (c *ConfigMap) AppendDir(path string) error AddFile adds files from given path to the configmap. It is not recursive, to add all files in a directory, you need to call this function for each subdirectory. -### func \(\*ConfigMap\) [AppendFile]() +### func \(\*ConfigMap\) [AppendFile]() ```go func (c *ConfigMap) AppendFile(path string) error @@ -185,7 +185,7 @@ func (c *ConfigMap) AppendFile(path string) error -### func \(\*ConfigMap\) [Filename]() +### func \(\*ConfigMap\) [Filename]() ```go func (c *ConfigMap) Filename() string @@ -194,7 +194,7 @@ func (c *ConfigMap) Filename() string Filename returns the filename of the configmap. If the configmap is used for files, the filename contains the path. -### func \(\*ConfigMap\) [SetData]() +### func \(\*ConfigMap\) [SetData]() ```go func (c *ConfigMap) SetData(data map[string]string) @@ -203,7 +203,7 @@ func (c *ConfigMap) SetData(data map[string]string) SetData sets the data of the configmap. It replaces the entire data. -### func \(\*ConfigMap\) [Yaml]() +### func \(\*ConfigMap\) [Yaml]() ```go func (c *ConfigMap) Yaml() ([]byte, error) @@ -275,7 +275,7 @@ Yaml returns the yaml representation of the cronjob. Implements the Yaml interface. -## type [CronJobValue]() +## type [CronJobValue]() CronJobValue is a cronjob configuration that will be saved in values.yaml. @@ -376,7 +376,7 @@ func (d *Deployment) BindFrom(service types.ServiceConfig, binded *Deployment) -### func \(\*Deployment\) [BindMapFilesToContainer]() +### func \(\*Deployment\) [BindMapFilesToContainer]() ```go func (d *Deployment) BindMapFilesToContainer(service types.ServiceConfig, secrets []string, appName string) (*corev1.Container, int) @@ -403,7 +403,7 @@ func (d *Deployment) Filename() string Filename returns the filename of the deployment. -### func \(\*Deployment\) [MountExchangeVolumes]() +### func \(\*Deployment\) [MountExchangeVolumes]() ```go func (d *Deployment) MountExchangeVolumes() @@ -421,7 +421,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, sam SetEnvFrom sets the environment variables to a configmap. The configmap is created. -### func \(\*Deployment\) [Yaml]() +### func \(\*Deployment\) [Yaml]() ```go func (d *Deployment) Yaml() ([]byte, error) @@ -471,7 +471,7 @@ type HelmChart struct { ``` -### func [Generate]() +### func [Generate]() ```go func Generate(project *types.Project) (*HelmChart, error) @@ -509,7 +509,7 @@ func (chart *HelmChart) SaveTemplates(templateDir string) SaveTemplates the templates of the chart to the given directory. -## type [Ingress]() +## type [Ingress]() @@ -521,7 +521,7 @@ type Ingress struct { ``` -### func [NewIngress]() +### func [NewIngress]() ```go func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress @@ -530,7 +530,7 @@ func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress NewIngress creates a new Ingress from a compose service. -### func \(\*Ingress\) [Filename]() +### func \(\*Ingress\) [Filename]() ```go func (ingress *Ingress) Filename() string @@ -539,7 +539,7 @@ func (ingress *Ingress) Filename() string -### func \(\*Ingress\) [Yaml]() +### func \(\*Ingress\) [Yaml]() ```go func (ingress *Ingress) Yaml() ([]byte, error) @@ -548,7 +548,7 @@ func (ingress *Ingress) Yaml() ([]byte, error) -## type [IngressValue]() +## type [IngressValue]() IngressValue is a ingress configuration that will be saved in values.yaml. @@ -809,18 +809,19 @@ func (r *ServiceAccount) Yaml() ([]byte, error) -## type [TLS]() +## type [TLS]() ```go type TLS struct { - Enabled bool `yaml:"enabled"` + Enabled bool `yaml:"enabled"` + SecretName string `yaml:"secretName"` } ``` -## type [Value]() +## type [Value]() Value will be saved in values.yaml. It contains configuration for all deployment and services. @@ -840,7 +841,7 @@ type Value struct { ``` -### func [NewValue]() +### func [NewValue]() ```go func NewValue(service types.ServiceConfig, main ...bool) *Value @@ -851,7 +852,7 @@ NewValue creates a new Value from a compose service. The value contains the nece If \`main\` is true, the tag will be empty because it will be set in the helm chart appVersion. -### func \(\*Value\) [AddIngress]() +### func \(\*Value\) [AddIngress]() ```go func (v *Value) AddIngress(host, path string) @@ -860,7 +861,7 @@ func (v *Value) AddIngress(host, path string) -### func \(\*Value\) [AddPersistence]() +### func \(\*Value\) [AddPersistence]() ```go func (v *Value) AddPersistence(volumeName string) diff --git a/doc/docs/packages/generator/extrafiles.md b/doc/docs/packages/generator/extrafiles.md index cb56223..5c59366 100644 --- a/doc/docs/packages/generator/extrafiles.md +++ b/doc/docs/packages/generator/extrafiles.md @@ -17,7 +17,7 @@ func NotesFile(services []string) string NotesFile returns the content of the note.txt file. -## func [ReadMeFile]() +## func [ReadMeFile]() ```go func ReadMeFile(charname, description string, values map[string]any) string diff --git a/doc/docs/packages/generator/katenaryfile.md b/doc/docs/packages/generator/katenaryfile.md index 02ade60..3e1d02e 100644 --- a/doc/docs/packages/generator/katenaryfile.md +++ b/doc/docs/packages/generator/katenaryfile.md @@ -12,7 +12,7 @@ A katenary file, named "katenary.yml" or "katenary.yaml", is a file where you ca Formely, the file describe the same structure as in labels, and so that can be validated and completed by LSP. It also ease the use of katenary. -## func [GenerateSchema]() +## func [GenerateSchema]() ```go func GenerateSchema() string diff --git a/doc/docs/packages/generator/labels.md b/doc/docs/packages/generator/labels.md index 7e9bfbc..c990ce8 100644 --- a/doc/docs/packages/generator/labels.md +++ b/doc/docs/packages/generator/labels.md @@ -15,7 +15,7 @@ const KatenaryLabelPrefix = "katenary.v3" ``` -## func [GetLabelHelp]() +## func [GetLabelHelp]() ```go func GetLabelHelp(asMarkdown bool) string @@ -24,7 +24,7 @@ func GetLabelHelp(asMarkdown bool) string Generate the help for the labels. -## func [GetLabelHelpFor]() +## func [GetLabelHelpFor]() ```go func GetLabelHelpFor(labelname string, asMarkdown bool) string @@ -33,7 +33,7 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string GetLabelHelpFor returns the help for a specific label. -## func [GetLabelNames]() +## func [GetLabelNames]() ```go func GetLabelNames() []string @@ -42,7 +42,7 @@ func GetLabelNames() []string GetLabelNames returns a sorted list of all katenary label names. -## func [Prefix]() +## func [Prefix]() ```go func Prefix() string @@ -51,7 +51,7 @@ func Prefix() string -## type [Help]() +## type [Help]() Help is the documentation of a label. @@ -65,7 +65,7 @@ type Help struct { ``` -## type [Label]() +## type [Label]() Label is a katenary label to find in compose files. @@ -97,7 +97,7 @@ const ( ``` -### func [LabelName]() +### func [LabelName]() ```go func LabelName(name string) Label diff --git a/doc/docs/packages/update.md b/doc/docs/packages/update.md deleted file mode 100644 index ff63677..0000000 --- a/doc/docs/packages/update.md +++ /dev/null @@ -1,60 +0,0 @@ - - -# update - -```go -import "katenary/update" -``` - -Update package is used to check if a new version of katenary is available. - -## Variables - - - -```go -var ( - Version = "master" // reset by cmd/main.go -) -``` - - -## func [DownloadFile]() - -```go -func DownloadFile(url, exe string) error -``` - -DownloadFile will download a url to a local file. It also ensure that the file is executable. - - -## func [DownloadLatestVersion]() - -```go -func DownloadLatestVersion(assets []Asset) error -``` - -DownloadLatestVersion will download the latest version of katenary. - - -## type [Asset]() - -Asset is a github asset from release url. - -```go -type Asset struct { - Name string `json:"name"` - URL string `json:"browser_download_url"` -} -``` - - -### func [CheckLatestVersion]() - -```go -func CheckLatestVersion() (string, []Asset, error) -``` - -CheckLatestVersion check katenary latest version from release and propose to download it - -Generated by [gomarkdoc]() diff --git a/doc/docs/packages/utils.md b/doc/docs/packages/utils.md index 35a62ba..fe5e325 100644 --- a/doc/docs/packages/utils.md +++ b/doc/docs/packages/utils.md @@ -8,7 +8,7 @@ import "katenary/utils" Utils package provides some utility functions used in katenary. It defines some constants and functions used in the whole project. -## func [AsResourceName]() +## func [AsResourceName]() ```go func AsResourceName(name string) string @@ -35,7 +35,7 @@ func CountStartingSpaces(line string) int CountStartingSpaces counts the number of spaces at the beginning of a string. -## func [EncodeBasicYaml]() +## func [EncodeBasicYaml]() ```go func EncodeBasicYaml(data any) ([]byte, error) @@ -44,7 +44,7 @@ func EncodeBasicYaml(data any) ([]byte, error) EncodeBasicYaml encodes a basic yaml from an interface. -## func [FixedResourceName]() +## func [FixedResourceName]() ```go func FixedResourceName(name string) string @@ -146,7 +146,7 @@ GetContainerByName returns a container by name and its index in the array. ## func [Warn]() ```go -func Warn(msg ...interface{}) +func Warn(msg ...any) ``` Warn prints a warning message diff --git a/doc/mkdocs.yml b/doc/mkdocs.yml index 09d446d..cb24c58 100644 --- a/doc/mkdocs.yml +++ b/doc/mkdocs.yml @@ -54,7 +54,6 @@ nav: - Go Packages: - packages/cmd/katenary.md - packages/parser.md - - packages/update.md - packages/utils.md - Generator: - Index: packages/generator.md