From 7c9b18f70bfe25b6681eb01c9208411dc475b90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Wed, 20 Nov 2024 22:03:22 +0100 Subject: [PATCH] test: add framework for go-git related testing --- internal/git/util_test.go | 169 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 internal/git/util_test.go diff --git a/internal/git/util_test.go b/internal/git/util_test.go new file mode 100644 index 0000000..2ef4840 --- /dev/null +++ b/internal/git/util_test.go @@ -0,0 +1,169 @@ +package git + +import ( + "io" + "log/slog" + "testing" + "time" + + "github.com/go-git/go-billy/v5/memfs" + "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/stretchr/testify/require" +) + +var ( + author = &object.Signature{ + Name: "releaser-pleaser", + When: time.Date(2020, 01, 01, 01, 01, 01, 01, time.UTC), + } +) + +type CommitOption func(*commitOptions) +type commitOptions struct { + cleanFiles bool + files []commitFile + tags []string + newRef plumbing.ReferenceName + parentRef plumbing.ReferenceName +} +type commitFile struct { + path string + content string +} + +type TestCommit func(*testing.T, *Repository) error +type TestRepo func(*testing.T) *Repository + +func WithCommit(message string, options ...CommitOption) TestCommit { + return func(t *testing.T, repo *Repository) error { + t.Helper() + + require.NotEmpty(t, message, "commit message is required") + + opts := &commitOptions{} + for _, opt := range options { + opt(opts) + } + + wt, err := repo.r.Worktree() + require.NoError(t, err) + + if opts.parentRef != "" { + checkoutOptions := &git.CheckoutOptions{} + + if opts.newRef != "" { + parentRef, err := repo.r.Reference(opts.parentRef, false) + require.NoError(t, err) + + checkoutOptions.Create = true + checkoutOptions.Hash = parentRef.Hash() + checkoutOptions.Branch = opts.newRef + } else { + checkoutOptions.Branch = opts.parentRef + } + + err = wt.Checkout(checkoutOptions) + require.NoError(t, err) + } + + // Yeet all files + if opts.cleanFiles { + files, err := wt.Filesystem.ReadDir(".") + require.NoError(t, err, "failed to get current files") + + for _, fileInfo := range files { + err = wt.Filesystem.Remove(fileInfo.Name()) + require.NoError(t, err, "failed to remove file %q", fileInfo.Name()) + } + } + + // Create new files + for _, fileInfo := range opts.files { + file, err := wt.Filesystem.Create(fileInfo.path) + require.NoError(t, err, "failed to create file %q", fileInfo.path) + + _, err = file.Write([]byte(fileInfo.content)) + _ = file.Close() + require.NoError(t, err, "failed to write content to file %q", fileInfo.path) + } + + // Commit + commitHash, err := wt.Commit(message, &git.CommitOptions{ + All: true, + AllowEmptyCommits: true, + Author: author, + Committer: author, + }) + require.NoError(t, err, "failed to commit") + + // Create tags + for _, tagName := range opts.tags { + _, err = repo.r.CreateTag(tagName, commitHash, nil) + require.NoError(t, err, "failed to create tag %q", tagName) + } + + return nil + + } +} + +func WithFile(path, content string) CommitOption { + return func(opts *commitOptions) { + opts.files = append(opts.files, commitFile{path: path, content: content}) + } +} + +func WithCleanFiles() CommitOption { + return func(opts *commitOptions) { + opts.cleanFiles = true + } +} + +func AsNewBranch(ref plumbing.ReferenceName) CommitOption { + return func(opts *commitOptions) { + opts.newRef = ref + } +} + +func OnBranch(ref plumbing.ReferenceName) CommitOption { + return func(opts *commitOptions) { + opts.parentRef = ref + } +} + +func WithTag(name string) CommitOption { + return func(opts *commitOptions) { + opts.tags = append(opts.tags, name) + } +} + +func WithTestRepo(commits ...TestCommit) TestRepo { + return func(t *testing.T) *Repository { + t.Helper() + + repo := &Repository{ + logger: slog.New(slog.NewTextHandler(io.Discard, nil)), + } + + var err error + + repo.r, err = git.InitWithOptions(memory.NewStorage(), memfs.New(), git.InitOptions{ + DefaultBranch: plumbing.Main, + }) + require.NoError(t, err, "failed to create in-memory repository") + + // Make initial commit + err = WithCommit("chore: init")(t, repo) + require.NoError(t, err, "failed to create init commit") + + for i, commit := range commits { + err = commit(t, repo) + require.NoError(t, err, "failed to create commit %d", i) + } + + return repo + } +}