1
0
mirror of https://github.com/go-task/task.git synced 2025-11-23 22:24:45 +02:00

refactor: migrate from go-git to go-getter

This commit is contained in:
Valentin Maerten
2025-11-11 20:34:44 +01:00
parent 2b713f564f
commit 8361745c6a
5 changed files with 314 additions and 109 deletions

View File

@@ -3,16 +3,13 @@ package taskfile
import (
"context"
"fmt"
"io"
"net/url"
"os"
"path/filepath"
"strings"
giturls "github.com/chainguard-dev/git-urls"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/storage/memory"
"github.com/hashicorp/go-getter"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/execext"
@@ -72,24 +69,53 @@ func (node *GitNode) Read() ([]byte, error) {
return node.ReadContext(context.Background())
}
func (node *GitNode) ReadContext(_ context.Context) ([]byte, error) {
fs := memfs.New()
storer := memory.NewStorage()
_, err := git.Clone(storer, fs, &git.CloneOptions{
URL: node.url.String(),
ReferenceName: plumbing.ReferenceName(node.ref),
SingleBranch: true,
Depth: 1,
})
func (node *GitNode) buildURL() string {
// Get the base URL
baseURL := node.url.String()
ref := node.ref
if ref == "" {
ref = "HEAD"
}
// Always use git:: prefix for git URLs (following Terraform's pattern)
// This forces go-getter to use git protocol
return fmt.Sprintf("git::%s?ref=%s&depth=1", baseURL, ref)
}
func (node *GitNode) ReadContext(ctx context.Context) ([]byte, error) {
// Create temporary directory for git clone
tmpDir, err := os.MkdirTemp("", "task-git-*")
if err != nil {
return nil, fmt.Errorf("failed to create temp dir: %w", err)
}
defer func() {
_ = os.RemoveAll(tmpDir)
}()
getterURL := node.buildURL()
client := &getter.Client{
Ctx: ctx,
Src: getterURL,
Dst: tmpDir,
Mode: getter.ClientModeDir,
}
// Clone repository into tmpdir
if err := client.Get(); err != nil {
return nil, err
}
file, err := fs.Open(node.path)
if err != nil {
return nil, err
// Build path to Taskfile in tmpdir
// If no path specified, use default Taskfile.yml
taskfilePath := node.path
if taskfilePath == "" {
taskfilePath = "Taskfile.yml"
}
// Read the entire response body
b, err := io.ReadAll(file)
filePath := filepath.Join(tmpDir, taskfilePath)
// Read file
b, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}

View File

@@ -102,3 +102,50 @@ func TestGitNode_CacheKey(t *testing.T) {
assert.Equal(t, tt.expectedKey, key)
}
}
func TestGitNode_buildURL(t *testing.T) {
t.Parallel()
tests := []struct {
name string
entrypoint string
expectedURL string
}{
{
name: "HTTPS with ref",
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
expectedURL: "git::https://github.com/foo/bar.git?ref=main&depth=1",
},
{
name: "SSH with ref",
entrypoint: "git@github.com:foo/bar.git//Taskfile.yml?ref=main",
expectedURL: "git::ssh://git@github.com/foo/bar.git?ref=main&depth=1",
},
{
name: "HTTPS with tag ref",
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml?ref=v1.0.0",
expectedURL: "git::https://github.com/foo/bar.git?ref=v1.0.0&depth=1",
},
{
name: "HTTPS without ref (uses remote HEAD)",
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml",
expectedURL: "git::https://github.com/foo/bar.git?ref=HEAD&depth=1",
},
{
name: "SSH with directory path",
entrypoint: "git@github.com:foo/bar.git//directory/Taskfile.yml?ref=dev",
expectedURL: "git::ssh://git@github.com/foo/bar.git?ref=dev&depth=1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
node, err := NewGitNode(tt.entrypoint, "", false)
require.NoError(t, err)
gotURL := node.buildURL()
assert.Equal(t, tt.expectedURL, gotURL)
})
}
}