1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
package gittest
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v14/internal/git"
"gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v14/internal/helper/text"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
)
const (
committerName = "Scrooge McDuck"
committerEmail = "scrooge@mcduck.com"
)
type writeCommitConfig struct {
branch string
parents []git.ObjectID
message string
treeEntries []TreeEntry
}
// WriteCommitOption is an option which can be passed to WriteCommit.
type WriteCommitOption func(*writeCommitConfig)
// WithBranch is an option for WriteCommit which will cause it to update the update the given branch
// name to the new commit.
func WithBranch(branch string) WriteCommitOption {
return func(cfg *writeCommitConfig) {
cfg.branch = branch
}
}
// WithMessage is an option for WriteCommit which will set the commit message.
func WithMessage(message string) WriteCommitOption {
return func(cfg *writeCommitConfig) {
cfg.message = message
}
}
// WithParents is an option for WriteCommit which will set the parent OIDs of the resulting commit.
func WithParents(parents ...git.ObjectID) WriteCommitOption {
return func(cfg *writeCommitConfig) {
if parents != nil {
cfg.parents = parents
} else {
// We're explicitly initializing parents here such that we can discern the
// case where the commit should be created with no parents.
cfg.parents = []git.ObjectID{}
}
}
}
// WithTreeEntries is an option for WriteCommit which will cause it to create a new tree and use it
// as root tree of the resulting commit.
func WithTreeEntries(entries ...TreeEntry) WriteCommitOption {
return func(cfg *writeCommitConfig) {
cfg.treeEntries = entries
}
}
// WriteCommit writes a new commit into the target repository.
func WriteCommit(t testing.TB, cfg config.Cfg, repoPath string, opts ...WriteCommitOption) git.ObjectID {
t.Helper()
var writeCommitConfig writeCommitConfig
for _, opt := range opts {
opt(&writeCommitConfig)
}
message := "message"
if writeCommitConfig.message != "" {
message = writeCommitConfig.message
}
stdin := bytes.NewBufferString(message)
// The ID of an arbitrary commit known to exist in the test repository.
parents := []git.ObjectID{"1a0b36b3cdad1d2ee32457c102a8c0b7056fa863"}
if writeCommitConfig.parents != nil {
parents = writeCommitConfig.parents
}
var tree string
if len(writeCommitConfig.treeEntries) > 0 {
tree = WriteTree(t, cfg, repoPath, writeCommitConfig.treeEntries).String()
} else if len(parents) == 0 {
// If there are no parents, then we set the root tree to the empty tree.
tree = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
} else {
tree = parents[0].String() + "^{tree}"
}
// Use 'commit-tree' instead of 'commit' because we are in a bare
// repository. What we do here is the same as "commit -m message
// --allow-empty".
commitArgs := []string{
"-c", fmt.Sprintf("user.name=%s", committerName),
"-c", fmt.Sprintf("user.email=%s", committerEmail),
"-C", repoPath,
"commit-tree", "-F", "-", tree,
}
for _, parent := range parents {
commitArgs = append(commitArgs, "-p", parent.String())
}
stdout := ExecStream(t, cfg, stdin, commitArgs...)
oid, err := git.NewObjectIDFromHex(text.ChompBytes(stdout))
require.NoError(t, err)
if writeCommitConfig.branch != "" {
Exec(t, cfg, "-C", repoPath, "update-ref", "refs/heads/"+writeCommitConfig.branch, oid.String())
}
return oid
}
// CreateCommitInAlternateObjectDirectory runs a command such that its created
// objects will live in an alternate objects directory. It returns the current
// head after the command is run and the alternate objects directory path
func CreateCommitInAlternateObjectDirectory(t testing.TB, gitBin, repoPath, altObjectsDir string, cmd *exec.Cmd) (currentHead []byte) {
gitPath := filepath.Join(repoPath, ".git")
altObjectsPath := filepath.Join(gitPath, altObjectsDir)
gitObjectEnv := []string{
fmt.Sprintf("GIT_OBJECT_DIRECTORY=%s", altObjectsPath),
fmt.Sprintf("GIT_ALTERNATE_OBJECT_DIRECTORIES=%s", filepath.Join(gitPath, "objects")),
}
require.NoError(t, os.MkdirAll(altObjectsPath, 0755))
// Because we set 'gitObjectEnv', the new objects created by this command
// will go into 'find-commits-alt-test-repo/.git/alt-objects'.
cmd.Env = append(cmd.Env, gitObjectEnv...)
if output, err := cmd.Output(); err != nil {
stderr := err.(*exec.ExitError).Stderr
t.Fatalf("stdout: %s, stderr: %s", output, stderr)
}
cmd = exec.Command(gitBin, "-C", repoPath, "rev-parse", "HEAD")
cmd.Env = gitObjectEnv
currentHead, err := cmd.Output()
require.NoError(t, err)
return currentHead[:len(currentHead)-1]
}
func authorEqualIgnoringDate(t testing.TB, expected *gitalypb.CommitAuthor, actual *gitalypb.CommitAuthor) {
t.Helper()
require.Equal(t, expected.GetName(), actual.GetName(), "author name does not match")
require.Equal(t, expected.GetEmail(), actual.GetEmail(), "author mail does not match")
}
// AuthorEqual tests if two `CommitAuthor`s are equal.
func AuthorEqual(t testing.TB, expected *gitalypb.CommitAuthor, actual *gitalypb.CommitAuthor) {
t.Helper()
authorEqualIgnoringDate(t, expected, actual)
require.Equal(t, expected.GetDate().GetSeconds(), actual.GetDate().GetSeconds(),
"date does not match")
}
// CommitEqual tests if two `GitCommit`s are equal
func CommitEqual(t testing.TB, expected, actual *gitalypb.GitCommit) {
t.Helper()
authorEqualIgnoringDate(t, expected.GetAuthor(), actual.GetAuthor())
authorEqualIgnoringDate(t, expected.GetCommitter(), actual.GetCommitter())
require.Equal(t, expected.GetBody(), actual.GetBody(), "body does not match")
require.Equal(t, expected.GetSubject(), actual.GetSubject(), "subject does not match")
require.Equal(t, expected.GetId(), actual.GetId(), "object ID does not match")
require.Equal(t, expected.GetParentIds(), actual.GetParentIds(), "parent IDs do not match")
}
|