100
internal/git/git.go
Normal file
100
internal/git/git.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
gogit "github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||
)
|
||||
|
||||
// Service handles Git operations for projects.
|
||||
type Service struct{}
|
||||
|
||||
// New creates a new Git Service.
|
||||
func New() *Service {
|
||||
return &Service{}
|
||||
}
|
||||
|
||||
// CloneOrPull clones a repo if it doesn't exist locally, or pulls latest changes.
|
||||
// Returns the commit hash of HEAD after the operation.
|
||||
func (s *Service) CloneOrPull(url, branch, username, password, dstDir string) (string, error) {
|
||||
// Check if repo already exists
|
||||
repo, err := gogit.PlainOpen(dstDir)
|
||||
if err == nil {
|
||||
// Repo exists, pull
|
||||
return s.pull(repo, branch, username, password)
|
||||
}
|
||||
|
||||
// Clone fresh
|
||||
return s.clone(url, branch, username, password, dstDir)
|
||||
}
|
||||
|
||||
func (s *Service) clone(url, branch, username, password, dstDir string) (string, error) {
|
||||
// Ensure parent directory exists
|
||||
os.MkdirAll(filepath.Dir(dstDir), 0755)
|
||||
// Remove target if it exists (shouldn't, but be safe)
|
||||
os.RemoveAll(dstDir)
|
||||
|
||||
var auth transport.AuthMethod
|
||||
if username != "" || password != "" {
|
||||
auth = &http.BasicAuth{
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
}
|
||||
|
||||
refName := plumbing.NewBranchReferenceName(branch)
|
||||
repo, err := gogit.PlainClone(dstDir, false, &gogit.CloneOptions{
|
||||
URL: url,
|
||||
Auth: auth,
|
||||
ReferenceName: refName,
|
||||
SingleBranch: true,
|
||||
Depth: 1,
|
||||
Progress: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("clone failed: %w", err)
|
||||
}
|
||||
|
||||
return getHeadHash(repo)
|
||||
}
|
||||
|
||||
func (s *Service) pull(repo *gogit.Repository, branch, username, password string) (string, error) {
|
||||
w, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("worktree: %w", err)
|
||||
}
|
||||
|
||||
var auth transport.AuthMethod
|
||||
if username != "" || password != "" {
|
||||
auth = &http.BasicAuth{
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
}
|
||||
|
||||
refName := plumbing.NewBranchReferenceName(branch)
|
||||
err = w.Pull(&gogit.PullOptions{
|
||||
RemoteName: "origin",
|
||||
Auth: auth,
|
||||
ReferenceName: refName,
|
||||
SingleBranch: true,
|
||||
})
|
||||
if err != nil && err != gogit.NoErrAlreadyUpToDate {
|
||||
return "", fmt.Errorf("pull failed: %w", err)
|
||||
}
|
||||
|
||||
return getHeadHash(repo)
|
||||
}
|
||||
|
||||
func getHeadHash(repo *gogit.Repository) (string, error) {
|
||||
ref, err := repo.Head()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ref.Hash().String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user