Skip to content

Commit 1a56719

Browse files
authored
feat: add additional git repo functions (#153)
1 parent 40377f3 commit 1a56719

File tree

15 files changed

+290
-57
lines changed

15 files changed

+290
-57
lines changed

cli/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.23.0
44

55
require (
66
cuelang.org/go v0.12.0
7+
github.com/adrg/xdg v0.5.3
78
github.com/alecthomas/kong v0.9.0
89
github.com/aws/aws-sdk-go v1.55.5
910
github.com/aws/aws-sdk-go-v2 v1.32.6

cli/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEP
219219
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
220220
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
221221
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
222+
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
223+
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
222224
github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
223225
github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
224226
github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA=

lib/project/deployment/deployer/deployer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ func (d *Deployer) clone(url, ref string, fs fs.Filesystem) (repo.GitRepo, error
305305
return repo.GitRepo{}, fmt.Errorf("could not create git repository: %w", err)
306306
}
307307

308-
if err := r.Clone(url, ref); err != nil {
308+
if err := r.Clone(url, repo.WithRef(ref), repo.WithCloneDepth(1)); err != nil {
309309
return repo.GitRepo{}, fmt.Errorf("could not clone repository: %w", err)
310310
}
311311

@@ -365,7 +365,7 @@ func NewDeployerConfigFromProject(p *project.Project) DeployerConfig {
365365
return DeployerConfig{
366366
Git: DeployerConfigGit{
367367
Creds: p.Blueprint.Global.Ci.Providers.Git.Credentials,
368-
Ref: p.Blueprint.Global.Deployment.Repo.Ref,
368+
Ref: fmt.Sprintf("refs/heads/%s", p.Blueprint.Global.Deployment.Repo.Ref),
369369
Url: p.Blueprint.Global.Deployment.Repo.Url,
370370
},
371371
RootDir: p.Blueprint.Global.Deployment.Root,

lib/project/deployment/deployer/deployer_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ func TestDeployerCreateDeployment(t *testing.T) {
154154
auth := r.cloneOpts.Auth.(*http.BasicAuth)
155155
assert.Equal(t, gitPassword, auth.Password)
156156
assert.Equal(t, cfg.Git.Url, r.cloneOpts.URL)
157-
assert.Equal(t, fmt.Sprintf("refs/heads/%s", cfg.Git.Ref), r.cloneOpts.ReferenceName.String())
157+
assert.Equal(t, cfg.Git.Ref, r.cloneOpts.ReferenceName.String())
158158
},
159159
},
160160
{

lib/project/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ require (
3232
github.com/Masterminds/squirrel v1.5.4 // indirect
3333
github.com/Microsoft/go-winio v0.6.2 // indirect
3434
github.com/ProtonMail/go-crypto v1.0.0 // indirect
35+
github.com/adrg/xdg v0.5.3 // indirect
3536
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230219212500-1f9a474cc2dc // indirect
3637
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
3738
github.com/aws/aws-sdk-go-v2 v1.31.0 // indirect

lib/project/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEP
219219
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
220220
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
221221
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
222+
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
223+
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
222224
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
223225
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
224226
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=

lib/tools/git/repo/cache.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package repo
2+
3+
import (
4+
"fmt"
5+
"log/slog"
6+
"path/filepath"
7+
"strings"
8+
9+
"github.com/adrg/xdg"
10+
bfs "github.com/input-output-hk/catalyst-forge/lib/tools/fs/billy"
11+
"github.com/input-output-hk/catalyst-forge/lib/tools/git/repo/remote"
12+
)
13+
14+
// NewCachedRepo creates a new GitRepo instance that uses a predefined cache path.
15+
// If the repository does not exist in the cache, it will be cloned.
16+
// If the repository exists in the cache, it will be opened.
17+
func NewCachedRepo(url string, logger *slog.Logger, opts ...GitRepoOption) (GitRepo, error) {
18+
cUrl := strings.TrimPrefix(url, "https://")
19+
cUrl = strings.TrimPrefix(cUrl, "git://")
20+
cUrl = strings.TrimSuffix(cUrl, ".git")
21+
22+
path := filepath.Join(xdg.CacheHome, "forge")
23+
gp := filepath.Join(path, cUrl, ".git")
24+
wp := filepath.Join(path, cUrl)
25+
26+
r := GitRepo{
27+
logger: logger,
28+
remote: remote.GoGitRemoteInteractor{},
29+
}
30+
31+
for _, opt := range opts {
32+
opt(&r)
33+
}
34+
35+
r.fs = bfs.NewBaseOsFS()
36+
r.gfs = bfs.NewOsFs(gp)
37+
r.wfs = bfs.NewOsFs(wp)
38+
39+
exists, err := r.fs.Exists(filepath.Join(gp))
40+
if err != nil {
41+
return GitRepo{}, fmt.Errorf("could not check if repo exists: %w", err)
42+
} else if !exists {
43+
r.logger.Info("No cached repo found, cloning", "url", url)
44+
if err := r.Clone(url); err != nil {
45+
return GitRepo{}, fmt.Errorf("could not clone: %w", err)
46+
}
47+
} else {
48+
r.logger.Info("Cached repo found, opening", "url", url)
49+
if err := r.Open(); err != nil {
50+
return GitRepo{}, fmt.Errorf("could not open repo: %w", err)
51+
}
52+
}
53+
54+
return r, nil
55+
}

lib/tools/git/repo/opts.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package repo
2+
3+
import (
4+
gg "github.com/go-git/go-git/v5"
5+
"github.com/go-git/go-git/v5/config"
6+
"github.com/go-git/go-git/v5/plumbing"
7+
"github.com/go-git/go-git/v5/plumbing/transport/http"
8+
"github.com/input-output-hk/catalyst-forge/lib/tools/fs"
9+
bfs "github.com/input-output-hk/catalyst-forge/lib/tools/fs/billy"
10+
"github.com/input-output-hk/catalyst-forge/lib/tools/git/repo/remote"
11+
)
12+
13+
type GitRepoOption func(*GitRepo)
14+
15+
// WithAuth sets the authentication for the interacting with a remote repository.
16+
func WithAuth(username, password string) GitRepoOption {
17+
return func(g *GitRepo) {
18+
g.auth = &http.BasicAuth{
19+
Username: username,
20+
Password: password,
21+
}
22+
}
23+
}
24+
25+
// WithAuthor sets the author for all commits.
26+
func WithAuthor(name, email string) GitRepoOption {
27+
return func(g *GitRepo) {
28+
g.commitAuthor = name
29+
g.commitEmail = email
30+
}
31+
}
32+
33+
// WithGitRemoteInteractor sets the remote interactor for the repository.
34+
func WithGitRemoteInteractor(remote remote.GitRemoteInteractor) GitRepoOption {
35+
return func(g *GitRepo) {
36+
g.remote = remote
37+
}
38+
}
39+
40+
// WithFS sets the filesystem for the repository.
41+
func WithFS(fs fs.Filesystem) GitRepoOption {
42+
return func(g *GitRepo) {
43+
if bg, ok := fs.(*bfs.BillyFs); ok {
44+
g.fs = bg
45+
} else {
46+
panic("must use billy filesystem for git filesystem")
47+
}
48+
}
49+
}
50+
51+
// CloneOption is an option for cloning a repository.
52+
type CloneOption func(*gg.CloneOptions)
53+
54+
// WithCloneDepth sets the depth of the clone.
55+
func WithCloneDepth(depth int) CloneOption {
56+
return func(o *gg.CloneOptions) {
57+
o.Depth = depth
58+
}
59+
}
60+
61+
// WithRef sets the reference name for the clone.
62+
func WithRef(ref string) CloneOption {
63+
return func(o *gg.CloneOptions) {
64+
o.ReferenceName = plumbing.ReferenceName(ref)
65+
}
66+
}
67+
68+
// FetchOption is an option for fetching a repository.
69+
type FetchOption func(*gg.FetchOptions)
70+
71+
// WithFetchDepth sets the depth of the fetch.
72+
func WithFetchDepth(depth int) FetchOption {
73+
return func(o *gg.FetchOptions) {
74+
o.Depth = depth
75+
}
76+
}
77+
78+
// WithRemoteName sets the name of the remote to fetch.
79+
func WithRemoteName(name string) FetchOption {
80+
return func(o *gg.FetchOptions) {
81+
o.RemoteName = name
82+
}
83+
}
84+
85+
// WithRefSpec sets the reference specification for the fetch.
86+
func WithRefSpec(spec string) FetchOption {
87+
return func(o *gg.FetchOptions) {
88+
o.RefSpecs = append(o.RefSpecs, config.RefSpec(spec))
89+
}
90+
}

lib/tools/git/repo/remote/gogit.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ func (g GoGitRemoteInteractor) Clone(s storage.Storer, worktree billy.Filesystem
1313
return git.Clone(s, worktree, o)
1414
}
1515

16+
func (g GoGitRemoteInteractor) Fetch(repo *git.Repository, o *git.FetchOptions) error {
17+
return repo.Fetch(o)
18+
}
19+
1620
func (g GoGitRemoteInteractor) Push(repo *git.Repository, o *git.PushOptions) error {
1721
return repo.Push(o)
1822
}

lib/tools/git/repo/remote/mocks/remote.go

Lines changed: 50 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)