Skip to content

Commit ce36811

Browse files
authored
Merge pull request #68 from codacy/init-behaviour-PLUTO-1384
Init behaviour PLUTO-1384
2 parents 0142cac + b97707f commit ce36811

File tree

5 files changed

+451
-25
lines changed

5 files changed

+451
-25
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ go.work.sum
2525
.vscode/
2626

2727
# Codacy CLI
28-
cli-v2
28+
cli-v2
29+
codacy-cli

cmd/init.go

Lines changed: 110 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"net/http"
1515
"os"
1616
"path/filepath"
17+
"strings"
1718
"time"
1819

1920
"github.com/spf13/cobra"
@@ -130,35 +131,83 @@ func createConfigurationFiles(tools []tools.Tool, cliLocalMode bool) error {
130131
}
131132

132133
func configFileTemplate(tools []tools.Tool) string {
134+
// Maps to track which tools are enabled
135+
toolsMap := make(map[string]bool)
136+
toolVersions := make(map[string]string)
137+
138+
// Track needed runtimes
139+
needsNode := false
140+
needsPython := false
133141

134142
// Default versions
135-
eslintVersion := "9.3.0"
136-
trivyVersion := "0.59.1" // Latest stable version
137-
pylintVersion := "3.3.6"
138-
pmdVersion := "6.55.0"
143+
defaultVersions := map[string]string{
144+
ESLint: "9.3.0",
145+
Trivy: "0.59.1",
146+
PyLint: "3.3.6",
147+
PMD: "6.55.0",
148+
}
139149

150+
// Build map of enabled tools with their versions
140151
for _, tool := range tools {
141-
switch tool.Uuid {
142-
case ESLint:
143-
eslintVersion = tool.Version
144-
case Trivy:
145-
trivyVersion = tool.Version
146-
case PyLint:
147-
pylintVersion = tool.Version
148-
case PMD:
149-
pmdVersion = tool.Version
152+
toolsMap[tool.Uuid] = true
153+
if tool.Version != "" {
154+
toolVersions[tool.Uuid] = tool.Version
155+
} else {
156+
toolVersions[tool.Uuid] = defaultVersions[tool.Uuid]
157+
}
158+
159+
// Check if tool needs a runtime
160+
if tool.Uuid == ESLint {
161+
needsNode = true
162+
} else if tool.Uuid == PyLint {
163+
needsPython = true
164+
}
165+
}
166+
167+
// Start building the YAML content
168+
var sb strings.Builder
169+
sb.WriteString("runtimes:\n")
170+
171+
// Only include runtimes needed by the enabled tools
172+
if len(tools) > 0 {
173+
if needsNode {
174+
sb.WriteString(" - [email protected]\n")
175+
}
176+
if needsPython {
177+
sb.WriteString(" - [email protected]\n")
178+
}
179+
} else {
180+
// In local mode with no tools specified, include all runtimes
181+
sb.WriteString(" - [email protected]\n")
182+
sb.WriteString(" - [email protected]\n")
183+
}
184+
185+
sb.WriteString("tools:\n")
186+
187+
// If we have tools from the API (enabled tools), use only those
188+
if len(tools) > 0 {
189+
// Add only the tools that are in the API response (enabled tools)
190+
uuidToName := map[string]string{
191+
ESLint: "eslint",
192+
Trivy: "trivy",
193+
PyLint: "pylint",
194+
PMD: "pmd",
195+
}
196+
197+
for uuid, name := range uuidToName {
198+
if toolsMap[uuid] {
199+
sb.WriteString(fmt.Sprintf(" - %s@%s\n", name, toolVersions[uuid]))
200+
}
150201
}
202+
} else {
203+
// If no tools were specified (local mode), include all defaults
204+
sb.WriteString(fmt.Sprintf(" - eslint@%s\n", defaultVersions[ESLint]))
205+
sb.WriteString(fmt.Sprintf(" - trivy@%s\n", defaultVersions[Trivy]))
206+
sb.WriteString(fmt.Sprintf(" - pylint@%s\n", defaultVersions[PyLint]))
207+
sb.WriteString(fmt.Sprintf(" - pmd@%s\n", defaultVersions[PMD]))
151208
}
152209

153-
return fmt.Sprintf(`runtimes:
154-
155-
156-
tools:
157-
- eslint@%s
158-
- trivy@%s
159-
- pylint@%s
160-
- pmd@%s
161-
`, eslintVersion, trivyVersion, pylintVersion, pmdVersion)
210+
return sb.String()
162211
}
163212

164213
func cliConfigFileTemplate(cliLocalMode bool) string {
@@ -183,6 +232,11 @@ func buildRepositoryConfigurationFiles(token string) error {
183232
return fmt.Errorf("failed to create tools-configs directory: %w", err)
184233
}
185234

235+
// Clear any previous configuration files
236+
if err := cleanConfigDirectory(toolsConfigDir); err != nil {
237+
return fmt.Errorf("failed to clean configuration directory: %w", err)
238+
}
239+
186240
client := &http.Client{
187241
Timeout: 10 * time.Second,
188242
}
@@ -192,12 +246,17 @@ func buildRepositoryConfigurationFiles(token string) error {
192246
return err
193247
}
194248

195-
err = createConfigurationFiles(apiTools, true)
249+
// Filter out any tools that use configuration file
250+
configuredToolsWithUI := tools.FilterToolsByConfigUsage(apiTools)
251+
252+
// Create main config files with all enabled API tools
253+
err = createConfigurationFiles(apiTools, false)
196254
if err != nil {
197255
log.Fatal(err)
198256
}
199257

200-
for _, tool := range apiTools {
258+
// Only generate config files for tools not using their own config file
259+
for _, tool := range configuredToolsWithUI {
201260
url := fmt.Sprintf("%s/api/v3/analysis/organizations/%s/%s/repositories/%s/tools/%s/patterns?enabled=true",
202261
CodacyApiBase,
203262
initFlags.provider,
@@ -375,6 +434,33 @@ func createDefaultEslintConfigFile(toolsConfigDir string) error {
375434
return os.WriteFile(filepath.Join(toolsConfigDir, "eslint.config.mjs"), []byte(content), utils.DefaultFilePerms)
376435
}
377436

437+
// cleanConfigDirectory removes all previous configuration files in the tools-configs directory
438+
func cleanConfigDirectory(toolsConfigDir string) error {
439+
// Check if directory exists
440+
if _, err := os.Stat(toolsConfigDir); os.IsNotExist(err) {
441+
return nil // Directory doesn't exist, nothing to clean
442+
}
443+
444+
// Read directory contents
445+
entries, err := os.ReadDir(toolsConfigDir)
446+
if err != nil {
447+
return fmt.Errorf("failed to read config directory: %w", err)
448+
}
449+
450+
// Remove all files
451+
for _, entry := range entries {
452+
if !entry.IsDir() { // Only remove files, not subdirectories
453+
filePath := filepath.Join(toolsConfigDir, entry.Name())
454+
if err := os.Remove(filePath); err != nil {
455+
return fmt.Errorf("failed to remove file %s: %w", filePath, err)
456+
}
457+
}
458+
}
459+
460+
fmt.Println("Cleaned previous configuration files")
461+
return nil
462+
}
463+
378464
const (
379465
ESLint string = "f8b29663-2cb2-498d-b923-a10c6a8c05cd"
380466
Trivy string = "2fd7fbe0-33f9-4ab3-ab73-e9b62404e2cb"

cmd/init_test.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package cmd
2+
3+
import (
4+
"codacy/cli-v2/tools"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestConfigFileTemplate(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
tools []tools.Tool
16+
expected []string
17+
notExpected []string
18+
}{
19+
{
20+
name: "empty tools list uses defaults",
21+
tools: []tools.Tool{},
22+
expected: []string{
23+
24+
25+
26+
27+
28+
29+
},
30+
notExpected: []string{},
31+
},
32+
{
33+
name: "only eslint enabled",
34+
tools: []tools.Tool{
35+
{
36+
Uuid: ESLint,
37+
Name: "eslint",
38+
Version: "9.4.0",
39+
},
40+
},
41+
expected: []string{
42+
43+
44+
},
45+
notExpected: []string{
46+
47+
"pylint",
48+
"pmd",
49+
"trivy",
50+
},
51+
},
52+
{
53+
name: "only pylint enabled",
54+
tools: []tools.Tool{
55+
{
56+
Uuid: PyLint,
57+
Name: "pylint",
58+
Version: "3.4.0",
59+
},
60+
},
61+
expected: []string{
62+
63+
64+
},
65+
notExpected: []string{
66+
67+
"eslint",
68+
"pmd",
69+
"trivy",
70+
},
71+
},
72+
{
73+
name: "eslint and trivy enabled",
74+
tools: []tools.Tool{
75+
{
76+
Uuid: ESLint,
77+
Name: "eslint",
78+
Version: "9.4.0",
79+
},
80+
{
81+
Uuid: Trivy,
82+
Name: "trivy",
83+
Version: "0.60.0",
84+
},
85+
},
86+
expected: []string{
87+
88+
89+
90+
},
91+
notExpected: []string{
92+
93+
"pylint",
94+
"pmd",
95+
},
96+
},
97+
{
98+
name: "all tools enabled",
99+
tools: []tools.Tool{
100+
{
101+
Uuid: ESLint,
102+
Name: "eslint",
103+
Version: "9.4.0",
104+
},
105+
{
106+
Uuid: Trivy,
107+
Name: "trivy",
108+
Version: "0.60.0",
109+
},
110+
{
111+
Uuid: PyLint,
112+
Name: "pylint",
113+
Version: "3.4.0",
114+
},
115+
{
116+
Uuid: PMD,
117+
Name: "pmd",
118+
Version: "6.56.0",
119+
},
120+
},
121+
expected: []string{
122+
123+
124+
125+
126+
127+
128+
},
129+
notExpected: []string{},
130+
},
131+
}
132+
133+
for _, tt := range tests {
134+
t.Run(tt.name, func(t *testing.T) {
135+
result := configFileTemplate(tt.tools)
136+
137+
// Check that expected strings are present
138+
for _, exp := range tt.expected {
139+
assert.Contains(t, result, exp, "Config file should contain %s", exp)
140+
}
141+
142+
// Check that not-expected strings are absent
143+
for _, notExp := range tt.notExpected {
144+
assert.NotContains(t, result, notExp, "Config file should not contain %s", notExp)
145+
}
146+
})
147+
}
148+
}
149+
150+
func TestCleanConfigDirectory(t *testing.T) {
151+
// Create a temporary directory for testing
152+
tempDir := t.TempDir()
153+
154+
// Create some test files in the temp dir
155+
testFiles := []string{
156+
"eslint.config.mjs",
157+
"pylint.rc",
158+
"ruleset.xml",
159+
"trivy.yaml",
160+
}
161+
162+
for _, file := range testFiles {
163+
filePath := filepath.Join(tempDir, file)
164+
err := os.WriteFile(filePath, []byte("test content"), 0644)
165+
assert.NoError(t, err, "Failed to create test file: %s", filePath)
166+
}
167+
168+
// Verify files exist
169+
files, err := os.ReadDir(tempDir)
170+
assert.NoError(t, err)
171+
assert.Equal(t, len(testFiles), len(files), "Expected %d files before cleaning", len(testFiles))
172+
173+
// Run the clean function
174+
err = cleanConfigDirectory(tempDir)
175+
assert.NoError(t, err, "cleanConfigDirectory should not return an error")
176+
177+
// Verify all files are gone
178+
files, err = os.ReadDir(tempDir)
179+
assert.NoError(t, err)
180+
assert.Equal(t, 0, len(files), "Expected 0 files after cleaning, got %d", len(files))
181+
}

tools/getTools.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,17 @@ type Tool struct {
138138
UsesConfigFile bool `json:"hasConfigurationFile"`
139139
} `json:"settings"`
140140
}
141+
142+
// FilterToolsByConfigUsage filters out tools that use their own configuration files
143+
// Returns only tools that need configuration to be generated for them (UsesConfigFile = false)
144+
func FilterToolsByConfigUsage(tools []Tool) []Tool {
145+
var filtered []Tool
146+
for _, tool := range tools {
147+
if !tool.Settings.UsesConfigFile {
148+
filtered = append(filtered, tool)
149+
} else {
150+
fmt.Printf("Skipping config generation for %s - configured to use repo's config file\n", tool.Name)
151+
}
152+
}
153+
return filtered
154+
}

0 commit comments

Comments
 (0)