diff --git a/pkg/autodetect/autodetect.go b/pkg/autodetect/autodetect.go index 12ef7c8a478..f5ad8988e2f 100644 --- a/pkg/autodetect/autodetect.go +++ b/pkg/autodetect/autodetect.go @@ -43,6 +43,7 @@ func detectors(path string) []detector.Detector { return []detector.Detector{ &detector.PythonDetector{Root: path}, &detector.PoetryDetector{Root: path}, + &detector.GoDetector{Root: path}, } } diff --git a/pkg/autodetect/detector/go.go b/pkg/autodetect/detector/go.go new file mode 100644 index 00000000000..0fa938db4da --- /dev/null +++ b/pkg/autodetect/detector/go.go @@ -0,0 +1,53 @@ +package detector + +import ( + "context" + "os" + "path/filepath" + "regexp" +) + +type GoDetector struct { + Root string +} + +var _ Detector = &GoDetector{} + +func (d *GoDetector) Relevance(path string) (float64, error) { + goModPath := filepath.Join(d.Root, "go.mod") + _, err := os.Stat(goModPath) + if err == nil { + return 1.0, nil + } + if os.IsNotExist(err) { + return 0, nil + } + return 0, err +} + +func (d *GoDetector) Packages(ctx context.Context) ([]string, error) { + goModPath := filepath.Join(d.Root, "go.mod") + goModContent, err := os.ReadFile(goModPath) + if err != nil { + return nil, err + } + + // Parse the Go version from go.mod + goVersion := parseGoVersion(string(goModContent)) + if goVersion != "" { + return []string{"go@" + goVersion}, nil + } + return []string{"go@latest"}, nil +} + +func parseGoVersion(goModContent string) string { + // Use a regular expression to find the Go version directive + re := regexp.MustCompile(`(?m)^go\s+(\d+\.\d+(\.\d+)?)`) + match := re.FindStringSubmatch(goModContent) + + if len(match) >= 2 { + return match[1] + } + + return "" +} diff --git a/pkg/autodetect/detector/go_test.go b/pkg/autodetect/detector/go_test.go new file mode 100644 index 00000000000..758a63ca134 --- /dev/null +++ b/pkg/autodetect/detector/go_test.go @@ -0,0 +1,103 @@ +package detector + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGoDetectorRelevance(t *testing.T) { + tempDir := t.TempDir() + detector := &GoDetector{Root: tempDir} + + t.Run("No go.mod file", func(t *testing.T) { + relevance, err := detector.Relevance(tempDir) + assert.NoError(t, err) + assert.Equal(t, 0.0, relevance) + }) + + t.Run("With go.mod file", func(t *testing.T) { + err := os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte("module example.com"), 0o644) + assert.NoError(t, err) + + relevance, err := detector.Relevance(tempDir) + assert.NoError(t, err) + assert.Equal(t, 1.0, relevance) + }) +} + +func TestGoDetectorPackages(t *testing.T) { + tempDir := t.TempDir() + detector := &GoDetector{Root: tempDir} + + t.Run("No go.mod file", func(t *testing.T) { + packages, err := detector.Packages(context.Background()) + assert.Error(t, err) + assert.Nil(t, packages) + }) + + t.Run("With go.mod file and no version", func(t *testing.T) { + err := os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte("module example.com"), 0o644) + assert.NoError(t, err) + + packages, err := detector.Packages(context.Background()) + assert.NoError(t, err) + assert.Equal(t, []string{"go@latest"}, packages) + }) + + t.Run("With go.mod file and specific version", func(t *testing.T) { + goModContent := ` +module example.com + +go 1.18 +` + err := os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte(goModContent), 0o644) + assert.NoError(t, err) + + packages, err := detector.Packages(context.Background()) + assert.NoError(t, err) + assert.Equal(t, []string{"go@1.18"}, packages) + }) +} + +func TestParseGoVersion(t *testing.T) { + testCases := []struct { + name string + content string + expected string + }{ + { + name: "No version", + content: "module example.com", + expected: "", + }, + { + name: "With version", + content: ` +module example.com + +go 1.18 +`, + expected: "1.18", + }, + { + name: "With patch version", + content: ` +module example.com + +go 1.18.3 +`, + expected: "1.18.3", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + version := parseGoVersion(tc.content) + assert.Equal(t, tc.expected, version) + }) + } +}