From 05a6d4d19604ae549bb7e6646e5855381743995d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Costa?= Date: Wed, 22 May 2024 17:20:50 +0100 Subject: [PATCH 01/10] Big refactor to unify information location --- cli-v2.go | 8 +-- cmd/analyze.go | 15 ++--- cmd/install.go | 48 +++++----------- {config => config-file}/configFile.go | 28 ++++----- {config => config-file}/configTool.go | 2 +- config/config.go | 43 +++++++++----- config/eslint-utils.go | 35 +++++++++++ config/node-utils.go | 83 +++++++++++++++++++++++++++ config/runtime.go | 36 +++++++----- config/toolsInfo.go | 70 ---------------------- tool-utils/eslint-utils.go | 26 --------- utils/extract.go | 6 +- 12 files changed, 206 insertions(+), 194 deletions(-) rename {config => config-file}/configFile.go (53%) rename {config => config-file}/configTool.go (95%) create mode 100644 config/eslint-utils.go create mode 100644 config/node-utils.go delete mode 100644 config/toolsInfo.go delete mode 100644 tool-utils/eslint-utils.go diff --git a/cli-v2.go b/cli-v2.go index c6b149b..f0df1e9 100644 --- a/cli-v2.go +++ b/cli-v2.go @@ -2,18 +2,18 @@ package main import ( "codacy/cli-v2/cmd" - cfg "codacy/cli-v2/config" + "codacy/cli-v2/config" + cfg "codacy/cli-v2/config-file" "log" ) func main() { - cfg.Init() + config.Init() - runtimes, configErr := cfg.ReadConfigFile(cfg.Config.ProjectConfigFile()) + configErr := cfg.ReadConfigFile(config.Config.ProjectConfigFile()) if configErr != nil { log.Fatal(configErr) } - cfg.Config.SetRuntimes(runtimes) cmd.Execute() } \ No newline at end of file diff --git a/cmd/analyze.go b/cmd/analyze.go index 30a17de..6174747 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -22,26 +22,23 @@ var analyzeCmd = &cobra.Command{ Short: "Runs all linters.", Long: "Runs all tools for all runtimes.", Run: func(cmd *cobra.Command, args []string) { - fmt.Println(outputFolder) - eslintRunInfo, err := config.GetToolRunInfo("eslint") - if err != nil { - log.Fatal(err) - } - workDirectory, err := os.Getwd() if err != nil { log.Fatal(err) } - eslintInstallationDirectory := eslintRunInfo["eslintInstallationDirectory"] - nodeBinary := eslintRunInfo["nodeBinary"] - if len(args) == 0 { log.Fatal("You need to specify the tool you want to run for now! ;D") } + eslint := config.Config.Tools()["eslint"] + eslintInstallationDirectory := eslint.Info()["installDir"] + + nodeRuntime := config.Config.Runtimes()["node"] + nodeBinary := nodeRuntime.Info()["node"] + fmt.Printf("Running the tool %s. Output will be available at %s\n", args[0], outputFolder) err = tools.RunEslintToFile(workDirectory, eslintInstallationDirectory, nodeBinary, outputFolder) if err != nil { diff --git a/cmd/install.go b/cmd/install.go index 04ead0c..407c02e 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -2,12 +2,8 @@ package cmd import ( cfg "codacy/cli-v2/config" - toolutils "codacy/cli-v2/tool-utils" - "codacy/cli-v2/utils" "github.com/spf13/cobra" "log" - "os" - "path/filepath" ) func init() { @@ -16,38 +12,21 @@ func init() { var installCmd = &cobra.Command{ Use: "install", - Short: "Installs the tools specified in the project's config.", - Long: "Installs all runtimes and tools specified in the project's config file.", + Short: "Installs the tools specified in the project's config-file.", + Long: "Installs all runtimes and tools specified in the project's config-file file.", Run: func(cmd *cobra.Command, args []string) { // install runtimes - fetchRuntimes(cfg.Config.Runtimes(), cfg.Config.RuntimesDirectory()) + fetchRuntimes(&cfg.Config) // install tools - for _, r := range cfg.Config.Runtimes() { - fetchTools(r, cfg.Config.RuntimesDirectory(), cfg.Config.ToolsDirectory()) - } + fetchTools(&cfg.Config) }, } -func fetchRuntimes(runtimes map[string]*cfg.Runtime, runtimesDirectory string) { - for _, r := range runtimes { +func fetchRuntimes(config *cfg.ConfigType) { + for _, r := range config.Runtimes() { switch r.Name() { case "node": - // TODO should delete downloaded archive - // TODO check for deflated archive - log.Println("Fetching node...") - downloadNodeURL := cfg.GetNodeDownloadURL(r) - nodeTar, err := utils.DownloadFile(downloadNodeURL, runtimesDirectory) - if err != nil { - log.Fatal(err) - } - - // deflate node archive - t, err := os.Open(nodeTar) - defer t.Close() - if err != nil { - log.Fatal(err) - } - err = utils.ExtractTarGz(t, runtimesDirectory) + err := cfg.InstallNode(r) if err != nil { log.Fatal(err) } @@ -57,13 +36,16 @@ func fetchRuntimes(runtimes map[string]*cfg.Runtime, runtimesDirectory string) { } } -func fetchTools(runtime *cfg.Runtime, runtimesDirectory string, toolsDirectory string) { - for _, tool := range runtime.Tools() { +func fetchTools(config *cfg.ConfigType) { + for _, tool := range config.Tools() { switch tool.Name() { case "eslint": - npmPath := filepath.Join(runtimesDirectory, cfg.GetNodeFileName(runtime), - "bin", "npm") - toolutils.InstallESLint(npmPath, "eslint@" + tool.Version(), toolsDirectory) + // eslint needs node runtime + nodeRuntime := config.Runtimes()["node"] + err := cfg.InstallEslint(nodeRuntime, tool) + if err != nil { + log.Fatal(err) + } default: log.Fatal("Unknown tool:", tool.Name()) } diff --git a/config/configFile.go b/config-file/configFile.go similarity index 53% rename from config/configFile.go rename to config-file/configFile.go index 933aa8e..e47671f 100644 --- a/config/configFile.go +++ b/config-file/configFile.go @@ -1,6 +1,7 @@ -package config +package config_file import ( + "codacy/cli-v2/config" "gopkg.in/yaml.v3" "os" ) @@ -10,42 +11,35 @@ type configFile struct { TOOLS []string } -func parseConfigFile(configContents []byte) (map[string]*Runtime, error) { +func parseConfigFile(configContents []byte) error { configFile := configFile{} if err := yaml.Unmarshal(configContents, &configFile); err != nil { - return nil, err + return err } - runtimes := make(map[string]*Runtime) for _, rt := range configFile.RUNTIMES { ct, err := parseConfigTool(rt) if err != nil { - return nil, err - } - runtimes[ct.name] = &Runtime{ - name: ct.name, - version: ct.version, + return err } + config.Config.AddRuntime(config.NewRuntime(ct.name, ct.version)) } for _, tl := range configFile.TOOLS { ct, err := parseConfigTool(tl) if err != nil { - return nil, err - } - switch ct.name { - case "eslint": - runtimes["node"].AddTool(ct) + return err } + config.Config.AddTool(config.NewRuntime(ct.name, ct.version)) } - return runtimes, nil + return nil } -func ReadConfigFile(configPath string) (map[string]*Runtime, error) { +func ReadConfigFile(configPath string) error { content, err := os.ReadFile(configPath) if err != nil { - return nil, err + return err } return parseConfigFile(content) diff --git a/config/configTool.go b/config-file/configTool.go similarity index 95% rename from config/configTool.go rename to config-file/configTool.go index 67e75b7..6ebe3bc 100644 --- a/config/configTool.go +++ b/config-file/configTool.go @@ -1,4 +1,4 @@ -package config +package config_file import ( "errors" diff --git a/config/config.go b/config/config.go index 5a66b1f..6fe2769 100644 --- a/config/config.go +++ b/config/config.go @@ -6,10 +6,7 @@ import ( "path/filepath" ) - -var Config = configType{} - -type configType struct { +type ConfigType struct { homePath string codacyDirectory string runtimesDirectory string @@ -18,41 +15,51 @@ type configType struct { projectConfigFile string runtimes map[string]*Runtime + tools map[string]*Runtime } -func (c *configType) HomePath() string { +func (c *ConfigType) HomePath() string { return c.homePath } -func (c *configType) CodacyDirectory() string { +func (c *ConfigType) CodacyDirectory() string { return c.codacyDirectory } -func (c *configType) RuntimesDirectory() string { +func (c *ConfigType) RuntimesDirectory() string { return c.runtimesDirectory } -func (c *configType) ToolsDirectory() string { +func (c *ConfigType) ToolsDirectory() string { return c.toolsDirectory } -func (c *configType) LocalCodacyDirectory() string { +func (c *ConfigType) LocalCodacyDirectory() string { return c.localCodacyDirectory } -func (c *configType) ProjectConfigFile() string { +func (c *ConfigType) ProjectConfigFile() string { return c.projectConfigFile } -func (c *configType) Runtimes() map[string]*Runtime { +func (c *ConfigType) Runtimes() map[string]*Runtime { return c.runtimes } -func (c *configType) SetRuntimes(runtimes map[string]*Runtime) { - c.runtimes = runtimes +func (c *ConfigType) AddRuntime(r *Runtime) { + c.runtimes[r.Name()] = r } -func (c *configType) initCodacyDirs() { +// TODO do inheritance with tool +func (c *ConfigType) Tools() map[string]*Runtime { + return c.tools +} + +func (c *ConfigType) AddTool(t *Runtime) { + c.tools[t.Name()] = t +} + +func (c *ConfigType) initCodacyDirs() { c.codacyDirectory = filepath.Join(c.homePath, ".cache", "codacy") err := os.MkdirAll(c.codacyDirectory, 0777) if err != nil { @@ -87,4 +94,10 @@ func Init() { Config.homePath = homePath Config.initCodacyDirs() -} \ No newline at end of file + + Config.runtimes = make(map[string]*Runtime) + Config.tools = make(map[string]*Runtime) +} + +// Global singleton config-file +var Config = ConfigType{} diff --git a/config/eslint-utils.go b/config/eslint-utils.go new file mode 100644 index 0000000..05ea4bf --- /dev/null +++ b/config/eslint-utils.go @@ -0,0 +1,35 @@ +package config + +import ( + "fmt" + "log" + "os/exec" + "path" +) + +func genInfoEslint(r *Runtime) map[string]string { + eslintFolder := fmt.Sprintf("%s@%s", r.Name(), r.Version()) + installDir := path.Join(Config.ToolsDirectory(), eslintFolder) + + return map[string]string{ + "installDir": installDir, + "eslint": path.Join(installDir, "node_modules", ".bin", "eslint"), + } +} + +/* + * This installs eslint using node's npm alongside its sarif extension + */ +func InstallEslint(nodeRuntime *Runtime, eslint *Runtime) error { + log.Println("Installing ESLint") + + eslintInstallArg := fmt.Sprintf("%s@%s", eslint.Name(), eslint.Version()) + cmd := exec.Command(nodeRuntime.Info()["npm"], "install", "--prefix", eslint.Info()["installDir"], + eslintInstallArg, "@microsoft/eslint-formatter-sarif") + // to use the chdir command we needed to create the folder before, we can change this after + // cmd.Dir = eslintInstallationFolder + stdout, err := cmd.Output() + // Print the output + fmt.Println(string(stdout)) + return err +} diff --git a/config/node-utils.go b/config/node-utils.go new file mode 100644 index 0000000..94c2613 --- /dev/null +++ b/config/node-utils.go @@ -0,0 +1,83 @@ +package config + +import ( + "codacy/cli-v2/utils" + "fmt" + "log" + "os" + "path" + "runtime" +) + +func getNodeFileName(nodeRuntime *Runtime) string { + // Detect the OS and architecture + goos := runtime.GOOS + goarch := runtime.GOARCH + + // Map Go architecture to Node.js architecture + var nodeArch string + switch goarch { + case "386": + nodeArch = "x86" + case "amd64": + nodeArch = "x64" + case "arm": + nodeArch = "armv7l" + case "arm64": + nodeArch = "arm64" + default: + nodeArch = goarch + } + + return fmt.Sprintf("node-v%s-%s-%s", nodeRuntime.Version(), goos, nodeArch) +} + +func genInfoNode(r *Runtime) map[string]string { + nodeFileName := getNodeFileName(r) + + return map[string]string{ + "nodeFileName": nodeFileName, + "installDir": path.Join(Config.RuntimesDirectory(), nodeFileName), + "node": path.Join(Config.RuntimesDirectory(), nodeFileName, "bin", "node"), + "npm": path.Join(Config.RuntimesDirectory(), nodeFileName, "bin", "npm"), + } +} + +func getNodeDownloadURL(nodeRuntime *Runtime) string { + // Detect the OS and architecture + goos := runtime.GOOS + + // Construct the Node.js download URL + extension := "tar.gz" + if goos == "windows" { + extension = "zip" + } + + downloadURL := fmt.Sprintf("https://nodejs.org/dist/v%s/%s.%s", nodeRuntime.Version(), getNodeFileName(nodeRuntime), extension) + return downloadURL +} + +func InstallNode(r *Runtime) error { + // TODO should delete downloaded archive + // TODO check for deflated archive + log.Println("Fetching node...") + downloadNodeURL := getNodeDownloadURL(r) + nodeTar, err := utils.DownloadFile(downloadNodeURL, Config.RuntimesDirectory()) + if err != nil { + return err + } + + // deflate node archive + t, err := os.Open(nodeTar) + defer t.Close() + if err != nil { + return err + } + err = utils.ExtractTarGz(t, Config.RuntimesDirectory()) + if err != nil { + return err + } + + return nil +} + diff --git a/config/runtime.go b/config/runtime.go index e036349..ff9fa2a 100644 --- a/config/runtime.go +++ b/config/runtime.go @@ -1,11 +1,13 @@ package config -import "fmt" +import ( + "fmt" +) type Runtime struct { name string version string - tools []ConfigTool + info map[string]string } func (r *Runtime) Name() string { @@ -16,24 +18,28 @@ func (r *Runtime) Version() string { return r.version } -func (r *Runtime) Tools() []ConfigTool { - return r.tools +func (r *Runtime) FullName() string { + return fmt.Sprintf("%s-%s", r.name, r.version) } -func (r *Runtime) AddTool(tool *ConfigTool) { - r.tools = append(r.tools, *tool) +func (r *Runtime) Info() map[string]string { + return r.info } -func (r *Runtime) FullName() string { - return fmt.Sprintf("%s-%s", r.name, r.version) +func (r *Runtime) populateInfo() { + switch r.Name() { + case "node": + r.info = genInfoNode(r) + case "eslint": + r.info = genInfoEslint(r) + } } -func (r *Runtime) GetTool(name string) *ConfigTool { - // TODO might become a map - for _, tool := range r.tools { - if tool.name == name { - return &tool - } +func NewRuntime(name string, version string) *Runtime { + r := Runtime{ + name: name, + version: version, } - return nil + r.populateInfo() + return &r } \ No newline at end of file diff --git a/config/toolsInfo.go b/config/toolsInfo.go deleted file mode 100644 index f759379..0000000 --- a/config/toolsInfo.go +++ /dev/null @@ -1,70 +0,0 @@ -package config - -import ( - "fmt" - "log" - "path/filepath" - "runtime" -) - -func GetToolRunInfo(name string) (map[string]string, error) { - // Let's assume that for each tool we can get a map[string]string - // with the tools parameters needed to run it - switch name { - case "eslint": - m := make(map[string]string) - - node := Config.runtimes["node"] - eslint := node.GetTool("eslint") - eslintFolder := fmt.Sprintf("%s@%s", eslint.name, eslint.version) - - - m["eslintInstallationDirectory"] = filepath.Join(Config.ToolsDirectory(), eslintFolder) - m["nodeBinary"] = filepath.Join(Config.RuntimesDirectory(), GetNodeFileName(node), "bin", "node") - - return m, nil - default: - log.Fatal("eslint is the only supported tool") - // This never gets called - // TODO return an error type instead of nil - return nil, nil - } - -} - -func GetNodeFileName(nodeRuntime *Runtime) string { - // Detect the OS and architecture - goos := runtime.GOOS - goarch := runtime.GOARCH - - // Map Go architecture to Node.js architecture - var nodeArch string - switch goarch { - case "386": - nodeArch = "x86" - case "amd64": - nodeArch = "x64" - case "arm": - nodeArch = "armv7l" - case "arm64": - nodeArch = "arm64" - default: - nodeArch = goarch - } - - return fmt.Sprintf("node-v%s-%s-%s", nodeRuntime.Version(), goos, nodeArch) -} - -func GetNodeDownloadURL(nodeRuntime *Runtime) string { - // Detect the OS and architecture - goos := runtime.GOOS - - // Construct the Node.js download URL - extension := "tar.gz" - if goos == "windows" { - extension = "zip" - } - - downloadURL := fmt.Sprintf("https://nodejs.org/dist/v%s/%s.%s", nodeRuntime.Version(), GetNodeFileName(nodeRuntime), extension) - return downloadURL -} \ No newline at end of file diff --git a/tool-utils/eslint-utils.go b/tool-utils/eslint-utils.go deleted file mode 100644 index 89df6a6..0000000 --- a/tool-utils/eslint-utils.go +++ /dev/null @@ -1,26 +0,0 @@ -package tool_utils - -import ( - "fmt" - "log" - "os/exec" - "path/filepath" -) - -func InstallESLint(npmExecutablePath string, ESLintversion string, toolsDirectory string) { - log.Println("Installing ESLint") - - eslintInstallationFolder := filepath.Join(toolsDirectory, ESLintversion) - - cmd := exec.Command(npmExecutablePath, "install", "--prefix", eslintInstallationFolder, ESLintversion, "@microsoft/eslint-formatter-sarif") - // to use the chdir command we needed to create the folder before, we can change this after - // cmd.Dir = eslintInstallationFolder - stdout, err := cmd.Output() - - // Print the output - fmt.Println(string(stdout)) - - if err != nil { - log.Fatal(err) - } -} diff --git a/utils/extract.go b/utils/extract.go index 05ea370..5e4b21c 100644 --- a/utils/extract.go +++ b/utils/extract.go @@ -2,10 +2,8 @@ package utils import ( "context" - "fmt" "github.com/mholt/archiver/v4" "io" - "log" "os" "path/filepath" ) @@ -22,14 +20,14 @@ func ExtractTarGz(archive *os.File, targetDir string) error { switch f.IsDir() { case true: // create a directory - fmt.Println("creating: " + f.NameInArchive) + //fmt.Println("creating: " + f.NameInArchive) err := os.MkdirAll(path, 0777) if err != nil { return err } case false: - log.Print("extracting: " + f.NameInArchive) + //log.Print("extracting: " + f.NameInArchive) // if is a symlink if f.LinkTarget != "" { From a5a4903848aeaa9fe9f5be2a05354a90cd9ddf57 Mon Sep 17 00:00:00 2001 From: Joao Machado <13315199+machadoit@users.noreply.github.com> Date: Wed, 22 May 2024 15:29:36 +0100 Subject: [PATCH 02/10] Only write to file when -o is specified --- cmd/analyze.go | 29 ++++++++++++++++++----------- tools/eslintRunner.go | 19 +++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/cmd/analyze.go b/cmd/analyze.go index 6174747..81e2cd1 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -3,17 +3,16 @@ package cmd import ( "codacy/cli-v2/config" "codacy/cli-v2/tools" - "fmt" - "github.com/spf13/cobra" "log" "os" - "path" + + "github.com/spf13/cobra" ) -var outputFolder string +var outputFile string func init() { - analyzeCmd.Flags().StringVarP(&outputFolder, "output", "o", path.Join(".codacy", "out"), "where to output the results") + analyzeCmd.Flags().StringVarP(&outputFile, "output", "o", "", "output file for the results") rootCmd.AddCommand(analyzeCmd) } @@ -22,8 +21,6 @@ var analyzeCmd = &cobra.Command{ Short: "Runs all linters.", Long: "Runs all tools for all runtimes.", Run: func(cmd *cobra.Command, args []string) { - fmt.Println(outputFolder) - workDirectory, err := os.Getwd() if err != nil { log.Fatal(err) @@ -39,10 +36,20 @@ var analyzeCmd = &cobra.Command{ nodeRuntime := config.Config.Runtimes()["node"] nodeBinary := nodeRuntime.Info()["node"] - fmt.Printf("Running the tool %s. Output will be available at %s\n", args[0], outputFolder) - err = tools.RunEslintToFile(workDirectory, eslintInstallationDirectory, nodeBinary, outputFolder) - if err != nil { - log.Fatal(err) + log.Printf("Running %s...\n", args[0]) + if outputFile != "" { + log.Printf("Output will be available at %s\n", outputFile) + err = tools.RunEslintToFile(workDirectory, eslintInstallationDirectory, nodeBinary, outputFile) + if err != nil { + log.Fatal(err) + } + } else { + out, err2 := tools.RunEslintToString(workDirectory, eslintInstallationDirectory, nodeBinary) + if err2 != nil { + log.Fatal(err2) + } + + log.Println(out) } }, } diff --git a/tools/eslintRunner.go b/tools/eslintRunner.go index fafdcdd..5147426 100644 --- a/tools/eslintRunner.go +++ b/tools/eslintRunner.go @@ -6,8 +6,8 @@ import ( "path/filepath" ) -func RunEslintToFile(repositoryToAnalyseDirectory string, eslintInstallationDirectory string, nodeBinary string, outputFolder string) error { - _, err := runEslint(repositoryToAnalyseDirectory, eslintInstallationDirectory, nodeBinary, outputFolder) +func RunEslintToFile(repositoryToAnalyseDirectory string, eslintInstallationDirectory string, nodeBinary string, outputFile string) error { + _, err := runEslint(repositoryToAnalyseDirectory, eslintInstallationDirectory, nodeBinary, outputFile) return err } @@ -18,15 +18,14 @@ func RunEslintToString(repositoryToAnalyseDirectory string, eslintInstallationDi // * 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, outputFolder string) (string, error) { +func runEslint(repositoryToAnalyseDirectory string, eslintInstallationDirectory string, nodeBinary string, outputFile string) (string, error) { eslintInstallationNodeModules := filepath.Join(eslintInstallationDirectory, "node_modules") eslintJsPath := filepath.Join(eslintInstallationNodeModules, ".bin", "eslint") - cmd := exec.Command(nodeBinary, eslintJsPath, "-f", "@microsoft/eslint-formatter-sarif") - - if outputFolder != "" { - outputFile := filepath.Join(outputFolder, "eslint.sarif") - cmd.Args = append(cmd.Args, "-o", outputFile) + cmd := exec.Command(nodeBinary, eslintJsPath) + if outputFile != "" { + //When writing to file, we write is SARIF + cmd.Args = append(cmd.Args, "-f", "@microsoft/eslint-formatter-sarif", "-o", outputFile) } cmd.Dir = repositoryToAnalyseDirectory @@ -38,5 +37,9 @@ func runEslint(repositoryToAnalyseDirectory string, eslintInstallationDirectory // TODO eslint returns 1 when it finds errors, so we're not propagating it out, _ := cmd.Output() + //DEBUG: + //fmt.Println(cmd.Env) + //fmt.Println(cmd) + return string(out), nil } From 03aa0c17d2876bb2ed297c869c2571050b8812f0 Mon Sep 17 00:00:00 2001 From: Joao Machado <13315199+machadoit@users.noreply.github.com> Date: Wed, 22 May 2024 15:47:12 +0100 Subject: [PATCH 03/10] Rely on run command so the stdout of eslint is shown on terminal --- cmd/analyze.go | 17 +---------------- tools/eslintRunner.go | 20 +++----------------- tools/eslintRunner_test.go | 38 +------------------------------------- 3 files changed, 5 insertions(+), 70 deletions(-) diff --git a/cmd/analyze.go b/cmd/analyze.go index 81e2cd1..f27ff09 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -32,24 +32,9 @@ var analyzeCmd = &cobra.Command{ eslint := config.Config.Tools()["eslint"] eslintInstallationDirectory := eslint.Info()["installDir"] - nodeRuntime := config.Config.Runtimes()["node"] nodeBinary := nodeRuntime.Info()["node"] - log.Printf("Running %s...\n", args[0]) - if outputFile != "" { - log.Printf("Output will be available at %s\n", outputFile) - err = tools.RunEslintToFile(workDirectory, eslintInstallationDirectory, nodeBinary, outputFile) - if err != nil { - log.Fatal(err) - } - } else { - out, err2 := tools.RunEslintToString(workDirectory, eslintInstallationDirectory, nodeBinary) - if err2 != nil { - log.Fatal(err2) - } - - log.Println(out) - } + tools.RunEslint(workDirectory, eslintInstallationDirectory, nodeBinary, outputFile) }, } diff --git a/tools/eslintRunner.go b/tools/eslintRunner.go index 5147426..84e4435 100644 --- a/tools/eslintRunner.go +++ b/tools/eslintRunner.go @@ -6,19 +6,10 @@ import ( "path/filepath" ) -func RunEslintToFile(repositoryToAnalyseDirectory string, eslintInstallationDirectory string, nodeBinary string, outputFile string) error { - _, err := runEslint(repositoryToAnalyseDirectory, eslintInstallationDirectory, nodeBinary, outputFile) - return err -} - -func RunEslintToString(repositoryToAnalyseDirectory string, eslintInstallationDirectory string, nodeBinary string) (string, error) { - return runEslint(repositoryToAnalyseDirectory, eslintInstallationDirectory, nodeBinary, "") -} - // * 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, outputFile string) (string, error) { +func RunEslint(repositoryToAnalyseDirectory string, eslintInstallationDirectory string, nodeBinary string, outputFile string) { eslintInstallationNodeModules := filepath.Join(eslintInstallationDirectory, "node_modules") eslintJsPath := filepath.Join(eslintInstallationNodeModules, ".bin", "eslint") @@ -30,16 +21,11 @@ func runEslint(repositoryToAnalyseDirectory string, eslintInstallationDirectory cmd.Dir = repositoryToAnalyseDirectory cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout nodePathEnv := "NODE_PATH=" + eslintInstallationNodeModules cmd.Env = append(cmd.Env, nodePathEnv) // TODO eslint returns 1 when it finds errors, so we're not propagating it - out, _ := cmd.Output() - - //DEBUG: - //fmt.Println(cmd.Env) - //fmt.Println(cmd) - - return string(out), nil + cmd.Run() } diff --git a/tools/eslintRunner_test.go b/tools/eslintRunner_test.go index ccced40..0b99725 100644 --- a/tools/eslintRunner_test.go +++ b/tools/eslintRunner_test.go @@ -10,39 +10,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRunEslintToString(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" - repositoryToAnalyze := filepath.Join(testDirectory, "src") - sarifOutputFile := filepath.Join(testDirectory, "sarif.json") - eslintInstallationDirectory := filepath.Join(homeDirectory, ".cache/codacy-cli-v2/tools/eslint") - nodeBinary := "node" - - eslintOutput, err := RunEslintToString(repositoryToAnalyze, eslintInstallationDirectory, nodeBinary) - if err != nil { - log.Fatal(err.Error()) - } - - expectedSarifBytes, err := os.ReadFile(sarifOutputFile) - if err != nil { - log.Fatal(err.Error()) - } - - filePrefix := "file://" + currentDirectory + "/" - actualSarif := strings.ReplaceAll(eslintOutput, filePrefix, "") - - expectedSarif := string(expectedSarifBytes) - - assert.Equal(t, expectedSarif, actualSarif, "output did not match expected") -} - func TestRunEslintToFile(t *testing.T) { homeDirectory, err := os.UserHomeDir() if err != nil { @@ -61,10 +28,7 @@ func TestRunEslintToFile(t *testing.T) { eslintInstallationDirectory := filepath.Join(homeDirectory, ".cache/codacy-cli-v2/tools/eslint") nodeBinary := "node" - err = RunEslintToFile(repositoryToAnalyze, eslintInstallationDirectory, nodeBinary, tempDir) - if err != nil { - log.Fatal(err.Error()) - } + RunEslint(repositoryToAnalyze, eslintInstallationDirectory, nodeBinary, sarifOutputFile) expectedSarifBytes, err := os.ReadFile(sarifOutputFile) if err != nil { From 4ede1a084b38474856c766b93a485bd5b5f2ac74 Mon Sep 17 00:00:00 2001 From: Pedro Pereira Date: Wed, 22 May 2024 15:56:18 +0100 Subject: [PATCH 04/10] solves potential package reference problems with config --- config/config.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/config.go b/config/config.go index 6fe2769..0ccec64 100644 --- a/config/config.go +++ b/config/config.go @@ -7,12 +7,12 @@ import ( ) type ConfigType struct { - homePath string - codacyDirectory string - runtimesDirectory string - toolsDirectory string + homePath string + codacyDirectory string + runtimesDirectory string + toolsDirectory string localCodacyDirectory string - projectConfigFile string + projectConfigFile string runtimes map[string]*Runtime tools map[string]*Runtime From 0fa487fd087da54bf77d3861028e3e68c7bd597a Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Wed, 22 May 2024 17:04:33 +0200 Subject: [PATCH 05/10] Fix eslintRunner test --- tools/eslintRunner_test.go | 19 ++++++------ .../test1/{sarif.json => expected.sarif} | 0 .../testdata/repositories/test1/eslint.sarif | 29 +++++++++++++++++++ .../repositories/test1/expected.sarif | 29 +++++++++++++++++++ .../testdata/repositories/test1/sarif.json | 29 +++++++++++++++++++ 5 files changed, 96 insertions(+), 10 deletions(-) rename tools/testdata/repositories/test1/{sarif.json => expected.sarif} (100%) create mode 100644 tools/testdata/repositories/test1/src/testdata/repositories/test1/eslint.sarif create mode 100644 tools/testdata/repositories/test1/src/testdata/repositories/test1/expected.sarif create mode 100644 tools/testdata/repositories/test1/src/testdata/repositories/test1/sarif.json diff --git a/tools/eslintRunner_test.go b/tools/eslintRunner_test.go index 0b99725..4b8b392 100644 --- a/tools/eslintRunner_test.go +++ b/tools/eslintRunner_test.go @@ -24,26 +24,25 @@ func TestRunEslintToFile(t *testing.T) { defer os.RemoveAll(tempDir) repositoryToAnalyze := filepath.Join(testDirectory, "src") - sarifOutputFile := filepath.Join(testDirectory, "sarif.json") - eslintInstallationDirectory := filepath.Join(homeDirectory, ".cache/codacy-cli-v2/tools/eslint") + expectedSarifFile := filepath.Join(testDirectory, "expected.sarif") + eslintInstallationDirectory := filepath.Join(homeDirectory, ".cache/codacy/tools/eslint@9.3.0") nodeBinary := "node" + obtainedSarifFile := filepath.Join(tempDir, "eslint.sarif") - RunEslint(repositoryToAnalyze, eslintInstallationDirectory, nodeBinary, sarifOutputFile) + RunEslint(repositoryToAnalyze, eslintInstallationDirectory, nodeBinary, obtainedSarifFile) - expectedSarifBytes, err := os.ReadFile(sarifOutputFile) + expectedSarifBytes, err := os.ReadFile(expectedSarifFile) if err != nil { - log.Fatal(err.Error()) + log.Fatal(err) } - eslintOutputPath := filepath.Join(tempDir, "eslint.sarif") - - eslintOutputBytes, err := os.ReadFile(eslintOutputPath) + obtainedSarifBytes, err := os.ReadFile(obtainedSarifFile) if err != nil { log.Fatal(err.Error()) } - eslintOutput := string(eslintOutputBytes) + obtainedSarif := string(obtainedSarifBytes) filePrefix := "file://" + currentDirectory + "/" - actualSarif := strings.ReplaceAll(eslintOutput, filePrefix, "") + actualSarif := strings.ReplaceAll(obtainedSarif, filePrefix, "") expectedSarif := strings.TrimSpace(string(expectedSarifBytes)) diff --git a/tools/testdata/repositories/test1/sarif.json b/tools/testdata/repositories/test1/expected.sarif similarity index 100% rename from tools/testdata/repositories/test1/sarif.json rename to tools/testdata/repositories/test1/expected.sarif diff --git a/tools/testdata/repositories/test1/src/testdata/repositories/test1/eslint.sarif b/tools/testdata/repositories/test1/src/testdata/repositories/test1/eslint.sarif new file mode 100644 index 0000000..2285ac0 --- /dev/null +++ b/tools/testdata/repositories/test1/src/testdata/repositories/test1/eslint.sarif @@ -0,0 +1,29 @@ +{ + "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": "file:///Users/lorenzo/codacy/github/codacy-cli-v2/tools/testdata/repositories/test1/src/eslint.config.mjs" + } + }, + { + "location": { + "uri": "file:///Users/lorenzo/codacy/github/codacy-cli-v2/tools/testdata/repositories/test1/src/test.js" + } + } + ], + "results": [] + } + ] +} \ No newline at end of file diff --git a/tools/testdata/repositories/test1/src/testdata/repositories/test1/expected.sarif b/tools/testdata/repositories/test1/src/testdata/repositories/test1/expected.sarif new file mode 100644 index 0000000..2285ac0 --- /dev/null +++ b/tools/testdata/repositories/test1/src/testdata/repositories/test1/expected.sarif @@ -0,0 +1,29 @@ +{ + "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": "file:///Users/lorenzo/codacy/github/codacy-cli-v2/tools/testdata/repositories/test1/src/eslint.config.mjs" + } + }, + { + "location": { + "uri": "file:///Users/lorenzo/codacy/github/codacy-cli-v2/tools/testdata/repositories/test1/src/test.js" + } + } + ], + "results": [] + } + ] +} \ No newline at end of file diff --git a/tools/testdata/repositories/test1/src/testdata/repositories/test1/sarif.json b/tools/testdata/repositories/test1/src/testdata/repositories/test1/sarif.json new file mode 100644 index 0000000..2285ac0 --- /dev/null +++ b/tools/testdata/repositories/test1/src/testdata/repositories/test1/sarif.json @@ -0,0 +1,29 @@ +{ + "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": "file:///Users/lorenzo/codacy/github/codacy-cli-v2/tools/testdata/repositories/test1/src/eslint.config.mjs" + } + }, + { + "location": { + "uri": "file:///Users/lorenzo/codacy/github/codacy-cli-v2/tools/testdata/repositories/test1/src/test.js" + } + } + ], + "results": [] + } + ] +} \ No newline at end of file From baa2e4cc68fd5d134baf3b842d103a294ce4c115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Costa?= Date: Wed, 22 May 2024 14:57:17 +0100 Subject: [PATCH 06/10] Script clean up --- codacy-cli.sh | 67 ++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/codacy-cli.sh b/codacy-cli.sh index 049c590..4dc1947 100755 --- a/codacy-cli.sh +++ b/codacy-cli.sh @@ -29,45 +29,28 @@ download_file() { download() { local url="$1" - local file_name="$2" - local output_folder="$3" - local output_filename="$4" - local checksum_url="$5" - local original_folder - original_folder="$(pwd)" + local output_folder="$2" - cd "$output_folder" - - download_file "$url" - # checksum "$file_name" "$checksum_url" - - cd "$original_folder" + ( cd "$output_folder" && download_file "$url" ) } -download_reporter() { +download_cli() { # OS name lower case suffix=$(echo "$os_name" | tr '[:upper:]' '[:lower:]') - local binary_name="codacy-cli-v2-$suffix" - local reporter_path="$1" - local reporter_folder="$2" - local reporter_filename="$3" + local bin_folder="$1" + local bin_path="$2" - if [ ! -f "$reporter_path" ] - then - echo "$i" "Downloading the codacy cli v2 $binary_name... ($CODACY_CLI_V2_VERSION)" + if [ ! -f "$bin_path" ]; then + echo "Downloading the codacy cli v2 version ($CODACY_CLI_V2_VERSION)" remote_file="codacy-cli-v2_${CODACY_CLI_V2_VERSION}_${suffix}_${arch}.tar.gz" - binary_url="https://github.com/codacy/codacy-cli-v2/releases/download/${CODACY_CLI_V2_VERSION}/${remote_file}" - # echo $binary_url - # checksum_url="https://github.com/codacy/codacy-coverage-reporter/releases/download/$CODACY_CLI_V2_VERSION/$binary_name.SHA512SUM" - - download "$binary_url" "$binary_name" "$reporter_folder" "$reporter_filename" "$checksum_url" + url="https://github.com/codacy/codacy-cli-v2/releases/download/${CODACY_CLI_V2_VERSION}/${remote_file}" - echo "${reporter_folder}/${remote_file}" - tar xzfv "${reporter_folder}/${remote_file}" -C "${reporter_folder}" + download "$url" "$bin_folder" + tar xzfv "${bin_folder}/${remote_file}" -C "${bin_folder}" else - echo "$i" "Codacy reporter $binary_name already in cache" + echo "$i" "Codacy cli v2 $binary_name already in cache" fi } @@ -82,8 +65,6 @@ if [ -z "$CODACY_CLI_V2_TMP_FOLDER" ]; then fi fi -reporter_filename="codacy-cli-v2" - # if no version is specified, we fetch the latest if [ -z "$CODACY_CLI_V2_VERSION" ]; then CODACY_CLI_V2_VERSION="$(curl -Lq "https://api.github.com/repos/codacy/codacy-cli-v2/releases/latest" 2>/dev/null | grep -m 1 tag_name | cut -d'"' -f4)" @@ -91,27 +72,27 @@ if [ -z "$CODACY_CLI_V2_VERSION" ]; then fi # Folder containing the binary -reporter_folder="$CODACY_CLI_V2_TMP_FOLDER"/"$CODACY_CLI_V2_VERSION" +bin_folder="${CODACY_CLI_V2_TMP_FOLDER}/${CODACY_CLI_V2_VERSION}" +# Create the folder if not exists +mkdir -p "$bin_folder" -# Create the reporter folder if not exists -mkdir -p "$reporter_folder" +# name of the binary +bin_name="codacy-cli-v2" # Set binary path -reporter_path="$reporter_folder"/"$reporter_filename" - -download_reporter "$reporter_path" "$reporter_folder" "$reporter_filename" +bin_path="$bin_folder"/"$bin_name" -chmod +x "$reporter_path" -run_command="$reporter_path" +# download the tool +download_cli "$bin_folder" "$bin_path" +chmod +x "$bin_path" -if [ -z "$run_command" ] -then +run_command="$bin_path" +if [ -z "$run_command" ]; then fatal "Codacy cli v2 binary could not be found." fi -if [ "$#" -eq 1 ] && [ "$1" = "download" ]; -then - echo "$g" "Codacy reporter download succeeded"; +if [ "$#" -eq 1 ] && [ "$1" = "download" ]; then + echo "$g" "Codacy cli v2 download succeeded"; else eval "$run_command $*" fi \ No newline at end of file From be4ce9f20d23b61fac216b3edcb84bd2dd036e7a Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Wed, 22 May 2024 18:02:26 +0200 Subject: [PATCH 07/10] Avoid printing when binary is cached in script --- codacy-cli.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/codacy-cli.sh b/codacy-cli.sh index 4dc1947..7c4c9d0 100755 --- a/codacy-cli.sh +++ b/codacy-cli.sh @@ -49,8 +49,6 @@ download_cli() { download "$url" "$bin_folder" tar xzfv "${bin_folder}/${remote_file}" -C "${bin_folder}" - else - echo "$i" "Codacy cli v2 $binary_name already in cache" fi } @@ -68,7 +66,6 @@ fi # if no version is specified, we fetch the latest if [ -z "$CODACY_CLI_V2_VERSION" ]; then CODACY_CLI_V2_VERSION="$(curl -Lq "https://api.github.com/repos/codacy/codacy-cli-v2/releases/latest" 2>/dev/null | grep -m 1 tag_name | cut -d'"' -f4)" - echo "Fetching latest version: ${CODACY_CLI_V2_VERSION}" fi # Folder containing the binary From e40cc3cf2467f98bc5e343b3f74f98e16a68e33d Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Wed, 22 May 2024 18:04:23 +0200 Subject: [PATCH 08/10] Add brew formula --- brew/codacy-cli-v2.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 brew/codacy-cli-v2.rb diff --git a/brew/codacy-cli-v2.rb b/brew/codacy-cli-v2.rb new file mode 100644 index 0000000..3375c95 --- /dev/null +++ b/brew/codacy-cli-v2.rb @@ -0,0 +1,9 @@ +class CodacyCliV2 < Formula + version "1.0.0" + url "https://raw.githubusercontent.com/codacy/codacy-cli-v2/8ce8c5da6ee6cf3ff145b7b18f861a6d740e11c0/codacy-cli.sh" + sha256 "fb616e2f5c639985566c81a6e6ce51db2e8de56bf217e837d13efe2f3ccc3042" + + def install + bin.install "codacy-cli.sh" => "codacy-cli" + end +end From 9c20199b8d18df378707f51b282d127e22435b46 Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Wed, 22 May 2024 18:15:13 +0200 Subject: [PATCH 09/10] Move formula to Formula directory --- {brew => Formula}/codacy-cli-v2.rb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {brew => Formula}/codacy-cli-v2.rb (100%) diff --git a/brew/codacy-cli-v2.rb b/Formula/codacy-cli-v2.rb similarity index 100% rename from brew/codacy-cli-v2.rb rename to Formula/codacy-cli-v2.rb From 5155e9d259b26e0845d9fcf0d708d6a6c36d320f Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Wed, 22 May 2024 18:18:39 +0200 Subject: [PATCH 10/10] Use current latest tag for brew --- Formula/codacy-cli-v2.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Formula/codacy-cli-v2.rb b/Formula/codacy-cli-v2.rb index 3375c95..0943099 100644 --- a/Formula/codacy-cli-v2.rb +++ b/Formula/codacy-cli-v2.rb @@ -1,6 +1,6 @@ class CodacyCliV2 < Formula - version "1.0.0" - url "https://raw.githubusercontent.com/codacy/codacy-cli-v2/8ce8c5da6ee6cf3ff145b7b18f861a6d740e11c0/codacy-cli.sh" + version "0.1.0-main.35.70f0f48" + url "https://raw.githubusercontent.com/codacy/codacy-cli-v2/0.1.0-main.35.70f0f48/codacy-cli.sh" sha256 "fb616e2f5c639985566c81a6e6ce51db2e8de56bf217e837d13efe2f3ccc3042" def install