Skip to content

Commit e5ebc9d

Browse files
committed
Replace git exec commands with go-git library
Use go-git for cloning and checking out GitHub Action repositories instead of shelling out to git commands.
1 parent 5d52dca commit e5ebc9d

1 file changed

Lines changed: 63 additions & 16 deletions

File tree

nodes/gh-action@v1.go

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import (
1919
u "github.com/actionforge/actrun-cli/utils"
2020

2121
"github.com/Masterminds/semver/v3"
22+
"github.com/go-git/go-git/v5"
23+
"github.com/go-git/go-git/v5/plumbing"
24+
"github.com/go-git/go-git/v5/plumbing/transport/http"
2225
"github.com/google/uuid"
2326
"go.yaml.in/yaml/v4"
2427
)
@@ -398,34 +401,78 @@ func init() {
398401
return nil, []error{core.CreateErr(nil, nil, "INPUT_TOKEN not set")}
399402
}
400403

401-
cloneUrl := fmt.Sprintf("https://%s@github.com/%s/%s", ghToken, owner, repo)
404+
cloneUrl := fmt.Sprintf("https://github.com/%s/%s", owner, repo)
402405

403406
if err := os.MkdirAll(filepath.Dir(repoRoot), 0755); err != nil {
404407
return nil, []error{core.CreateErr(nil, err, "unable to create action directory")}
405408
}
406409

407-
c := exec.Command("git", "clone", "--quiet", "--no-checkout", cloneUrl, repoRoot)
408-
c.Stderr = os.Stderr
409-
err = c.Run()
410+
cloneOpts := &git.CloneOptions{
411+
URL: cloneUrl,
412+
NoCheckout: true,
413+
}
414+
415+
// TODO: (Seb) Find alternative for running in
416+
// debug mode if user has SSH keys set up instead of a token.
417+
cloneOpts.Auth = &http.BasicAuth{
418+
Username: "x-access-token",
419+
Password: ghToken,
420+
}
421+
422+
clonedRepo, err := git.PlainClone(repoRoot, false, cloneOpts)
410423
if err != nil {
411-
return nil, []error{err}
424+
return nil, []error{core.CreateErr(nil, err, "failed to clone repository")}
425+
}
426+
427+
// checkout the specified ref (or HEAD if empty)
428+
worktree, err := clonedRepo.Worktree()
429+
if err != nil {
430+
return nil, []error{core.CreateErr(nil, err, "failed to get worktree")}
431+
}
432+
433+
checkoutOpts := &git.CheckoutOptions{}
434+
if ref != "" {
435+
// resolve as a revision (commit hash, tag, or branch)
436+
hash, err := clonedRepo.ResolveRevision(plumbing.Revision(ref))
437+
if err != nil {
438+
// if not a hash, try as a branch name
439+
checkoutOpts.Branch = plumbing.NewBranchReferenceName(ref)
440+
} else {
441+
checkoutOpts.Hash = *hash
442+
}
412443
}
413444

414-
c = exec.Command("git", "checkout", u.If(ref == "", "HEAD", ref))
415-
c.Stderr = os.Stderr
416-
c.Dir = repoRoot
417-
err = c.Run()
445+
err = worktree.Checkout(checkoutOpts)
418446
if err != nil {
419-
return nil, []error{err}
447+
return nil, []error{core.CreateErr(nil, err, "failed to checkout ref '%s'", ref)}
420448
}
421449
} else {
422-
// reset in case something or someone tampered with the cached gh actions
423-
c := exec.Command("git", "reset", "--quiet", "--hard", u.If(ref == "", "HEAD", ref))
424-
c.Stderr = os.Stderr
425-
c.Dir = repoRoot
426-
err = c.Run()
450+
// reset in just case something tampered with the cached gh actions
451+
existingRepo, err := git.PlainOpen(repoRoot)
452+
if err != nil {
453+
return nil, []error{core.CreateErr(nil, err, "failed to open cached repository")}
454+
}
455+
456+
worktree, err := existingRepo.Worktree()
457+
if err != nil {
458+
return nil, []error{core.CreateErr(nil, err, "failed to get worktree")}
459+
}
460+
461+
checkoutOpts := &git.CheckoutOptions{
462+
Force: true,
463+
}
464+
if ref != "" {
465+
hash, err := existingRepo.ResolveRevision(plumbing.Revision(ref))
466+
if err != nil {
467+
checkoutOpts.Branch = plumbing.NewBranchReferenceName(ref)
468+
} else {
469+
checkoutOpts.Hash = *hash
470+
}
471+
}
472+
473+
err = worktree.Checkout(checkoutOpts)
427474
if err != nil {
428-
return nil, []error{err}
475+
return nil, []error{core.CreateErr(nil, err, "failed to reset to ref '%s'", ref)}
429476
}
430477
}
431478

0 commit comments

Comments
 (0)