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
|
package git
import (
"context"
"io"
"strings"
"gitlab.com/gitlab-org/gitaly/internal/command"
)
// InternalRefPrefixes is an array of all reference prefixes which are used internally by GitLab.
// These need special treatment in some cases, e.g. to restrict writing to them.
var InternalRefPrefixes = [...]string{
"refs/environments/",
"refs/keep-around/",
"refs/merge-requests/",
"refs/pipelines/",
}
// Revision represents anything that resolves to either a commit, multiple
// commits or to an object different than a commit. This could be e.g.
// "master", "master^{commit}", an object hash or similar. See gitrevisions(1)
// for supported syntax.
type Revision string
// String returns the string representation of the Revision.
func (r Revision) String() string {
return string(r)
}
// ReferenceName represents the name of a git reference, e.g.
// "refs/heads/master". It does not support extended revision notation like a
// Revision does and must always contain a fully qualified reference.
type ReferenceName string
// NewReferenceNameFromBranchName returns a new ReferenceName from a given
// branch name. Note that branch is treated as an unqualified branch name.
// This function will thus always prepend "refs/heads/".
func NewReferenceNameFromBranchName(branch string) ReferenceName {
return ReferenceName("refs/heads/" + branch)
}
// String returns the string representation of the ReferenceName.
func (r ReferenceName) String() string {
return string(r)
}
// Revision converts the ReferenceName to a Revision. This is safe to do as a
// reference is always also a revision.
func (r ReferenceName) Revision() Revision {
return Revision(r)
}
// Branch returns `true` and the branch name if the reference is a branch. E.g.
// if ReferenceName is "refs/heads/master", it will return "master". If it is
// not a branch, `false` is returned.
func (r ReferenceName) Branch() (string, bool) {
if strings.HasPrefix(r.String(), "refs/heads/") {
return r.String()[len("refs/heads/"):], true
}
return "", false
}
// Reference represents a Git reference.
type Reference struct {
// Name is the name of the reference
Name ReferenceName
// Target is the target of the reference. For direct references it
// contains the object ID, for symbolic references it contains the
// target branch name.
Target string
// IsSymbolic tells whether the reference is direct or symbolic
IsSymbolic bool
}
// NewReference creates a direct reference to an object.
func NewReference(name ReferenceName, target string) Reference {
return Reference{
Name: name,
Target: target,
IsSymbolic: false,
}
}
// NewSymbolicReference creates a symbolic reference to another reference.
func NewSymbolicReference(name ReferenceName, target string) Reference {
return Reference{
Name: name,
Target: target,
IsSymbolic: true,
}
}
// CheckRefFormat checks whether a fully-qualified refname is well
// well-formed using git-check-ref-format
func CheckRefFormat(ctx context.Context, gitCmdFactory CommandFactory, refName string) (bool, error) {
cmd, err := gitCmdFactory.NewWithoutRepo(ctx,
SubCmd{
Name: "check-ref-format",
Args: []string{refName},
},
WithStdout(io.Discard),
WithStderr(io.Discard),
)
if err != nil {
return false, err
}
if err := cmd.Wait(); err != nil {
if code, ok := command.ExitStatus(err); ok && code == 1 {
return false, nil
}
return false, err
}
return true, nil
}
|