Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .codacy/codacy.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
runtimes:
- node@22.2.0
- python@3.11.11
- dart@3.7.2
- java@17.0.10
- node@22.2.0
- python@3.11.11
tools:
- codacy-enigma-cli@0.0.1-main.8.49310c3
- dartanalyzer@3.7.2
- eslint@8.57.0
- trivy@0.59.1
- pylint@3.3.6
- lizard@1.17.19
- pmd@6.55.0
- pylint@3.3.6
- semgrep@1.78.0
- dartanalyzer@3.7.2
- lizard@1.17.19
- codacy-enigma-cli@0.0.1-main.8.49310c3
- trivy@0.59.1
6 changes: 0 additions & 6 deletions .github/workflows/it-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ jobs:
with:
fetch-depth: 0 # Needed for git history

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
cache: true

- name: Download CLI binaries
uses: actions/download-artifact@v4
with:
Expand Down
187 changes: 127 additions & 60 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
codacyclient "codacy/cli-v2/codacy-client"
"codacy/cli-v2/config"
"codacy/cli-v2/domain"
"codacy/cli-v2/plugins"
"codacy/cli-v2/tools"
"codacy/cli-v2/tools/lizard"
"codacy/cli-v2/tools/pylint"
Expand All @@ -12,6 +13,7 @@ import (
"log"
"os"
"path/filepath"
"sort"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -151,46 +153,65 @@ func createConfigurationFiles(tools []domain.Tool, cliLocalMode bool) error {
return nil
}

// Map tool UUIDs to their names
var toolNameMap = map[string]string{
ESLint: "eslint",
Trivy: "trivy",
PyLint: "pylint",
PMD: "pmd",
DartAnalyzer: "dartanalyzer",
Semgrep: "semgrep",
Lizard: "lizard",
}

// RuntimePluginConfig holds the structure of the runtime plugin.yaml file
type RuntimePluginConfig struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
DefaultVersion string `yaml:"default_version"`
}

