summaryrefslogtreecommitdiffstats
path: root/services/mirror
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2023-05-26 09:04:48 +0800
committerGitHub <noreply@github.com>2023-05-26 01:04:48 +0000
commitf9cfd6ce5bd7f27e2655fd307022461a802fc49c (patch)
tree9279cab7249c1c7e66a81e694f1096e709c1a8a1 /services/mirror
parent26fa94bc25ecba731a12af16b6172768389287a7 (diff)
downloadgitea-f9cfd6ce5bd7f27e2655fd307022461a802fc49c.tar.gz
gitea-f9cfd6ce5bd7f27e2655fd307022461a802fc49c.zip
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 <dev.lh@web.de>
Diffstat (limited to 'services/mirror')
-rw-r--r--services/mirror/mirror_pull.go74
-rw-r--r--services/mirror/mirror_test.go46
2 files changed, 88 insertions, 32 deletions
diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go
index 60699294c1..53ab632b01 100644
--- a/services/mirror/mirror_pull.go
+++ b/services/mirror/mirror_pull.go
@@ -78,13 +78,23 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
// If the oldCommitID is "0000000", it means a new reference, the value of newCommitID is empty.
// If the newCommitID is "0000000", it means the reference is deleted, the value of oldCommitID is empty.
type mirrorSyncResult struct {
- refName string
+ refName git.RefName
oldCommitID string
newCommitID string
}
// parseRemoteUpdateOutput detects create, update and delete operations of references from upstream.
-func parseRemoteUpdateOutput(output string) []*mirrorSyncResult {
+// possible output example:
+/*
+// * [new tag] v0.1.8 -> v0.1.8
+// * [new branch] master -> origin/master
+// - [deleted] (none) -> origin/test // delete a branch
+// - [deleted] (none) -> 1 // delete a tag
+// 957a993..a87ba5f test -> origin/test
+// + f895a1e...957a993 test -> origin/test (forced update)
+*/
+// TODO: return whether it's a force update
+func parseRemoteUpdateOutput(output, remoteName string) []*mirrorSyncResult {
results := make([]*mirrorSyncResult, 0, 3)
lines := strings.Split(output, "\n")
for i := range lines {
@@ -94,22 +104,30 @@ func parseRemoteUpdateOutput(output string) []*mirrorSyncResult {
continue
}
- refName := lines[i][idx+3:]
+ refName := strings.TrimSpace(lines[i][idx+3:])
switch {
- case strings.HasPrefix(lines[i], " * "): // New reference
- if strings.HasPrefix(lines[i], " * [new tag]") {
- refName = git.TagPrefix + refName
- } else if strings.HasPrefix(lines[i], " * [new branch]") {
- refName = git.BranchPrefix + refName
- }
+ case strings.HasPrefix(lines[i], " * [new tag]"): // new tag
results = append(results, &mirrorSyncResult{
- refName: refName,
+ refName: git.RefNameFromTag(refName),
+ oldCommitID: gitShortEmptySha,
+ })
+ case strings.HasPrefix(lines[i], " * [new branch]"): // new branch
+ refName = strings.TrimPrefix(refName, remoteName+"/")
+ results = append(results, &mirrorSyncResult{
+ refName: git.RefNameFromBranch(refName),
oldCommitID: gitShortEmptySha,
})
case strings.HasPrefix(lines[i], " - "): // Delete reference
+ isTag := !strings.HasPrefix(refName, remoteName+"/")
+ var refFullName git.RefName
+ if isTag {
+ refFullName = git.RefNameFromTag(refName)
+ } else {
+ refFullName = git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/"))
+ }
results = append(results, &mirrorSyncResult{
- refName: refName,
+ refName: refFullName,
newCommitID: gitShortEmptySha,
})
case strings.HasPrefix(lines[i], " + "): // Force update
@@ -127,7 +145,7 @@ func parseRemoteUpdateOutput(output string) []*mirrorSyncResult {
continue
}
results = append(results, &mirrorSyncResult{
- refName: refName,
+ refName: git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")),
oldCommitID: shas[0],
newCommitID: shas[1],
})
@@ -143,7 +161,7 @@ func parseRemoteUpdateOutput(output string) []*mirrorSyncResult {
continue
}
results = append(results, &mirrorSyncResult{
- refName: refName,
+ refName: git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")),
oldCommitID: shas[0],
newCommitID: shas[1],
})
@@ -204,11 +222,12 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
log.Trace("SyncMirrors [repo: %-v]: running git remote update...", m.Repo)
- cmd := git.NewCommand(ctx, "remote", "update")
+ // use fetch but not remote update because git fetch support --tags but remote update doesn't
+ cmd := git.NewCommand(ctx, "fetch")
if m.EnablePrune {
cmd.AddArguments("--prune")
}
- cmd.AddDynamicArguments(m.GetRemoteName())
+ cmd.AddArguments("--tags").AddDynamicArguments(m.GetRemoteName())
remoteURL, remoteErr := git.GetRemoteURL(ctx, repoPath, m.GetRemoteName())
if remoteErr != nil {
@@ -384,7 +403,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
}
m.UpdatedUnix = timeutil.TimeStampNow()
- return parseRemoteUpdateOutput(output), true
+ return parseRemoteUpdateOutput(output, m.GetRemoteName()), true
}
// SyncPullMirror starts the sync of the pull mirror and schedules the next run.
@@ -444,20 +463,13 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
for _, result := range results {
// Discard GitHub pull requests, i.e. refs/pull/*
- if strings.HasPrefix(result.refName, git.PullPrefix) {
+ if result.refName.IsPull() {
continue
}
- tp, _ := git.SplitRefName(result.refName)
-
// Create reference
if result.oldCommitID == gitShortEmptySha {
- if tp == git.TagPrefix {
- tp = "tag"
- } else if tp == git.BranchPrefix {
- tp = "branch"
- }
- commitID, err := gitRepo.GetRefCommitID(result.refName)
+ commitID, err := gitRepo.GetRefCommitID(result.refName.String())
if err != nil {
log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err)
continue
@@ -467,13 +479,13 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
OldCommitID: git.EmptySHA,
NewCommitID: commitID,
}, repo_module.NewPushCommits())
- notification.NotifySyncCreateRef(ctx, m.Repo.MustOwner(ctx), m.Repo, tp, result.refName, commitID)
+ notification.NotifySyncCreateRef(ctx, m.Repo.MustOwner(ctx), m.Repo, result.refName, commitID)
continue
}
// Delete reference
if result.newCommitID == gitShortEmptySha {
- notification.NotifySyncDeleteRef(ctx, m.Repo.MustOwner(ctx), m.Repo, tp, result.refName)
+ notification.NotifySyncDeleteRef(ctx, m.Repo.MustOwner(ctx), m.Repo, result.refName)
continue
}
@@ -547,13 +559,11 @@ func checkAndUpdateEmptyRepository(m *repo_model.Mirror, gitRepo *git.Repository
}
firstName := ""
for _, result := range results {
- if strings.HasPrefix(result.refName, git.PullPrefix) {
- continue
- }
- tp, name := git.SplitRefName(result.refName)
- if len(tp) > 0 && tp != git.BranchPrefix {
+ if !result.refName.IsBranch() {
continue
}
+
+ name := result.refName.BranchName()
if len(firstName) == 0 {
firstName = name
}
diff --git a/services/mirror/mirror_test.go b/services/mirror/mirror_test.go
new file mode 100644
index 0000000000..8ad524b608
--- /dev/null
+++ b/services/mirror/mirror_test.go
@@ -0,0 +1,46 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package mirror
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_parseRemoteUpdateOutput(t *testing.T) {
+ output := `
+ * [new tag] v0.1.8 -> v0.1.8
+ * [new branch] master -> origin/master
+ - [deleted] (none) -> origin/test1
+ - [deleted] (none) -> tag1
+ + f895a1e...957a993 test2 -> origin/test2 (forced update)
+ 957a993..a87ba5f test3 -> origin/test3
+`
+ results := parseRemoteUpdateOutput(output, "origin")
+ assert.Len(t, results, 6)
+ assert.EqualValues(t, "refs/tags/v0.1.8", results[0].refName.String())
+ assert.EqualValues(t, gitShortEmptySha, results[0].oldCommitID)
+ assert.EqualValues(t, "", results[0].newCommitID)
+
+ assert.EqualValues(t, "refs/heads/master", results[1].refName.String())
+ assert.EqualValues(t, gitShortEmptySha, results[1].oldCommitID)
+ assert.EqualValues(t, "", results[1].newCommitID)
+
+ assert.EqualValues(t, "refs/heads/test1", results[2].refName.String())
+ assert.EqualValues(t, "", results[2].oldCommitID)
+ assert.EqualValues(t, gitShortEmptySha, results[2].newCommitID)
+
+ assert.EqualValues(t, "refs/tags/tag1", results[3].refName.String())
+ assert.EqualValues(t, "", results[3].oldCommitID)
+ assert.EqualValues(t, gitShortEmptySha, results[3].newCommitID)
+
+ assert.EqualValues(t, "refs/heads/test2", results[4].refName.String())
+ assert.EqualValues(t, "f895a1e", results[4].oldCommitID)
+ assert.EqualValues(t, "957a993", results[4].newCommitID)
+
+ assert.EqualValues(t, "refs/heads/test3", results[5].refName.String())
+ assert.EqualValues(t, "957a993", results[5].oldCommitID)
+ assert.EqualValues(t, "a87ba5f", results[5].newCommitID)
+}