Skip to content

Commit 599d2d5

Browse files
feature: enhance command handling and configuration validation
- Updated command handling to include 'version' and 'help' in the list of commands that do not require configuration. - Refactored codacy.yaml validation logic to ensure it is performed for all commands except 'init', 'help', and 'version'. - Introduced a new validation function to check for the existence and validity of the codacy.yaml file, improving error handling and user feedback.
1 parent 1eeeff8 commit 599d2d5

File tree

4 files changed

+121
-23
lines changed

4 files changed

+121
-23
lines changed

cli-v2.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,13 @@ func main() {
3939
}
4040
}
4141

42-
// Check if command is init/update
43-
if len(os.Args) > 1 && (os.Args[1] == "init" || os.Args[1] == "update") {
44-
cmd.Execute()
45-
return
42+
// Check if command is init/update/version/help - these don't require configuration
43+
if len(os.Args) > 1 {
44+
cmdName := os.Args[1]
45+
if cmdName == "init" || cmdName == "update" || cmdName == "version" || cmdName == "help" {
46+
cmd.Execute()
47+
return
48+
}
4649
}
4750

4851
// All other commands require a configuration file

cmd/config.go

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -341,25 +341,14 @@ func updateLanguagesConfig(detectedLanguages map[string]struct{}, toolsConfigDir
341341
func updateCodacyYAML(detectedLanguages map[string]struct{}, codacyYAMLPath string, defaultToolLangMap map[string]domain.ToolLanguageInfo, initFlags domain.InitFlags, cliMode string) error {
342342
var configData map[string]interface{}
343343

344-
if _, err := os.Stat(codacyYAMLPath); err == nil {
345-
content, err := os.ReadFile(codacyYAMLPath)
346-
if err != nil {
347-
return fmt.Errorf("error reading %s: %w", codacyYAMLPath, err)
348-
}
349-
if err := yaml.Unmarshal(content, &configData); err != nil {
350-
if strings.Contains(err.Error(), "cannot unmarshal") {
351-
return fmt.Errorf(
352-
"❌ Fatal: %s contains invalid configuration - run 'codacy-cli config reset' to fix: %v",
353-
filepath.Base(codacyYAMLPath), err)
354-
}
355-
return fmt.Errorf(
356-
"❌ Fatal: %s is broken or has invalid YAML format - run 'codacy-cli config reset' to reinitialize your configuration",
357-
filepath.Base(codacyYAMLPath))
358-
}
359-
} else if os.IsNotExist(err) {
360-
return fmt.Errorf("codacy.yaml file not found")
361-
} else {
362-
return fmt.Errorf("error accessing %s: %w", codacyYAMLPath, err)
344+
// Read and parse codacy.yaml (validation is done globally in PersistentPreRun)
345+
content, err := os.ReadFile(codacyYAMLPath)
346+
if err != nil {
347+
return fmt.Errorf("error reading %s: %w", codacyYAMLPath, err)
348+
}
349+
350+
if err := yaml.Unmarshal(content, &configData); err != nil {
351+
return fmt.Errorf("error parsing %s: %w", codacyYAMLPath, err)
363352
}
364353

365354
toolsRaw, _ := configData["tools"].([]interface{})

cmd/root.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ var rootCmd = &cobra.Command{
3636
"full_command": maskedArgs,
3737
"args": args,
3838
})
39+
40+
// Validate codacy.yaml for all commands except init, help, and version
41+
if !shouldSkipValidation(cmd.Name()) {
42+
if err := validateCodacyYAML(); err != nil {
43+
logger.Error("Global validation failed", logrus.Fields{
44+
"command": cmd.Name(),
45+
"error": err.Error(),
46+
})
47+
fmt.Println(err)
48+
os.Exit(1)
49+
}
50+
}
3951
},
4052
Run: func(cmd *cobra.Command, args []string) {
4153
// Check if .codacy directory exists

cmd/validation.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
9+
"codacy/cli-v2/config"
10+
"codacy/cli-v2/utils/logger"
11+
12+
"github.com/sirupsen/logrus"
13+
"gopkg.in/yaml.v3"
14+
)
15+
16+
// validateCodacyYAML validates that codacy.yaml exists and is not empty
17+
// Returns an error if validation fails, nil if validation passes
18+
func validateCodacyYAML() error {
19+
codacyYAMLPath := config.Config.ProjectConfigFile()
20+
21+
// Check if file exists
22+
if _, err := os.Stat(codacyYAMLPath); os.IsNotExist(err) {
23+
logger.Error("codacy.yaml file not found", logrus.Fields{
24+
"file": codacyYAMLPath,
25+
})
26+
return fmt.Errorf("❌ Fatal: codacy.yaml file not found. Please run 'codacy-cli init' to initialize your configuration first")
27+
} else if err != nil {
28+
logger.Error("Error accessing codacy.yaml file", logrus.Fields{
29+
"file": codacyYAMLPath,
30+
"error": err,
31+
})
32+
return fmt.Errorf("error accessing %s: %w", codacyYAMLPath, err)
33+
}
34+
35+
// Read file content
36+
content, err := os.ReadFile(codacyYAMLPath)
37+
if err != nil {
38+
logger.Error("Failed to read codacy.yaml file", logrus.Fields{
39+
"file": codacyYAMLPath,
40+
"error": err,
41+
})
42+
return fmt.Errorf("error reading %s: %w", codacyYAMLPath, err)
43+
}
44+
45+
// Check if file is empty or contains only whitespace
46+
if len(strings.TrimSpace(string(content))) == 0 {
47+
logger.Error("codacy.yaml file is empty", logrus.Fields{
48+
"file": codacyYAMLPath,
49+
})
50+
return fmt.Errorf("❌ Fatal: %s is empty. Please run 'codacy-cli init' to initialize your configuration first", filepath.Base(codacyYAMLPath))
51+
}
52+
53+
// Try to parse YAML to ensure it's valid
54+
var configData map[string]interface{}
55+
if err := yaml.Unmarshal(content, &configData); err != nil {
56+
logger.Error("Failed to parse codacy.yaml file", logrus.Fields{
57+
"file": codacyYAMLPath,
58+
"error": err,
59+
})
60+
if strings.Contains(err.Error(), "cannot unmarshal") {
61+
return fmt.Errorf("❌ Fatal: %s contains invalid configuration - run 'codacy-cli config reset' to fix: %v", filepath.Base(codacyYAMLPath), err)
62+
}
63+
return fmt.Errorf("❌ Fatal: %s is broken or has invalid YAML format - run 'codacy-cli config reset' to reinitialize your configuration", filepath.Base(codacyYAMLPath))
64+
}
65+
66+
// Ensure configData is not nil after unmarshaling
67+
if configData == nil {
68+
logger.Error("codacy.yaml unmarshaled to nil data", logrus.Fields{
69+
"file": codacyYAMLPath,
70+
})
71+
return fmt.Errorf("❌ Fatal: %s contains no valid configuration. Please run 'codacy-cli init' to initialize your configuration first", filepath.Base(codacyYAMLPath))
72+
}
73+
74+
return nil
75+
}
76+
77+
// shouldSkipValidation checks if the current command should skip codacy.yaml validation
78+
func shouldSkipValidation(cmdName string) bool {
79+
skipCommands := []string{
80+
"init",
81+
"help",
82+
"version",
83+
"reset", // config reset should work even with empty/invalid codacy.yaml
84+
"codacy-cli", // root command when called without subcommands
85+
}
86+
87+
for _, skipCmd := range skipCommands {
88+
if cmdName == skipCmd {
89+
return true
90+
}
91+
}
92+
93+
return false
94+
}

0 commit comments

Comments
 (0)