diff --git a/.codacy/codacy.yaml b/.codacy/codacy.yaml index bed1d05..9929d63 100644 --- a/.codacy/codacy.yaml +++ b/.codacy/codacy.yaml @@ -3,14 +3,13 @@ runtimes: - java@17.0.10 - node@22.2.0 - python@3.11.11 - - dart@3.7.2 + - flutter@3.7.2 tools: - - codacy-enigma-cli@0.0.1-main.8.49310c3 - - dartanalyzer@3.7.2 - - eslint@8.57.0 + - eslint@9.38.0 - lizard@1.17.31 - pmd@6.55.0 - - pylint@3.3.7 - - revive@1.11.0 + - pylint@3.3.9 + - revive@1.12.0 - semgrep@1.78.0 - trivy@0.66.0 + - dartanalyzer@3.7.2 diff --git a/config/runtimes-installer.go b/config/runtimes-installer.go index a16f020..0445eb8 100644 --- a/config/runtimes-installer.go +++ b/config/runtimes-installer.go @@ -128,10 +128,11 @@ func downloadAndExtractRuntime(runtimeInfo *plugins.RuntimeInfo) error { if strings.HasSuffix(fileName, ".zip") { err = utils.ExtractZip(file.Name(), runtimesDir) + } else if strings.HasSuffix(fileName, ".tar.xz") || strings.HasSuffix(fileName, ".txz") { + err = utils.ExtractTarXz(file, runtimesDir) } else { err = utils.ExtractTarGz(file, runtimesDir) } - if err != nil { return fmt.Errorf("failed to extract runtime: %w", err) } diff --git a/config/tools-installer_test.go b/config/tools-installer_test.go index bb39a79..2b92bd2 100644 --- a/config/tools-installer_test.go +++ b/config/tools-installer_test.go @@ -32,6 +32,10 @@ func TestAddTools(t *testing.T) { Name: "eslint", Version: "8.38.0", }, + { + Name: "dartanalyzer", + Version: "3.7.2", + }, } // Add tools to the config diff --git a/plugins/runtime-utils.go b/plugins/runtime-utils.go index 35feaa1..c17d428 100644 --- a/plugins/runtime-utils.go +++ b/plugins/runtime-utils.go @@ -46,8 +46,14 @@ func processRuntime(config RuntimeConfig, runtimesDir string) (*RuntimeInfo, err // Get the filename using the template fileName := GetFileName(pluginConfig.Download.FileNameTemplate, config.Version, mappedArch, runtime.GOOS) + customURLConfig, hasCustomURL := getCustomDownloadURL(pluginConfig.Download.CustomURLConfig, runtime.GOOS) // Get the download URL using the template - downloadURL := GetDownloadURL(pluginConfig.Download.URLTemplate, fileName, config.Version, mappedArch, mappedOS, extension, pluginConfig.Download.ReleaseVersion) + downloadURL := "" + if hasCustomURL { + downloadURL = GetDownloadURL(customURLConfig, fileName, config.Version, mappedArch, mappedOS, extension, pluginConfig.Download.ReleaseVersion) + } else { + downloadURL = GetDownloadURL(pluginConfig.Download.URLTemplate, fileName, config.Version, mappedArch, mappedOS, extension, pluginConfig.Download.ReleaseVersion) + } // For Python, we want to use a simpler directory structure var installDir string diff --git a/plugins/runtime-utils_test.go b/plugins/runtime-utils_test.go index 73532bb..c910fcb 100644 --- a/plugins/runtime-utils_test.go +++ b/plugins/runtime-utils_test.go @@ -14,6 +14,10 @@ func TestProcessRuntimes(t *testing.T) { Name: "node", Version: "18.17.1", }, + { + Name: "flutter", + Version: "3.35.7", + }, } // Define a test runtime directory @@ -27,9 +31,15 @@ func TestProcessRuntimes(t *testing.T) { // Assert we have the expected runtime in the results assert.Contains(t, runtimeInfos, "node") + assert.Contains(t, runtimeInfos, "flutter") // Get the node runtime info nodeInfo := runtimeInfos["node"] + flutterInfo := runtimeInfos["flutter"] + + // Basic assertions for flutter + assert.Equal(t, "flutter", flutterInfo.Name) + assert.Equal(t, "3.35.7", flutterInfo.Version) // Assert the basic runtime info is correct assert.Equal(t, "node", nodeInfo.Name) @@ -56,6 +66,73 @@ func TestProcessRuntimes(t *testing.T) { expectedExtension = "zip" } + flutterExpectedExtension := "zip" + if runtime.GOOS == "linux" { + flutterExpectedExtension = "tar.xz" + } + + // Assert flutter extension + assert.Equal(t, flutterExpectedExtension, flutterInfo.Extension) + + // Additional flutter assertions + // Assert the filename is correctly set to a constant "flutter" + assert.Equal(t, "flutter", flutterInfo.FileName) + + // Assert the install directory is correct for flutter + assert.Equal(t, runtimesDir+"/"+flutterInfo.FileName, flutterInfo.InstallDir) + + // Compute expected OS mapping for flutter download URL + var expectedFlutterOS string + switch runtime.GOOS { + case "darwin": + expectedFlutterOS = "macos" + case "linux": + expectedFlutterOS = "linux" + case "windows": + expectedFlutterOS = "windows" + default: + expectedFlutterOS = runtime.GOOS + } + + // Compute expected arch for flutter (only used on macOS/default template) + var expectedFlutterArch string + switch runtime.GOARCH { + case "386": + expectedFlutterArch = "ia32" + case "amd64": + expectedFlutterArch = "x64" + case "arm": + expectedFlutterArch = "arm" + case "arm64": + expectedFlutterArch = "arm64" + default: + expectedFlutterArch = runtime.GOARCH + } + + // Build expected flutter download URL + var expectedFlutterURL string + if runtime.GOOS == "linux" { + expectedFlutterURL = "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_" + flutterInfo.Version + "-stable." + flutterExpectedExtension + } else if runtime.GOOS == "windows" { + expectedFlutterURL = "https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_" + flutterInfo.Version + "-stable." + flutterExpectedExtension + } else { + // Default template includes arch and mapped OS (e.g., macos) + expectedFlutterURL = "https://storage.googleapis.com/flutter_infra_release/releases/stable/" + expectedFlutterOS + "/flutter_" + expectedFlutterOS + "_" + expectedFlutterArch + "_" + flutterInfo.Version + "-stable." + flutterExpectedExtension + } + + assert.Equal(t, expectedFlutterURL, flutterInfo.DownloadURL) + + // Assert flutter binaries map has expected entries + assert.NotNil(t, flutterInfo.Binaries) + assert.Greater(t, len(flutterInfo.Binaries), 0) + + // Check if dart binary is present and correctly mapped + flutterDartBinary := flutterInfo.InstallDir + "/bin/dart" + if runtime.GOOS == "windows" { + flutterDartBinary += ".exe" + } + assert.Equal(t, flutterDartBinary, flutterInfo.Binaries["dart"]) + // Assert the filename is correctly formatted expectedFileName := "node-v18.17.1-" + runtime.GOOS + "-" + expectedArch assert.Equal(t, expectedFileName, nodeInfo.FileName) @@ -69,21 +146,21 @@ func TestProcessRuntimes(t *testing.T) { // Assert the download URL is correctly formatted expectedDownloadURL := "https://nodejs.org/dist/v18.17.1/" + expectedFileName + "." + expectedExtension assert.Equal(t, expectedDownloadURL, nodeInfo.DownloadURL) - + // Assert binary paths are correctly set assert.NotNil(t, nodeInfo.Binaries) assert.Greater(t, len(nodeInfo.Binaries), 0) - + // Check if node and npm binaries are present nodeBinary := nodeInfo.InstallDir + "/bin/node" npmBinary := nodeInfo.InstallDir + "/bin/npm" - + // Add .exe extension for Windows if runtime.GOOS == "windows" { nodeBinary += ".exe" npmBinary += ".exe" } - + assert.Equal(t, nodeBinary, nodeInfo.Binaries["node"]) assert.Equal(t, npmBinary, nodeInfo.Binaries["npm"]) } diff --git a/plugins/runtimes/flutter/plugin.yaml b/plugins/runtimes/flutter/plugin.yaml index 5a92a24..a906863 100644 --- a/plugins/runtimes/flutter/plugin.yaml +++ b/plugins/runtimes/flutter/plugin.yaml @@ -3,10 +3,13 @@ description: Dart Flutterruntime default_version: "3.7.2" download: url_template: "https://storage.googleapis.com/flutter_infra_release/releases/stable/{{.OS}}/flutter_{{.OS}}_{{.Arch}}_{{.Version}}-stable.{{.Extension}}" + custom_url_config: + linux: "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_{{.OS}}_{{.Version}}-stable.{{.Extension}}" + windows: "https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_{{.OS}}_{{.Version}}-stable.{{.Extension}}" file_name_template: "flutter" extension: - default: "zip" linux: "tar.xz" + default: "zip" arch_mapping: "386": "ia32" "amd64": "x64" diff --git a/plugins/shared.go b/plugins/shared.go index 1e418bd..b518b81 100644 --- a/plugins/shared.go +++ b/plugins/shared.go @@ -8,13 +8,22 @@ import ( // ExtensionConfig defines the file extension based on OS type ExtensionConfig struct { + Linux string `yaml:"linux"` Windows string `yaml:"windows"` Default string `yaml:"default"` } +type CustomURLConfig struct { + Linux string `yaml:"linux"` + Windows string `yaml:"windows"` + MacOS string `yaml:"macos"` + Default string `yaml:"default"` +} + // DownloadConfig holds the download configuration from the plugin.yaml type DownloadConfig struct { URLTemplate string `yaml:"url_template"` + CustomURLConfig CustomURLConfig `yaml:"custom_url_config,omitempty"` FileNameTemplate string `yaml:"file_name_template"` Extension ExtensionConfig `yaml:"extension"` ArchMapping map[string]string `yaml:"arch_mapping"` @@ -80,9 +89,33 @@ func GetExtension(extension ExtensionConfig, goos string) string { if goos == "windows" { return extension.Windows } + if goos == "linux" && extension.Linux != "" { + return extension.Linux + } return extension.Default } +func getCustomDownloadURL(customURLConfig CustomURLConfig, goos string) (string, bool) { + switch goos { + case "linux": + if customURLConfig.Linux != "" { + return customURLConfig.Linux, true + } + case "windows": + if customURLConfig.Windows != "" { + return customURLConfig.Windows, true + } + case "darwin": + if customURLConfig.MacOS != "" { + return customURLConfig.MacOS, true + } + } + if customURLConfig.Default != "" { + return customURLConfig.Default, true + } + return "", false +} + // GetMajorVersion extracts the major version from a version string (e.g. "17.0.10" -> "17") func GetMajorVersion(version string) string { if idx := strings.Index(version, "."); idx != -1 { diff --git a/utils/extract.go b/utils/extract.go index 41ff8a3..442ce4e 100644 --- a/utils/extract.go +++ b/utils/extract.go @@ -14,8 +14,16 @@ import ( ) func ExtractTarGz(archive *os.File, targetDir string) error { + return ExtractTar(archive, targetDir, archiver.Gz{}) +} + +func ExtractTarXz(archive *os.File, targetDir string) error { + return ExtractTar(archive, targetDir, archiver.Xz{}) +} + +func ExtractTar(archive *os.File, targetDir string, compression archiver.Compression) error { format := archiver.CompressedArchive{ - Compression: archiver.Gz{}, + Compression: compression, Archival: archiver.Tar{}, }