Skip to content

Commit f9cfd6c

Browse files
lunnydelvh
andauthored
Use the type RefName for all the needed places and fix pull mirror sync bugs (#24634)
This PR replaces all string refName as a type `git.RefName` to make the code more maintainable. Fix #15367 Replaces #23070 It also fixed a bug that tags are not sync because `git remote --prune origin` will not remove local tags if remote removed. We in fact should use `git fetch --prune --tags origin` but not `git remote update origin` to do the sync. Some answer from ChatGPT as ref. > If the git fetch --prune --tags command is not working as expected, there could be a few reasons why. Here are a few things to check: > >Make sure that you have the latest version of Git installed on your system. You can check the version by running git --version in your terminal. If you have an outdated version, try updating Git and see if that resolves the issue. > >Check that your Git repository is properly configured to track the remote repository's tags. You can check this by running git config --get-all remote.origin.fetch and verifying that it includes +refs/tags/*:refs/tags/*. If it does not, you can add it by running git config --add remote.origin.fetch "+refs/tags/*:refs/tags/*". > >Verify that the tags you are trying to prune actually exist on the remote repository. You can do this by running git ls-remote --tags origin to list all the tags on the remote repository. > >Check if any local tags have been created that match the names of tags on the remote repository. If so, these local tags may be preventing the git fetch --prune --tags command from working properly. You can delete local tags using the git tag -d command. --------- Co-authored-by: delvh <[email protected]>
1 parent 26fa94b commit f9cfd6c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+415
-355
lines changed

cmd/hook.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ Gitea or set your environment appropriately.`, "")
201201

202202
oldCommitIDs := make([]string, hookBatchSize)
203203
newCommitIDs := make([]string, hookBatchSize)
204-
refFullNames := make([]string, hookBatchSize)
204+
refFullNames := make([]git.RefName, hookBatchSize)
205205
count := 0
206206
total := 0
207207
lastline := 0
@@ -236,14 +236,14 @@ Gitea or set your environment appropriately.`, "")
236236

237237
oldCommitID := string(fields[0])
238238
newCommitID := string(fields[1])
239-
refFullName := string(fields[2])
239+
refFullName := git.RefName(fields[2])
240240
total++
241241
lastline++
242242

243243
// If the ref is a branch or tag, check if it's protected
244244
// if supportProcReceive all ref should be checked because
245245
// permission check was delayed
246-
if supportProcReceive || strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) {
246+
if supportProcReceive || refFullName.IsBranch() || refFullName.IsTag() {
247247
oldCommitIDs[count] = oldCommitID
248248
newCommitIDs[count] = newCommitID
249249
refFullNames[count] = refFullName
@@ -351,7 +351,7 @@ Gitea or set your environment appropriately.`, "")
351351
}
352352
oldCommitIDs := make([]string, hookBatchSize)
353353
newCommitIDs := make([]string, hookBatchSize)
354-
refFullNames := make([]string, hookBatchSize)
354+
refFullNames := make([]git.RefName, hookBatchSize)
355355
count := 0
356356
total := 0
357357
wasEmpty := false
@@ -373,7 +373,7 @@ Gitea or set your environment appropriately.`, "")
373373
fmt.Fprintf(out, ".")
374374
oldCommitIDs[count] = string(fields[0])
375375
newCommitIDs[count] = string(fields[1])
376-
refFullNames[count] = string(fields[2])
376+
refFullNames[count] = git.RefName(fields[2])
377377
if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != git.EmptySHA && count == total {
378378
masterPushed = true
379379
}
@@ -575,7 +575,7 @@ Gitea or set your environment appropriately.`, "")
575575
}
576576
hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize)
577577
hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize)
578-
hookOptions.RefFullNames = make([]string, 0, hookBatchSize)
578+
hookOptions.RefFullNames = make([]git.RefName, 0, hookBatchSize)
579579

580580
for {
581581
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
@@ -593,7 +593,7 @@ Gitea or set your environment appropriately.`, "")
593593
}
594594
hookOptions.OldCommitIDs = append(hookOptions.OldCommitIDs, t[0])
595595
hookOptions.NewCommitIDs = append(hookOptions.NewCommitIDs, t[1])
596-
hookOptions.RefFullNames = append(hookOptions.RefFullNames, t[2])
596+
hookOptions.RefFullNames = append(hookOptions.RefFullNames, git.RefName(t[2]))
597597
}
598598

