feat(tests): Fixing linter problems

Using golangci-lint
This commit is contained in:
2025-06-04 14:29:13 +02:00
parent d77029b597
commit def5d097a4
13 changed files with 195 additions and 49 deletions

26
.golangci.yml Normal file
View File

@@ -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"

View File

@@ -10,6 +10,7 @@ import (
"katenary/generator/katenaryfile" "katenary/generator/katenaryfile"
"katenary/generator/labels" "katenary/generator/labels"
"katenary/utils" "katenary/utils"
"log"
"os" "os"
"strings" "strings"
@@ -24,7 +25,10 @@ Each [command] and subcommand has got an "help" and "--help" flag to show more i
func main() { func main() {
rootCmd := buildRootCmd() rootCmd := buildRootCmd()
rootCmd.Execute()
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
}
} }
func buildRootCmd() *cobra.Command { func buildRootCmd() *cobra.Command {
@@ -97,26 +101,26 @@ func generateCompletionCommand(name string) *cobra.Command {
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
Short: "Generates completion scripts", Short: "Generates completion scripts",
Long: fmt.Sprintf(completionHelp, name), Long: fmt.Sprintf(completionHelp, name),
Run: func(cmd *cobra.Command, args []string) { RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 { if len(args) == 0 {
cmd.Help() return cmd.Help()
return
} }
switch args[0] { switch args[0] {
case "bash": case "bash":
// get the bash version // get the bash version
if cmd.Flags().Changed("bash-v1") { if cmd.Flags().Changed("bash-v1") {
cmd.Root().GenBashCompletion(os.Stdout) return cmd.Root().GenBashCompletion(os.Stdout)
return
} }
cmd.Root().GenBashCompletionV2(os.Stdout, true) return cmd.Root().GenBashCompletionV2(os.Stdout, true)
case "zsh": case "zsh":
cmd.Root().GenZshCompletion(os.Stdout) return cmd.Root().GenZshCompletion(os.Stdout)
case "fish": case "fish":
cmd.Root().GenFishCompletion(os.Stdout, true) return cmd.Root().GenFishCompletion(os.Stdout, true)
case "powershell": case "powershell":
cmd.Root().GenPowerShellCompletion(os.Stdout) return cmd.Root().GenPowerShellCompletion(os.Stdout)
} }
return fmt.Errorf("unknown completion type: %s", args[0])
}, },
} }

View File

