From a066ee042fc3f43b777f11826b8a7e18d3b887eb Mon Sep 17 00:00:00 2001 From: "andrzej.janczak" Date: Thu, 8 May 2025 12:54:37 +0200 Subject: [PATCH 1/6] fix: app starting on windows --- .cursor/rules/cursor.mdc | 1 + plugins/runtime-utils.go | 4 ++-- plugins/tool-utils.go | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.cursor/rules/cursor.mdc b/.cursor/rules/cursor.mdc index e3af94ec..65eb3b75 100644 --- a/.cursor/rules/cursor.mdc +++ b/.cursor/rules/cursor.mdc @@ -7,6 +7,7 @@ alwaysApply: true # Your rule content ## Key Rules +- use fulnames like e.g. feature, instaed of feat - run go build after each code modification to see if app compiles ## Code Style Guidelines diff --git a/plugins/runtime-utils.go b/plugins/runtime-utils.go index 23ce4a45..dab24c9c 100644 --- a/plugins/runtime-utils.go +++ b/plugins/runtime-utils.go @@ -5,7 +5,6 @@ import ( "embed" "fmt" "path" - "path/filepath" "runtime" "strings" "text/template" @@ -134,7 +133,8 @@ func processRuntime(config RuntimeConfig, runtimesDir string) (*RuntimeInfo, err // LoadPlugin loads a plugin configuration from the specified plugin directory func loadPlugin(runtimeName string) (*runtimePlugin, error) { - pluginPath := filepath.Join("runtimes", runtimeName, "plugin.yaml") + // Always use forward slashes for embedded filesystem paths (for windows support) + pluginPath := fmt.Sprintf("runtimes/%s/plugin.yaml", runtimeName) // Read from embedded filesystem data, err := pluginsFS.ReadFile(pluginPath) diff --git a/plugins/tool-utils.go b/plugins/tool-utils.go index 2d96fae8..05c8d8cf 100644 --- a/plugins/tool-utils.go +++ b/plugins/tool-utils.go @@ -114,8 +114,8 @@ func ProcessTools(configs []ToolConfig, toolDir string, runtimes map[string]*Run result := make(map[string]*ToolInfo) for _, config := range configs { - // Load the tool plugin - pluginPath := filepath.Join("tools", config.Name, "plugin.yaml") + // Load the tool plugin - always use forward slashes for embedded filesystem paths (for windows support) + pluginPath := fmt.Sprintf("tools/%s/plugin.yaml", config.Name) // Read from embedded filesystem data, err := toolsFS.ReadFile(pluginPath) @@ -321,7 +321,8 @@ func GetSupportedTools() (map[string]struct{}, error) { } toolName := entry.Name() - pluginPath := filepath.Join("tools", toolName, "plugin.yaml") + // Always use forward slashes for embedded filesystem paths + pluginPath := fmt.Sprintf("tools/%s/plugin.yaml", toolName) // Check if plugin.yaml exists _, err := toolsFS.ReadFile(pluginPath) From 08160cb6c0ad61822d4da8cd50f0761dc9375c12 Mon Sep 17 00:00:00 2001 From: "andrzej.janczak" Date: Thu, 8 May 2025 13:13:57 +0200 Subject: [PATCH 2/6] WIP --- cli-v2.go | 6 +- cmd/root.go | 3 +- config/runtimes-installer.go | 58 +++++++++++++++-- config/tools-installer.go | 119 +++++++++++++++++++++++++++++++---- utils/logger/logger.go | 6 +- 5 files changed, 166 insertions(+), 26 deletions(-) diff --git a/cli-v2.go b/cli-v2.go index 26e28639..5342dd95 100644 --- a/cli-v2.go +++ b/cli-v2.go @@ -7,6 +7,7 @@ import ( "codacy/cli-v2/utils/logger" "fmt" "os" + "path/filepath" "github.com/sirupsen/logrus" ) @@ -15,8 +16,9 @@ func main() { // Initialize config global object config.Init() - // Initialize logger - if err := logger.Initialize(&config.Config); err != nil { + // Initialize logger with the logs directory + logsDir := filepath.Join(config.Config.LocalCodacyDirectory(), "logs") + if err := logger.Initialize(logsDir); err != nil { fmt.Printf("Failed to initialize logger: %v\n", err) } diff --git a/cmd/root.go b/cmd/root.go index 76f2bc83..f31f6d5b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -19,7 +19,8 @@ var rootCmd = &cobra.Command{ Example: getExampleText(), PersistentPreRun: func(cmd *cobra.Command, args []string) { // Initialize logger before any command runs - if err := logger.Initialize(&config.Config); err != nil { + logsDir := filepath.Join(config.Config.LocalCodacyDirectory(), "logs") + if err := logger.Initialize(logsDir); err != nil { fmt.Printf("Warning: Failed to initialize file logger: %v\n", err) } }, diff --git a/config/runtimes-installer.go b/config/runtimes-installer.go index bb632f6e..fd98f632 100644 --- a/config/runtimes-installer.go +++ b/config/runtimes-installer.go @@ -3,20 +3,44 @@ package config import ( "codacy/cli-v2/plugins" "codacy/cli-v2/utils" + "codacy/cli-v2/utils/logger" "fmt" - "log" "os" "path/filepath" "strings" + + "github.com/sirupsen/logrus" ) // InstallRuntimes installs all runtimes defined in the configuration func InstallRuntimes(config *ConfigType) error { + var failedRuntimes []string + for name, runtimeInfo := range config.Runtimes() { + logger.Info("Starting runtime installation", logrus.Fields{ + "runtime": name, + "version": runtimeInfo.Version, + }) + err := InstallRuntime(name, runtimeInfo) if err != nil { - return fmt.Errorf("failed to install runtime %s: %w", name, err) + logger.Error("Failed to install runtime", logrus.Fields{ + "runtime": name, + "version": runtimeInfo.Version, + "error": err.Error(), + }) + failedRuntimes = append(failedRuntimes, name) + continue } + + logger.Info("Successfully installed runtime", logrus.Fields{ + "runtime": name, + "version": runtimeInfo.Version, + }) + } + + if len(failedRuntimes) > 0 { + return fmt.Errorf("failed to install the following runtimes: %v", failedRuntimes) } return nil } @@ -25,6 +49,10 @@ func InstallRuntimes(config *ConfigType) error { func InstallRuntime(name string, runtimeInfo *plugins.RuntimeInfo) error { // Check if the runtime is already installed if isRuntimeInstalled(runtimeInfo) { + logger.Info("Runtime already installed", logrus.Fields{ + "runtime": name, + "version": runtimeInfo.Version, + }) fmt.Printf("Runtime %s v%s is already installed\n", name, runtimeInfo.Version) return nil } @@ -67,7 +95,12 @@ func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error { _, err := os.Stat(downloadPath) if os.IsNotExist(err) { // Download the file - // log.Printf("Downloading %s v%s...\n", runtimeInfo.Name, runtimeInfo.Version) + logger.Debug("Downloading runtime", logrus.Fields{ + "runtime": runtimeInfo.Name, + "version": runtimeInfo.Version, + "downloadURL": runtimeInfo.DownloadURL, + "downloadPath": downloadPath, + }) downloadPath, err = utils.DownloadFile(runtimeInfo.DownloadURL, Config.RuntimesDirectory()) if err != nil { return fmt.Errorf("failed to download runtime: %w", err) @@ -75,7 +108,11 @@ func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error { } else if err != nil { return fmt.Errorf("error checking for existing download: %w", err) } else { - log.Printf("Using existing download for %s v%s\n", runtimeInfo.Name, runtimeInfo.Version) + logger.Debug("Using existing runtime download", logrus.Fields{ + "runtime": runtimeInfo.Name, + "version": runtimeInfo.Version, + "downloadPath": downloadPath, + }) } // Open the downloaded file @@ -86,7 +123,13 @@ func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error { defer file.Close() // Extract based on file extension - // log.Printf("Extracting %s v%s...\n", runtimeInfo.Name, runtimeInfo.Version) + logger.Debug("Extracting runtime", logrus.Fields{ + "runtime": runtimeInfo.Name, + "version": runtimeInfo.Version, + "fileName": fileName, + "extractDirectory": Config.RuntimesDirectory(), + }) + if strings.HasSuffix(fileName, ".zip") { err = utils.ExtractZip(file.Name(), Config.RuntimesDirectory()) } else { @@ -97,6 +140,9 @@ func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error { return fmt.Errorf("failed to extract runtime: %w", err) } - log.Printf("Successfully installed %s v%s\n", runtimeInfo.Name, runtimeInfo.Version) + logger.Debug("Runtime extraction completed", logrus.Fields{ + "runtime": runtimeInfo.Name, + "version": runtimeInfo.Version, + }) return nil } diff --git a/config/tools-installer.go b/config/tools-installer.go index 3f53f863..03300843 100644 --- a/config/tools-installer.go +++ b/config/tools-installer.go @@ -4,8 +4,8 @@ import ( "bytes" "codacy/cli-v2/plugins" "codacy/cli-v2/utils" + "codacy/cli-v2/utils/logger" "fmt" - "log" "os" "os/exec" "path/filepath" @@ -15,14 +15,39 @@ import ( // InstallTools installs all tools defined in the configuration func InstallTools(config *ConfigType, registry string) error { + var failedTools []string + for name, toolInfo := range config.Tools() { + logger.Info("Starting tool installation", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + "runtime": toolInfo.Runtime, + }) + fmt.Printf("Installing tool: %s v%s...\n", name, toolInfo.Version) err := InstallTool(name, toolInfo, registry) if err != nil { - return fmt.Errorf("failed to install tool %s: %w", name, err) + logger.Error("Failed to install tool", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + "runtime": toolInfo.Runtime, + "error": err.Error(), + }) + failedTools = append(failedTools, name) + continue } + + logger.Info("Successfully installed tool", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + "runtime": toolInfo.Runtime, + }) fmt.Printf("Successfully installed %s v%s\n", name, toolInfo.Version) } + + if len(failedTools) > 0 { + return fmt.Errorf("failed to install the following tools: %v", failedTools) + } return nil } @@ -30,12 +55,16 @@ func InstallTools(config *ConfigType, registry string) error { func InstallTool(name string, toolInfo *plugins.ToolInfo, registry string) error { // Check if the tool is already installed if isToolInstalled(toolInfo) { + logger.Info("Tool already installed", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + "runtime": toolInfo.Runtime, + }) fmt.Printf("Tool %s v%s is already installed\n", name, toolInfo.Version) return nil } // Make sure the installation directory exists - err := os.MkdirAll(toolInfo.InstallDir, 0755) if err != nil { return fmt.Errorf("failed to create installation directory: %w", err) @@ -44,17 +73,31 @@ func InstallTool(name string, toolInfo *plugins.ToolInfo, registry string) error // Check if this is a download-based tool (like trivy) or a runtime-based tool (like eslint) if toolInfo.DownloadURL != "" { // This is a download-based tool + logger.Debug("Installing download-based tool", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + "downloadURL": toolInfo.DownloadURL, + }) fmt.Printf("Downloading %s...\n", name) return installDownloadBasedTool(toolInfo) } // Handle Python tools differently if toolInfo.Runtime == "python" { + logger.Debug("Installing Python tool", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + }) fmt.Printf("Installing Python tool %s...\n", name) return installPythonTool(name, toolInfo) } // For runtime-based tools + logger.Debug("Installing runtime-based tool", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + "runtime": toolInfo.Runtime, + }) fmt.Printf("Installing %s using %s runtime...\n", name, toolInfo.Runtime) return installRuntimeTool(name, toolInfo, registry) } @@ -88,7 +131,12 @@ func installRuntimeTool(name string, toolInfo *plugins.ToolInfo, registry string return fmt.Errorf("failed to prepare registry command: %w", err) } - log.Printf("Setting registry...\n %s %s\n", packageManagerBinary, regCmd) + logger.Debug("Setting registry", map[string]interface{}{ + "tool": name, + "packageManager": packageManagerName, + "packageManagerBin": packageManagerBinary, + "command": regCmd, + }) if regCmd != "" { registryCmd := exec.Command(packageManagerBinary, strings.Split(regCmd, " ")...) @@ -104,16 +152,25 @@ func installRuntimeTool(name string, toolInfo *plugins.ToolInfo, registry string return fmt.Errorf("failed to prepare install command: %w", err) } + logger.Debug("Installing tool", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + "packageManager": packageManagerName, + "packageManagerBin": packageManagerBinary, + "command": installCmd, + }) + // Execute the installation command using the package manager cmd := exec.Command(packageManagerBinary, strings.Split(installCmd, " ")...) - - log.Printf("Installing %s v%s...\n", toolInfo.Name, toolInfo.Version) output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to install tool: %s: %w", string(output), err) } - log.Printf("Successfully installed %s v%s\n", toolInfo.Name, toolInfo.Version) + logger.Debug("Tool installation completed", map[string]interface{}{ + "tool": name, + "version": toolInfo.Version, + }) return nil } @@ -127,7 +184,12 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { _, err := os.Stat(downloadPath) if os.IsNotExist(err) { // Download the file - log.Printf("Downloading %s v%s...\n", toolInfo.Name, toolInfo.Version) + logger.Debug("Downloading tool", map[string]interface{}{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + "downloadURL": toolInfo.DownloadURL, + "downloadPath": downloadPath, + }) downloadPath, err = utils.DownloadFile(toolInfo.DownloadURL, Config.ToolsDirectory()) if err != nil { return fmt.Errorf("failed to download tool: %w", err) @@ -135,7 +197,11 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { } else if err != nil { return fmt.Errorf("error checking for existing download: %w", err) } else { - log.Printf("Using existing download for %s v%s\n", toolInfo.Name, toolInfo.Version) + logger.Debug("Using existing tool download", map[string]interface{}{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + "downloadPath": downloadPath, + }) } // Open the downloaded file @@ -152,7 +218,13 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { } // Extract directly to the installation directory - log.Printf("Extracting %s v%s...\n", toolInfo.Name, toolInfo.Version) + logger.Debug("Extracting tool", map[string]interface{}{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + "fileName": fileName, + "extractDirectory": toolInfo.InstallDir, + }) + if strings.HasSuffix(fileName, ".zip") { err = utils.ExtractZip(file.Name(), toolInfo.InstallDir) } else { @@ -171,12 +243,18 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { } } - log.Printf("Successfully installed %s v%s\n", toolInfo.Name, toolInfo.Version) + logger.Debug("Tool extraction completed", map[string]interface{}{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + }) return nil } func installPythonTool(name string, toolInfo *plugins.ToolInfo) error { - log.Printf("Installing %s v%s...\n", toolInfo.Name, toolInfo.Version) + logger.Debug("Starting Python tool installation", map[string]interface{}{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + }) runtimeInfo, ok := Config.Runtimes()[toolInfo.Runtime] if !ok { @@ -189,6 +267,12 @@ func installPythonTool(name string, toolInfo *plugins.ToolInfo) error { } // Create venv + logger.Debug("Creating Python virtual environment", map[string]interface{}{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + "venvDir": filepath.Join(toolInfo.InstallDir, "venv"), + }) + cmd := exec.Command(pythonBinary, "-m", "venv", filepath.Join(toolInfo.InstallDir, "venv")) output, err := cmd.CombinedOutput() if err != nil { @@ -197,13 +281,22 @@ func installPythonTool(name string, toolInfo *plugins.ToolInfo) error { // Install the tool using pip from venv pipPath := filepath.Join(toolInfo.InstallDir, "venv", "bin", "pip") + logger.Debug("Installing Python package", map[string]interface{}{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + "pipPath": pipPath, + }) + cmd = exec.Command(pipPath, "install", fmt.Sprintf("%s==%s", toolInfo.Name, toolInfo.Version)) output, err = cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to install tool: %s\nError: %w", string(output), err) } - log.Printf("Successfully installed %s v%s\n", toolInfo.Name, toolInfo.Version) + logger.Debug("Python tool installation completed", map[string]interface{}{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + }) return nil } diff --git a/utils/logger/logger.go b/utils/logger/logger.go index 4be68326..c9da9997 100644 --- a/utils/logger/logger.go +++ b/utils/logger/logger.go @@ -1,7 +1,6 @@ package logger import ( - "codacy/cli-v2/config" "codacy/cli-v2/utils" "fmt" "os" @@ -61,13 +60,12 @@ func (f *CustomTextFormatter) Format(entry *logrus.Entry) ([]byte, error) { var fileLogger *logrus.Logger -// Initialize sets up the file logger with the given configuration -func Initialize(conf *config.ConfigType) error { +// Initialize sets up the file logger with the given log directory +func Initialize(logsDir string) error { // Create a new logger instance fileLogger = logrus.New() // Create logs directory if it doesn't exist - logsDir := filepath.Join(conf.LocalCodacyDirectory(), "logs") if err := os.MkdirAll(logsDir, utils.DefaultDirPerms); err != nil { return fmt.Errorf("failed to create logs directory: %w", err) } From 4f19cdeae8eac8e4cf16a3b158d2e9aded5475df Mon Sep 17 00:00:00 2001 From: "andrzej.janczak" Date: Thu, 8 May 2025 13:24:34 +0200 Subject: [PATCH 3/6] refactor: enhance installation process with error handling and warnings - Replace fatal errors with warnings for failed installations of runtimes and tools - Update installation completion message to reflect any failures - Add guideline to remove dead unused code --- .cursor/rules/cursor.mdc | 1 + cmd/install.go | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/.cursor/rules/cursor.mdc b/.cursor/rules/cursor.mdc index 65eb3b75..17991805 100644 --- a/.cursor/rules/cursor.mdc +++ b/.cursor/rules/cursor.mdc @@ -9,6 +9,7 @@ alwaysApply: true ## Key Rules - use fulnames like e.g. feature, instaed of feat - run go build after each code modification to see if app compiles +- remove dead unused code ## Code Style Guidelines - **Imports**: Standard lib first, external packages second, internal last diff --git a/cmd/install.go b/cmd/install.go index 52733d48..a5d74bcc 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -166,7 +166,10 @@ var installCmd = &cobra.Command{ "version": runtime.Version, "error": err.Error(), }) - log.Fatal(err) + fmt.Printf("\n⚠️ Warning: Failed to install runtime %s v%s: %v\n", name, runtime.Version, err) + // Continue with next runtime instead of fatal + progressBar.Add(1) + continue } logger.Info("Successfully installed runtime", logrus.Fields{ "runtime": name, @@ -191,7 +194,10 @@ var installCmd = &cobra.Command{ "version": tool.Version, "error": err.Error(), }) - log.Fatal(err) + fmt.Printf("\n⚠️ Warning: Failed to install tool %s v%s: %v\n", name, tool.Version, err) + // Continue with next tool instead of fatal + progressBar.Add(1) + continue } logger.Info("Successfully installed tool", logrus.Fields{ "tool": name, @@ -206,21 +212,39 @@ var installCmd = &cobra.Command{ devNull.Close() log.SetOutput(os.Stderr) - // Print completion status + // Print completion status with warnings for failed installations fmt.Println() + var hasFailures bool for name, runtime := range cfg.Config.Runtimes() { if !cfg.Config.IsRuntimeInstalled(name, runtime) { - green.Printf(" ✓ Runtime: %s v%s\n", name, runtime.Version) + if cfg.Config.IsRuntimeInstalled(name, runtime) { + green.Printf(" ✓ Runtime: %s v%s\n", name, runtime.Version) + } else { + color.Yellow(" ⚠️ Runtime: %s v%s (installation failed)", name, runtime.Version) + hasFailures = true + } } } for name, tool := range cfg.Config.Tools() { if !cfg.Config.IsToolInstalled(name, tool) { - green.Printf(" ✓ Tool: %s v%s\n", name, tool.Version) + if cfg.Config.IsToolInstalled(name, tool) { + green.Printf(" ✓ Tool: %s v%s\n", name, tool.Version) + } else { + color.Yellow(" ⚠️ Tool: %s v%s (installation failed)", name, tool.Version) + hasFailures = true + } } } fmt.Println() - logger.Info("Installation completed successfully", nil) - bold.Println("✅ Installation completed successfully!") + if hasFailures { + logger.Warn("Installation completed with some failures", nil) + bold.Println("⚠️ Installation completed with some failures!") + fmt.Println("Some components failed to install. You can try installing them again with:") + fmt.Println(" codacy-cli install") + } else { + logger.Info("Installation completed successfully", nil) + bold.Println("✅ Installation completed successfully!") + } }, } From 163b7bb39ea8b2a4c7ce9f91fb2dc4929115d820 Mon Sep 17 00:00:00 2001 From: "andrzej.janczak" Date: Thu, 8 May 2025 14:08:55 +0200 Subject: [PATCH 4/6] refactor: streamline installation feedback and enhance tool path resolution - Simplify installation status reporting for runtimes and tools by removing redundant checks - Improve handling of relative binary paths in tool installation checks --- cmd/install.go | 41 ++++++++--------------------------------- config/config.go | 11 +++++++++++ 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/cmd/install.go b/cmd/install.go index a5d74bcc..aebf000f 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -217,22 +217,18 @@ var installCmd = &cobra.Command{ var hasFailures bool for name, runtime := range cfg.Config.Runtimes() { if !cfg.Config.IsRuntimeInstalled(name, runtime) { - if cfg.Config.IsRuntimeInstalled(name, runtime) { - green.Printf(" ✓ Runtime: %s v%s\n", name, runtime.Version) - } else { - color.Yellow(" ⚠️ Runtime: %s v%s (installation failed)", name, runtime.Version) - hasFailures = true - } + color.Yellow(" ⚠️ Runtime: %s v%s (installation failed)", name, runtime.Version) + hasFailures = true + } else { + green.Printf(" ✓ Runtime: %s v%s\n", name, runtime.Version) } } for name, tool := range cfg.Config.Tools() { if !cfg.Config.IsToolInstalled(name, tool) { - if cfg.Config.IsToolInstalled(name, tool) { - green.Printf(" ✓ Tool: %s v%s\n", name, tool.Version) - } else { - color.Yellow(" ⚠️ Tool: %s v%s (installation failed)", name, tool.Version) - hasFailures = true - } + color.Yellow(" ⚠️ Tool: %s v%s (installation failed)", name, tool.Version) + hasFailures = true + } else { + green.Printf(" ✓ Tool: %s v%s\n", name, tool.Version) } } fmt.Println() @@ -247,24 +243,3 @@ var installCmd = &cobra.Command{ } }, } - -func installRuntimes(config *cfg.ConfigType) { - err := cfg.InstallRuntimes(config) - if err != nil { - logger.Error("Failed to install runtimes", logrus.Fields{ - "error": err.Error(), - }) - log.Fatal(err) - } -} - -func installTools(config *cfg.ConfigType, registry string) { - // Use the new tools-installer instead of manual installation - err := cfg.InstallTools(config, registry) - if err != nil { - logger.Error("Failed to install tools", logrus.Fields{ - "error": err.Error(), - }) - log.Fatal(err) - } -} diff --git a/config/config.go b/config/config.go index e18c4ab8..ca2165f9 100644 --- a/config/config.go +++ b/config/config.go @@ -209,10 +209,21 @@ func (c *ConfigType) IsToolInstalled(name string, tool *plugins.ToolInfo) bool { // Check if at least one binary exists for _, binaryPath := range tool.Binaries { + // If the path is relative, join it with the installation directory + if !filepath.IsAbs(binaryPath) { + binaryPath = filepath.Join(tool.InstallDir, binaryPath) + } + + // Try both with and without .exe _, err := os.Stat(binaryPath) if err == nil { return true } + + _, err = os.Stat(binaryPath + ".exe") + if err == nil { + return true + } } return false From 0235e006da2b980871c09251cbbf8202828d04cd Mon Sep 17 00:00:00 2001 From: "andrzej.janczak" Date: Thu, 8 May 2025 14:57:20 +0200 Subject: [PATCH 5/6] - enable windows it tests --- .github/workflows/go.yml | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index bc728976..3a98e81d 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -54,7 +54,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] steps: - name: Checkout uses: actions/checkout@v4 @@ -81,18 +81,15 @@ jobs: if: matrix.os != 'windows-latest' run: | ./cli-v2 install - # Disable windows it test for now. - # - name: Install dependencies from .codacy/codacy.yaml (Windows) - # if: matrix.os == 'windows-latest' - # shell: pwsh - # run: | - # Get-ChildItem - # Write-Host "Current directory contents:" - # dir - # Write-Host "Node.js version:" - # node --version - # Write-Host "Attempting to run CLI..." - # .\cli-v2.exe install + - name: Install dependencies from .codacy/codacy.yaml (Windows) + if: matrix.os == 'windows-latest' + shell: pwsh + run: | + Get-ChildItem + Write-Host "Current directory contents:" + dir + Write-Host "Attempting to run CLI..." + .\cli-v2.exe install # For now we are not releasing the CLI, as we are making some quicker iterations release: From c46cdf7a00ae2bdd91f8267a0e3f7208003e60a9 Mon Sep 17 00:00:00 2001 From: "andrzej.janczak" Date: Fri, 9 May 2025 09:58:41 +0200 Subject: [PATCH 6/6] refactor: replace map[string]interface{} with logrus.Fields in logging --- config/tools-installer.go | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/config/tools-installer.go b/config/tools-installer.go index 03300843..f9994e32 100644 --- a/config/tools-installer.go +++ b/config/tools-installer.go @@ -11,6 +11,8 @@ import ( "path/filepath" "strings" "text/template" + + "github.com/sirupsen/logrus" ) // InstallTools installs all tools defined in the configuration @@ -18,7 +20,7 @@ func InstallTools(config *ConfigType, registry string) error { var failedTools []string for name, toolInfo := range config.Tools() { - logger.Info("Starting tool installation", map[string]interface{}{ + logger.Info("Starting tool installation", logrus.Fields{ "tool": name, "version": toolInfo.Version, "runtime": toolInfo.Runtime, @@ -27,7 +29,7 @@ func InstallTools(config *ConfigType, registry string) error { fmt.Printf("Installing tool: %s v%s...\n", name, toolInfo.Version) err := InstallTool(name, toolInfo, registry) if err != nil { - logger.Error("Failed to install tool", map[string]interface{}{ + logger.Error("Failed to install tool", logrus.Fields{ "tool": name, "version": toolInfo.Version, "runtime": toolInfo.Runtime, @@ -37,7 +39,7 @@ func InstallTools(config *ConfigType, registry string) error { continue } - logger.Info("Successfully installed tool", map[string]interface{}{ + logger.Info("Successfully installed tool", logrus.Fields{ "tool": name, "version": toolInfo.Version, "runtime": toolInfo.Runtime, @@ -55,7 +57,7 @@ func InstallTools(config *ConfigType, registry string) error { func InstallTool(name string, toolInfo *plugins.ToolInfo, registry string) error { // Check if the tool is already installed if isToolInstalled(toolInfo) { - logger.Info("Tool already installed", map[string]interface{}{ + logger.Info("Tool already installed", logrus.Fields{ "tool": name, "version": toolInfo.Version, "runtime": toolInfo.Runtime, @@ -73,7 +75,7 @@ func InstallTool(name string, toolInfo *plugins.ToolInfo, registry string) error // Check if this is a download-based tool (like trivy) or a runtime-based tool (like eslint) if toolInfo.DownloadURL != "" { // This is a download-based tool - logger.Debug("Installing download-based tool", map[string]interface{}{ + logger.Debug("Installing download-based tool", logrus.Fields{ "tool": name, "version": toolInfo.Version, "downloadURL": toolInfo.DownloadURL, @@ -84,7 +86,7 @@ func InstallTool(name string, toolInfo *plugins.ToolInfo, registry string) error // Handle Python tools differently if toolInfo.Runtime == "python" { - logger.Debug("Installing Python tool", map[string]interface{}{ + logger.Debug("Installing Python tool", logrus.Fields{ "tool": name, "version": toolInfo.Version, }) @@ -93,7 +95,7 @@ func InstallTool(name string, toolInfo *plugins.ToolInfo, registry string) error } // For runtime-based tools - logger.Debug("Installing runtime-based tool", map[string]interface{}{ + logger.Debug("Installing runtime-based tool", logrus.Fields{ "tool": name, "version": toolInfo.Version, "runtime": toolInfo.Runtime, @@ -131,7 +133,7 @@ func installRuntimeTool(name string, toolInfo *plugins.ToolInfo, registry string return fmt.Errorf("failed to prepare registry command: %w", err) } - logger.Debug("Setting registry", map[string]interface{}{ + logger.Debug("Setting registry", logrus.Fields{ "tool": name, "packageManager": packageManagerName, "packageManagerBin": packageManagerBinary, @@ -152,7 +154,7 @@ func installRuntimeTool(name string, toolInfo *plugins.ToolInfo, registry string return fmt.Errorf("failed to prepare install command: %w", err) } - logger.Debug("Installing tool", map[string]interface{}{ + logger.Debug("Installing tool", logrus.Fields{ "tool": name, "version": toolInfo.Version, "packageManager": packageManagerName, @@ -167,7 +169,7 @@ func installRuntimeTool(name string, toolInfo *plugins.ToolInfo, registry string return fmt.Errorf("failed to install tool: %s: %w", string(output), err) } - logger.Debug("Tool installation completed", map[string]interface{}{ + logger.Debug("Tool installation completed", logrus.Fields{ "tool": name, "version": toolInfo.Version, }) @@ -184,7 +186,7 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { _, err := os.Stat(downloadPath) if os.IsNotExist(err) { // Download the file - logger.Debug("Downloading tool", map[string]interface{}{ + logger.Debug("Downloading tool", logrus.Fields{ "tool": toolInfo.Name, "version": toolInfo.Version, "downloadURL": toolInfo.DownloadURL, @@ -197,7 +199,7 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { } else if err != nil { return fmt.Errorf("error checking for existing download: %w", err) } else { - logger.Debug("Using existing tool download", map[string]interface{}{ + logger.Debug("Using existing tool download", logrus.Fields{ "tool": toolInfo.Name, "version": toolInfo.Version, "downloadPath": downloadPath, @@ -217,8 +219,8 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { return fmt.Errorf("failed to create installation directory: %w", err) } - // Extract directly to the installation directory - logger.Debug("Extracting tool", map[string]interface{}{ + // Extract based on file extension + logger.Debug("Extracting tool", logrus.Fields{ "tool": toolInfo.Name, "version": toolInfo.Version, "fileName": fileName, @@ -243,7 +245,7 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { } } - logger.Debug("Tool extraction completed", map[string]interface{}{ + logger.Debug("Tool extraction completed", logrus.Fields{ "tool": toolInfo.Name, "version": toolInfo.Version, }) @@ -251,7 +253,7 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { } func installPythonTool(name string, toolInfo *plugins.ToolInfo) error { - logger.Debug("Starting Python tool installation", map[string]interface{}{ + logger.Debug("Starting Python tool installation", logrus.Fields{ "tool": toolInfo.Name, "version": toolInfo.Version, }) @@ -267,7 +269,7 @@ func installPythonTool(name string, toolInfo *plugins.ToolInfo) error { } // Create venv - logger.Debug("Creating Python virtual environment", map[string]interface{}{ + logger.Debug("Creating Python virtual environment", logrus.Fields{ "tool": toolInfo.Name, "version": toolInfo.Version, "venvDir": filepath.Join(toolInfo.InstallDir, "venv"), @@ -281,7 +283,7 @@ func installPythonTool(name string, toolInfo *plugins.ToolInfo) error { // Install the tool using pip from venv pipPath := filepath.Join(toolInfo.InstallDir, "venv", "bin", "pip") - logger.Debug("Installing Python package", map[string]interface{}{ + logger.Debug("Installing Python package", logrus.Fields{ "tool": toolInfo.Name, "version": toolInfo.Version, "pipPath": pipPath, @@ -293,7 +295,7 @@ func installPythonTool(name string, toolInfo *plugins.ToolInfo) error { return fmt.Errorf("failed to install tool: %s\nError: %w", string(output), err) } - logger.Debug("Python tool installation completed", map[string]interface{}{ + logger.Debug("Python tool installation completed", logrus.Fields{ "tool": toolInfo.Name, "version": toolInfo.Version, })