599599
hookOptions.GitPushOptions = make(map[string]string)
@@ -640,15 +640,15 @@ Gitea or set your environment appropriately.`, "")
640640

641641
for _, rs := range resp.Results {
642642
if len(rs.Err) > 0 {
643-
err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
643+
err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef.String()+" "+rs.Err))
644644
if err != nil {
645645
return err
646646
}
647647
continue
648648
}
649649

650650
if rs.IsNotMatched {
651-
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
651+
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef.String()))
652652
if err != nil {
653653
return err
654654
}

models/actions/run.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (run *ActionRun) Link() string {
7070
// RefLink return the url of run's ref
7171
func (run *ActionRun) RefLink() string {
7272
refName := git.RefName(run.Ref)
73-
if refName.RefGroup() == "pull" {
73+
if refName.IsPull() {
7474
return run.Repo.Link() + "/pulls/" + refName.ShortName()
7575
}
7676
return git.RefURL(run.Repo.Link(), run.Ref)
@@ -79,7 +79,7 @@ func (run *ActionRun) RefLink() string {
7979
// PrettyRef return #id for pull ref or ShortName for others
8080
func (run *ActionRun) PrettyRef() string {
8181
refName := git.RefName(run.Ref)
82-
if refName.RefGroup() == "pull" {
82+
if refName.IsPull() {
8383
return "#" + strings.TrimSuffix(strings.TrimPrefix(run.Ref, git.PullPrefix), "/head")
8484
}
8585
return refName.ShortName()

models/activities/action.go

+1-12
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
"code.gitea.io/gitea/modules/setting"
2727
"code.gitea.io/gitea/modules/structs"
2828
"code.gitea.io/gitea/modules/timeutil"
29-
"code.gitea.io/gitea/modules/util"
3029

3130
"xorm.io/builder"
3231
"xorm.io/xorm/schemas"
@@ -367,17 +366,7 @@ func (a *Action) GetBranch() string {
367366

368367
// GetRefLink returns the action's ref link.
369368
func (a *Action) GetRefLink() string {
370-
switch {
371-
case strings.HasPrefix(a.RefName, git.BranchPrefix):
372-
return a.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.BranchPrefix))
373-
case strings.HasPrefix(a.RefName, git.TagPrefix):
374-
return a.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.TagPrefix))
375-
case len(a.RefName) == git.SHAFullLength && git.IsValidSHAPattern(a.RefName):
376-
return a.GetRepoLink() + "/src/commit/" + a.RefName
377-
default:
378-
// FIXME: we will just assume it's a branch - this was the old way - at some point we may want to enforce that there is always a ref here.
379-
return a.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.BranchPrefix))
380-
}
369+
return git.RefURL(a.GetRepoLink(), a.RefName)
381370
}
382371

383372
// GetTag returns the action's repository tag.

modules/actions/workflows.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
204204
if err != nil {
205205
break
206206
}
207-
if !workflowpattern.Skip(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) {
207+
if !workflowpattern.Skip(patterns, []string{refName.BranchName()}, &workflowpattern.EmptyTraceWriter{}) {
208208
matchTimes++
209209
}
210210
case "branches-ignore":
@@ -216,7 +216,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
216216
if err != nil {
217217
break
218218
}
219-
if !workflowpattern.Filter(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) {
219+
if !workflowpattern.Filter(patterns, []string{refName.BranchName()}, &workflowpattern.EmptyTraceWriter{}) {
220220
matchTimes++
221221
}
222222
case "tags":
@@ -228,7 +228,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
228228
if err != nil {
229229
break
230230
}
231-
if !workflowpattern.Skip(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) {
231+
if !workflowpattern.Skip(patterns, []string{refName.TagName()}, &workflowpattern.EmptyTraceWriter{}) {
232232
matchTimes++
233233
}
234234
case "tags-ignore":
@@ -240,7 +240,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
240240
if err != nil {
241241
break
242242
}
243-
if !workflowpattern.Filter(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) {
243+
if !workflowpattern.Filter(patterns, []string{refName.TagName()}, &workflowpattern.EmptyTraceWriter{}) {
244244
matchTimes++
245245
}
246246
case "paths":

modules/git/ref.go

+104-21
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ package git
66
import (
77
"regexp"
88
"strings"
9+
10+
"code.gitea.io/gitea/modules/util"
911
)
1012

1113
const (
1214
// RemotePrefix is the base directory of the remotes information of git.
1315
RemotePrefix = "refs/remotes/"
1416
// PullPrefix is the base directory of the pull information of git.
1517
PullPrefix = "refs/pull/"
16-
17-
pullLen = len(PullPrefix)
1818
)
1919

2020
// refNamePatternInvalid is regular expression with unallowed characters in git reference name
@@ -53,19 +53,32 @@ func (ref *Reference) Commit() (*Commit, error) {
5353
return ref.repo.getCommit(ref.Object)
5454
}
5555

56-
// ShortName returns the short name of the reference
57-
func (ref *Reference) ShortName() string {
58-
return RefName(ref.Name).ShortName()
59-
}
60-
6156
// RefGroup returns the group type of the reference
6257
func (ref *Reference) RefGroup() string {
6358
return RefName(ref.Name).RefGroup()
6459
}
6560

66-
// RefName represents a git reference name
61+
// ForPrefix special ref to create a pull request: refs/for/<target-branch>/<topic-branch>
62+
// or refs/for/<targe-branch> -o topic='<topic-branch>'
63+
const ForPrefix = "refs/for/"
64+
65+
// TODO: /refs/for-review for suggest change interface
66+
67+
// RefName represents a full git reference name
6768
type RefName string
6869

70+
func RefNameFromBranch(shortName string) RefName {
71+
return RefName(BranchPrefix + shortName)
72+
}
73+
74+
func RefNameFromTag(shortName string) RefName {
75+
return RefName(TagPrefix + shortName)
76+
}
77+
78+
func (ref RefName) String() string {
79+
return string(ref)
80+
}
81+
6982
func (ref RefName) IsBranch() bool {
7083
return strings.HasPrefix(string(ref), BranchPrefix)
7184
}
@@ -74,39 +87,109 @@ func (ref RefName) IsTag() bool {
7487
return strings.HasPrefix(string(ref), TagPrefix)
7588
}
7689

90+
func (ref RefName) IsRemote() bool {
91+
return strings.HasPrefix(string(ref), RemotePrefix)
92+
}
93+
94+
func (ref RefName) IsPull() bool {
95+
return strings.HasPrefix(string(ref), PullPrefix) && strings.IndexByte(string(ref)[len(PullPrefix):], '/') > -1
96+
}
97+
98+
func (ref RefName) IsFor() bool {
99+
return strings.HasPrefix(string(ref), ForPrefix)
100+
}
101+
102+
func (ref RefName) nameWithoutPrefix(prefix string) string {
103+
if strings.HasPrefix(string(ref), prefix) {
104+
return strings.TrimPrefix(string(ref), prefix)
105+
}
106+
return ""
107+
}
108+
109+
// TagName returns simple tag name if it's an operation to a tag
110+
func (ref RefName) TagName() string {
111+
return ref.nameWithoutPrefix(TagPrefix)
112+
}
113+
114+
// BranchName returns simple branch name if it's an operation to branch
115+
func (ref RefName) BranchName() string {
116+
return ref.nameWithoutPrefix(BranchPrefix)
117+
}
118+
119+
// PullName returns the pull request name part of refs like refs/pull/<pull_name>/head
120+
func (ref RefName) PullName() string {
121+
refName := string(ref)
122+
lastIdx := strings.LastIndexByte(refName[len(PullPrefix):], '/')
123+
if strings.HasPrefix(refName, PullPrefix) && lastIdx > -1 {
124+
return refName[len(PullPrefix) : lastIdx+len(PullPrefix)]
125+
}
126+
return ""
127+
}
128+
129+
// ForBranchName returns the branch name part of refs like refs/for/<branch_name>
130+
func (ref RefName) ForBranchName() string {
131+
return ref.nameWithoutPrefix(ForPrefix)
132+
}
133+
134+
func (ref RefName) RemoteName() string {
135+
return ref.nameWithoutPrefix(RemotePrefix)
136+
}
137+
77138
// ShortName returns the short name of the reference name
78139
func (ref RefName) ShortName() string {
79140
refName := string(ref)
80-
if strings.HasPrefix(refName, BranchPrefix) {
81-
return strings.TrimPrefix(refName, BranchPrefix)
141+
if ref.IsBranch() {
142+
return ref.BranchName()
143+
}
144+
if ref.IsTag() {
145+
return ref.TagName()
82146
}
83-
if strings.HasPrefix(refName, TagPrefix) {
84-
return strings.TrimPrefix(refName, TagPrefix)
147+
if ref.IsRemote() {
148+
return ref.RemoteName()
85149
}
86-
if strings.HasPrefix(refName, RemotePrefix) {
87-
return strings.TrimPrefix(refName, RemotePrefix)
150+
if ref.IsPull() {
151+
return ref.PullName()
88152
}
89-
if strings.HasPrefix(refName, PullPrefix) && strings.IndexByte(refName[pullLen:], '/') > -1 {
90-
return refName[pullLen : strings.IndexByte(refName[pullLen:], '/')+pullLen]
153+
if ref.IsFor() {
154+
return ref.ForBranchName()
91155
}
92156

93157
return refName
94158
}
95159

96160
// RefGroup returns the group type of the reference
97161
func (ref RefName) RefGroup() string {
98-
refName := string(ref)
99-
if strings.HasPrefix(refName, BranchPrefix) {
162+
if ref.IsBranch() {
100163
return "heads"
101164
}
102-
if strings.HasPrefix(refName, TagPrefix) {
165+
if ref.IsTag() {
103166
return "tags"
104167
}
105-
if strings.HasPrefix(refName, RemotePrefix) {
168+
if ref.IsRemote() {
106169
return "remotes"
107170
}
108-
if strings.HasPrefix(refName, PullPrefix) && strings.IndexByte(refName[pullLen:], '/') > -1 {
171+
if ref.IsPull() {
109172
return "pull"
110173
}
174+
if ref.IsFor() {
175+
return "for"
176+
}
111177
return ""
112178
}
179+
180+
// RefURL returns the absolute URL for a ref in a repository
181+
func RefURL(repoURL, ref string) string {
182+
refFullName := RefName(ref)
183+
refName := util.PathEscapeSegments(refFullName.ShortName())
184+
switch {
185+
case refFullName.IsBranch():
186+
return repoURL + "/src/branch/" + refName
187+
case refFullName.IsTag():
188+
return repoURL + "/src/tag/" + refName
189+
case !IsValidSHAPattern(ref):
190+
// assume they mean a branch
191+
return repoURL + "/src/branch/" + refName
192+
default:
193+
return repoURL + "/src/commit/" + refName
194+
}
195+
}

modules/git/ref_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package git
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestRefName(t *testing.T) {
13+
// Test branch names (with and without slash).
14+
assert.Equal(t, "foo", RefName("refs/heads/foo").BranchName())
15+
assert.Equal(t, "feature/foo", RefName("refs/heads/feature/foo").BranchName())
16+
17+
// Test tag names (with and without slash).
18+
assert.Equal(t, "foo", RefName("refs/tags/foo").TagName())
19+
assert.Equal(t, "release/foo", RefName("refs/tags/release/foo").TagName())
20+
21+
// Test pull names
22+
assert.Equal(t, "1", RefName("refs/pull/1/head").PullName())
23+
assert.Equal(t, "my/pull", RefName("refs/pull/my/pull/head").PullName())
24+
25+
// Test for branch names
26+
assert.Equal(t, "main", RefName("refs/for/main").ForBranchName())
27+
assert.Equal(t, "my/branch", RefName("refs/for/my/branch").ForBranchName())
28+
29+
// Test commit hashes.
30+
assert.Equal(t, "c0ffee", RefName("c0ffee").ShortName())
31+
}
32+
33+
func TestRefURL(t *testing.T) {
34+
repoURL := "/user/repo"
35+
assert.Equal(t, repoURL+"/src/branch/foo", RefURL(repoURL, "refs/heads/foo"))
36+
assert.Equal(t, repoURL+"/src/tag/foo", RefURL(repoURL, "refs/tags/foo"))
37+
assert.Equal(t, repoURL+"/src/commit/c0ffee", RefURL(repoURL, "c0ffee"))
38+
}

modules/git/repo_branch.go

-8
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@ import (
1414
// BranchPrefix base dir of the branch information file store on git
1515
const BranchPrefix = "refs/heads/"
1616

17-
// AGit Flow
18-
19-
// PullRequestPrefix special ref to create a pull request: refs/for/<targe-branch>/<topic-branch>
20-
// or refs/for/<targe-branch> -o topic='<topic-branch>'
21-
const PullRequestPrefix = "refs/for/"
22-
23-
// TODO: /refs/for-review for suggest change interface
24-
2517
// IsReferenceExist returns true if given reference exists in the repository.
2618
func IsReferenceExist(ctx context.Context, repoPath, name string) bool {
2719
_, _, err := NewCommand(ctx, "show-ref", "--verify").AddDashesAndList(name).RunStdString(&RunOpts{Dir: repoPath})

0 commit comments

Comments
 (0)