@@ -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,133 @@ 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+ if len (files ) == 0 {
124+ // If no files specified, return all tools
125+ return tools
126+ }
127+
128+ langConfig , err := LoadLanguageConfig ()
129+ if err != nil {
130+ log .Printf ("Warning: Failed to load language configuration: %v. Running all tools." , err )
131+ return tools
132+ }
133+
134+ result := make (map [string ]* plugins.ToolInfo )
135+
136+ // For each tool, check if it supports at least one of the files
137+ for toolName , toolInfo := range tools {
138+ supported := false
139+
140+ for _ , file := range files {
141+ if IsToolSupportedForFile (toolName , file , langConfig ) {
142+ supported = true
143+ break
144+ }
145+ }
146+
147+ if supported {
148+ result [toolName ] = toolInfo
149+ } else {
150+ log .Printf ("Skipping %s as it doesn't support the specified file(s)" , toolName )
151+ }
152+ }
153+
154+ return result
155+ }
156+
28157type Sarif struct {
29158 Runs []struct {
30159 Tool struct {
@@ -247,7 +376,15 @@ var analyzeCmd = &cobra.Command{
247376 log .Fatal ("No tools configured. Please run 'codacy-cli init' and 'codacy-cli install' first" )
248377 }
249378
250- log .Println ("Running all configured tools..." )
379+ // Filter tools by language support
380+ toolsToRun = FilterToolsByLanguageSupport (toolsToRun , args )
381+
382+ if len (toolsToRun ) == 0 {
383+ log .Println ("No tools support the specified file(s). Skipping analysis." )
384+ return
385+ }
386+
387+ log .Println ("Running tools for the specified file(s)..." )
251388
252389 if outputFormat == "sarif" {
253390 // Create temporary directory for individual tool outputs
0 commit comments