Skip to content

Commit d20cdb5

Browse files
author
Paulo Gomes
committed
Refactor initGitRepo to use libgit2 instead of go-git
Signed-off-by: Paulo Gomes <[email protected]>
1 parent 5e704a8 commit d20cdb5

File tree

2 files changed

+170
-39
lines changed

2 files changed

+170
-39
lines changed

controllers/git_test.go

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ package controllers
22

33
import (
44
"context"
5+
"fmt"
56
"os"
67
"path/filepath"
78
"testing"
89
"time"
910

1011
"github.com/go-git/go-billy/v5/memfs"
1112
gogit "github.com/go-git/go-git/v5"
12-
"github.com/go-git/go-git/v5/plumbing"
1313
"github.com/go-git/go-git/v5/plumbing/object"
1414
"github.com/go-git/go-git/v5/storage/memory"
1515
"github.com/go-logr/logr"
@@ -144,18 +144,11 @@ func TestPushRejected(t *testing.T) {
144144
t.Fatal(err)
145145
}
146146

147-
tmp, err := os.MkdirTemp("", "gotest-imageauto-git")
148-
if err != nil {
149-
t.Fatal(err)
150-
}
151-
repoURL := gitServer.HTTPAddress() + "/appconfig.git"
152-
repo, err := gogit.PlainClone(tmp, false, &gogit.CloneOptions{
153-
URL: repoURL,
154-
ReferenceName: plumbing.NewBranchReferenceName("main"),
155-
})
147+
repoURL := gitServer.HTTPAddressWithCredentials() + "/appconfig.git"
148+
repo, err := clone(repoURL, "origin", "main")
156149

157150
// This is here to guard against push in general being broken
158-
err = push(context.TODO(), tmp, "main", repoAccess{
151+
err = push(context.TODO(), repo.Workdir(), "main", repoAccess{
159152
url: repoURL,
160153
auth: nil,
161154
})
@@ -164,13 +157,13 @@ func TestPushRejected(t *testing.T) {
164157
}
165158

166159
// This is not under test, but needed for the next bit
167-
if err = switchBranch(repo, branch); err != nil {
160+
if err = repo.SetHead(fmt.Sprintf("refs/heads/%s", branch)); err != nil {
168161
t.Fatal(err)
169162
}
170163

171164
// This is supposed to fail, because the hook rejects the branch
172165
// pushed to.
173-
err = push(context.TODO(), tmp, branch, repoAccess{
166+
err = push(context.TODO(), repo.Workdir(), branch, repoAccess{
174167
url: repoURL,
175168
auth: nil,
176169
})

controllers/update_test.go

Lines changed: 164 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"bytes"
2121
"context"
2222
"fmt"
23+
"io/ioutil"
2324
"math/rand"
2425
"net/url"
2526
"os"
@@ -28,6 +29,7 @@ import (
2829
"strings"
2930
"time"
3031

32+
securejoin "github.com/cyphar/filepath-securejoin"
3133
"github.com/fluxcd/pkg/apis/acl"
3234
git2go "github.com/libgit2/git2go/v33"
3335
"golang.org/x/crypto/openpgp"
@@ -1329,57 +1331,170 @@ func commitInRepo(repoURL, branch, msg string, changeFiles func(path string)) {
13291331

13301332
// Initialise a git server with a repo including the files in dir.
13311333
func initGitRepo(gitServer *gittestserver.GitServer, fixture, branch, repositoryPath string) error {
1332-
fs := memfs.New()
1333-
repo, err := git.Init(memory.NewStorage(), fs)
1334+
workDir, err := securejoin.SecureJoin(gitServer.Root(), repositoryPath)
13341335
if err != nil {
13351336
return err
13361337
}
13371338

1338-
err = populateRepoFromFixture(repo, fixture)
1339+
repo, err := initGitRepoPlain(fixture, workDir)
13391340
if err != nil {
13401341
return err
13411342
}
13421343

1343-
working, err := repo.Worktree()
1344+
commitID, err := headCommit(repo)
13441345
if err != nil {
13451346
return err
13461347
}
1347-
if err = working.Checkout(&git.CheckoutOptions{
1348-
Branch: plumbing.NewBranchReferenceName(branch),
1349-
Create: true,
1350-
}); err != nil {
1348+
1349+
_, err = repo.CreateBranch(branch, commitID, false)
1350+
if err != nil {
13511351
return err
13521352
}
13531353

1354-
remote, err := repo.CreateRemote(&config.RemoteConfig{
1355-
Name: "origin",
1356-
URLs: []string{gitServer.HTTPAddressWithCredentials() + repositoryPath},
1357-
})
1354+
return repo.Remotes.AddPush("origin", branchRefName(branch))
1355+
}
1356+
1357+
func initGitRepoPlain(fixture, repositoryPath string) (*git2go.Repository, error) {
1358+
repo, err := git2go.InitRepository(repositoryPath, false)
13581359
if err != nil {
1359-
return err
1360+
return nil, err
13601361
}
13611362

1362-
err = remote.Push(&git.PushOptions{
1363-
RefSpecs: []config.RefSpec{
1364-
config.RefSpec(fmt.Sprintf("refs/heads/%s:refs/heads/%s", branch, branch)),
1365-
},
1366-
})
1363+
err = copyDir(fixture, repositoryPath)
13671364
if err != nil {
1365+
return nil, err
1366+
}
1367+
1368+
_, err = commitWorkDir(repo, "main")
1369+
if err != nil {
1370+
return nil, err
1371+
}
1372+
1373+
return repo, nil
1374+
}
1375+
1376+
func headFromBranch(repo *git2go.Repository, branchName string) (*git2go.Commit, error) {
1377+
branch, err := repo.LookupBranch(branchName, git2go.BranchAll)
1378+
if err != nil {
1379+
return nil, err
1380+
}
1381+
defer branch.Free()
1382+
1383+
return repo.LookupCommit(branch.Reference.Target())
1384+
}
1385+
1386+
func commitWorkDir(repo *git2go.Repository, branchName string) (*git2go.Oid, error) {
1387+
var parentC []*git2go.Commit
1388+
head, err := headFromBranch(repo, branchName)
1389+
if err == nil {
1390+
defer head.Free()
1391+
parentC = append(parentC, head)
1392+
}
1393+
1394+
index, err := repo.Index()
1395+
if err != nil {
1396+
return nil, err
1397+
}
1398+
defer index.Free()
1399+
1400+
// add to index any files that are not within .git/
1401+
if err = filepath.Walk(repo.Workdir(),
1402+
func(path string, info os.FileInfo, err error) error {
1403+
if err != nil {
1404+
return err
1405+
}
1406+
rel, err := filepath.Rel(repo.Workdir(), path)
1407+
if err != nil {
1408+
return err
1409+
}
1410+
f, err := os.Stat(path)
1411+
if err != nil {
1412+
return err
1413+
}
1414+
if f.IsDir() || strings.HasPrefix(rel, ".git") || rel == "." {
1415+
return nil
1416+
}
1417+
if err := index.AddByPath(rel); err != nil {
1418+
return err
1419+
}
1420+
return nil
1421+
}); err != nil {
1422+
return nil, err
1423+
}
1424+
1425+
if err := index.Write(); err != nil {
1426+
return nil, err
1427+
}
1428+
1429+
treeID, err := index.WriteTree()
1430+
if err != nil {
1431+
return nil, err
1432+
}
1433+
1434+
tree, err := repo.LookupTree(treeID)
1435+
if err != nil {
1436+
return nil, err
1437+
}
1438+
defer tree.Free()
1439+
1440+
sig := mockSignature(time.Now())
1441+
c, err := repo.CreateCommit("HEAD", sig, sig, "Committing "+repo.Workdir(), tree, parentC...)
1442+
if err != nil {
1443+
return nil, err
1444+
}
1445+
return c, nil
1446+
}
1447+
1448+
func copyDir(src string, dest string) error {
1449+
file, err := os.Stat(src)
1450+
if err != nil {
1451+
return err
1452+
}
1453+
if !file.IsDir() {
1454+
return fmt.Errorf("source %q must be a directory", file.Name())
1455+
}
1456+
1457+
if err = os.MkdirAll(dest, 0o755); err != nil {
13681458
return err
13691459
}
13701460

1371-
// Adhoc fix to a bug in which most clone operations during test fail.
1372-
// This started with the upgrade from libgit2 1.1.1 to 1.3.0, and
1373-
// requires further investigation as to why repositories created and
1374-
// amended by go-git stopped working for libgit2 clone operations.
1375-
repo2, err := git2go.OpenRepository(gitServer.Root() + repositoryPath)
1461+
files, err := ioutil.ReadDir(src)
13761462
if err != nil {
13771463
return err
13781464
}
1379-
defer repo2.Free()
1380-
_, err = commitFile(repo2, "branch", "init", time.Now())
13811465

1382-
return err
1466+
for _, f := range files {
1467+
srcFile := filepath.Join(src, f.Name())
1468+
destFile := filepath.Join(dest, f.Name())
1469+
1470+
if f.IsDir() {
1471+
if err = copyDir(srcFile, destFile); err != nil {
1472+
return err
1473+
}
1474+
}
1475+
1476+
if !f.IsDir() {
1477+
// ignore symlinks
1478+
if f.Mode()&os.ModeSymlink == os.ModeSymlink {
1479+
continue
1480+
}
1481+
1482+
content, err := ioutil.ReadFile(srcFile)
1483+
if err != nil {
1484+
return err
1485+
}
1486+
1487+
if err = ioutil.WriteFile(destFile, content, 0o755); err != nil {
1488+
return err
1489+
}
1490+
}
1491+
}
1492+
1493+
return nil
1494+
}
1495+
1496+
func branchRefName(branch string) string {
1497+
return fmt.Sprintf("refs/heads/%s:refs/heads/%s", branch, branch)
13831498
}
13841499

13851500
func checkoutBranch(repo *git.Repository, branch string) error {
@@ -1509,3 +1624,26 @@ func headCommit(repo *git2go.Repository) (*git2go.Commit, error) {
15091624
}
15101625
return c, nil
15111626
}
1627+
1628+
func clone(repoURL, remoteName, branchName string) (*git2go.Repository, error) {
1629+
dir, err := os.MkdirTemp("", "iac-clone-*")
1630+
if err != nil {
1631+
return nil, err
1632+
}
1633+
opts := &git2go.CloneOptions{
1634+
Bare: false,
1635+
CheckoutBranch: branchName,
1636+
CheckoutOptions: git2go.CheckoutOptions{
1637+
Strategy: git2go.CheckoutForce,
1638+
},
1639+
FetchOptions: git2go.FetchOptions{
1640+
RemoteCallbacks: git2go.RemoteCallbacks{
1641+
CertificateCheckCallback: func(cert *git2go.Certificate, valid bool, hostname string) error {
1642+
return nil
1643+
},
1644+
},
1645+
},
1646+
}
1647+
1648+
return git2go.Clone(repoURL, dir, opts)
1649+
}

0 commit comments

Comments
 (0)