Skip to content

Commit 0a57dfa

Browse files
feature: continue the installation process when some installation fails (#106)
feature: continue the installation process when installation fails - Modified installation to continue after individual failures - Added status indicators (✓, ⚠️) for installation results - Improved binary detection across different OS - Added installation summary with success/failure status - Fixed tool detection for Windows executables Previously the installation would stop on first error, now it attempts to install all tools and provides a complete status report at the end.
1 parent abc3de3 commit 0a57dfa

File tree

9 files changed

+216
-66
lines changed

9 files changed

+216
-66
lines changed

.cursor/rules/cursor.mdc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ alwaysApply: true
99
## Key Rules
1010
- use full names like e.g. feature, instead of feat
1111
- run go build after each code modification to see if app compiles
12+
- remove dead unused code
1213

1314
## Code Style Guidelines
1415
- **Imports**: Standard lib first, external packages second, internal last

.github/workflows/go.yml

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
runs-on: ${{ matrix.os }}
5555
strategy:
5656
matrix:
57-
os: [ubuntu-latest, macos-latest]
57+
os: [ubuntu-latest, macos-latest, windows-latest]
5858
steps:
5959
- name: Checkout
6060
uses: actions/checkout@v4
@@ -81,18 +81,15 @@ jobs:
8181
if: matrix.os != 'windows-latest'
8282
run: |
8383
./cli-v2 install
84-
# Disable windows it test for now.
85-
# - name: Install dependencies from .codacy/codacy.yaml (Windows)
86-
# if: matrix.os == 'windows-latest'
87-
# shell: pwsh
88-
# run: |
89-
# Get-ChildItem
90-
# Write-Host "Current directory contents:"
91-
# dir
92-
# Write-Host "Node.js version:"
93-
# node --version
94-
# Write-Host "Attempting to run CLI..."
95-
# .\cli-v2.exe install
84+
- name: Install dependencies from .codacy/codacy.yaml (Windows)
85+
if: matrix.os == 'windows-latest'
86+
shell: pwsh
87+
run: |
88+
Get-ChildItem
89+
Write-Host "Current directory contents:"
90+
dir
91+
Write-Host "Attempting to run CLI..."
92+
.\cli-v2.exe install
9693
9794
# For now we are not releasing the CLI, as we are making some quicker iterations
9895
release:

cli-v2.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"codacy/cli-v2/utils/logger"
88
"fmt"
99
"os"
10+
"path/filepath"
1011

1112
"github.com/sirupsen/logrus"
1213
)
@@ -15,8 +16,9 @@ func main() {
1516
// Initialize config global object
1617
config.Init()
1718

18-
// Initialize logger
19-
if err := logger.Initialize(&config.Config); err != nil {
19+
// Initialize logger with the logs directory
20+
logsDir := filepath.Join(config.Config.LocalCodacyDirectory(), "logs")
21+
if err := logger.Initialize(logsDir); err != nil {
2022
fmt.Printf("Failed to initialize logger: %v\n", err)
2123
}
2224

cmd/install.go

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,10 @@ var installCmd = &cobra.Command{
166166
"version": runtime.Version,
167167
"error": err.Error(),
168168
})
169-
log.Fatal(err)
169+
fmt.Printf("\n⚠️ Warning: Failed to install runtime %s v%s: %v\n", name, runtime.Version, err)
170+
// Continue with next runtime instead of fatal
171+
progressBar.Add(1)
172+
continue
170173
}
171174
logger.Info("Successfully installed runtime", logrus.Fields{
172175
"runtime": name,
@@ -191,7 +194,10 @@ var installCmd = &cobra.Command{
191194
"version": tool.Version,
192195
"error": err.Error(),
193196
})
194-
log.Fatal(err)
197+
fmt.Printf("\n⚠️ Warning: Failed to install tool %s v%s: %v\n", name, tool.Version, err)
198+
// Continue with next tool instead of fatal
199+
progressBar.Add(1)
200+
continue
195201
}
196202
logger.Info("Successfully installed tool", logrus.Fields{
197203
"tool": name,
@@ -206,41 +212,34 @@ var installCmd = &cobra.Command{
206212
devNull.Close()
207213
log.SetOutput(os.Stderr)
208214

209-
// Print completion status
215+
// Print completion status with warnings for failed installations
210216
fmt.Println()
217+
var hasFailures bool
211218
for name, runtime := range cfg.Config.Runtimes() {
212219
if !cfg.Config.IsRuntimeInstalled(name, runtime) {
220+
color.Yellow(" ⚠️ Runtime: %s v%s (installation failed)", name, runtime.Version)
221+
hasFailures = true
222+
} else {
213223
green.Printf(" ✓ Runtime: %s v%s\n", name, runtime.Version)
214224
}
215225
}
216226
for name, tool := range cfg.Config.Tools() {
217227
if !cfg.Config.IsToolInstalled(name, tool) {
228+
color.Yellow(" ⚠️ Tool: %s v%s (installation failed)", name, tool.Version)
229+
hasFailures = true
230+
} else {
218231
green.Printf(" ✓ Tool: %s v%s\n", name, tool.Version)
219232
}
220233
}
221234
fmt.Println()
222-
logger.Info("Installation completed successfully", nil)
223-
bold.Println("✅ Installation completed successfully!")
235+
if hasFailures {
236+
logger.Warn("Installation completed with some failures", nil)
237+
bold.Println("⚠️ Installation completed with some failures!")
238+
fmt.Println("Some components failed to install. You can try installing them again with:")
239+
fmt.Println(" codacy-cli install")
240+
} else {
241+
logger.Info("Installation completed successfully", nil)
242+
bold.Println("✅ Installation completed successfully!")
243+
}
224244
},
225245
}
226-
227-
func installRuntimes(config *cfg.ConfigType) {
228-
err := cfg.InstallRuntimes(config)
229-
if err != nil {
230-
logger.Error("Failed to install runtimes", logrus.Fields{
231-
"error": err.Error(),
232-
})
233-
log.Fatal(err)
234-
}
235-
}
236-
237-
func installTools(config *cfg.ConfigType, registry string) {
238-
// Use the new tools-installer instead of manual installation
239-
err := cfg.InstallTools(config, registry)
240-
if err != nil {
241-
logger.Error("Failed to install tools", logrus.Fields{
242-
"error": err.Error(),
243-
})
244-
log.Fatal(err)
245-
}
246-
}

cmd/root.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ var rootCmd = &cobra.Command{
1919
Example: getExampleText(),
2020
PersistentPreRun: func(cmd *cobra.Command, args []string) {
2121
// Initialize logger before any command runs
22-
if err := logger.Initialize(&config.Config); err != nil {
22+
logsDir := filepath.Join(config.Config.LocalCodacyDirectory(), "logs")
23+
if err := logger.Initialize(logsDir); err != nil {
2324
fmt.Printf("Warning: Failed to initialize file logger: %v\n", err)
2425
}
2526
},

config/config.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,21 @@ func (c *ConfigType) IsToolInstalled(name string, tool *plugins.ToolInfo) bool {
209209

210210
// Check if at least one binary exists
211211
for _, binaryPath := range tool.Binaries {
212+
// If the path is relative, join it with the installation directory
213+
if !filepath.IsAbs(binaryPath) {
214+
binaryPath = filepath.Join(tool.InstallDir, binaryPath)
215+
}
216+
217+
// Try both with and without .exe
212218
_, err := os.Stat(binaryPath)
213219
if err == nil {
214220
return true
215221
}
222+
223+
_, err = os.Stat(binaryPath + ".exe")
224+
if err == nil {
225+
return true
226+
}
216227
}
217228

218229
return false

config/runtimes-installer.go

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,44 @@ package config
33
import (
44
"codacy/cli-v2/plugins"
55
"codacy/cli-v2/utils"
6+
"codacy/cli-v2/utils/logger"
67
"fmt"
7-
"log"
88
"os"
99
"path/filepath"
1010
"strings"
11+
12+
"github.com/sirupsen/logrus"
1113
)
1214

1315
// InstallRuntimes installs all runtimes defined in the configuration
1416
func InstallRuntimes(config *ConfigType) error {
17+
var failedRuntimes []string
18+
1519
for name, runtimeInfo := range config.Runtimes() {
20+
logger.Info("Starting runtime installation", logrus.Fields{
21+
"runtime": name,
22+
"version": runtimeInfo.Version,
23+
})
24+
1625
err := InstallRuntime(name, runtimeInfo)
1726
if err != nil {
18-
return fmt.Errorf("failed to install runtime %s: %w", name, err)
27+
logger.Error("Failed to install runtime", logrus.Fields{
28+
"runtime": name,
29+
"version": runtimeInfo.Version,
30+
"error": err.Error(),
31+
})
32+
failedRuntimes = append(failedRuntimes, name)
33+
continue
1934
}
35+
36+
logger.Info("Successfully installed runtime", logrus.Fields{
37+
"runtime": name,
38+
"version": runtimeInfo.Version,
39+
})
40+
}
41+
42+
if len(failedRuntimes) > 0 {
43+
return fmt.Errorf("failed to install the following runtimes: %v", failedRuntimes)
2044
}
2145
return nil
2246
}
@@ -25,6 +49,10 @@ func InstallRuntimes(config *ConfigType) error {
2549
func InstallRuntime(name string, runtimeInfo *plugins.RuntimeInfo) error {
2650
// Check if the runtime is already installed
2751
if isRuntimeInstalled(runtimeInfo) {
52+
logger.Info("Runtime already installed", logrus.Fields{
53+
"runtime": name,
54+
"version": runtimeInfo.Version,
55+
})
2856
fmt.Printf("Runtime %s v%s is already installed\n", name, runtimeInfo.Version)
2957
return nil
3058
}
@@ -67,15 +95,24 @@ func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error {
6795
_, err := os.Stat(downloadPath)
6896
if os.IsNotExist(err) {
6997
// Download the file
70-
// log.Printf("Downloading %s v%s...\n", runtimeInfo.Name, runtimeInfo.Version)
98+
logger.Debug("Downloading runtime", logrus.Fields{
99+
"runtime": runtimeInfo.Name,
100+
"version": runtimeInfo.Version,
101+
"downloadURL": runtimeInfo.DownloadURL,
102+
"downloadPath": downloadPath,
103+
})
71104
downloadPath, err = utils.DownloadFile(runtimeInfo.DownloadURL, Config.RuntimesDirectory())
72105
if err != nil {
73106
return fmt.Errorf("failed to download runtime: %w", err)
74107
}
75108
} else if err != nil {
76109
return fmt.Errorf("error checking for existing download: %w", err)
77110
} else {
78-
log.Printf("Using existing download for %s v%s\n", runtimeInfo.Name, runtimeInfo.Version)
111+
logger.Debug("Using existing runtime download", logrus.Fields{
112+
"runtime": runtimeInfo.Name,
113+
"version": runtimeInfo.Version,
114+
"downloadPath": downloadPath,
115+
})
79116
}
80117

81118
// Open the downloaded file
@@ -86,7 +123,13 @@ func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error {
86123
defer file.Close()
87124

88125
// Extract based on file extension
89-
// log.Printf("Extracting %s v%s...\n", runtimeInfo.Name, runtimeInfo.Version)
126+
logger.Debug("Extracting runtime", logrus.Fields{
127+
"runtime": runtimeInfo.Name,
128+
"version": runtimeInfo.Version,
129+
"fileName": fileName,
130+
"extractDirectory": Config.RuntimesDirectory(),
131+
})
132+
90133
if strings.HasSuffix(fileName, ".zip") {
91134
err = utils.ExtractZip(file.Name(), Config.RuntimesDirectory())
92135
} else {
@@ -97,6 +140,9 @@ func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error {
97140
return fmt.Errorf("failed to extract runtime: %w", err)
98141
}
99142

100-
log.Printf("Successfully installed %s v%s\n", runtimeInfo.Name, runtimeInfo.Version)
143+
logger.Debug("Runtime extraction completed", logrus.Fields{
144+
"runtime": runtimeInfo.Name,
145+
"version": runtimeInfo.Version,
146+
})
101147
return nil
102148
}

0 commit comments

Comments
 (0)