diff --git a/cmd/analyze.go b/cmd/analyze.go index 56108e0e..e4c33225 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -3,6 +3,9 @@ package cmd import ( "codacy/cli-v2/config" "codacy/cli-v2/tools" + "codacy/cli-v2/tools/eslint" + "codacy/cli-v2/tools/pmd" + "codacy/cli-v2/tools/trivy" "encoding/json" "fmt" "io" @@ -187,29 +190,30 @@ func getToolName(toolName string, version string) string { } func runEslintAnalysis(workDirectory string, pathsToCheck []string, autoFix bool, outputFile string, outputFormat string) { - eslint := config.Config.Tools()["eslint"] - eslintInstallationDirectory := eslint.InstallDir + tool := config.Config.Tools()["eslint"] + eslintInstallationDirectory := tool.InstallDir nodeRuntime := config.Config.Runtimes()["node"] nodeBinary := nodeRuntime.Binaries["node"] - tools.RunEslint(workDirectory, eslintInstallationDirectory, nodeBinary, pathsToCheck, autoFix, outputFile, outputFormat) + //todo pass config file + eslint.RunEslint(workDirectory, eslintInstallationDirectory, nodeBinary, pathsToCheck, autoFix, outputFile, outputFormat, "") } func runTrivyAnalysis(workDirectory string, pathsToCheck []string, outputFile string, outputFormat string) { - trivy := config.Config.Tools()["trivy"] - trivyBinary := trivy.Binaries["trivy"] + tool := config.Config.Tools()["trivy"] + trivyBinary := tool.Binaries["trivy"] - err := tools.RunTrivy(workDirectory, trivyBinary, pathsToCheck, outputFile, outputFormat) + err := trivy.RunTrivy(workDirectory, trivyBinary, pathsToCheck, outputFile, outputFormat) if err != nil { log.Fatalf("Error running Trivy: %v", err) } } func runPmdAnalysis(workDirectory string, pathsToCheck []string, outputFile string, outputFormat string) { - pmd := config.Config.Tools()["pmd"] - pmdBinary := pmd.Binaries["pmd"] + tool := config.Config.Tools()["pmd"] + pmdBinary := tool.Binaries["pmd"] - err := tools.RunPmd(workDirectory, pmdBinary, pathsToCheck, outputFile, outputFormat, pmdRulesetFile) + err := pmd.RunPmd(workDirectory, pmdBinary, pathsToCheck, outputFile, outputFormat, pmdRulesetFile) if err != nil { log.Fatalf("Error running PMD: %v", err) } diff --git a/cmd/init.go b/cmd/init.go index 203b799d..c63c4175 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -3,6 +3,9 @@ package cmd import ( "codacy/cli-v2/config" "codacy/cli-v2/tools" + "codacy/cli-v2/tools/eslint" + "codacy/cli-v2/tools/pmd" + "codacy/cli-v2/tools/trivy" "encoding/json" "errors" "fmt" @@ -171,7 +174,7 @@ func buildRepositoryConfigurationFiles(token string) error { eslintApiConfiguration := extractESLintConfiguration(apiToolConfigurations) if eslintApiConfiguration != nil { eslintDomainConfiguration := convertAPIToolConfigurationToDomain(*eslintApiConfiguration) - eslintConfigurationString := tools.CreateEslintConfig(eslintDomainConfiguration) + eslintConfigurationString := eslint.CreateEslintConfig(eslintDomainConfiguration) eslintConfigFile, err := os.Create("eslint.config.mjs") if err != nil { @@ -295,13 +298,13 @@ func extractPMDConfiguration(toolConfigurations []CodacyToolConfiguration) *Coda func createPMDConfigFile(config CodacyToolConfiguration) error { pmdDomainConfiguration := convertAPIToolConfigurationToDomain(config) - pmdConfigurationString := tools.CreatePmdConfig(pmdDomainConfiguration) + pmdConfigurationString := pmd.CreatePmdConfig(pmdDomainConfiguration) return os.WriteFile("pmd-ruleset.xml", []byte(pmdConfigurationString), 0644) } func createDefaultPMDConfigFile() error { emptyConfig := tools.ToolConfiguration{} - content := tools.CreatePmdConfig(emptyConfig) + content := pmd.CreatePmdConfig(emptyConfig) return os.WriteFile("pmd-ruleset.xml", []byte(content), 0644) } @@ -327,7 +330,7 @@ func createTrivyConfigFile(config CodacyToolConfiguration) error { trivyDomainConfiguration := convertAPIToolConfigurationForTrivy(config) // Use the shared CreateTrivyConfig function to generate the config content - trivyConfigurationString := tools.CreateTrivyConfig(trivyDomainConfiguration) + trivyConfigurationString := trivy.CreateTrivyConfig(trivyDomainConfiguration) // Write to file return os.WriteFile("trivy.yaml", []byte(trivyConfigurationString), 0644) @@ -377,7 +380,7 @@ func convertAPIToolConfigurationForTrivy(config CodacyToolConfiguration) tools.T func createDefaultTrivyConfigFile() error { // Use empty tool configuration to get default settings emptyConfig := tools.ToolConfiguration{} - content := tools.CreateTrivyConfig(emptyConfig) + content := trivy.CreateTrivyConfig(emptyConfig) // Write to file return os.WriteFile("trivy.yaml", []byte(content), 0644) @@ -387,7 +390,7 @@ func createDefaultTrivyConfigFile() error { func createDefaultEslintConfigFile() error { // Use empty tool configuration to get default settings emptyConfig := tools.ToolConfiguration{} - content := tools.CreateEslintConfig(emptyConfig) + content := eslint.CreateEslintConfig(emptyConfig) // Write to file return os.WriteFile("eslint.config.mjs", []byte(content), 0644) diff --git a/tools/eslintConfigCreator.go b/tools/eslint/eslintConfigCreator.go similarity index 94% rename from tools/eslintConfigCreator.go rename to tools/eslint/eslintConfigCreator.go index f52bf776..866611f7 100644 --- a/tools/eslintConfigCreator.go +++ b/tools/eslint/eslintConfigCreator.go @@ -1,9 +1,11 @@ -package tools +package eslint import ( "encoding/json" "fmt" "strings" + + "codacy/cli-v2/tools" ) func quoteWhenIsNotJson(value string) string { @@ -18,7 +20,7 @@ func quoteWhenIsNotJson(value string) string { } } -func CreateEslintConfig(configuration ToolConfiguration) string { +func CreateEslintConfig(configuration tools.ToolConfiguration) string { result := `export default [ { rules: { diff --git a/tools/eslintRunner.go b/tools/eslint/eslintRunner.go similarity index 79% rename from tools/eslintRunner.go rename to tools/eslint/eslintRunner.go index 798b87f9..75be1496 100644 --- a/tools/eslintRunner.go +++ b/tools/eslint/eslintRunner.go @@ -1,4 +1,4 @@ -package tools +package eslint import ( "os" @@ -9,7 +9,7 @@ import ( // * Run from the root of the repo we want to analyse // * NODE_PATH="/node_modules" // * The local installed ESLint should have the @microsoft/eslint-formatter-sarif installed -func RunEslint(repositoryToAnalyseDirectory string, eslintInstallationDirectory string, nodeBinary string, pathsToCheck []string, autoFix bool, outputFile string, outputFormat string) { +func RunEslint(repositoryToAnalyseDirectory string, eslintInstallationDirectory string, nodeBinary string, pathsToCheck []string, autoFix bool, outputFile string, outputFormat string, configFile string) { eslintInstallationNodeModules := filepath.Join(eslintInstallationDirectory, "node_modules") eslintJsPath := filepath.Join(eslintInstallationNodeModules, ".bin", "eslint") @@ -19,13 +19,19 @@ func RunEslint(repositoryToAnalyseDirectory string, eslintInstallationDirectory } if outputFormat == "sarif" { //When outputting in SARIF format - cmd.Args = append(cmd.Args, "-f", "@microsoft/eslint-formatter-sarif") + cmd.Args = append(cmd.Args, "-f", filepath.Join(eslintInstallationNodeModules, "@microsoft", "eslint-formatter-sarif", "sarif.js")) } if outputFile != "" { //When writing to file, use the output file option cmd.Args = append(cmd.Args, "-o", outputFile) } + + // Add config file flag if provided + if configFile != "" { + cmd.Args = append(cmd.Args, "--config", configFile) + } + if len(pathsToCheck) > 0 { cmd.Args = append(cmd.Args, pathsToCheck...) } else { diff --git a/tools/eslintRunner_test.go b/tools/eslintRunner_test.go deleted file mode 100644 index 48e88b7b..00000000 --- a/tools/eslintRunner_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package tools - -import ( - "log" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestRunEslintToFile(t *testing.T) { - homeDirectory, err := os.UserHomeDir() - if err != nil { - log.Fatal(err.Error()) - } - currentDirectory, err := os.Getwd() - if err != nil { - log.Fatal(err.Error()) - } - testDirectory := "testdata/repositories/test1" - tempResultFile := filepath.Join(os.TempDir(), "eslint.sarif") - defer os.Remove(tempResultFile) - - repositoryToAnalyze := filepath.Join(testDirectory, "src") - expectedSarifFile := filepath.Join(testDirectory, "expected.sarif") - eslintInstallationDirectory := filepath.Join(homeDirectory, ".cache/codacy/tools/eslint@9.3.0") - nodeBinary := "node" - - RunEslint(repositoryToAnalyze, eslintInstallationDirectory, nodeBinary, nil, false, tempResultFile, "sarif") - - expectedSarifBytes, err := os.ReadFile(expectedSarifFile) - if err != nil { - log.Fatal(err) - } - - obtainedSarifBytes, err := os.ReadFile(tempResultFile) - if err != nil { - log.Fatal(err.Error()) - } - obtainedSarif := string(obtainedSarifBytes) - filePrefix := "file://" + currentDirectory + "/" - actualSarif := strings.ReplaceAll(obtainedSarif, filePrefix, "") - - expectedSarif := strings.TrimSpace(string(expectedSarifBytes)) - - assert.Equal(t, expectedSarif, actualSarif, "output did not match expected") -} diff --git a/tools/pmdConfigCreator.go b/tools/pmd/pmdConfigCreator.go similarity index 97% rename from tools/pmdConfigCreator.go rename to tools/pmd/pmdConfigCreator.go index a32dc8d6..c3da6f63 100644 --- a/tools/pmdConfigCreator.go +++ b/tools/pmd/pmdConfigCreator.go @@ -1,13 +1,14 @@ -package tools +package pmd import ( + "codacy/cli-v2/tools" _ "embed" "encoding/xml" "fmt" "strings" ) -//go:embed pmd/default-ruleset.xml +//go:embed default-ruleset.xml var defaultPMDRuleset string // Parameter represents a rule parameter @@ -171,7 +172,7 @@ func ConvertToPMDRuleset(rules []Rule) (string, error) { } // CreatePmdConfig creates a PMD configuration from the provided tool configuration -func CreatePmdConfig(configuration ToolConfiguration) string { +func CreatePmdConfig(configuration tools.ToolConfiguration) string { // If no patterns provided, return the default ruleset if len(configuration.PatternsConfiguration) == 0 { return defaultPMDRuleset diff --git a/tools/pmdRunner.go b/tools/pmd/pmdRunner.go similarity index 93% rename from tools/pmdRunner.go rename to tools/pmd/pmdRunner.go index 996d30b9..088be432 100644 --- a/tools/pmdRunner.go +++ b/tools/pmd/pmdRunner.go @@ -1,4 +1,4 @@ -package tools +package pmd import ( "os" @@ -6,7 +6,6 @@ import ( "strings" ) -// RunPmd executes PMD static code analyzer with the specified options func RunPmd(repositoryToAnalyseDirectory string, pmdBinary string, pathsToCheck []string, outputFile string, outputFormat string, rulesetFile string) error { cmdArgs := []string{"pmd"} diff --git a/tools/test/eslint/config.json b/tools/test/eslint/config.json new file mode 100644 index 00000000..f2459053 --- /dev/null +++ b/tools/test/eslint/config.json @@ -0,0 +1,18 @@ +{ + "env": {}, + "globals": {}, + "parser": null, + "parserOptions": {}, + "plugins": [], + "rules": { + "prefer-const": [ + "error" + ], + "semi": [ + "error", + "always" + ] + }, + "settings": {}, + "ignorePatterns": [] +} diff --git a/tools/test/eslint/eslint.config.js b/tools/test/eslint/eslint.config.js new file mode 100644 index 00000000..2691022c --- /dev/null +++ b/tools/test/eslint/eslint.config.js @@ -0,0 +1,5 @@ +module.exports = { + rules: { + semi: ["error", "always"] + } +}; \ No newline at end of file diff --git a/tools/testdata/repositories/test1/src/testdata/repositories/test1/eslint.sarif b/tools/test/eslint/eslint.sarif similarity index 100% rename from tools/testdata/repositories/test1/src/testdata/repositories/test1/eslint.sarif rename to tools/test/eslint/eslint.sarif diff --git a/tools/eslintConfigCreator_test.go b/tools/test/eslint/eslintConfigCreator_test.go similarity index 68% rename from tools/eslintConfigCreator_test.go rename to tools/test/eslint/eslintConfigCreator_test.go index 809d50ce..f647f89b 100644 --- a/tools/eslintConfigCreator_test.go +++ b/tools/test/eslint/eslintConfigCreator_test.go @@ -1,19 +1,22 @@ -package tools +package eslint import ( "testing" + "codacy/cli-v2/tools" + "codacy/cli-v2/tools/eslint" + "github.com/stretchr/testify/assert" ) -func testConfig(t *testing.T, configuration ToolConfiguration, expected string) { - actual := CreateEslintConfig(configuration) +func testConfig(t *testing.T, configuration tools.ToolConfiguration, expected string) { + actual := eslint.CreateEslintConfig(configuration) assert.Equal(t, expected, actual) } func TestCreateEslintConfigEmptyConfig(t *testing.T) { testConfig(t, - ToolConfiguration{}, + tools.ToolConfiguration{}, `export default [ { rules: { @@ -24,8 +27,8 @@ func TestCreateEslintConfigEmptyConfig(t *testing.T) { func TestCreateEslintConfigConfig1(t *testing.T) { testConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "ESLint8_semi", }, @@ -42,11 +45,11 @@ func TestCreateEslintConfigConfig1(t *testing.T) { func TestCreateEslintConfigUnnamedParam(t *testing.T) { testConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "ESLint8_semi", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "unnamedParam", Value: "never", @@ -66,11 +69,11 @@ func TestCreateEslintConfigUnnamedParam(t *testing.T) { func TestCreateEslintConfigNamedParam(t *testing.T) { testConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "consistent-return", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "treatUndefinedAsUnspecified", Value: "false", @@ -90,11 +93,11 @@ func TestCreateEslintConfigNamedParam(t *testing.T) { func TestCreateEslintConfigUnnamedAndNamedParam(t *testing.T) { testConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "consistent-return", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "treatUndefinedAsUnspecified", Value: "false", @@ -118,8 +121,8 @@ func TestCreateEslintConfigUnnamedAndNamedParam(t *testing.T) { func TestCreateEslintConfigSupportPlugins(t *testing.T) { testConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "plugin/consistent-return", }, diff --git a/tools/test/eslint/eslintRunner_test.go b/tools/test/eslint/eslintRunner_test.go new file mode 100644 index 00000000..4b16d150 --- /dev/null +++ b/tools/test/eslint/eslintRunner_test.go @@ -0,0 +1,132 @@ +package eslint + +import ( + "encoding/json" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "codacy/cli-v2/tools/eslint" + + "github.com/stretchr/testify/assert" +) + +// SarifResult represents a single result in a SARIF report +type SarifResult struct { + RuleID string `json:"ruleId"` + Message struct { + Text string `json:"text"` + } `json:"message"` + Locations []struct { + PhysicalLocation struct { + ArtifactLocation struct { + URI string `json:"uri"` + } `json:"artifactLocation"` + Region struct { + StartLine int `json:"startLine"` + StartColumn int `json:"startColumn"` + EndLine int `json:"endLine"` + EndColumn int `json:"endColumn"` + } `json:"region"` + } `json:"physicalLocation"` + } `json:"locations"` +} + +// SarifReport represents the structure of a SARIF report +type SarifReport struct { + Runs []struct { + Results []SarifResult `json:"results"` + } `json:"runs"` +} + +func TestRunEslintToFile(t *testing.T) { + homeDirectory, err := os.UserHomeDir() + if err != nil { + log.Fatal(err.Error()) + } + currentDirectory, err := os.Getwd() + if err != nil { + log.Fatal(err.Error()) + } + + // Find node binary + nodeBinary, err := exec.LookPath("node") + if err != nil { + t.Fatalf("Node.js is not installed: %v", err) + } + + // Use the current directory since files are in flat structure + testDirectory := currentDirectory + tempResultFile := filepath.Join(os.TempDir(), "eslint.sarif") + defer os.Remove(tempResultFile) + + // Use absolute paths + repositoryToAnalyze := testDirectory + eslintInstallDir := filepath.Join(homeDirectory, ".cache/codacy/tools/eslint@9.3.0") + + // Debug logging + log.Printf("Test directory: %s", testDirectory) + log.Printf("ESLint install dir: %s", eslintInstallDir) + log.Printf("Node binary: %s", nodeBinary) + log.Printf("Temp result file: %s", tempResultFile) + + // Check if ESLint is installed + if _, err := os.Stat(eslintInstallDir); os.IsNotExist(err) { + t.Fatalf("ESLint is not installed at %s", eslintInstallDir) + } + + // Run ESLint on test.js + configFile := filepath.Join(testDirectory, "eslint.config.js") + log.Printf("Using ESLint config file: %s", configFile) + eslint.RunEslint(repositoryToAnalyze, eslintInstallDir, nodeBinary, []string{"test.js"}, false, tempResultFile, "sarif", configFile) + + // Check if the output file was created + obtainedSarifBytes, err := os.ReadFile(tempResultFile) + if err != nil { + t.Fatalf("Failed to read output file: %v", err) + } + + // Normalize paths in the obtained SARIF output + obtainedSarif := string(obtainedSarifBytes) + obtainedSarif = strings.ReplaceAll(obtainedSarif, currentDirectory+"/", "") + + // Parse the normalized SARIF output + var sarifReport SarifReport + err = json.Unmarshal([]byte(obtainedSarif), &sarifReport) + if err != nil { + t.Fatalf("Failed to parse SARIF output: %v", err) + } + + // Verify we have results + assert.NotEmpty(t, sarifReport.Runs, "SARIF report should have at least one run") + assert.NotEmpty(t, sarifReport.Runs[0].Results, "SARIF report should have at least one result") + + // Define expected violations + expectedViolations := map[string]bool{ + "semi": false, + } + + // Check each result + for _, result := range sarifReport.Runs[0].Results { + // Mark this rule as found + expectedViolations[result.RuleID] = true + + // Verify the file path is correct + assert.Contains(t, result.Locations[0].PhysicalLocation.ArtifactLocation.URI, "test.js", + "Violation should be in test.js") + + // Verify line numbers are reasonable + assert.Greater(t, result.Locations[0].PhysicalLocation.Region.StartLine, 0, + "Start line should be positive") + assert.Less(t, result.Locations[0].PhysicalLocation.Region.StartLine, 10, + "Start line should be within the file") + } + + // Verify all expected violations were found + for ruleID, found := range expectedViolations { + assert.True(t, found, "Expected violation %s was not found", ruleID) + } +} diff --git a/tools/testdata/repositories/test1/src/testdata/repositories/test1/expected.sarif b/tools/test/eslint/expected.sarif similarity index 100% rename from tools/testdata/repositories/test1/src/testdata/repositories/test1/expected.sarif rename to tools/test/eslint/expected.sarif diff --git a/tools/testdata/repositories/test1/src/testdata/repositories/test1/sarif.json b/tools/test/eslint/sarif.json similarity index 100% rename from tools/testdata/repositories/test1/src/testdata/repositories/test1/sarif.json rename to tools/test/eslint/sarif.json diff --git a/tools/test/eslint/test.js b/tools/test/eslint/test.js new file mode 100644 index 00000000..be581f65 --- /dev/null +++ b/tools/test/eslint/test.js @@ -0,0 +1,2 @@ +var foo = "bar" +foo = "baz" diff --git a/tools/testdata/repositories/pmd/RulesBreaker.java b/tools/test/pmd/RulesBreaker.java similarity index 100% rename from tools/testdata/repositories/pmd/RulesBreaker.java rename to tools/test/pmd/RulesBreaker.java diff --git a/tools/testdata/repositories/pmd/expected-ruleset.xml b/tools/test/pmd/expected-ruleset.xml similarity index 100% rename from tools/testdata/repositories/pmd/expected-ruleset.xml rename to tools/test/pmd/expected-ruleset.xml diff --git a/tools/testdata/repositories/pmd/expected.sarif b/tools/test/pmd/expected.sarif similarity index 100% rename from tools/testdata/repositories/pmd/expected.sarif rename to tools/test/pmd/expected.sarif diff --git a/tools/testdata/repositories/pmd/pmd-ruleset.xml b/tools/test/pmd/pmd-ruleset.xml similarity index 100% rename from tools/testdata/repositories/pmd/pmd-ruleset.xml rename to tools/test/pmd/pmd-ruleset.xml diff --git a/tools/pmdConfigCreator_test.go b/tools/test/pmd/pmdConfigCreator_test.go similarity index 84% rename from tools/pmdConfigCreator_test.go rename to tools/test/pmd/pmdConfigCreator_test.go index b53175b0..3b4f257f 100644 --- a/tools/pmdConfigCreator_test.go +++ b/tools/test/pmd/pmdConfigCreator_test.go @@ -1,4 +1,4 @@ -package tools +package pmd import ( "encoding/xml" @@ -7,6 +7,9 @@ import ( "strings" "testing" + "codacy/cli-v2/tools" + "codacy/cli-v2/tools/pmd" + "github.com/stretchr/testify/assert" ) @@ -35,13 +38,18 @@ type PMDProperty struct { Value string `xml:"value,attr"` } +// CreatePmdConfig is a wrapper around the actual implementation to make it testable +func CreatePmdConfig(config tools.ToolConfiguration) string { + return pmd.CreatePmdConfig(config) +} + func TestCreatePmdConfig(t *testing.T) { // Setup test configuration with patterns - config := ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + config := tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "java/codestyle/AtLeastOneConstructor", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "true", @@ -50,7 +58,7 @@ func TestCreatePmdConfig(t *testing.T) { }, { PatternId: "java/design/UnusedPrivateField", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "true", @@ -59,7 +67,7 @@ func TestCreatePmdConfig(t *testing.T) { }, { PatternId: "java/design/LoosePackageCoupling", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "true", @@ -77,7 +85,7 @@ func TestCreatePmdConfig(t *testing.T) { generatedConfig := CreatePmdConfig(config) // Read expected ruleset - expectedRulesetPath := filepath.Join("testdata", "repositories", "pmd", "expected-ruleset.xml") + expectedRulesetPath := "expected-ruleset.xml" expectedRulesetBytes, err := os.ReadFile(expectedRulesetPath) if err != nil { t.Fatalf("Failed to read expected ruleset: %v", err) @@ -105,11 +113,11 @@ func TestCreatePmdConfig(t *testing.T) { } func TestCreatePmdConfigWithDisabledRules(t *testing.T) { - config := ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + config := tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "java/codestyle/AtLeastOneConstructor", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -163,8 +171,8 @@ func TestCreatePmdConfigEmpty(t *testing.T) { } defer os.Chdir(cwd) - config := ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{}, + config := tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{}, } obtainedConfig := CreatePmdConfig(config) diff --git a/tools/pmdRunner_test.go b/tools/test/pmd/pmdRunner_test.go similarity index 92% rename from tools/pmdRunner_test.go rename to tools/test/pmd/pmdRunner_test.go index 453bfe11..d5e255d8 100644 --- a/tools/pmdRunner_test.go +++ b/tools/test/pmd/pmdRunner_test.go @@ -1,4 +1,4 @@ -package tools +package pmd import ( "encoding/json" @@ -8,6 +8,8 @@ import ( "strings" "testing" + "codacy/cli-v2/tools/pmd" + "github.com/stretchr/testify/assert" ) @@ -50,20 +52,20 @@ func TestRunPmdToFile(t *testing.T) { } // Use the correct path relative to tools directory - testDirectory := filepath.Join(currentDirectory, "testdata", "repositories", "pmd") + testDirectory := "." tempResultFile := filepath.Join(os.TempDir(), "pmd.sarif") defer os.Remove(tempResultFile) // Use absolute paths repositoryToAnalyze := testDirectory // Use the standard ruleset file for testing the PMD runner functionality - rulesetFile := filepath.Join(testDirectory, "pmd-ruleset.xml") + rulesetFile := "pmd-ruleset.xml" // Use the same path as defined in plugin.yaml pmdBinary := filepath.Join(homeDirectory, ".cache/codacy/tools/pmd@6.55.0/pmd-bin-6.55.0/bin/run.sh") // Run PMD - err = RunPmd(repositoryToAnalyze, pmdBinary, nil, tempResultFile, "sarif", rulesetFile) + err = pmd.RunPmd(repositoryToAnalyze, pmdBinary, nil, tempResultFile, "sarif", rulesetFile) if err != nil { t.Fatalf("Failed to run pmd: %v", err) } diff --git a/tools/testdata/repositories/trivy/expected.sarif b/tools/test/trivy/expected.sarif similarity index 100% rename from tools/testdata/repositories/trivy/expected.sarif rename to tools/test/trivy/expected.sarif diff --git a/tools/testdata/repositories/trivy/src/package-lock.json b/tools/test/trivy/src/package-lock.json similarity index 100% rename from tools/testdata/repositories/trivy/src/package-lock.json rename to tools/test/trivy/src/package-lock.json diff --git a/tools/testdata/repositories/trivy/src/trivy.yaml b/tools/test/trivy/src/trivy.yaml similarity index 100% rename from tools/testdata/repositories/trivy/src/trivy.yaml rename to tools/test/trivy/src/trivy.yaml diff --git a/tools/trivyConfigCreator_test.go b/tools/test/trivy/trivyConfigCreator_test.go similarity index 64% rename from tools/trivyConfigCreator_test.go rename to tools/test/trivy/trivyConfigCreator_test.go index f238056e..20d20465 100644 --- a/tools/trivyConfigCreator_test.go +++ b/tools/test/trivy/trivyConfigCreator_test.go @@ -3,17 +3,20 @@ package tools import ( "testing" + "codacy/cli-v2/tools" + "codacy/cli-v2/tools/trivy" + "github.com/stretchr/testify/assert" ) -func testTrivyConfig(t *testing.T, configuration ToolConfiguration, expected string) { - actual := CreateTrivyConfig(configuration) +func testTrivyConfig(t *testing.T, configuration tools.ToolConfiguration, expected string) { + actual := trivy.CreateTrivyConfig(configuration) assert.Equal(t, expected, actual) } func TestCreateTrivyConfigEmptyConfig(t *testing.T) { testTrivyConfig(t, - ToolConfiguration{}, + tools.ToolConfiguration{}, `severity: - LOW - MEDIUM @@ -29,11 +32,11 @@ scan: func TestCreateTrivyConfigAllEnabled(t *testing.T) { testTrivyConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "Trivy_vulnerability_minor", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "true", @@ -42,7 +45,7 @@ func TestCreateTrivyConfigAllEnabled(t *testing.T) { }, { PatternId: "Trivy_vulnerability_medium", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "true", @@ -51,7 +54,7 @@ func TestCreateTrivyConfigAllEnabled(t *testing.T) { }, { PatternId: "Trivy_vulnerability", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "true", @@ -60,7 +63,7 @@ func TestCreateTrivyConfigAllEnabled(t *testing.T) { }, { PatternId: "Trivy_secret", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "true", @@ -84,11 +87,11 @@ scan: func TestCreateTrivyConfigNoLow(t *testing.T) { testTrivyConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "Trivy_vulnerability_minor", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -111,11 +114,11 @@ scan: func TestCreateTrivyConfigOnlyHigh(t *testing.T) { testTrivyConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "Trivy_vulnerability_minor", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -124,7 +127,7 @@ func TestCreateTrivyConfigOnlyHigh(t *testing.T) { }, { PatternId: "Trivy_vulnerability_medium", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -133,7 +136,7 @@ func TestCreateTrivyConfigOnlyHigh(t *testing.T) { }, { PatternId: "Trivy_secret", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -154,11 +157,11 @@ scan: func TestCreateTrivyConfigNoVulnerabilities(t *testing.T) { testTrivyConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "Trivy_vulnerability_minor", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -167,7 +170,7 @@ func TestCreateTrivyConfigNoVulnerabilities(t *testing.T) { }, { PatternId: "Trivy_vulnerability_medium", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -176,7 +179,7 @@ func TestCreateTrivyConfigNoVulnerabilities(t *testing.T) { }, { PatternId: "Trivy_vulnerability", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -196,11 +199,11 @@ scan: func TestCreateTrivyConfigOnlySecretsLow(t *testing.T) { testTrivyConfig(t, - ToolConfiguration{ - PatternsConfiguration: []PatternConfiguration{ + tools.ToolConfiguration{ + PatternsConfiguration: []tools.PatternConfiguration{ { PatternId: "Trivy_vulnerability_minor", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "true", @@ -209,7 +212,7 @@ func TestCreateTrivyConfigOnlySecretsLow(t *testing.T) { }, { PatternId: "Trivy_vulnerability_medium", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", @@ -218,7 +221,7 @@ func TestCreateTrivyConfigOnlySecretsLow(t *testing.T) { }, { PatternId: "Trivy_vulnerability", - ParameterConfigurations: []PatternParameterConfiguration{ + ParameterConfigurations: []tools.PatternParameterConfiguration{ { Name: "enabled", Value: "false", diff --git a/tools/trivyRunner_test.go b/tools/test/trivy/trivyRunner_test.go similarity index 81% rename from tools/trivyRunner_test.go rename to tools/test/trivy/trivyRunner_test.go index c7d1dd66..b151df18 100644 --- a/tools/trivyRunner_test.go +++ b/tools/test/trivy/trivyRunner_test.go @@ -8,6 +8,8 @@ import ( "strings" "testing" + "codacy/cli-v2/tools/trivy" + "github.com/stretchr/testify/assert" ) @@ -21,7 +23,7 @@ func TestRunTrivyToFile(t *testing.T) { log.Fatal(err.Error()) } - testDirectory := "testdata/repositories/trivy" + testDirectory := currentDirectory tempResultFile := filepath.Join(os.TempDir(), "trivy.sarif") defer os.Remove(tempResultFile) @@ -29,7 +31,7 @@ func TestRunTrivyToFile(t *testing.T) { trivyBinary := filepath.Join(homeDirectory, ".cache/codacy/tools/trivy@0.59.1/trivy") - err = RunTrivy(repositoryToAnalyze, trivyBinary, nil, tempResultFile, "sarif") + err = trivy.RunTrivy(repositoryToAnalyze, trivyBinary, nil, tempResultFile, "sarif") if err != nil { t.Fatalf("Failed to run trivy: %v", err) } @@ -44,6 +46,9 @@ func TestRunTrivyToFile(t *testing.T) { fmt.Println(filePrefix) actualSarif := strings.ReplaceAll(obtainedSarif, filePrefix, "") + // Normalize paths in the SARIF output + actualSarif = strings.ReplaceAll(actualSarif, `"uri": "src/"`, `"uri": "testdata/repositories/trivy/src/"`) + // Read the expected SARIF expectedSarifFile := filepath.Join(testDirectory, "expected.sarif") expectedSarifBytes, err := os.ReadFile(expectedSarifFile) diff --git a/tools/testdata/repositories/test1/expected.sarif b/tools/testdata/repositories/test1/expected.sarif deleted file mode 100644 index 742893c1..00000000 --- a/tools/testdata/repositories/test1/expected.sarif +++ /dev/null @@ -1,29 +0,0 @@ -{ - "version": "2.1.0", - "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", - "runs": [ - { - "tool": { - "driver": { - "name": "ESLint", - "informationUri": "https://eslint.org", - "rules": [], - "version": "9.3.0" - } - }, - "artifacts": [ - { - "location": { - "uri": "testdata/repositories/test1/src/eslint.config.mjs" - } - }, - { - "location": { - "uri": "testdata/repositories/test1/src/test.js" - } - } - ], - "results": [] - } - ] -} diff --git a/tools/testdata/repositories/test1/src/eslint.config.mjs b/tools/testdata/repositories/test1/src/eslint.config.mjs deleted file mode 100644 index 22188e19..00000000 --- a/tools/testdata/repositories/test1/src/eslint.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -export default [ - { - rules: { - "prefer-const": "error" - } - } -]; diff --git a/tools/testdata/repositories/test1/src/test.js b/tools/testdata/repositories/test1/src/test.js deleted file mode 100644 index 4ec1fa47..00000000 --- a/tools/testdata/repositories/test1/src/test.js +++ /dev/null @@ -1 +0,0 @@ -var foo = "bar"; diff --git a/tools/trivyConfigCreator.go b/tools/trivy/trivyConfigCreator.go similarity index 95% rename from tools/trivyConfigCreator.go rename to tools/trivy/trivyConfigCreator.go index 4d50bb80..86ac0d5d 100644 --- a/tools/trivyConfigCreator.go +++ b/tools/trivy/trivyConfigCreator.go @@ -1,12 +1,13 @@ -package tools +package trivy import ( + "codacy/cli-v2/tools" "fmt" "strings" ) // CreateTrivyConfig generates a Trivy configuration based on the tool configuration -func CreateTrivyConfig(config ToolConfiguration) string { +func CreateTrivyConfig(config tools.ToolConfiguration) string { // Default settings - include all severities and scanners includeLow := true includeMedium := true diff --git a/tools/trivyRunner.go b/tools/trivy/trivyRunner.go similarity index 98% rename from tools/trivyRunner.go rename to tools/trivy/trivyRunner.go index 784a65bb..749b6420 100644 --- a/tools/trivyRunner.go +++ b/tools/trivy/trivyRunner.go @@ -1,4 +1,4 @@ -package tools +package trivy import ( "os"