1
// Copyright 2018 The Gitea Authors. All rights reserved.
2
// SPDX-License-Identifier: MIT
10
"code.gitea.io/gitea/modules/util"
14
// RemotePrefix is the base directory of the remotes information of git.
15
RemotePrefix = "refs/remotes/"
16
// PullPrefix is the base directory of the pull information of git.
17
PullPrefix = "refs/pull/"
20
// refNamePatternInvalid is regular expression with unallowed characters in git reference name
21
// They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere.
22
// They cannot have question-mark ?, asterisk *, or open bracket [ anywhere
23
var refNamePatternInvalid = regexp.MustCompile(
24
`[\000-\037\177 \\~^:?*[]|` + // No absolutely invalid characters
25
`(?:^[/.])|` + // Not HasPrefix("/") or "."
26
`(?:/\.)|` + // no "/."
27
`(?:\.lock$)|(?:\.lock/)|` + // No ".lock/"" or ".lock" at the end
28
`(?:\.\.)|` + // no ".." anywhere
29
`(?://)|` + // no "//" anywhere
30
`(?:@{)|` + // no "@{"
31
`(?:[/.]$)|` + // no terminal '/' or '.'
34
// IsValidRefPattern ensures that the provided string could be a valid reference
35
func IsValidRefPattern(name string) bool {
36
return !refNamePatternInvalid.MatchString(name)
39
func SanitizeRefPattern(name string) string {
40
return refNamePatternInvalid.ReplaceAllString(name, "_")
43
// Reference represents a Git ref.
44
type Reference struct {
47
Object ObjectID // The id of this commit object
51
// Commit return the commit of the reference
52
func (ref *Reference) Commit() (*Commit, error) {
53
return ref.repo.getCommit(ref.Object)
56
// ShortName returns the short name of the reference
57
func (ref *Reference) ShortName() string {
58
return RefName(ref.Name).ShortName()
61
// RefGroup returns the group type of the reference
62
func (ref *Reference) RefGroup() string {
63
return RefName(ref.Name).RefGroup()
66
// ForPrefix special ref to create a pull request: refs/for/<target-branch>/<topic-branch>
67
// or refs/for/<targe-branch> -o topic='<topic-branch>'
68
const ForPrefix = "refs/for/"
70
// TODO: /refs/for-review for suggest change interface
72
// RefName represents a full git reference name
75
func RefNameFromBranch(shortName string) RefName {
76
return RefName(BranchPrefix + shortName)
79
func RefNameFromTag(shortName string) RefName {
80
return RefName(TagPrefix + shortName)
83
func (ref RefName) String() string {
87
func (ref RefName) IsBranch() bool {
88
return strings.HasPrefix(string(ref), BranchPrefix)
91
func (ref RefName) IsTag() bool {
92
return strings.HasPrefix(string(ref), TagPrefix)
95
func (ref RefName) IsRemote() bool {
96
return strings.HasPrefix(string(ref), RemotePrefix)
99
func (ref RefName) IsPull() bool {
100
return strings.HasPrefix(string(ref), PullPrefix) && strings.IndexByte(string(ref)[len(PullPrefix):], '/') > -1
103
func (ref RefName) IsFor() bool {
104
return strings.HasPrefix(string(ref), ForPrefix)
107
func (ref RefName) nameWithoutPrefix(prefix string) string {
108
if strings.HasPrefix(string(ref), prefix) {
109
return strings.TrimPrefix(string(ref), prefix)
114
// TagName returns simple tag name if it's an operation to a tag
115
func (ref RefName) TagName() string {
116
return ref.nameWithoutPrefix(TagPrefix)
119
// BranchName returns simple branch name if it's an operation to branch
120
func (ref RefName) BranchName() string {
121
return ref.nameWithoutPrefix(BranchPrefix)
124
// PullName returns the pull request name part of refs like refs/pull/<pull_name>/head
125
func (ref RefName) PullName() string {
126
refName := string(ref)
127
lastIdx := strings.LastIndexByte(refName[len(PullPrefix):], '/')
128
if strings.HasPrefix(refName, PullPrefix) && lastIdx > -1 {
129
return refName[len(PullPrefix) : lastIdx+len(PullPrefix)]
134
// ForBranchName returns the branch name part of refs like refs/for/<branch_name>
135
func (ref RefName) ForBranchName() string {
136
return ref.nameWithoutPrefix(ForPrefix)
139
func (ref RefName) RemoteName() string {
140
return ref.nameWithoutPrefix(RemotePrefix)
143
// ShortName returns the short name of the reference name
144
func (ref RefName) ShortName() string {
145
refName := string(ref)
147
return ref.BranchName()
153
return ref.RemoteName()
156
return ref.PullName()
159
return ref.ForBranchName()
165
// RefGroup returns the group type of the reference
166
// Using the name of the directory under .git/refs
167
func (ref RefName) RefGroup() string {
186
// RefType returns the simple ref type of the reference, e.g. branch, tag
187
// It's differrent from RefGroup, which is using the name of the directory under .git/refs
188
// Here we using branch but not heads, using tag but not tags
189
func (ref RefName) RefType() string {
193
} else if ref.IsTag() {
199
// RefURL returns the absolute URL for a ref in a repository
200
func RefURL(repoURL, ref string) string {
201
refFullName := RefName(ref)
202
refName := util.PathEscapeSegments(refFullName.ShortName())
204
case refFullName.IsBranch():
205
return repoURL + "/src/branch/" + refName
206
case refFullName.IsTag():
207
return repoURL + "/src/tag/" + refName
208
case !Sha1ObjectFormat.IsValid(ref):
209
// assume they mean a branch
210
return repoURL + "/src/branch/" + refName
212
return repoURL + "/src/commit/" + refName