func configFileTemplate(tools []domain.Tool) string {
// Maps to track which tools are enabled
toolsMap := make(map[string]bool)
toolVersions := make(map[string]string)

// Track needed runtimes
needsNode := false
needsPython := false
needsDart := false
needsJava := false

// Default versions
defaultVersions := map[string]string{
ESLint: "8.57.0",
Trivy: "0.59.1",
PyLint: "3.3.6",
PMD: "6.55.0",
DartAnalyzer: "3.7.2",
Semgrep: "1.78.0",
Lizard: "1.17.19",
}
neededRuntimes := make(map[string]bool)

// Get tool versions from plugin configurations
defaultVersions := plugins.GetToolVersions()

// Get runtime versions all at once
runtimeVersions := plugins.GetRuntimeVersions()

// Get tool runtime dependencies
runtimeDependencies := plugins.GetToolRuntimeDependencies()

// Build map of enabled tools with their versions
for _, tool := range tools {
toolsMap[tool.Uuid] = true
if tool.Version != "" {
toolVersions[tool.Uuid] = tool.Version
} else {
toolVersions[tool.Uuid] = defaultVersions[tool.Uuid]
toolName := toolNameMap[tool.Uuid]
if defaultVersion, ok := defaultVersions[toolName]; ok {
toolVersions[tool.Uuid] = defaultVersion
}
}

// Check if tool needs a runtime
if tool.Uuid == ESLint {
needsNode = true
} else if tool.Uuid == PyLint || tool.Uuid == Lizard {
needsPython = true
} else if tool.Uuid == DartAnalyzer {
needsDart = true
} else if tool.Uuid == PMD {
needsJava = true
// Get the tool's runtime dependency
toolName := toolNameMap[tool.Uuid]
if toolName != "" {
if runtime, ok := runtimeDependencies[toolName]; ok {
// Handle special case for dartanalyzer which can use either dart or flutter
if toolName == "dartanalyzer" {
// For now, default to dart runtime
neededRuntimes["dart"] = true
} else {
neededRuntimes[runtime] = true
}
}
}
}

Expand All @@ -200,55 +221,101 @@ func configFileTemplate(tools []domain.Tool) string {

// Only include runtimes needed by the enabled tools
if len(tools) > 0 {
if needsNode {
sb.WriteString(" - node@22.2.0\n")
// Create a sorted slice of runtimes
var sortedRuntimes []string
for runtime := range neededRuntimes {
sortedRuntimes = append(sortedRuntimes, runtime)
}
if needsPython {
sb.WriteString(" - python@3.11.11\n")
sort.Strings(sortedRuntimes)

// Write sorted runtimes
for _, runtime := range sortedRuntimes {
sb.WriteString(fmt.Sprintf(" - %s@%s\n", runtime, runtimeVersions[runtime]))
}
if needsDart {
sb.WriteString(" - dart@3.7.2\n")
} else {
// In local mode with no tools specified, include only the necessary runtimes
supportedTools, err := plugins.GetSupportedTools()
if err != nil {
log.Printf("Warning: failed to get supported tools: %v", err)
return sb.String()
}
if needsJava {
sb.WriteString(" - java@17.0.10\n")

// Get runtimes needed by supported tools
for toolName := range supportedTools {
if runtime, ok := runtimeDependencies[toolName]; ok {
if toolName == "dartanalyzer" {
neededRuntimes["dart"] = true
} else {
neededRuntimes[runtime] = true
}
}
}

// Create a sorted slice of runtimes
var sortedRuntimes []string
for runtime := range neededRuntimes {
sortedRuntimes = append(sortedRuntimes, runtime)
}
sort.Strings(sortedRuntimes)

// Write sorted runtimes
for _, runtime := range sortedRuntimes {
sb.WriteString(fmt.Sprintf(" - %s@%s\n", runtime, runtimeVersions[runtime]))
}
} else {
// In local mode with no tools specified, include all runtimes
sb.WriteString(" - node@22.2.0\n")
sb.WriteString(" - python@3.11.11\n")
sb.WriteString(" - dart@3.7.2\n")
sb.WriteString(" - java@17.0.10\n")
}

sb.WriteString("tools:\n")

// If we have tools from the API (enabled tools), use only those
if len(tools) > 0 {
// Add only the tools that are in the API response (enabled tools)
uuidToName := map[string]string{
ESLint: "eslint",
Trivy: "trivy",
PyLint: "pylint",
PMD: "pmd",
DartAnalyzer: "dartanalyzer",
Semgrep: "semgrep",
Lizard: "lizard",
}

for uuid, name := range uuidToName {
// Create a sorted slice of tool names
var sortedTools []string
for uuid, name := range toolNameMap {
if toolsMap[uuid] {
sb.WriteString(fmt.Sprintf(" - %s@%s\n", name, toolVersions[uuid]))
sortedTools = append(sortedTools, name)
}
}
sort.Strings(sortedTools)

// Write sorted tools
for _, name := range sortedTools {
// Find the UUID for this tool name to get its version
for uuid, toolName := range toolNameMap {
if toolName == name && toolsMap[uuid] {
version := toolVersions[uuid]
sb.WriteString(fmt.Sprintf(" - %s@%s\n", name, version))
break
}
}
}
} else {
// If no tools were specified (local mode), include all defaults
sb.WriteString(fmt.Sprintf(" - eslint@%s\n", defaultVersions[ESLint]))
sb.WriteString(fmt.Sprintf(" - trivy@%s\n", defaultVersions[Trivy]))
sb.WriteString(fmt.Sprintf(" - pylint@%s\n", defaultVersions[PyLint]))
sb.WriteString(fmt.Sprintf(" - pmd@%s\n", defaultVersions[PMD]))
sb.WriteString(fmt.Sprintf(" - dartanalyzer@%s\n", defaultVersions[DartAnalyzer]))
sb.WriteString(fmt.Sprintf(" - semgrep@%s\n", defaultVersions[Semgrep]))
sb.WriteString(fmt.Sprintf(" - lizard@%s\n", defaultVersions[Lizard]))
// If no tools were specified (local mode), include all tools in sorted order
var sortedTools []string

// Get supported tools from plugin system
supportedTools, err := plugins.GetSupportedTools()
if err != nil {
log.Printf("Warning: failed to get supported tools: %v", err)
return sb.String()
}

// Convert map keys to slice and sort them
for toolName := range supportedTools {
if version, ok := defaultVersions[toolName]; ok {
// Skip tools without a version
if version != "" {
sortedTools = append(sortedTools, toolName)
}
}
}
sort.Strings(sortedTools)

// Write sorted tools
for _, toolName := range sortedTools {
if version, ok := defaultVersions[toolName]; ok {
sb.WriteString(fmt.Sprintf(" - %s@%s\n", toolName, version))
}
}
}

return sb.String()
Expand Down
2 changes: 1 addition & 1 deletion cmd/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestConfigFileTemplate(t *testing.T) {
expected: []string{
"node@22.2.0",
"python@3.11.11",
"eslint@8.57.0",
"eslint@9.3.0",
"trivy@0.59.1",
"pylint@3.3.6",
"pmd@6.55.0",
Expand Down
38 changes: 3 additions & 35 deletions config/runtimes-installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ func InstallRuntimes(config *ConfigType) error {

// InstallRuntime installs a specific runtime
func InstallRuntime(name string, runtimeInfo *plugins.RuntimeInfo) error {

// Check if the runtime is already installed
if isRuntimeInstalled(runtimeInfo) {
// Skip if already installed
if Config.IsRuntimeInstalled(name, runtimeInfo) {
logger.Info("Runtime already installed", logrus.Fields{
"runtime": name,
"version": runtimeInfo.Version,
Expand All @@ -65,7 +64,7 @@ func InstallRuntime(name string, runtimeInfo *plugins.RuntimeInfo) error {
}

// Verify that the runtime binaries are available
if !isRuntimeInstalled(runtimeInfo) {
if !Config.IsRuntimeInstalled(name, runtimeInfo) {
logger.Error("Runtime binaries not found after extraction", logrus.Fields{
"runtime": name,
"version": runtimeInfo.Version,
Expand All @@ -76,37 +75,6 @@ func InstallRuntime(name string, runtimeInfo *plugins.RuntimeInfo) error {
return nil
}

// isRuntimeInstalled checks if a runtime is already installed by checking for the binary
func isRuntimeInstalled(runtimeInfo *plugins.RuntimeInfo) bool {
// If there are no binaries, check the install directory
if len(runtimeInfo.Binaries) == 0 {
_, err := os.Stat(runtimeInfo.InstallDir)
if err != nil {
logger.Debug("Runtime install directory not found", logrus.Fields{
"directory": runtimeInfo.InstallDir,
"error": err,
})
return false
}
return true
}

// Check if at least one binary exists
for binaryName, binaryPath := range runtimeInfo.Binaries {
_, err := os.Stat(binaryPath)
if err != nil {
logger.Debug("Runtime binary not found", logrus.Fields{
"binary": binaryName,
"path": binaryPath,
"error": err,
})
return false
}
}

return true
}

// downloadAndExtractRuntime downloads and extracts a runtime
func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error {
// Create a file name for the downloaded archive
Expand Down
8 changes: 4 additions & 4 deletions config/runtimes-installer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ func TestIsRuntimeInstalled(t *testing.T) {
}

// Test when the install directory doesn't exist
assert.False(t, isRuntimeInstalled(runtimeInfoNoBinaries))
assert.False(t, Config.IsRuntimeInstalled("test-runtime", runtimeInfoNoBinaries))

// Create the install directory
err = os.MkdirAll(runtimeInfoNoBinaries.InstallDir, utils.DefaultDirPerms)
assert.NoError(t, err)

// Test when the install directory exists
assert.True(t, isRuntimeInstalled(runtimeInfoNoBinaries))
assert.True(t, Config.IsRuntimeInstalled("test-runtime", runtimeInfoNoBinaries))

// Create a mock RuntimeInfo with binaries
binPath := filepath.Join(tempDir, "test-runtime-bin")
Expand All @@ -45,12 +45,12 @@ func TestIsRuntimeInstalled(t *testing.T) {
}

// Test when the binary doesn't exist
assert.False(t, isRuntimeInstalled(runtimeInfoWithBinaries))
assert.False(t, Config.IsRuntimeInstalled("test-runtime", runtimeInfoWithBinaries))

// Create a mock binary file
_, err = os.Create(binPath)
assert.NoError(t, err)

// Test when the binary exists
assert.True(t, isRuntimeInstalled(runtimeInfoWithBinaries))
assert.True(t, Config.IsRuntimeInstalled("test-runtime", runtimeInfoWithBinaries))
}
2 changes: 1 addition & 1 deletion config/tools-installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func InstallTools(config *ConfigType, registry string) error {
// InstallTool installs a specific tool
func InstallTool(name string, toolInfo *plugins.ToolInfo, registry string) error {
// Check if the tool is already installed
if isToolInstalled(toolInfo) {
if Config.IsToolInstalled(name, toolInfo) {
logger.Info("Tool already installed", logrus.Fields{
"tool": name,
"version": toolInfo.Version,
Expand Down
Loading