11package tools
22
33import (
4+ "encoding/json"
45 "fmt"
6+ "io"
7+ "net/http"
58 "os"
69 "path/filepath"
10+ "slices"
11+ "strings"
12+ "time"
713
814 "codacy/cli-v2/utils"
915
1016 "gopkg.in/yaml.v3"
1117)
1218
19+ var CodacyApiBase = "https://app.codacy.com"
20+
1321// ToolLanguageInfo contains language and extension information for a tool
1422type ToolLanguageInfo struct {
1523 Name string `yaml:"name"`
@@ -23,7 +31,7 @@ type LanguagesConfig struct {
2331}
2432
2533// CreateLanguagesConfigFile creates languages-config.yaml based on API response
26- func CreateLanguagesConfigFile (apiTools []Tool , toolsConfigDir string , toolIDMap map [string ]string ) error {
34+ func CreateLanguagesConfigFile (apiTools []Tool , toolsConfigDir string , toolIDMap map [string ]string , apiToken string , provider string , organization string , repository string ) error {
2735 // Map tool names to their language/extension information
2836 toolLanguageMap := map [string ]ToolLanguageInfo {
2937 "cppcheck" : {
@@ -61,6 +69,11 @@ func CreateLanguagesConfigFile(apiTools []Tool, toolsConfigDir string, toolIDMap
6169 // Build a list of tool language info for enabled tools
6270 var configTools []ToolLanguageInfo
6371
72+ repositoryLanguages , err := getRepositoryLanguages (apiToken , provider , organization , repository )
73+ if err != nil {
74+ return fmt .Errorf ("failed to get repository languages: %w" , err )
75+ }
76+
6477 for _ , tool := range apiTools {
6578 shortName , exists := toolIDMap [tool .Uuid ]
6679 if ! exists {
@@ -71,7 +84,36 @@ func CreateLanguagesConfigFile(apiTools []Tool, toolsConfigDir string, toolIDMap
7184 // Get language info for this tool
7285 langInfo , exists := toolLanguageMap [shortName ]
7386 if exists {
74- configTools = append (configTools , langInfo )
87+ // Special case for Trivy - always include it
88+ if shortName == "trivy" {
89+ configTools = append (configTools , langInfo )
90+ continue
91+ }
92+
93+ // Filter languages based on repository languages
94+ var filteredLanguages []string
95+ var filteredExtensionsSet = make (map [string ]struct {})
96+ for _ , lang := range langInfo .Languages {
97+ lowerLang := strings .ToLower (lang )
98+ if extensions , exists := repositoryLanguages [lowerLang ]; exists && len (extensions ) > 0 {
99+ filteredLanguages = append (filteredLanguages , lang )
100+ for _ , ext := range extensions {
101+ filteredExtensionsSet [ext ] = struct {}{}
102+ }
103+ }
104+ }
105+ filteredExtensions := make ([]string , 0 , len (filteredExtensionsSet ))
106+ for ext := range filteredExtensionsSet {
107+ filteredExtensions = append (filteredExtensions , ext )
108+ }
109+ slices .Sort (filteredExtensions )
110+ langInfo .Languages = filteredLanguages
111+ langInfo .Extensions = filteredExtensions
112+
113+ // Only add tool if it has languages that exist in the repository
114+ if len (filteredLanguages ) > 0 {
115+ configTools = append (configTools , langInfo )
116+ }
75117 }
76118 }
77119
@@ -102,3 +144,90 @@ func CreateLanguagesConfigFile(apiTools []Tool, toolsConfigDir string, toolIDMap
102144 fmt .Println ("Created languages configuration file based on enabled tools" )
103145 return nil
104146}
147+
148+ func getRepositoryLanguages (apiToken string , provider string , organization string , repository string ) (map [string ][]string , error ) {
149+ client := & http.Client {
150+ Timeout : 10 * time .Second ,
151+ }
152+
153+ url := fmt .Sprintf ("%s/api/v3/organizations/%s/%s/repositories/%s/settings/languages" ,
154+ CodacyApiBase ,
155+ provider ,
156+ organization ,
157+ repository )
158+
159+ // Create a new GET request
160+ req , err := http .NewRequest ("GET" , url , nil )
161+ if err != nil {
162+ return nil , fmt .Errorf ("failed to create request: %w" , err )
163+ }
164+
165+ // Set the API token header
166+ req .Header .Set ("api-token" , apiToken )
167+
168+ // Send the request
169+ resp , err := client .Do (req )
170+ if err != nil {
171+ return nil , fmt .Errorf ("failed to send request: %w" , err )
172+ }
173+ defer resp .Body .Close ()
174+
175+ if resp .StatusCode != 200 {
176+ return nil , fmt .Errorf ("failed to get repository languages: status code %d" , resp .StatusCode )
177+ }
178+
179+ // Read the response body
180+ body , err := io .ReadAll (resp .Body )
181+ if err != nil {
182+ return nil , fmt .Errorf ("failed to read response body: %w" , err )
183+ }
184+
185+ // Define the response structure
186+ type LanguageResponse struct {
187+ Name string `json:"name"`
188+ CodacyDefaults []string `json:"codacyDefaults"`
189+ Extensions []string `json:"extensions"`
190+ Enabled bool `json:"enabled"`
191+ Detected bool `json:"detected"`
192+ }
193+
194+ type LanguagesResponse struct {
195+ Languages []LanguageResponse `json:"languages"`
196+ }
197+
198+ var response LanguagesResponse
199+ if err := json .Unmarshal (body , & response ); err != nil {
200+ return nil , fmt .Errorf ("failed to unmarshal response: %w" , err )
201+ }
202+
203+ // Create map to store language name -> combined extensions
204+ result := make (map [string ][]string )
205+
206+ // Filter and process languages
207+ for _ , lang := range response .Languages {
208+ if lang .Enabled && lang .Detected {
209+ // Combine and deduplicate extensions
210+ extensions := make (map [string ]struct {})
211+ for _ , ext := range lang .CodacyDefaults {
212+ extensions [ext ] = struct {}{}
213+ }
214+ for _ , ext := range lang .Extensions {
215+ extensions [ext ] = struct {}{}
216+ }
217+
218+ // Convert map to slice
219+ extSlice := make ([]string , 0 , len (extensions ))
220+ for ext := range extensions {
221+ extSlice = append (extSlice , ext )
222+ }
223+
224+ // Sort extensions for consistent ordering in the config file
225+ slices .Sort (extSlice )
226+
227+ // Add to result map with lowercase key for case-insensitive matching
228+ result [strings .ToLower (lang .Name )] = extSlice
229+ }
230+ }
231+
232+ return result , nil
233+ }
0 commit comments