11package tools
22
33import (
4+ "encoding/json"
45 "fmt"
6+ "io"
7+ "net/http"
58 "os"
69 "path/filepath"
10+ "strings"
11+ "time"
712
813 "codacy/cli-v2/utils"
914
1015 "gopkg.in/yaml.v3"
1116)
1217
18+ const CodacyApiBase = "https://app.codacy.com"
19+
1320// ToolLanguageInfo contains language and extension information for a tool
1421type ToolLanguageInfo struct {
1522 Name string `yaml:"name"`
@@ -23,7 +30,7 @@ type LanguagesConfig struct {
2330}
2431
2532// CreateLanguagesConfigFile creates languages-config.yaml based on API response
26- func CreateLanguagesConfigFile (apiTools []Tool , toolsConfigDir string , toolIDMap map [string ]string ) error {
33+ func CreateLanguagesConfigFile (apiTools []Tool , toolsConfigDir string , toolIDMap map [string ]string , apiToken string , provider string , organization string , repository string ) error {
2734 // Map tool names to their language/extension information
2835 toolLanguageMap := map [string ]ToolLanguageInfo {
2936 "cppcheck" : {
@@ -61,6 +68,11 @@ func CreateLanguagesConfigFile(apiTools []Tool, toolsConfigDir string, toolIDMap
6168 // Build a list of tool language info for enabled tools
6269 var configTools []ToolLanguageInfo
6370
71+ repositoryLanguages , err := getRepositoryLanguages (apiToken , provider , organization , repository )
72+ if err != nil {
73+ return fmt .Errorf ("failed to get repository languages: %w" , err )
74+ }
75+
6476 for _ , tool := range apiTools {
6577 shortName , exists := toolIDMap [tool .Uuid ]
6678 if ! exists {
@@ -71,7 +83,27 @@ func CreateLanguagesConfigFile(apiTools []Tool, toolsConfigDir string, toolIDMap
7183 // Get language info for this tool
7284 langInfo , exists := toolLanguageMap [shortName ]
7385 if exists {
74- configTools = append (configTools , langInfo )
86+ // Special case for Trivy - always include it
87+ if shortName == "trivy" {
88+ configTools = append (configTools , langInfo )
89+ continue
90+ }
91+
92+ // Filter languages based on repository languages
93+ var filteredLanguages []string
94+ for _ , lang := range langInfo .Languages {
95+ // Convert both to lowercase for case-insensitive comparison
96+ lowerLang := strings .ToLower (lang )
97+ if extensions , exists := repositoryLanguages [lowerLang ]; exists && len (extensions ) > 0 {
98+ filteredLanguages = append (filteredLanguages , lang )
99+ }
100+ }
101+
102+ // Only add tool if it has languages that exist in the repository
103+ if len (filteredLanguages ) > 0 {
104+ langInfo .Languages = filteredLanguages
105+ configTools = append (configTools , langInfo )
106+ }
75107 }
76108 }
77109
@@ -102,3 +134,88 @@ func CreateLanguagesConfigFile(apiTools []Tool, toolsConfigDir string, toolIDMap
102134 fmt .Println ("Created languages configuration file based on enabled tools" )
103135 return nil
104136}
137+
138+ // https://app.codacy.com/api/v3/organizations/gh/troubleshoot-codacy/repositories/eslint-test-examples/settings/languages
139+ func getRepositoryLanguages (apiToken string , provider string , organization string , repository string ) (map [string ][]string , error ) {
140+ client := & http.Client {
141+ Timeout : 10 * time .Second ,
142+ }
143+
144+ url := fmt .Sprintf ("%s/api/v3/organizations/%s/%s/repositories/%s/settings/languages" ,
145+ CodacyApiBase ,
146+ provider ,
147+ organization ,
148+ repository )
149+
150+ // Create a new GET request
151+ req , err := http .NewRequest ("GET" , url , nil )
152+ if err != nil {
153+ return nil , fmt .Errorf ("failed to create request: %w" , err )
154+ }
155+
156+ // Set the API token header
157+ req .Header .Set ("api-token" , apiToken )
158+
159+ // Send the request
160+ resp , err := client .Do (req )
161+ if err != nil {
162+ return nil , fmt .Errorf ("failed to send request: %w" , err )
163+ }
164+ defer resp .Body .Close ()
165+
166+ if resp .StatusCode != 200 {
167+ return nil , fmt .Errorf ("failed to get repository languages: status code %d" , resp .StatusCode )
168+ }
169+
170+ // Read the response body
171+ body , err := io .ReadAll (resp .Body )
172+ if err != nil {
173+ return nil , fmt .Errorf ("failed to read response body: %w" , err )
174+ }
175+
176+ // Define the response structure
177+ type LanguageResponse struct {
178+ Name string `json:"name"`
179+ CodacyDefaults []string `json:"codacyDefaults"`
180+ Extensions []string `json:"extensions"`
181+ Enabled bool `json:"enabled"`
182+ Detected bool `json:"detected"`
183+ }
184+
185+ type LanguagesResponse struct {
186+ Languages []LanguageResponse `json:"languages"`
187+ }
188+
189+ var response LanguagesResponse
190+ if err := json .Unmarshal (body , & response ); err != nil {
191+ return nil , fmt .Errorf ("failed to unmarshal response: %w" , err )
192+ }
193+
194+ // Create map to store language name -> combined extensions
195+ result := make (map [string ][]string )
196+
197+ // Filter and process languages
198+ for _ , lang := range response .Languages {
199+ if lang .Enabled && lang .Detected {
200+ // Combine and deduplicate extensions
201+ extensions := make (map [string ]struct {})
202+ for _ , ext := range lang .CodacyDefaults {
203+ extensions [ext ] = struct {}{}
204+ }
205+ for _ , ext := range lang .Extensions {
206+ extensions [ext ] = struct {}{}
207+ }
208+
209+ // Convert map to slice
210+ extSlice := make ([]string , 0 , len (extensions ))
211+ for ext := range extensions {
212+ extSlice = append (extSlice , ext )
213+ }
214+
215+ // Add to result map with lowercase key for case-insensitive matching
216+ result [strings .ToLower (lang .Name )] = extSlice
217+ }
218+ }
219+
220+ return result , nil
221+ }
0 commit comments