Skip to content

[autodetect] Add go autodetection #2381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
[autodetect] Add go autodetection
  • Loading branch information
mikeland73 committed Oct 24, 2024
commit e7abad4543a7903c7d71e86342f35bd6a0b5fc75
1 change: 1 addition & 0 deletions pkg/autodetect/autodetect.go
Original file line number Diff line number Diff line change
Expand Up @@ -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},
}
}

Expand Down
53 changes: 53 additions & 0 deletions pkg/autodetect/detector/go.go
Original file line number Diff line number Diff line change
@@ -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 ""
}
103 changes: 103 additions & 0 deletions pkg/autodetect/detector/go_test.go
Original file line number Diff line number Diff line change
@@ -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"), 0644)
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"), 0644)
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), 0644)
assert.NoError(t, err)

packages, err := detector.Packages(context.Background())
assert.NoError(t, err)
assert.Equal(t, []string{"[email protected]"}, 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)
})
}
}
Loading