diff --git a/.gitea/workflows/go-test.yaml b/.gitea/workflows/go-test.yaml index 70df3a3..58f054d 100644 --- a/.gitea/workflows/go-test.yaml +++ b/.gitea/workflows/go-test.yaml @@ -33,7 +33,8 @@ jobs: - name: Launch Test run: | go vet ./... - go test -coverprofile=coverprofile.out -json -v ./... > gotest.json + go test -tags ci -coverprofile=coverprofile.out -v ./... + go test -tags ci -coverprofile=coverprofile.out -json -v ./... > gotest.json go tool cover -func=coverprofile.out # - uses: actions/upload-artifact@v4 - name: Upload artifact diff --git a/internal/generator/chart.go b/internal/generator/chart.go index 804c165..50dfc9a 100644 --- a/internal/generator/chart.go +++ b/internal/generator/chart.go @@ -11,6 +11,7 @@ import ( "katenary.io/internal/generator/labels" "katenary.io/internal/generator/labels/labelstructs" + "katenary.io/internal/logger" "katenary.io/internal/utils" "github.com/compose-spec/compose-go/types" @@ -77,36 +78,36 @@ func (chart *HelmChart) SaveTemplates(templateDir string) { // t = addModeline(t) kind := utils.GetKind(name) - var icon utils.Icon + var icon logger.Icon switch kind { case "deployment": - icon = utils.IconPackage + icon = logger.IconPackage case "service": - icon = utils.IconPlug + icon = logger.IconPlug case "ingress": - icon = utils.IconWorld + icon = logger.IconWorld case "volumeclaim": - icon = utils.IconCabinet + icon = logger.IconCabinet case "configmap": - icon = utils.IconConfig + icon = logger.IconConfig case "secret": - icon = utils.IconSecret + icon = logger.IconSecret default: - icon = utils.IconInfo + icon = logger.IconInfo } servicename := template.Servicename if err := os.MkdirAll(filepath.Join(templateDir, servicename), utils.DirectoryPermission); err != nil { - fmt.Println(utils.IconFailure, err) + logger.Failure(err.Error()) os.Exit(1) } - fmt.Println(icon, "Creating", kind, servicename) + logger.Log(icon, "Creating ", kind, " ", name) // if the name is a path, create the directory if strings.Contains(name, string(filepath.Separator)) { name = filepath.Join(templateDir, name) err := os.MkdirAll(filepath.Dir(name), utils.DirectoryPermission) if err != nil { - fmt.Println(utils.IconFailure, err) + logger.Failure(err.Error()) os.Exit(1) } } else { @@ -116,14 +117,14 @@ func (chart *HelmChart) SaveTemplates(templateDir string) { } f, err := os.Create(name) if err != nil { - fmt.Println(utils.IconFailure, err) + fmt.Println(logger.IconFailure, err) os.Exit(1) } defer f.Close() if _, err := f.Write(t); err != nil { - log.Fatal("error writing template file:", err) + logger.Failure("error wrting template file: ", err.Error()) + os.Exit(1) } - } } @@ -144,14 +145,15 @@ func (chart *HelmChart) generateConfigMapsAndSecrets(project *types.Project) err if v, ok := s.Labels[labels.LabelSecrets]; ok { list, err := labelstructs.SecretsFrom(v) if err != nil { - log.Fatal("error unmarshaling secrets label:", err) + logger.Failure("error unmarshaling secrets label:", err) + os.Exit(1) } for _, secret := range list { if secret == "" { continue } if _, ok := s.Environment[secret]; !ok { - fmt.Printf("%s secret %s not found in environment", utils.IconWarning, secret) + fmt.Printf("%s secret %s not found in environment", logger.IconWarning, secret) continue } secretsVar[secret] = s.Environment[secret] @@ -195,7 +197,7 @@ func (chart *HelmChart) generateDeployment(service types.ServiceConfig, deployme // isgnored service if isIgnored(service) { - fmt.Printf("%s Ignoring service %s\n", utils.IconInfo, service.Name) + logger.Info("Ignoring service ", service.Name) return nil } @@ -305,7 +307,7 @@ func (chart *HelmChart) setDependencies(service types.ServiceConfig) (bool, erro } for _, dep := range d { - fmt.Printf("%s Adding dependency to %s\n", utils.IconDependency, dep.Name) + logger.Log(logger.IconDependency, "Adding dependency to ", dep.Name) chart.Dependencies = append(chart.Dependencies, dep) name := dep.Name if dep.Alias != "" { diff --git a/internal/generator/configMap.go b/internal/generator/configMap.go index ca7438b..b8a497f 100644 --- a/internal/generator/configMap.go +++ b/internal/generator/configMap.go @@ -11,6 +11,7 @@ import ( "katenary.io/internal/generator/labels" "katenary.io/internal/generator/labels/labelstructs" + "katenary.io/internal/logger" "katenary.io/internal/utils" "github.com/compose-spec/compose-go/types" @@ -178,7 +179,7 @@ func (c *ConfigMap) AppendDir(path string) error { } for _, file := range files { if file.IsDir() { - utils.Warn("Subdirectories are ignored for the moment, skipping", filepath.Join(path, file.Name())) + logger.Warn("Subdirectories are ignored for the moment, skipping", filepath.Join(path, file.Name())) continue } path := filepath.Join(path, file.Name()) diff --git a/internal/generator/converter.go b/internal/generator/converter.go index c0243e1..6526b0f 100644 --- a/internal/generator/converter.go +++ b/internal/generator/converter.go @@ -16,6 +16,7 @@ import ( "katenary.io/internal/generator/katenaryfile" "katenary.io/internal/generator/labels" "katenary.io/internal/generator/labels/labelstructs" + "katenary.io/internal/logger" "katenary.io/internal/parser" "katenary.io/internal/utils" @@ -111,12 +112,13 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) error { currentDir, _ := os.Getwd() // go to the root of the project if err := os.Chdir(filepath.Dir(dockerComposeFile[0])); err != nil { - fmt.Println(utils.IconFailure, err) + logger.Failure(err.Error()) return err } defer func() { if err := os.Chdir(currentDir); err != nil { // after the generation, go back to the original directory - log.Fatal(err) + logger.Failure(err.Error()) + os.Exit(1) } }() @@ -134,7 +136,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) error { // check older version of labels if err := checkOldLabels(project); err != nil { - fmt.Println(utils.IconFailure, err) + logger.Failure(err.Error()) return err } @@ -147,7 +149,7 @@ func Convert(config ConvertOptions, dockerComposeFile ...string) error { if _, err := os.Stat(config.OutputDir); err == nil { overwrite := utils.Confirm( "The chart directory "+config.OutputDir+" already exists, do you want to overwrite it?", - utils.IconWarning, + logger.IconWarning, ) if !overwrite { fmt.Println("Aborting") @@ -399,7 +401,7 @@ func addMainTagAppDoc(values []byte, project *types.Project) []byte { } else if v == "false" || v == "no" || v == "0" { continue } else { - fmt.Printf("%s Adding main tag app doc %s\n", utils.IconConfig, service.Name) + logger.Log(logger.IconConfig, "Adding main tag app doc for service", service.Name) } lines = addMainAppDoc(lines, service) @@ -579,15 +581,15 @@ func buildValues(chart *HelmChart, project *types.Project, valuesPath string) { func callHelmUpdate(config ConvertOptions) { executeAndHandleError := func(fn func(ConvertOptions) error, config ConvertOptions, message string) { if err := fn(config); err != nil { - fmt.Println(utils.IconFailure, err) + logger.Failure("Helm command failed, please check the output above", err.Error()) os.Exit(1) } - fmt.Println(utils.IconSuccess, message) + logger.Success(message) } if config.HelmUpdate { executeAndHandleError(helmUpdate, config, "Helm dependencies updated") executeAndHandleError(helmLint, config, "Helm chart linted") - fmt.Println(utils.IconSuccess, "Helm chart created successfully") + logger.Success("Helm chart created successfully") } } @@ -627,7 +629,7 @@ func removeUnwantedLines(values []byte) []byte { func writeContent(path string, content []byte) { f, err := os.Create(path) if err != nil { - fmt.Println(utils.IconFailure, err) + logger.Failure("Cannot create file "+path, err.Error()) os.Exit(1) } defer f.Close() @@ -640,10 +642,10 @@ func writeContent(path string, content []byte) { // helmLint runs "helm lint" on the output directory. func helmLint(config ConvertOptions) error { - fmt.Println(utils.IconInfo, "Linting...") + logger.Info("Linting...") helm, err := exec.LookPath("helm") if err != nil { - fmt.Println(utils.IconFailure, err) + logger.Failure("Helm is not installed or not in your PATH", err.Error()) os.Exit(1) } cmd := exec.Command(helm, "lint", config.OutputDir) @@ -655,10 +657,10 @@ func helmLint(config ConvertOptions) error { // helmUpdate runs "helm dependency update" on the output directory. func helmUpdate(config ConvertOptions) error { // lookup for "helm" binary - fmt.Println(utils.IconInfo, "Updating helm dependencies...") + logger.Info("Updating helm dependencies...") helm, err := exec.LookPath("helm") if err != nil { - fmt.Println(utils.IconFailure, err) + fmt.Println(logger.IconFailure, err) os.Exit(1) } // run "helm dependency update" diff --git a/internal/generator/deployment.go b/internal/generator/deployment.go index 675bbbd..a1fc677 100644 --- a/internal/generator/deployment.go +++ b/internal/generator/deployment.go @@ -11,6 +11,7 @@ import ( "katenary.io/internal/generator/labels" "katenary.io/internal/generator/labels/labelstructs" + "katenary.io/internal/logger" "katenary.io/internal/utils" "github.com/compose-spec/compose-go/types" @@ -119,7 +120,7 @@ func (d *Deployment) AddContainer(service types.ServiceConfig) { for _, port := range service.Ports { name := utils.GetServiceNameByPort(int(port.Target)) if name == "" { - utils.Warn("Port name not found for port ", port.Target, " in service ", service.Name, ". Using port number instead") + logger.Warn("Port name not found for port ", port.Target, " in service ", service.Name, ". Using port number instead") name = fmt.Sprintf("port-%d", port.Target) } ports = append(ports, corev1.ContainerPort{ @@ -274,7 +275,7 @@ func (d *Deployment) DependsOn(to *Deployment, servicename string) error { for _, container := range to.Spec.Template.Spec.Containers { commands := []string{} if len(container.Ports) == 0 { - utils.Warn("No ports found for service ", + logger.Warn("No ports found for service ", servicename, ". You should declare a port in the service or use "+ labels.LabelPorts+ @@ -340,7 +341,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, sam _, ok := service.Environment[secret] if !ok { drop = append(drop, secret) - utils.Warn("Secret " + secret + " not found in service " + service.Name + " - skpped") + logger.Warn("Secret " + secret + " not found in service " + service.Name + " - skpped") continue } secrets = append(secrets, secret) @@ -357,7 +358,7 @@ func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, sam val, ok := service.Environment[value] if !ok { drop = append(drop, value) - utils.Warn("Environment variable " + value + " not found in service " + service.Name + " - skpped") + logger.Warn("Environment variable " + value + " not found in service " + service.Name + " - skpped") continue } if d.chart.Values[service.Name].(*Value).Environment == nil { @@ -413,7 +414,7 @@ func (d *Deployment) BindMapFilesToContainer(service types.ServiceConfig, secret container, index := utils.GetContainerByName(service.ContainerName, d.Spec.Template.Spec.Containers) if container == nil { - utils.Warn("Container not found for service " + service.Name) + logger.Warn("Container not found for service " + service.Name) return nil, -1 } @@ -677,7 +678,7 @@ func (d *Deployment) bindVolumes(volume types.ServiceVolumeConfig, isSamePod boo }(d, container, index) if _, found := tobind[volume.Source]; !isSamePod && volume.Type == "bind" && !found { - utils.Warn( + logger.Warn( "Bind volumes are not supported yet, " + "excepting for those declared as " + labels.LabelConfigMapFiles + @@ -688,7 +689,7 @@ func (d *Deployment) bindVolumes(volume types.ServiceVolumeConfig, isSamePod boo } if container == nil { - utils.Warn("Container not found for volume", volume.Source) + logger.Warn("Container not found for volume", volume.Source) return } diff --git a/internal/generator/extrafiles/readme_test.go b/internal/generator/extrafiles/readme_test.go index e819872..b386e59 100644 --- a/internal/generator/extrafiles/readme_test.go +++ b/internal/generator/extrafiles/readme_test.go @@ -15,7 +15,6 @@ func TestReadMeFile_Basic(t *testing.T) { } 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 { diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 6c9f48f..7548e03 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -233,7 +233,6 @@ func fixResourceNames(project *types.Project) error { return err } for varname, bind := range *vf { - log.Printf("service %s, varname %s, bind %s", service.Name, varname, bind) bind := strings.ReplaceAll(bind, service.Name, fixed) (*vf)[varname] = bind } diff --git a/internal/generator/katenaryfile/main.go b/internal/generator/katenaryfile/main.go index de120c3..ed72216 100644 --- a/internal/generator/katenaryfile/main.go +++ b/internal/generator/katenaryfile/main.go @@ -3,7 +3,6 @@ package katenaryfile import ( "bytes" "encoding/json" - "fmt" "log" "os" "reflect" @@ -11,7 +10,7 @@ import ( "katenary.io/internal/generator/labels" "katenary.io/internal/generator/labels/labelstructs" - "katenary.io/internal/utils" + "katenary.io/internal/logger" "github.com/compose-spec/compose-go/types" "github.com/invopop/jsonschema" @@ -60,7 +59,7 @@ func OverrideWithConfig(project *types.Project) { // no katenary file found return } - fmt.Println(utils.IconInfo, "Using katenary file", yamlFile) + logger.Info("Using katenary file", yamlFile) services := make(map[string]Service) fp, err := os.Open(yamlFile) @@ -102,7 +101,7 @@ func OverrideWithConfig(project *types.Project) { mustGetLabelContent(s.ValuesFrom, &project.Services[i], labels.LabelValuesFrom) } } - fmt.Println(utils.IconInfo, "Katenary file loaded successfully, the services are now configured.") + logger.Info("Katenary file loaded successfully, the services are now configured.") } func getLabelContent(o any, service *types.ServiceConfig, labelName string) error { diff --git a/internal/generator/katenaryfile/main_test.go b/internal/generator/katenaryfile/main_test.go index 7df48a5..bef7da4 100644 --- a/internal/generator/katenaryfile/main_test.go +++ b/internal/generator/katenaryfile/main_test.go @@ -1,7 +1,6 @@ package katenaryfile import ( - "log" "os" "path/filepath" "testing" @@ -39,18 +38,15 @@ webapp: composeFile := filepath.Join(tmpDir, "compose.yaml") katenaryFile := filepath.Join(tmpDir, "katenary.yaml") - os.MkdirAll(tmpDir, 0755) - if err := os.WriteFile(composeFile, []byte(composeContent), 0644); err != nil { + os.MkdirAll(tmpDir, 0o755) + if err := os.WriteFile(composeFile, []byte(composeContent), 0o644); err != nil { t.Log(err) } - if err := os.WriteFile(katenaryFile, []byte(katenaryfileContent), 0644); err != nil { + if err := os.WriteFile(katenaryFile, []byte(katenaryfileContent), 0o644); err != nil { t.Log(err) } defer os.RemoveAll(tmpDir) - c, _ := os.ReadFile(composeFile) - log.Println(string(c)) - // chand dir to this directory os.Chdir(tmpDir) options, _ := cli.NewProjectOptions(nil, @@ -92,18 +88,15 @@ webapp: composeFile := filepath.Join(tmpDir, "compose.yaml") katenaryFile := filepath.Join(tmpDir, "katenary.yaml") - os.MkdirAll(tmpDir, 0755) - if err := os.WriteFile(composeFile, []byte(composeContent), 0644); err != nil { + os.MkdirAll(tmpDir, 0o755) + if err := os.WriteFile(composeFile, []byte(composeContent), 0o644); err != nil { t.Log(err) } - if err := os.WriteFile(katenaryFile, []byte(katenaryfileContent), 0644); err != nil { + if err := os.WriteFile(katenaryFile, []byte(katenaryfileContent), 0o644); err != nil { t.Log(err) } defer os.RemoveAll(tmpDir) - c, _ := os.ReadFile(composeFile) - log.Println(string(c)) - // chand dir to this directory os.Chdir(tmpDir) options, _ := cli.NewProjectOptions(nil, @@ -150,18 +143,15 @@ webapp: composeFile := filepath.Join(tmpDir, "compose.yaml") katenaryFile := filepath.Join(tmpDir, "katenary.yaml") - os.MkdirAll(tmpDir, 0755) - if err := os.WriteFile(composeFile, []byte(composeContent), 0644); err != nil { + os.MkdirAll(tmpDir, 0o755) + if err := os.WriteFile(composeFile, []byte(composeContent), 0o644); err != nil { t.Log(err) } - if err := os.WriteFile(katenaryFile, []byte(katenaryfileContent), 0644); err != nil { + if err := os.WriteFile(katenaryFile, []byte(katenaryfileContent), 0o644); err != nil { t.Log(err) } defer os.RemoveAll(tmpDir) - c, _ := os.ReadFile(composeFile) - log.Println(string(c)) - // chand dir to this directory os.Chdir(tmpDir) options, _ := cli.NewProjectOptions(nil, diff --git a/internal/generator/volume_test.go b/internal/generator/volume_test.go index 8357504..53c1614 100644 --- a/internal/generator/volume_test.go +++ b/internal/generator/volume_test.go @@ -5,7 +5,6 @@ import ( "image" "image/color" "image/png" - "log" "os" "path/filepath" "testing" @@ -173,7 +172,6 @@ services: ` composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix) tmpDir := setup(composeFile) - log.Println(tmpDir) defer teardown(tmpDir) os.Mkdir(filepath.Join(tmpDir, "images"), utils.DirectoryPermission) @@ -243,7 +241,6 @@ services: ` composeFile = fmt.Sprintf(composeFile, labels.KatenaryLabelPrefix) tmpDir := setup(composeFile) - log.Println(tmpDir) defer teardown(tmpDir) os.Mkdir(filepath.Join(tmpDir, "images"), utils.DirectoryPermission) diff --git a/internal/utils/icons.go b/internal/logger/logger.go similarity index 53% rename from internal/utils/icons.go rename to internal/logger/logger.go index 2a2a38d..0cc0993 100644 --- a/internal/utils/icons.go +++ b/internal/logger/logger.go @@ -1,6 +1,5 @@ -package utils - -import "fmt" +// Package logger provides simple logging functions with icons and colors. +package logger // Icon is a unicode icon type Icon string @@ -21,11 +20,28 @@ const ( IconDependency Icon = "🔗" ) +const reset = "\033[0m" + +func Info(msg ...any) { + message("", IconInfo, msg...) +} + // Warn prints a warning message func Warn(msg ...any) { orange := "\033[38;5;214m" - reset := "\033[0m" - fmt.Print(IconWarning, orange, " ") - fmt.Print(msg...) - fmt.Println(reset) + message(orange, IconWarning, msg...) +} + +func Success(msg ...any) { + green := "\033[38;5;34m" + message(green, IconSuccess, msg...) +} + +func Failure(msg ...any) { + red := "\033[38;5;196m" + message(red, IconFailure, msg...) +} + +func Log(icon Icon, msg ...any) { + message("", icon, msg...) } diff --git a/internal/logger/printer.go b/internal/logger/printer.go new file mode 100644 index 0000000..699f6d5 --- /dev/null +++ b/internal/logger/printer.go @@ -0,0 +1,12 @@ +//go:build !ci +// +build !ci + +package logger + +import "fmt" + +func message(color string, icon Icon, msg ...any) { + fmt.Print(icon, " ", color) + fmt.Print(msg...) + fmt.Println(reset) +} diff --git a/internal/logger/printer_ci.go b/internal/logger/printer_ci.go new file mode 100644 index 0000000..abeeb66 --- /dev/null +++ b/internal/logger/printer_ci.go @@ -0,0 +1,9 @@ +//go:build ci +// +build ci + +package logger + +// CI should be no-op +func message(color string, icon Icon, msg ...any) { + // no-op +} diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 9f082f3..4e6030b 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -12,6 +12,7 @@ import ( "github.com/thediveo/netdb" "gopkg.in/yaml.v3" corev1 "k8s.io/api/core/v1" + "katenary.io/internal/logger" ) // DirectoryPermission is the default values for permissions apply to created directories. @@ -64,7 +65,7 @@ func GetKind(path string) (kind string) { } else { kind = strings.Split(path, ".")[1] } - return + return kind } // Wrap wraps a string with a string above and below. It will respect the indentation of the src string. @@ -161,7 +162,7 @@ func WordWrap(text string, lineWidth int) string { } // Confirm asks a question and returns true if the answer is y. -func Confirm(question string, icon ...Icon) bool { +func Confirm(question string, icon ...logger.Icon) bool { if len(icon) > 0 { fmt.Printf("%s %s [y/N] ", icon[0], question) } else {