11package cmd
22
33import (
4+ "codacy/cli-v2/cmd/cmdutils"
5+ "codacy/cli-v2/cmd/configsetup"
46 "codacy/cli-v2/config"
7+ "codacy/cli-v2/constants"
58 "codacy/cli-v2/domain"
69 "codacy/cli-v2/plugins"
710 "codacy/cli-v2/tools"
@@ -44,7 +47,7 @@ type LanguagesConfig struct {
4447// LoadLanguageConfig loads the language configuration from the file
4548func LoadLanguageConfig () (* LanguagesConfig , error ) {
4649 // First, try to load the YAML config
47- yamlPath := filepath .Join (config .Config .ToolsConfigDirectory (), "languages-config.yaml" )
50+ yamlPath := filepath .Join (config .Config .ToolsConfigDirectory (), constants . LanguagesConfigFileName )
4851
4952 // Check if the YAML file exists
5053 if _ , err := os .Stat (yamlPath ); err == nil {
@@ -219,6 +222,7 @@ func init() {
219222 analyzeCmd .Flags ().StringVarP (& toolsToAnalyzeParam , "tool" , "t" , "" , "Which tool to run analysis with. If not specified, all configured tools will be run" )
220223 analyzeCmd .Flags ().StringVar (& outputFormat , "format" , "" , "Output format (use 'sarif' for SARIF format)" )
221224 analyzeCmd .Flags ().BoolVar (& autoFix , "fix" , false , "Apply auto fix to your issues when available" )
225+ cmdutils .AddCloudFlags (analyzeCmd , & initFlags )
222226 rootCmd .AddCommand (analyzeCmd )
223227}
224228
@@ -279,7 +283,56 @@ func validateToolName(toolName string) error {
279283 return nil
280284}
281285
282- func runToolByName (toolName string , workDirectory string , pathsToCheck []string , autoFix bool , outputFile string , outputFormat string , tool * plugins.ToolInfo , runtime * plugins.RuntimeInfo ) error {
286+ // checkIfConfigExistsAndIsNeeded validates if a tool has config file and creates one if needed
287+ func checkIfConfigExistsAndIsNeeded (toolName string , cliLocalMode bool ) error {
288+ configFileName := constants .ToolConfigFileNames [toolName ]
289+ if configFileName == "" {
290+ // Tool doesn't use config file
291+ return nil
292+ }
293+
294+ // Use the configuration system to get the tools config directory
295+ toolsConfigDir := config .Config .ToolsConfigDirectory ()
296+ toolConfigPath := filepath .Join (toolsConfigDir , configFileName )
297+
298+ // Check if the config file exists
299+ if _ , err := os .Stat (toolConfigPath ); os .IsNotExist (err ) {
300+ // Config file does not exist - create it if we have the means to do so
301+ if (! cliLocalMode && initFlags .ApiToken != "" ) || cliLocalMode {
302+ fmt .Printf ("Creating new config file for tool %s\n " , toolName )
303+ if err := configsetup .CreateToolConfigurationFile (toolName , initFlags ); err != nil {
304+ return fmt .Errorf ("failed to create config file for tool %s: %w" , toolName , err )
305+ }
306+
307+ // Ensure .gitignore exists FIRST to prevent config files from being analyzed
308+ if err := configsetup .CreateGitIgnoreFile (); err != nil {
309+ logger .Warn ("Failed to create .gitignore file" , logrus.Fields {
310+ "error" : err ,
311+ })
312+ }
313+ } else {
314+ logger .Debug ("Config file not found for tool, using tool defaults" , logrus.Fields {
315+ "tool" : toolName ,
316+ "toolConfigPath" : toolConfigPath ,
317+ "message" : "No API token provided" ,
318+ })
319+ }
320+ } else if err != nil {
321+ return fmt .Errorf ("error checking config file for tool %s: %w" , toolName , err )
322+ } else {
323+ logger .Info ("Config file found for tool" , logrus.Fields {
324+ "tool" : toolName ,
325+ "toolConfigPath" : toolConfigPath ,
326+ })
327+ }
328+ return nil
329+ }
330+
331+ func runToolByName (toolName string , workDirectory string , pathsToCheck []string , autoFix bool , outputFile string , outputFormat string , tool * plugins.ToolInfo , runtime * plugins.RuntimeInfo , cliLocalMode bool ) error {
332+ err := checkIfConfigExistsAndIsNeeded (toolName , cliLocalMode )
333+ if err != nil {
334+ return err
335+ }
283336 switch toolName {
284337 case "eslint" :
285338 binaryPath := runtime .Binaries [tool .Runtime ]
@@ -310,13 +363,13 @@ func runToolByName(toolName string, workDirectory string, pathsToCheck []string,
310363 return fmt .Errorf ("unsupported tool: %s" , toolName )
311364}
312365
313- func runTool (workDirectory string , toolName string , pathsToCheck []string , outputFile string , autoFix bool , outputFormat string ) error {
366+ func runTool (workDirectory string , toolName string , pathsToCheck []string , outputFile string , autoFix bool , outputFormat string , cliLocalMode bool ) error {
314367 err := validateToolName (toolName )
315368 if err != nil {
316369 return err
317370 }
318371 log .Println ("Running tools for the specified file(s)..." )
319- log .Printf ("Running %s...\n " , toolName )
372+ log .Printf ("Running %s..." , toolName )
320373
321374 tool := config .Config .Tools ()[toolName ]
322375 var isToolInstalled bool
@@ -348,7 +401,7 @@ func runTool(workDirectory string, toolName string, pathsToCheck []string, outpu
348401 runtime = config .Config .Runtimes ()[tool .Runtime ]
349402 isRuntimeInstalled = runtime == nil || config .Config .IsRuntimeInstalled (tool .Runtime , runtime )
350403 if ! isRuntimeInstalled {
351- fmt .Printf ("%s runtime is not installed, installing...\n " , tool .Runtime )
404+ fmt .Printf ("%s runtime is not installed, installing..." , tool .Runtime )
352405 err := config .InstallRuntime (tool .Runtime , runtime )
353406 if err != nil {
354407 return fmt .Errorf ("failed to install %s runtime: %w" , tool .Runtime , err )
@@ -360,15 +413,15 @@ func runTool(workDirectory string, toolName string, pathsToCheck []string, outpu
360413 runtime = config .Config .Runtimes ()[tool .Runtime ]
361414 isRuntimeInstalled = runtime == nil || config .Config .IsRuntimeInstalled (tool .Runtime , runtime )
362415 if ! isRuntimeInstalled {
363- fmt .Printf ("%s runtime is not installed, installing...\n " , tool .Runtime )
416+ fmt .Printf ("%s runtime is not installed, installing..." , tool .Runtime )
364417 err := config .InstallRuntime (tool .Runtime , runtime )
365418 if err != nil {
366419 return fmt .Errorf ("failed to install %s runtime: %w" , tool .Runtime , err )
367420 }
368421 runtime = config .Config .Runtimes ()[tool .Runtime ]
369422 }
370423 }
371- return runToolByName (toolName , workDirectory , pathsToCheck , autoFix , outputFile , outputFormat , tool , runtime )
424+ return runToolByName (toolName , workDirectory , pathsToCheck , autoFix , outputFile , outputFormat , tool , runtime , cliLocalMode )
372425}
373426
374427// validatePaths checks if all provided paths exist and returns an error if any don't
@@ -384,10 +437,19 @@ func validatePaths(paths []string) error {
384437 return nil
385438}
386439
440+ func validateCloudMode (cliLocalMode bool ) error {
441+ if cliLocalMode {
442+ fmt .Println ("Warning: cannot run in cloud mode" )
443+ }
444+ return nil
445+ }
446+
387447var analyzeCmd = & cobra.Command {
388448 Use : "analyze" ,
389449 Short : "Analyze code using configured tools" ,
390- Long : `Analyze code using configured tools and output results in the specified format.` ,
450+ Long : `Analyze code using configured tools and output results in the specified format.
451+
452+ Supports API token, provider, and repository flags to automatically fetch tool configurations from Codacy API if they don't exist locally.` ,
391453 Run : func (cmd * cobra.Command , args []string ) {
392454 // Validate paths before proceeding
393455 if err := validatePaths (args ); err != nil {
@@ -401,6 +463,10 @@ var analyzeCmd = &cobra.Command{
401463 log .Fatalf ("Failed to get current working directory: %v" , err )
402464 }
403465
466+ cliLocalMode := len (initFlags .ApiToken ) == 0
467+
468+ validateCloudMode (cliLocalMode )
469+
404470 var toolsToRun map [string ]* plugins.ToolInfo
405471
406472 if toolsToAnalyzeParam != "" {
@@ -437,7 +503,7 @@ var analyzeCmd = &cobra.Command{
437503 var sarifOutputs []string
438504 for toolName := range toolsToRun {
439505 tmpFile := filepath .Join (tmpDir , fmt .Sprintf ("%s.sarif" , toolName ))
440- if err := runTool (workDirectory , toolName , args , tmpFile , autoFix , outputFormat ); err != nil {
506+ if err := runTool (workDirectory , toolName , args , tmpFile , autoFix , outputFormat , cliLocalMode ); err != nil {
441507 log .Printf ("Tool failed to run: %v\n " , err )
442508 }
443509 sarifOutputs = append (sarifOutputs , tmpFile )
@@ -472,7 +538,7 @@ var analyzeCmd = &cobra.Command{
472538 } else {
473539 // Run tools without merging outputs
474540 for toolName := range toolsToRun {
475- if err := runTool (workDirectory , toolName , args , outputFile , autoFix , outputFormat ); err != nil {
541+ if err := runTool (workDirectory , toolName , args , outputFile , autoFix , outputFormat , cliLocalMode ); err != nil {
476542 log .Printf ("Tool failed to run: %v\n " , err )
477543 }
478544 }
0 commit comments