@@ -117,8 +117,13 @@ func (chart *HelmChart) SaveTemplates(templateDir string) {
os.Exit(1) os.Exit(1)
} }
f.Write(t) if _, err := f.Write(t); err != nil {
f.Close() 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 { func (chart *HelmChart) generateConfigMapsAndSecrets(project *types.Project) error {
appName := chart.Name appName := chart.Name
for _, s := range project.Services { for _, s := range project.Services {
if s.Environment == nil || len(s.Environment) == 0 { if len(s.Environment) == 0 {
continue continue
} }

View File

@@ -142,7 +142,9 @@ func NewConfigMapFromDirectory(service types.ServiceConfig, appName, path string
// cumulate the path to the WorkingDir // cumulate the path to the WorkingDir
path = filepath.Join(service.WorkingDir, path) path = filepath.Join(service.WorkingDir, path)
path = filepath.Clean(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 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 // read all files in the path and add them to the configmap
stat, err := os.Stat(path) stat, err := os.Stat(path)
if err != nil { 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 // recursively read all files in the path and add them to the configmap
if stat.IsDir() { 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 // read all files in the path and add them to the configmap
stat, err := os.Stat(path) stat, err := os.Stat(path)
if err != nil { 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 // recursively read all files in the path and add them to the configmap
if !stat.IsDir() { if !stat.IsDir() {

View File

@@ -113,7 +113,11 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) error {
fmt.Println(utils.IconFailure, err) fmt.Println(utils.IconFailure, err)
return 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 // repove the directory part of the docker-compose files
for i, f := range dockerComposeFile { for i, f := range dockerComposeFile {
@@ -626,8 +630,14 @@ func writeContent(path string, content []byte) {
fmt.Println(utils.IconFailure, err) fmt.Println(utils.IconFailure, err)
os.Exit(1) os.Exit(1)
} }
defer f.Close() defer func() {
f.Write(content) 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. // helmLint runs "helm lint" on the output directory.

View File

@@ -305,10 +305,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, sam
if len(service.Environment) == 0 { if len(service.Environment) == 0 {
return return
} }
inSamePod := false inSamePod := len(samePod) > 0 && samePod[0]
if len(samePod) > 0 && samePod[0] {
inSamePod = true
}
drop := []string{} drop := []string{}
secrets := []string{} secrets := []string{}
@@ -660,7 +657,9 @@ func (d *Deployment) appendFileToConfigMap(service types.ServiceConfig, appName
d.configMaps[pathname].mountPath = mp 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) { func (d *Deployment) bindVolumes(volume types.ServiceVolumeConfig, isSamePod bool, tobind map[string]bool, service types.ServiceConfig, appName string) {

View File

@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
_ "embed" _ "embed"
"fmt" "fmt"
"log"
"sort" "sort"
"strings" "strings"
"text/template" "text/template"
@@ -48,7 +49,9 @@ func ReadMeFile(charname, description string, values map[string]any) string {
vv := map[string]any{} vv := map[string]any{}
out, _ := yaml.Marshal(values) 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) result := make(map[string]string)
parseValues("", vv, result) parseValues("", vv, result)

View File

@@ -117,7 +117,10 @@ func Generate(project *types.Project) (*HelmChart, error) {
for _, s := range project.Services { for _, s := range project.Services {
for _, d := range s.GetDependencies() { for _, d := range s.GetDependencies() {
if dep, ok := deployments[d]; ok { 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 { } else {
log.Printf("service %[1]s depends on %[2]s, but %[2]s is not defined", s.Name, d) 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 // 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 // if the env-from label is set, we need to add the env vars from the configmap
// to the environment of the service // to the environment of the service
@@ -385,7 +390,7 @@ func samePodVolume(service types.ServiceConfig, v types.ServiceVolumeConfig, dep
return false return false
} }
if service.Volumes == nil || len(service.Volumes) == 0 { if len(service.Volumes) == 0 {
return false return false
} }

View File

@@ -75,24 +75,30 @@ func OverrideWithConfig(project *types.Project) {
if project.Services[i].Labels == nil { if project.Services[i].Labels == nil {
project.Services[i].Labels = make(map[string]string) 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 { if s, ok := services[name]; ok {
getLabelContent(s.MainApp, &project.Services[i], labels.LabelMainApp) mustGetLabelContent(s.MainApp, &project.Services[i], labels.LabelMainApp)
getLabelContent(s.Values, &project.Services[i], labels.LabelValues) mustGetLabelContent(s.Values, &project.Services[i], labels.LabelValues)
getLabelContent(s.Secrets, &project.Services[i], labels.LabelSecrets) mustGetLabelContent(s.Secrets, &project.Services[i], labels.LabelSecrets)
getLabelContent(s.Ports, &project.Services[i], labels.LabelPorts) mustGetLabelContent(s.Ports, &project.Services[i], labels.LabelPorts)
getLabelContent(s.Ingress, &project.Services[i], labels.LabelIngress) mustGetLabelContent(s.Ingress, &project.Services[i], labels.LabelIngress)
getLabelContent(s.HealthCheck, &project.Services[i], labels.LabelHealthCheck) mustGetLabelContent(s.HealthCheck, &project.Services[i], labels.LabelHealthCheck)
getLabelContent(s.SamePod, &project.Services[i], labels.LabelSamePod) mustGetLabelContent(s.SamePod, &project.Services[i], labels.LabelSamePod)
getLabelContent(s.Description, &project.Services[i], labels.LabelDescription) mustGetLabelContent(s.Description, &project.Services[i], labels.LabelDescription)
getLabelContent(s.Ignore, &project.Services[i], labels.LabelIgnore) mustGetLabelContent(s.Ignore, &project.Services[i], labels.LabelIgnore)
getLabelContent(s.Dependencies, &project.Services[i], labels.LabelDependencies) mustGetLabelContent(s.Dependencies, &project.Services[i], labels.LabelDependencies)
getLabelContent(s.ConfigMapFile, &project.Services[i], labels.LabelConfigMapFiles) mustGetLabelContent(s.ConfigMapFile, &project.Services[i], labels.LabelConfigMapFiles)
getLabelContent(s.MapEnv, &project.Services[i], labels.LabelMapEnv) mustGetLabelContent(s.MapEnv, &project.Services[i], labels.LabelMapEnv)
getLabelContent(s.CronJob, &project.Services[i], labels.LabelCronJob) mustGetLabelContent(s.CronJob, &project.Services[i], labels.LabelCronJob)
getLabelContent(s.EnvFrom, &project.Services[i], labels.LabelEnvFrom) mustGetLabelContent(s.EnvFrom, &project.Services[i], labels.LabelEnvFrom)
getLabelContent(s.ExchangeVolumes, &project.Services[i], labels.LabelExchangeVolume) mustGetLabelContent(s.ExchangeVolumes, &project.Services[i], labels.LabelExchangeVolume)
getLabelContent(s.ValuesFrom, &project.Services[i], labels.LabelValueFrom) mustGetLabelContent(s.ValuesFrom, &project.Services[i], labels.LabelValueFrom)
} }
} }
fmt.Println(utils.IconInfo, "Katenary file loaded successfully, the services are now configured.") fmt.Println(utils.IconInfo, "Katenary file loaded successfully, the services are now configured.")
@@ -155,5 +161,5 @@ func GenerateSchema() string {
return err.Error() return err.Error()
} }
return string(out.Bytes()) return out.String()
} }

View File

@@ -5,6 +5,7 @@ import (
_ "embed" _ "embed"
"fmt" "fmt"
"katenary/utils" "katenary/utils"
"log"
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
@@ -125,23 +126,30 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string {
} }
var buf bytes.Buffer 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 string
}{ }{
KatenaryPrefix: KatenaryLabelPrefix, KatenaryPrefix: KatenaryLabelPrefix,
}) })
if err != nil {
log.Fatalf("Error executing template: %v", err)
}
help.Long = buf.String() help.Long = buf.String()
buf.Reset() 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 string
}{ }{
KatenaryPrefix: KatenaryLabelPrefix, KatenaryPrefix: KatenaryLabelPrefix,
}) })
if err != nil {
log.Fatalf("Error executing template: %v", err)
}
help.Example = buf.String() help.Example = buf.String()
buf.Reset() 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 Name string
Help Help Help Help
KatenaryPrefix string KatenaryPrefix string
@@ -150,6 +158,9 @@ func GetLabelHelpFor(labelname string, asMarkdown bool) string {
Help: help, Help: help,
KatenaryPrefix: KatenaryLabelPrefix, KatenaryPrefix: KatenaryLabelPrefix,
}) })
if err != nil {
log.Fatalf("Error executing template: %v", err)
}
return buf.String() return buf.String()
} }

60
parser/main_test.go Normal file
View File

@@ -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")
}
}

13
utils/hash_test.go Normal file
View File

@@ -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")
}
}

View File

@@ -165,7 +165,9 @@ func Confirm(question string, icon ...Icon) bool {
fmt.Print(question + " [y/N] ") fmt.Print(question + " [y/N] ")
} }
var response string 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" return strings.ToLower(response) == "y"
} }