From 2cee52ef67696fa0a4802ec7b312b91f59e7a9bd Mon Sep 17 00:00:00 2001 From: Milosz Jakubanis Date: Wed, 25 Mar 2026 13:34:57 +0000 Subject: [PATCH 1/2] feat: Fix for already existing config CF-2275 If config does not exist in .codacy/tools-configs it will first check if the root of the project contains any configurations. --- cmd/analyze.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cmd/analyze.go b/cmd/analyze.go index 1ead9705..3d11899d 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -272,10 +272,10 @@ var versionedToolNames = map[string]map[int]string{ } var simpleToolAliases = map[string]string{ - "lizard": "Lizard", + "lizard": "Lizard", "opengrep": "Opengrep", - "pylint": "pylintpython3", - "trivy": "Trivy", + "pylint": "pylintpython3", + "trivy": "Trivy", } func getToolName(toolName string, version string) string { @@ -328,7 +328,7 @@ func checkIfConfigExistsAndIsNeeded(toolName string, cliLocalMode bool) error { // Check if the config file exists if _, err := os.Stat(toolConfigPath); os.IsNotExist(err) { - // Config file does not exist - create it if we have the means to do so + repoConfigPath := filepath.Join(config.Config.RepositoryDirectory(), configFileName) if (!cliLocalMode && initFlags.ApiToken != "") || cliLocalMode { if err := configsetup.CreateToolConfigurationFile(toolName, initFlags); err != nil { return fmt.Errorf("failed to create config file for tool %s: %w", toolName, err) @@ -340,6 +340,13 @@ func checkIfConfigExistsAndIsNeeded(toolName string, cliLocalMode bool) error { "error": err, }) } + } else if _, repoErr := os.Stat(repoConfigPath); repoErr == nil { + // Config not in .codacy/tools-configs/ - check if it exists in the repo root + logger.Info("Config file found in repository root for tool, skipping config creation", logrus.Fields{ + "tool": toolName, + "toolConfigPath": repoConfigPath, + }) + return nil } else { logger.Debug("Config file not found for tool, using tool defaults", logrus.Fields{ "tool": toolName, From 926b9042daeb3ae3ccd13007fc0d19db0381c79f Mon Sep 17 00:00:00 2001 From: Milosz Jakubanis Date: Wed, 25 Mar 2026 14:16:05 +0000 Subject: [PATCH 2/2] feat: Small fix, added tests CF-2275 --- cmd/analyze.go | 16 ++--- cmd/analyze_test.go | 142 ++++++++++++++++++++++++++++++-------------- 2 files changed, 107 insertions(+), 51 deletions(-) diff --git a/cmd/analyze.go b/cmd/analyze.go index 3d11899d..bd9dff97 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -329,7 +329,14 @@ func checkIfConfigExistsAndIsNeeded(toolName string, cliLocalMode bool) error { // Check if the config file exists if _, err := os.Stat(toolConfigPath); os.IsNotExist(err) { repoConfigPath := filepath.Join(config.Config.RepositoryDirectory(), configFileName) - if (!cliLocalMode && initFlags.ApiToken != "") || cliLocalMode { + if _, repoErr := os.Stat(repoConfigPath); repoErr == nil { + // Config not in .codacy/tools-configs/ - check if it exists in the repo root + logger.Info("Config file found in repository root for tool, skipping config creation", logrus.Fields{ + "tool": toolName, + "toolConfigPath": repoConfigPath, + }) + return nil + } else if (!cliLocalMode && initFlags.ApiToken != "") || cliLocalMode { if err := configsetup.CreateToolConfigurationFile(toolName, initFlags); err != nil { return fmt.Errorf("failed to create config file for tool %s: %w", toolName, err) } @@ -340,13 +347,6 @@ func checkIfConfigExistsAndIsNeeded(toolName string, cliLocalMode bool) error { "error": err, }) } - } else if _, repoErr := os.Stat(repoConfigPath); repoErr == nil { - // Config not in .codacy/tools-configs/ - check if it exists in the repo root - logger.Info("Config file found in repository root for tool, skipping config creation", logrus.Fields{ - "tool": toolName, - "toolConfigPath": repoConfigPath, - }) - return nil } else { logger.Debug("Config file not found for tool, using tool defaults", logrus.Fields{ "tool": toolName, diff --git a/cmd/analyze_test.go b/cmd/analyze_test.go index d40703d3..b25ffc35 100644 --- a/cmd/analyze_test.go +++ b/cmd/analyze_test.go @@ -332,49 +332,81 @@ func TestCheckIfConfigExistsAndIsNeeded(t *testing.T) { }() tests := []struct { - name string - toolName string - cliLocalMode bool - apiToken string - configFileExists bool - expectError bool - description string + name string + toolName string + cliLocalMode bool + apiToken string + configFileExists bool + repoRootConfigExists bool + expectError bool + expectConfigCreatedInToolsDir bool + description string }{ { - name: "tool_without_config_file", - toolName: "unsupported-tool", - cliLocalMode: false, - apiToken: "test-token", - configFileExists: false, - expectError: false, - description: "Tool that doesn't use config files should return without error", + name: "tool_without_config_file", + toolName: "unsupported-tool", + cliLocalMode: false, + apiToken: "test-token", + configFileExists: false, + repoRootConfigExists: false, + expectError: false, + expectConfigCreatedInToolsDir: false, + description: "Tool that doesn't use config files should return without error", }, { - name: "config_file_exists", - toolName: "eslint", - cliLocalMode: false, - apiToken: "test-token", - configFileExists: true, - expectError: false, - description: "When config file exists, should find it successfully", + name: "config_file_exists_in_tools_dir", + toolName: "eslint", + cliLocalMode: false, + apiToken: "test-token", + configFileExists: true, + repoRootConfigExists: false, + expectError: false, + expectConfigCreatedInToolsDir: true, + description: "When config file exists in tools-configs, should find it successfully", }, { - name: "remote_mode_without_token_no_config", - toolName: "eslint", - cliLocalMode: false, - apiToken: "", - configFileExists: false, - expectError: false, - description: "Remote mode without token should show appropriate message", + name: "remote_mode_without_token_no_config", + toolName: "eslint", + cliLocalMode: false, + apiToken: "", + configFileExists: false, + repoRootConfigExists: false, + expectError: false, + expectConfigCreatedInToolsDir: false, + description: "Remote mode without token and no config anywhere should not create defaults", }, { - name: "local_mode_no_config", - toolName: "eslint", - cliLocalMode: true, - apiToken: "", - configFileExists: false, - expectError: false, - description: "Local mode should create config file if tools-configs directory exists", + name: "local_mode_no_config", + toolName: "eslint", + cliLocalMode: true, + apiToken: "", + configFileExists: false, + repoRootConfigExists: false, + expectError: false, + expectConfigCreatedInToolsDir: true, + description: "Local mode with no config anywhere should create a default config in tools-configs", + }, + { + name: "local_mode_config_exists_in_repo_root", + toolName: "eslint", + cliLocalMode: true, + apiToken: "", + configFileExists: false, + repoRootConfigExists: true, + expectError: false, + expectConfigCreatedInToolsDir: false, + description: "Local mode should not create default config when user's own config exists in repo root", + }, + { + name: "remote_mode_with_token_config_exists_in_repo_root", + toolName: "eslint", + cliLocalMode: false, + apiToken: "test-token", + configFileExists: false, + repoRootConfigExists: true, + expectError: false, + expectConfigCreatedInToolsDir: false, + description: "Remote mode should not create default config when user's own config exists in repo root", }, } @@ -392,7 +424,7 @@ func TestCheckIfConfigExistsAndIsNeeded(t *testing.T) { // Mock config to use our temporary directory BEFORE creating files config.Config = *config.NewConfigType(tmpDir, tmpDir, tmpDir) - // Create config file if needed - using the same path logic as the function under test + // Create config file in tools-configs if needed if tt.configFileExists && constants.ToolConfigFileNames[tt.toolName] != "" { // Use config.Config.ToolsConfigDirectory() to get the exact same path the function will use toolsConfigDir := config.Config.ToolsConfigDirectory() @@ -408,6 +440,13 @@ func TestCheckIfConfigExistsAndIsNeeded(t *testing.T) { require.NoError(t, err, "Config file should exist at %s", configPath) } + // Create config file in repo root if needed + if tt.repoRootConfigExists && constants.ToolConfigFileNames[tt.toolName] != "" { + repoRootConfigPath := filepath.Join(config.Config.RepositoryDirectory(), constants.ToolConfigFileNames[tt.toolName]) + err = os.WriteFile(repoRootConfigPath, []byte("user's own config"), constants.DefaultFilePerms) + require.NoError(t, err) + } + // Setup initFlags initFlags = domain.InitFlags{ ApiToken: tt.apiToken, @@ -423,6 +462,30 @@ func TestCheckIfConfigExistsAndIsNeeded(t *testing.T) { // Execute the function err = checkIfConfigExistsAndIsNeeded(tt.toolName, tt.cliLocalMode) + // Verify results + if tt.expectError { + assert.Error(t, err, tt.description) + } else { + assert.NoError(t, err, tt.description) + } + // Verify whether a config was created in .codacy/tools-configs/ + if constants.ToolConfigFileNames[tt.toolName] != "" { + toolsConfigDir := config.Config.ToolsConfigDirectory() + generatedConfigPath := filepath.Join(toolsConfigDir, constants.ToolConfigFileNames[tt.toolName]) + _, statErr := os.Stat(generatedConfigPath) + configCreated := statErr == nil + + if tt.expectConfigCreatedInToolsDir { + assert.True(t, configCreated, + "%s: expected a config file to exist in tools-configs at %s", + tt.description, generatedConfigPath) + } else { + assert.True(t, os.IsNotExist(statErr), + "%s: expected NO config file to be created in tools-configs, but found one at %s", + tt.description, generatedConfigPath) + } + } + // Clean up any files that might have been created by the function under test if !tt.configFileExists && constants.ToolConfigFileNames[tt.toolName] != "" { toolsConfigDir := config.Config.ToolsConfigDirectory() @@ -431,13 +494,6 @@ func TestCheckIfConfigExistsAndIsNeeded(t *testing.T) { os.Remove(configPath) } } - - // Verify results - if tt.expectError { - assert.Error(t, err, tt.description) - } else { - assert.NoError(t, err, tt.description) - } }) } }