Refactor initGitRepo to use libgit2 instead of go-git
Signed-off-by: Paulo Gomes <paulo.gomes@weave.works>
This commit is contained in:
parent
5e704a8751
commit
d20cdb532f
|
|
@ -2,6 +2,7 @@ package controllers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
|
@ -9,7 +10,6 @@ import (
|
|||
|
||||
"github.com/go-git/go-billy/v5/memfs"
|
||||
gogit "github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/storage/memory"
|
||||
"github.com/go-logr/logr"
|
||||
|
|
@ -144,18 +144,11 @@ func TestPushRejected(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tmp, err := os.MkdirTemp("", "gotest-imageauto-git")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
repoURL := gitServer.HTTPAddress() + "/appconfig.git"
|
||||
repo, err := gogit.PlainClone(tmp, false, &gogit.CloneOptions{
|
||||
URL: repoURL,
|
||||
ReferenceName: plumbing.NewBranchReferenceName("main"),
|
||||
})
|
||||
repoURL := gitServer.HTTPAddressWithCredentials() + "/appconfig.git"
|
||||
repo, err := clone(repoURL, "origin", "main")
|
||||
|
||||
// This is here to guard against push in general being broken
|
||||
err = push(context.TODO(), tmp, "main", repoAccess{
|
||||
err = push(context.TODO(), repo.Workdir(), "main", repoAccess{
|
||||
url: repoURL,
|
||||
auth: nil,
|
||||
})
|
||||
|
|
@ -164,13 +157,13 @@ func TestPushRejected(t *testing.T) {
|
|||
}
|
||||
|
||||
// This is not under test, but needed for the next bit
|
||||
if err = switchBranch(repo, branch); err != nil {
|
||||
if err = repo.SetHead(fmt.Sprintf("refs/heads/%s", branch)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// This is supposed to fail, because the hook rejects the branch
|
||||
// pushed to.
|
||||
err = push(context.TODO(), tmp, branch, repoAccess{
|
||||
err = push(context.TODO(), repo.Workdir(), branch, repoAccess{
|
||||
url: repoURL,
|
||||
auth: nil,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"os"
|
||||
|
|
@ -28,6 +29,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/fluxcd/pkg/apis/acl"
|
||||
git2go "github.com/libgit2/git2go/v33"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
|
|
@ -1329,57 +1331,170 @@ func commitInRepo(repoURL, branch, msg string, changeFiles func(path string)) {
|
|||
|
||||
// Initialise a git server with a repo including the files in dir.
|
||||
func initGitRepo(gitServer *gittestserver.GitServer, fixture, branch, repositoryPath string) error {
|
||||
fs := memfs.New()
|
||||
repo, err := git.Init(memory.NewStorage(), fs)
|
||||
workDir, err := securejoin.SecureJoin(gitServer.Root(), repositoryPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = populateRepoFromFixture(repo, fixture)
|
||||
repo, err := initGitRepoPlain(fixture, workDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
working, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = working.Checkout(&git.CheckoutOptions{
|
||||
Branch: plumbing.NewBranchReferenceName(branch),
|
||||
Create: true,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
remote, err := repo.CreateRemote(&config.RemoteConfig{
|
||||
Name: "origin",
|
||||
URLs: []string{gitServer.HTTPAddressWithCredentials() + repositoryPath},
|
||||
})
|
||||
commitID, err := headCommit(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = remote.Push(&git.PushOptions{
|
||||
RefSpecs: []config.RefSpec{
|
||||
config.RefSpec(fmt.Sprintf("refs/heads/%s:refs/heads/%s", branch, branch)),
|
||||
},
|
||||
})
|
||||
_, err = repo.CreateBranch(branch, commitID, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Adhoc fix to a bug in which most clone operations during test fail.
|
||||
// This started with the upgrade from libgit2 1.1.1 to 1.3.0, and
|
||||
// requires further investigation as to why repositories created and
|
||||
// amended by go-git stopped working for libgit2 clone operations.
|
||||
repo2, err := git2go.OpenRepository(gitServer.Root() + repositoryPath)
|
||||
return repo.Remotes.AddPush("origin", branchRefName(branch))
|
||||
}
|
||||
|
||||
func initGitRepoPlain(fixture, repositoryPath string) (*git2go.Repository, error) {
|
||||
repo, err := git2go.InitRepository(repositoryPath, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = copyDir(fixture, repositoryPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = commitWorkDir(repo, "main")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func headFromBranch(repo *git2go.Repository, branchName string) (*git2go.Commit, error) {
|
||||
branch, err := repo.LookupBranch(branchName, git2go.BranchAll)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer branch.Free()
|
||||
|
||||
return repo.LookupCommit(branch.Reference.Target())
|
||||
}
|
||||
|
||||
func commitWorkDir(repo *git2go.Repository, branchName string) (*git2go.Oid, error) {
|
||||
var parentC []*git2go.Commit
|
||||
head, err := headFromBranch(repo, branchName)
|
||||
if err == nil {
|
||||
defer head.Free()
|
||||
parentC = append(parentC, head)
|
||||
}
|
||||
|
||||
index, err := repo.Index()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer index.Free()
|
||||
|
||||
// add to index any files that are not within .git/
|
||||
if err = filepath.Walk(repo.Workdir(),
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rel, err := filepath.Rel(repo.Workdir(), path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.IsDir() || strings.HasPrefix(rel, ".git") || rel == "." {
|
||||
return nil
|
||||
}
|
||||
if err := index.AddByPath(rel); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := index.Write(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
treeID, err := index.WriteTree()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tree, err := repo.LookupTree(treeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tree.Free()
|
||||
|
||||
sig := mockSignature(time.Now())
|
||||
c, err := repo.CreateCommit("HEAD", sig, sig, "Committing "+repo.Workdir(), tree, parentC...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func copyDir(src string, dest string) error {
|
||||
file, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer repo2.Free()
|
||||
_, err = commitFile(repo2, "branch", "init", time.Now())
|
||||
if !file.IsDir() {
|
||||
return fmt.Errorf("source %q must be a directory", file.Name())
|
||||
}
|
||||
|
||||
return err
|
||||
if err = os.MkdirAll(dest, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
srcFile := filepath.Join(src, f.Name())
|
||||
destFile := filepath.Join(dest, f.Name())
|
||||
|
||||
if f.IsDir() {
|
||||
if err = copyDir(srcFile, destFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !f.IsDir() {
|
||||
// ignore symlinks
|
||||
if f.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
continue
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(srcFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(destFile, content, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func branchRefName(branch string) string {
|
||||
return fmt.Sprintf("refs/heads/%s:refs/heads/%s", branch, branch)
|
||||
}
|
||||
|
||||
func checkoutBranch(repo *git.Repository, branch string) error {
|
||||
|
|
@ -1509,3 +1624,26 @@ func headCommit(repo *git2go.Repository) (*git2go.Commit, error) {
|
|||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func clone(repoURL, remoteName, branchName string) (*git2go.Repository, error) {
|
||||
dir, err := os.MkdirTemp("", "iac-clone-*")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := &git2go.CloneOptions{
|
||||
Bare: false,
|
||||
CheckoutBranch: branchName,
|
||||
CheckoutOptions: git2go.CheckoutOptions{
|
||||
Strategy: git2go.CheckoutForce,
|
||||
},
|
||||
FetchOptions: git2go.FetchOptions{
|
||||
RemoteCallbacks: git2go.RemoteCallbacks{
|
||||
CertificateCheckCallback: func(cert *git2go.Certificate, valid bool, hostname string) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return git2go.Clone(repoURL, dir, opts)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue