@@ -11,10 +11,12 @@ import (
1111 "net/http"
1212 "os"
1313 "path/filepath"
14+ "strings"
1415
1516 "codacy/cli-v2/utils"
1617
1718 "github.com/spf13/cobra"
19+ "gopkg.in/yaml.v3"
1820)
1921
2022var outputFile string
@@ -25,6 +27,134 @@ var sarifPath string
2527var commitUuid string
2628var projectToken string
2729
30+ // LanguagesConfig represents the structure of the languages configuration file
31+ type LanguagesConfig struct {
32+ Tools []struct {
33+ Name string `yaml:"name" json:"name"`
34+ Languages []string `yaml:"languages" json:"languages"`
35+ Extensions []string `yaml:"extensions" json:"extensions"`
36+ } `yaml:"tools" json:"tools"`
37+ }
38+
39+ // LoadLanguageConfig loads the language configuration from the file
40+ func LoadLanguageConfig () (* LanguagesConfig , error ) {
41+ // First, try to load the YAML config
42+ yamlPath := filepath .Join (config .Config .ToolsConfigDirectory (), "languages-config.yaml" )
43+
44+ // Check if the YAML file exists
45+ if _ , err := os .Stat (yamlPath ); err == nil {
46+ data , err := os .ReadFile (yamlPath )
47+ if err != nil {
48+ return nil , fmt .Errorf ("failed to read languages configuration file: %w" , err )
49+ }
50+
51+ var config LanguagesConfig
52+ if err := yaml .Unmarshal (data , & config ); err != nil {
53+ return nil , fmt .Errorf ("failed to parse YAML languages configuration file: %w" , err )
54+ }
55+
56+ return & config , nil
57+ }
58+
59+ // If YAML file doesn't exist, try the JSON config for backward compatibility
60+ jsonPath := filepath .Join (config .Config .ToolsConfigDirectory (), "languages-config.json" )
61+
62+ // Check if the JSON file exists
63+ if _ , err := os .Stat (jsonPath ); os .IsNotExist (err ) {
64+ return nil , fmt .Errorf ("languages configuration file not found: neither %s nor %s exists" , yamlPath , jsonPath )
65+ }
66+
67+ data , err := os .ReadFile (jsonPath )
68+ if err != nil {
69+ return nil , fmt .Errorf ("failed to read JSON languages configuration file: %w" , err )
70+ }
71+
72+ var config LanguagesConfig
73+ if err := json .Unmarshal (data , & config ); err != nil {
74+ return nil , fmt .Errorf ("failed to parse JSON languages configuration file: %w" , err )
75+ }
76+
77+ return & config , nil
78+ }
79+
80+ // GetFileExtension extracts the file extension from a path
81+ func GetFileExtension (filePath string ) string {
82+ return strings .ToLower (filepath .Ext (filePath ))
83+ }
84+
85+ // IsToolSupportedForFile checks if a tool supports a given file based on its extension
86+ func IsToolSupportedForFile (toolName string , filePath string , langConfig * LanguagesConfig ) bool {
87+ if langConfig == nil {
88+ // If no language config is available, assume all tools are supported
89+ return true
90+ }
91+
92+ fileExt := GetFileExtension (filePath )
93+ if fileExt == "" {
94+ // If file has no extension, assume tool is supported
95+ return true
96+ }
97+
98+ for _ , tool := range langConfig .Tools {
99+ if tool .Name == toolName {
100+ // If tool has no extensions defined, assume it supports all files
101+ if len (tool .Extensions ) == 0 {
102+ return true
103+ }
104+
105+ // Check if file extension is supported by this tool
106+ for _ , ext := range tool .Extensions {
107+ if strings .EqualFold (ext , fileExt ) {
108+ return true
109+ }
110+ }
111+
112+ // Extension not found in tool's supported extensions
113+ return false
114+ }
115+ }
116+
117+ // If tool not found in config, assume it's supported
118+ return true
119+ }
120+
121+ // FilterToolsByLanguageSupport filters tools by language support for the given files
122+ func FilterToolsByLanguageSupport (tools map [string ]* plugins.ToolInfo , files []string ) map [string ]* plugins.ToolInfo {
123+
124+ if len (files ) == 0 || files [0 ] == "." {
125+ // If no files specified or current directory, return all tools
126+ return tools
127+ }
128+
129+ langConfig , err := LoadLanguageConfig ()
130+ if err != nil {
131+ log .Printf ("Warning: Failed to load language configuration: %v. Running all tools." , err )
132+ return tools
133+ }
134+
135+ result := make (map [string ]* plugins.ToolInfo )
136+
137+ // For each tool, check if it supports at least one of the files
138+ for toolName , toolInfo := range tools {
139+ supported := false
140+
141+ for _ , file := range files {
142+ if IsToolSupportedForFile (toolName , file , langConfig ) {
143+ supported = true
144+ break
145+ }
146+ }
147+
148+ if supported {
149+ result [toolName ] = toolInfo
150+ } else {
151+ log .Printf ("Skipping %s as it doesn't support the specified file(s)" , toolName )
152+ }
153+ }
154+
155+ return result
156+ }
157+
28158type Sarif struct {
29159 Runs []struct {
30160 Tool struct {
@@ -256,7 +386,15 @@ var analyzeCmd = &cobra.Command{
256386 log .Fatal ("No tools configured. Please run 'codacy-cli init' and 'codacy-cli install' first" )
257387 }
258388
259- log .Println ("Running all configured tools..." )
389+ // Filter tools by language support
390+ toolsToRun = FilterToolsByLanguageSupport (toolsToRun , args )
391+
392+ if len (toolsToRun ) == 0 {
393+ log .Println ("No tools support the specified file(s). Skipping analysis." )
394+ return
395+ }
396+
397+ log .Println ("Running tools for the specified file(s)..." )
260398
261399 if outputFormat == "sarif" {
262400 // Create temporary directory for individual tool outputs
0 commit comments