From f9cfd6ce5bd7f27e2655fd307022461a802fc49c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 26 May 2023 09:04:48 +0800 Subject: [PATCH] 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 --- cmd/hook.go | 18 ++-- models/actions/run.go | 4 +- models/activities/action.go | 13 +-- modules/actions/workflows.go | 8 +- modules/git/ref.go | 125 ++++++++++++++++++++---- modules/git/ref_test.go | 38 +++++++ modules/git/repo_branch.go | 8 -- modules/git/utils.go | 44 --------- modules/git/utils_test.go | 30 ------ modules/notification/action/action.go | 29 +++--- modules/notification/base/notifier.go | 9 +- modules/notification/base/null.go | 9 +- modules/notification/indexer/indexer.go | 13 ++- modules/notification/notification.go | 17 ++-- modules/private/hook.go | 5 +- modules/repository/push.go | 41 ++------ modules/repository/repo.go | 11 ++- routers/api/actions/runner/utils.go | 10 +- routers/private/hook_post_receive.go | 20 ++-- routers/private/hook_pre_receive.go | 21 ++-- routers/web/repo/branch.go | 2 +- routers/web/repo/issue.go | 4 +- services/actions/notifier.go | 34 +++---- services/actions/notifier_helper.go | 2 +- services/agit/agit.go | 4 +- services/issue/issue.go | 2 +- services/mirror/mirror_pull.go | 74 ++++++++------ services/mirror/mirror_test.go | 46 +++++++++ services/release/release.go | 10 +- services/repository/branch.go | 9 +- services/repository/cache.go | 16 +-- services/repository/push.go | 20 ++-- services/webhook/dingtalk.go | 6 +- services/webhook/discord.go | 6 +- services/webhook/feishu.go | 6 +- services/webhook/matrix.go | 4 +- services/webhook/msteams.go | 6 +- services/webhook/notifier.go | 30 +++--- services/webhook/slack.go | 4 +- services/webhook/telegram.go | 6 +- services/webhook/wechatwork.go | 6 +- 41 files changed, 415 insertions(+), 355 deletions(-) create mode 100644 modules/git/ref_test.go delete mode 100644 modules/git/utils_test.go create mode 100644 services/mirror/mirror_test.go diff --git a/cmd/hook.go b/cmd/hook.go index bd5575ab6..645326783 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -201,7 +201,7 @@ Gitea or set your environment appropriately.`, "") oldCommitIDs := make([]string, hookBatchSize) newCommitIDs := make([]string, hookBatchSize) - refFullNames := make([]string, hookBatchSize) + refFullNames := make([]git.RefName, hookBatchSize) count := 0 total := 0 lastline := 0 @@ -236,14 +236,14 @@ Gitea or set your environment appropriately.`, "") oldCommitID := string(fields[0]) newCommitID := string(fields[1]) - refFullName := string(fields[2]) + refFullName := git.RefName(fields[2]) total++ lastline++ // If the ref is a branch or tag, check if it's protected // if supportProcReceive all ref should be checked because // permission check was delayed - if supportProcReceive || strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) { + if supportProcReceive || refFullName.IsBranch() || refFullName.IsTag() { oldCommitIDs[count] = oldCommitID newCommitIDs[count] = newCommitID refFullNames[count] = refFullName @@ -351,7 +351,7 @@ Gitea or set your environment appropriately.`, "") } oldCommitIDs := make([]string, hookBatchSize) newCommitIDs := make([]string, hookBatchSize) - refFullNames := make([]string, hookBatchSize) + refFullNames := make([]git.RefName, hookBatchSize) count := 0 total := 0 wasEmpty := false @@ -373,7 +373,7 @@ Gitea or set your environment appropriately.`, "") fmt.Fprintf(out, ".") oldCommitIDs[count] = string(fields[0]) newCommitIDs[count] = string(fields[1]) - refFullNames[count] = string(fields[2]) + refFullNames[count] = git.RefName(fields[2]) if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != git.EmptySHA && count == total { masterPushed = true } @@ -575,7 +575,7 @@ Gitea or set your environment appropriately.`, "") } hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize) hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize) - hookOptions.RefFullNames = make([]string, 0, hookBatchSize) + hookOptions.RefFullNames = make([]git.RefName, 0, hookBatchSize) for { // note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed @@ -593,7 +593,7 @@ Gitea or set your environment appropriately.`, "") } hookOptions.OldCommitIDs = append(hookOptions.OldCommitIDs, t[0]) hookOptions.NewCommitIDs = append(hookOptions.NewCommitIDs, t[1]) - hookOptions.RefFullNames = append(hookOptions.RefFullNames, t[2]) + hookOptions.RefFullNames = append(hookOptions.RefFullNames, git.RefName(t[2])) } hookOptions.GitPushOptions = make(map[string]string) @@ -640,7 +640,7 @@ Gitea or set your environment appropriately.`, "") for _, rs := range resp.Results { if len(rs.Err) > 0 { - err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err)) + err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef.String()+" "+rs.Err)) if err != nil { return err } @@ -648,7 +648,7 @@ Gitea or set your environment appropriately.`, "") } if rs.IsNotMatched { - err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef)) + err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef.String())) if err != nil { return err } diff --git a/models/actions/run.go b/models/actions/run.go index b58683dd3..065480990 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -70,7 +70,7 @@ func (run *ActionRun) Link() string { // RefLink return the url of run's ref func (run *ActionRun) RefLink() string { refName := git.RefName(run.Ref) - if refName.RefGroup() == "pull" { + if refName.IsPull() { return run.Repo.Link() + "/pulls/" + refName.ShortName() } return git.RefURL(run.Repo.Link(), run.Ref) @@ -79,7 +79,7 @@ func (run *ActionRun) RefLink() string { // PrettyRef return #id for pull ref or ShortName for others func (run *ActionRun) PrettyRef() string { refName := git.RefName(run.Ref) - if refName.RefGroup() == "pull" { + if refName.IsPull() { return "#" + strings.TrimSuffix(strings.TrimPrefix(run.Ref, git.PullPrefix), "/head") } return refName.ShortName() diff --git a/models/activities/action.go b/models/activities/action.go index 33e476e34..57f579372 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -26,7 +26,6 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" "xorm.io/builder" "xorm.io/xorm/schemas" @@ -367,17 +366,7 @@ func (a *Action) GetBranch() string { // GetRefLink returns the action's ref link. func (a *Action) GetRefLink() string { - switch { - case strings.HasPrefix(a.RefName, git.BranchPrefix): - return a.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.BranchPrefix)) - case strings.HasPrefix(a.RefName, git.TagPrefix): - return a.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.TagPrefix)) - case len(a.RefName) == git.SHAFullLength && git.IsValidSHAPattern(a.RefName): - return a.GetRepoLink() + "/src/commit/" + a.RefName - default: - // 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. - return a.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.BranchPrefix)) - } + return git.RefURL(a.GetRepoLink(), a.RefName) } // GetTag returns the action's repository tag. diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index d560b7718..d9459288b 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -204,7 +204,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa if err != nil { break } - if !workflowpattern.Skip(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) { + if !workflowpattern.Skip(patterns, []string{refName.BranchName()}, &workflowpattern.EmptyTraceWriter{}) { matchTimes++ } case "branches-ignore": @@ -216,7 +216,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa if err != nil { break } - if !workflowpattern.Filter(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) { + if !workflowpattern.Filter(patterns, []string{refName.BranchName()}, &workflowpattern.EmptyTraceWriter{}) { matchTimes++ } case "tags": @@ -228,7 +228,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa if err != nil { break } - if !workflowpattern.Skip(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) { + if !workflowpattern.Skip(patterns, []string{refName.TagName()}, &workflowpattern.EmptyTraceWriter{}) { matchTimes++ } case "tags-ignore": @@ -240,7 +240,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa if err != nil { break } - if !workflowpattern.Filter(patterns, []string{refName.ShortName()}, &workflowpattern.EmptyTraceWriter{}) { + if !workflowpattern.Filter(patterns, []string{refName.TagName()}, &workflowpattern.EmptyTraceWriter{}) { matchTimes++ } case "paths": diff --git a/modules/git/ref.go b/modules/git/ref.go index 47cc04b7f..d3d1320e5 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -6,6 +6,8 @@ package git import ( "regexp" "strings" + + "code.gitea.io/gitea/modules/util" ) const ( @@ -13,8 +15,6 @@ const ( RemotePrefix = "refs/remotes/" // PullPrefix is the base directory of the pull information of git. PullPrefix = "refs/pull/" - - pullLen = len(PullPrefix) ) // refNamePatternInvalid is regular expression with unallowed characters in git reference name @@ -53,19 +53,32 @@ func (ref *Reference) Commit() (*Commit, error) { return ref.repo.getCommit(ref.Object) } -// ShortName returns the short name of the reference -func (ref *Reference) ShortName() string { - return RefName(ref.Name).ShortName() -} - // RefGroup returns the group type of the reference func (ref *Reference) RefGroup() string { return RefName(ref.Name).RefGroup() } -// RefName represents a git reference name +// ForPrefix special ref to create a pull request: refs/for// +// or refs/for/ -o topic='' +const ForPrefix = "refs/for/" + +// TODO: /refs/for-review for suggest change interface + +// RefName represents a full git reference name type RefName string +func RefNameFromBranch(shortName string) RefName { + return RefName(BranchPrefix + shortName) +} + +func RefNameFromTag(shortName string) RefName { + return RefName(TagPrefix + shortName) +} + +func (ref RefName) String() string { + return string(ref) +} + func (ref RefName) IsBranch() bool { return strings.HasPrefix(string(ref), BranchPrefix) } @@ -74,20 +87,71 @@ func (ref RefName) IsTag() bool { return strings.HasPrefix(string(ref), TagPrefix) } +func (ref RefName) IsRemote() bool { + return strings.HasPrefix(string(ref), RemotePrefix) +} + +func (ref RefName) IsPull() bool { + return strings.HasPrefix(string(ref), PullPrefix) && strings.IndexByte(string(ref)[len(PullPrefix):], '/') > -1 +} + +func (ref RefName) IsFor() bool { + return strings.HasPrefix(string(ref), ForPrefix) +} + +func (ref RefName) nameWithoutPrefix(prefix string) string { + if strings.HasPrefix(string(ref), prefix) { + return strings.TrimPrefix(string(ref), prefix) + } + return "" +} + +// TagName returns simple tag name if it's an operation to a tag +func (ref RefName) TagName() string { + return ref.nameWithoutPrefix(TagPrefix) +} + +// BranchName returns simple branch name if it's an operation to branch +func (ref RefName) BranchName() string { + return ref.nameWithoutPrefix(BranchPrefix) +} + +// PullName returns the pull request name part of refs like refs/pull//head +func (ref RefName) PullName() string { + refName := string(ref) + lastIdx := strings.LastIndexByte(refName[len(PullPrefix):], '/') + if strings.HasPrefix(refName, PullPrefix) && lastIdx > -1 { + return refName[len(PullPrefix) : lastIdx+len(PullPrefix)] + } + return "" +} + +// ForBranchName returns the branch name part of refs like refs/for/ +func (ref RefName) ForBranchName() string { + return ref.nameWithoutPrefix(ForPrefix) +} + +func (ref RefName) RemoteName() string { + return ref.nameWithoutPrefix(RemotePrefix) +} + // ShortName returns the short name of the reference name func (ref RefName) ShortName() string { refName := string(ref) - if strings.HasPrefix(refName, BranchPrefix) { - return strings.TrimPrefix(refName, BranchPrefix) + if ref.IsBranch() { + return ref.BranchName() } - if strings.HasPrefix(refName, TagPrefix) { - return strings.TrimPrefix(refName, TagPrefix) + if ref.IsTag() { + return ref.TagName() } - if strings.HasPrefix(refName, RemotePrefix) { - return strings.TrimPrefix(refName, RemotePrefix) + if ref.IsRemote() { + return ref.RemoteName() } - if strings.HasPrefix(refName, PullPrefix) && strings.IndexByte(refName[pullLen:], '/') > -1 { - return refName[pullLen : strings.IndexByte(refName[pullLen:], '/')+pullLen] + if ref.IsPull() { + return ref.PullName() + } + if ref.IsFor() { + return ref.ForBranchName() } return refName @@ -95,18 +159,37 @@ func (ref RefName) ShortName() string { // RefGroup returns the group type of the reference func (ref RefName) RefGroup() string { - refName := string(ref) - if strings.HasPrefix(refName, BranchPrefix) { + if ref.IsBranch() { return "heads" } - if strings.HasPrefix(refName, TagPrefix) { + if ref.IsTag() { return "tags" } - if strings.HasPrefix(refName, RemotePrefix) { + if ref.IsRemote() { return "remotes" } - if strings.HasPrefix(refName, PullPrefix) && strings.IndexByte(refName[pullLen:], '/') > -1 { + if ref.IsPull() { return "pull" } + if ref.IsFor() { + return "for" + } return "" } + +// RefURL returns the absolute URL for a ref in a repository +func RefURL(repoURL, ref string) string { + refFullName := RefName(ref) + refName := util.PathEscapeSegments(refFullName.ShortName()) + switch { + case refFullName.IsBranch(): + return repoURL + "/src/branch/" + refName + case refFullName.IsTag(): + return repoURL + "/src/tag/" + refName + case !IsValidSHAPattern(ref): + // assume they mean a branch + return repoURL + "/src/branch/" + refName + default: + return repoURL + "/src/commit/" + refName + } +} diff --git a/modules/git/ref_test.go b/modules/git/ref_test.go new file mode 100644 index 000000000..58f679b7d --- /dev/null +++ b/modules/git/ref_test.go @@ -0,0 +1,38 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRefName(t *testing.T) { + // Test branch names (with and without slash). + assert.Equal(t, "foo", RefName("refs/heads/foo").BranchName()) + assert.Equal(t, "feature/foo", RefName("refs/heads/feature/foo").BranchName()) + + // Test tag names (with and without slash). + assert.Equal(t, "foo", RefName("refs/tags/foo").TagName()) + assert.Equal(t, "release/foo", RefName("refs/tags/release/foo").TagName()) + + // Test pull names + assert.Equal(t, "1", RefName("refs/pull/1/head").PullName()) + assert.Equal(t, "my/pull", RefName("refs/pull/my/pull/head").PullName()) + + // Test for branch names + assert.Equal(t, "main", RefName("refs/for/main").ForBranchName()) + assert.Equal(t, "my/branch", RefName("refs/for/my/branch").ForBranchName()) + + // Test commit hashes. + assert.Equal(t, "c0ffee", RefName("c0ffee").ShortName()) +} + +func TestRefURL(t *testing.T) { + repoURL := "/user/repo" + assert.Equal(t, repoURL+"/src/branch/foo", RefURL(repoURL, "refs/heads/foo")) + assert.Equal(t, repoURL+"/src/tag/foo", RefURL(repoURL, "refs/tags/foo")) + assert.Equal(t, repoURL+"/src/commit/c0ffee", RefURL(repoURL, "c0ffee")) +} diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index 3bb6ef522..595809397 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -14,14 +14,6 @@ import ( // BranchPrefix base dir of the branch information file store on git const BranchPrefix = "refs/heads/" -// AGit Flow - -// PullRequestPrefix special ref to create a pull request: refs/for// -// or refs/for/ -o topic='' -const PullRequestPrefix = "refs/for/" - -// TODO: /refs/for-review for suggest change interface - // IsReferenceExist returns true if given reference exists in the repository. func IsReferenceExist(ctx context.Context, repoPath, name string) bool { _, _, err := NewCommand(ctx, "show-ref", "--verify").AddDashesAndList(name).RunStdString(&RunOpts{Dir: repoPath}) diff --git a/modules/git/utils.go b/modules/git/utils.go index 628faf509..b44363820 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -10,8 +10,6 @@ import ( "strconv" "strings" "sync" - - "code.gitea.io/gitea/modules/util" ) // ObjectCache provides thread-safe cache operations. @@ -78,48 +76,6 @@ func ConcatenateError(err error, stderr string) error { return fmt.Errorf("%w - %s", err, stderr) } -// RefEndName return the end name of a ref name -func RefEndName(refStr string) string { - if strings.HasPrefix(refStr, BranchPrefix) { - return refStr[len(BranchPrefix):] - } - - if strings.HasPrefix(refStr, TagPrefix) { - return refStr[len(TagPrefix):] - } - - return refStr -} - -// RefURL returns the absolute URL for a ref in a repository -func RefURL(repoURL, ref string) string { - refName := util.PathEscapeSegments(RefEndName(ref)) - switch { - case strings.HasPrefix(ref, BranchPrefix): - return repoURL + "/src/branch/" + refName - case strings.HasPrefix(ref, TagPrefix): - return repoURL + "/src/tag/" + refName - case !IsValidSHAPattern(ref): - // assume they mean a branch - return repoURL + "/src/branch/" + refName - default: - return repoURL + "/src/commit/" + refName - } -} - -// SplitRefName splits a full refname to reftype and simple refname -func SplitRefName(refStr string) (string, string) { - if strings.HasPrefix(refStr, BranchPrefix) { - return BranchPrefix, refStr[len(BranchPrefix):] - } - - if strings.HasPrefix(refStr, TagPrefix) { - return TagPrefix, refStr[len(TagPrefix):] - } - - return "", refStr -} - // ParseBool returns the boolean value represented by the string as per git's git_config_bool // true will be returned for the result if the string is empty, but valid will be false. // "true", "yes", "on" are all true, true diff --git a/modules/git/utils_test.go b/modules/git/utils_test.go deleted file mode 100644 index 718db700a..000000000 --- a/modules/git/utils_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package git - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestRefEndName(t *testing.T) { - // Test branch names (with and without slash). - assert.Equal(t, "foo", RefEndName("refs/heads/foo")) - assert.Equal(t, "feature/foo", RefEndName("refs/heads/feature/foo")) - - // Test tag names (with and without slash). - assert.Equal(t, "foo", RefEndName("refs/tags/foo")) - assert.Equal(t, "release/foo", RefEndName("refs/tags/release/foo")) - - // Test commit hashes. - assert.Equal(t, "c0ffee", RefEndName("c0ffee")) -} - -func TestRefURL(t *testing.T) { - repoURL := "/user/repo" - assert.Equal(t, repoURL+"/src/branch/foo", RefURL(repoURL, "refs/heads/foo")) - assert.Equal(t, repoURL+"/src/tag/foo", RefURL(repoURL, "refs/tags/foo")) - assert.Equal(t, repoURL+"/src/commit/c0ffee", RefURL(repoURL, "c0ffee")) -} diff --git a/modules/notification/action/action.go b/modules/notification/action/action.go index c043ef62d..1d759e492 100644 --- a/modules/notification/action/action.go +++ b/modules/notification/action/action.go @@ -13,6 +13,7 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification/base" @@ -321,7 +322,7 @@ func (a *actionNotifier) NotifyPushCommits(ctx context.Context, pusher *user_mod opType := activities_model.ActionCommitRepo // Check it's tag push or branch. - if opts.IsTag() { + if opts.RefFullName.IsTag() { opType = activities_model.ActionPushTag if opts.IsDelRef() { opType = activities_model.ActionDeleteTag @@ -337,16 +338,16 @@ func (a *actionNotifier) NotifyPushCommits(ctx context.Context, pusher *user_mod Content: string(data), RepoID: repo.ID, Repo: repo, - RefName: opts.RefFullName, + RefName: opts.RefFullName.String(), IsPrivate: repo.IsPrivate, }); err != nil { log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (a *actionNotifier) NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { opType := activities_model.ActionCommitRepo - if refType == "tag" { + if refFullName.IsTag() { // has sent same action in `NotifyPushCommits`, so skip it. return } @@ -357,15 +358,15 @@ func (a *actionNotifier) NotifyCreateRef(ctx context.Context, doer *user_model.U RepoID: repo.ID, Repo: repo, IsPrivate: repo.IsPrivate, - RefName: refFullName, + RefName: refFullName.String(), }); err != nil { log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (a *actionNotifier) NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { opType := activities_model.ActionDeleteBranch - if refType == "tag" { + if refFullName.IsTag() { // has sent same action in `NotifyPushCommits`, so skip it. return } @@ -376,7 +377,7 @@ func (a *actionNotifier) NotifyDeleteRef(ctx context.Context, doer *user_model.U RepoID: repo.ID, Repo: repo, IsPrivate: repo.IsPrivate, - RefName: refFullName, + RefName: refFullName.String(), }); err != nil { log.Error("NotifyWatchers: %v", err) } @@ -396,14 +397,14 @@ func (a *actionNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user RepoID: repo.ID, Repo: repo, IsPrivate: repo.IsPrivate, - RefName: opts.RefFullName, + RefName: opts.RefFullName.String(), Content: string(data), }); err != nil { log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (a *actionNotifier) NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: repo.OwnerID, ActUser: repo.MustOwner(ctx), @@ -411,13 +412,13 @@ func (a *actionNotifier) NotifySyncCreateRef(ctx context.Context, doer *user_mod RepoID: repo.ID, Repo: repo, IsPrivate: repo.IsPrivate, - RefName: refFullName, + RefName: refFullName.String(), }); err != nil { log.Error("NotifyWatchers: %v", err) } } -func (a *actionNotifier) NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (a *actionNotifier) NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{ ActUserID: repo.OwnerID, ActUser: repo.MustOwner(ctx), @@ -425,7 +426,7 @@ func (a *actionNotifier) NotifySyncDeleteRef(ctx context.Context, doer *user_mod RepoID: repo.ID, Repo: repo, IsPrivate: repo.IsPrivate, - RefName: refFullName, + RefName: refFullName.String(), }); err != nil { log.Error("NotifyWatchers: %v", err) } @@ -444,7 +445,7 @@ func (a *actionNotifier) NotifyNewRelease(ctx context.Context, rel *repo_model.R Repo: rel.Repo, IsPrivate: rel.Repo.IsPrivate, Content: rel.Title, - RefName: rel.TagName, + RefName: rel.TagName, // FIXME: use a full ref name? }); err != nil { log.Error("NotifyWatchers: %v", err) } diff --git a/modules/notification/base/notifier.go b/modules/notification/base/notifier.go index 4021bbe14..87eae3f41 100644 --- a/modules/notification/base/notifier.go +++ b/modules/notification/base/notifier.go @@ -10,6 +10,7 @@ import ( packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/repository" ) @@ -54,11 +55,11 @@ type Notifier interface { NotifyUpdateRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) NotifyDeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) - NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) - NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) + NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) + NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) - NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) - NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) + NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) + NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName) NotifyRepoPendingTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) NotifyPackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) NotifyPackageDelete(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) diff --git a/modules/notification/base/null.go b/modules/notification/base/null.go index 161eadfbe..187c36bee 100644 --- a/modules/notification/base/null.go +++ b/modules/notification/base/null.go @@ -10,6 +10,7 @@ import ( packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/repository" ) @@ -161,11 +162,11 @@ func (*NullNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.U } // NotifyCreateRef notifies branch or tag creation to notifiers -func (*NullNotifier) NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (*NullNotifier) NotifyCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { } // NotifyDeleteRef notifies branch or tag deletion to notifiers -func (*NullNotifier) NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (*NullNotifier) NotifyDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { } // NotifyRenameRepository places a place holder function @@ -181,11 +182,11 @@ func (*NullNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_mod } // NotifySyncCreateRef places a place holder function -func (*NullNotifier) NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (*NullNotifier) NotifySyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { } // NotifySyncDeleteRef places a place holder function -func (*NullNotifier) NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (*NullNotifier) NotifySyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { } // NotifyRepoPendingTransfer places a place holder function diff --git a/modules/notification/indexer/indexer.go b/modules/notification/indexer/indexer.go index c67f79d0f..0661c2c1a 100644 --- a/modules/notification/indexer/indexer.go +++ b/modules/notification/indexer/indexer.go @@ -9,7 +9,6 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" code_indexer "code.gitea.io/gitea/modules/indexer/code" issue_indexer "code.gitea.io/gitea/modules/indexer/issues" stats_indexer "code.gitea.io/gitea/modules/indexer/stats" @@ -126,7 +125,11 @@ func (r *indexerNotifier) NotifyMigrateRepository(ctx context.Context, doer, u * } func (r *indexerNotifier) NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { - if setting.Indexer.RepoIndexerEnabled && opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { + if !opts.RefFullName.IsBranch() { + return + } + + if setting.Indexer.RepoIndexerEnabled && opts.RefFullName.BranchName() == repo.DefaultBranch { code_indexer.UpdateRepoIndexer(repo) } if err := stats_indexer.UpdateRepoIndexer(repo); err != nil { @@ -135,7 +138,11 @@ func (r *indexerNotifier) NotifyPushCommits(ctx context.Context, pusher *user_mo } func (r *indexerNotifier) NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { - if setting.Indexer.RepoIndexerEnabled && opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { + if !opts.RefFullName.IsBranch() { + return + } + + if setting.Indexer.RepoIndexerEnabled && opts.RefFullName.BranchName() == repo.DefaultBranch { code_indexer.UpdateRepoIndexer(repo) } if err := stats_indexer.UpdateRepoIndexer(repo); err != nil { diff --git a/modules/notification/notification.go b/modules/notification/notification.go index da2a7ab3a..72dd1c99e 100644 --- a/modules/notification/notification.go +++ b/modules/notification/notification.go @@ -10,6 +10,7 @@ import ( packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification/action" "code.gitea.io/gitea/modules/notification/base" @@ -316,16 +317,16 @@ func NotifyPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_ } // NotifyCreateRef notifies branch or tag creation to notifiers -func NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { for _, notifier := range notifiers { - notifier.NotifyCreateRef(ctx, pusher, repo, refType, refFullName, refID) + notifier.NotifyCreateRef(ctx, pusher, repo, refFullName, refID) } } // NotifyDeleteRef notifies branch or tag deletion to notifiers -func NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { for _, notifier := range notifiers { - notifier.NotifyDeleteRef(ctx, pusher, repo, refType, refFullName) + notifier.NotifyDeleteRef(ctx, pusher, repo, refFullName) } } @@ -337,16 +338,16 @@ func NotifySyncPushCommits(ctx context.Context, pusher *user_model.User, repo *r } // NotifySyncCreateRef notifies branch or tag creation to notifiers -func NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { for _, notifier := range notifiers { - notifier.NotifySyncCreateRef(ctx, pusher, repo, refType, refFullName, refID) + notifier.NotifySyncCreateRef(ctx, pusher, repo, refFullName, refID) } } // NotifySyncDeleteRef notifies branch or tag deletion to notifiers -func NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { for _, notifier := range notifiers { - notifier.NotifySyncDeleteRef(ctx, pusher, repo, refType, refFullName) + notifier.NotifySyncDeleteRef(ctx, pusher, repo, refFullName) } } diff --git a/modules/private/hook.go b/modules/private/hook.go index c0fe9ef1f..23e03896e 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -10,6 +10,7 @@ import ( "strconv" "time" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" ) @@ -44,7 +45,7 @@ func (g GitPushOptions) Bool(key string, def bool) bool { type HookOptions struct { OldCommitIDs []string NewCommitIDs []string - RefFullNames []string + RefFullNames []git.RefName UserID int64 UserName string GitObjectDirectory string @@ -89,7 +90,7 @@ type HookProcReceiveRefResult struct { OldOID string NewOID string Ref string - OriginalRef string + OriginalRef git.RefName IsForcePush bool IsNotMatched bool Err string diff --git a/modules/repository/push.go b/modules/repository/push.go index aa1552351..ea03f9e15 100644 --- a/modules/repository/push.go +++ b/modules/repository/push.go @@ -4,8 +4,6 @@ package repository import ( - "strings" - "code.gitea.io/gitea/modules/git" ) @@ -15,7 +13,7 @@ type PushUpdateOptions struct { PusherName string RepoUserName string RepoName string - RefFullName string // branch, tag or other name to push + RefFullName git.RefName // branch, tag or other name to push OldCommitID string NewCommitID string } @@ -35,59 +33,34 @@ func (opts *PushUpdateOptions) IsUpdateRef() bool { return !opts.IsNewRef() && !opts.IsDelRef() } -// IsTag return true if it's an operation to a tag -func (opts *PushUpdateOptions) IsTag() bool { - return strings.HasPrefix(opts.RefFullName, git.TagPrefix) -} - // IsNewTag return true if it's a creation to a tag func (opts *PushUpdateOptions) IsNewTag() bool { - return opts.IsTag() && opts.IsNewRef() + return opts.RefFullName.IsTag() && opts.IsNewRef() } // IsDelTag return true if it's a deletion to a tag func (opts *PushUpdateOptions) IsDelTag() bool { - return opts.IsTag() && opts.IsDelRef() -} - -// IsBranch return true if it's a push to branch -func (opts *PushUpdateOptions) IsBranch() bool { - return strings.HasPrefix(opts.RefFullName, git.BranchPrefix) + return opts.RefFullName.IsTag() && opts.IsDelRef() } // IsNewBranch return true if it's the first-time push to a branch func (opts *PushUpdateOptions) IsNewBranch() bool { - return opts.IsBranch() && opts.IsNewRef() + return opts.RefFullName.IsBranch() && opts.IsNewRef() } // IsUpdateBranch return true if it's not the first push to a branch func (opts *PushUpdateOptions) IsUpdateBranch() bool { - return opts.IsBranch() && opts.IsUpdateRef() + return opts.RefFullName.IsBranch() && opts.IsUpdateRef() } // IsDelBranch return true if it's a deletion to a branch func (opts *PushUpdateOptions) IsDelBranch() bool { - return opts.IsBranch() && opts.IsDelRef() -} - -// TagName returns simple tag name if it's an operation to a tag -func (opts *PushUpdateOptions) TagName() string { - return opts.RefFullName[len(git.TagPrefix):] -} - -// BranchName returns simple branch name if it's an operation to branch -func (opts *PushUpdateOptions) BranchName() string { - return opts.RefFullName[len(git.BranchPrefix):] + return opts.RefFullName.IsBranch() && opts.IsDelRef() } // RefName returns simple name for ref func (opts *PushUpdateOptions) RefName() string { - if strings.HasPrefix(opts.RefFullName, git.TagPrefix) { - return opts.RefFullName[len(git.TagPrefix):] - } else if strings.HasPrefix(opts.RefFullName, git.BranchPrefix) { - return opts.RefFullName[len(git.BranchPrefix):] - } - return "" + return opts.RefFullName.ShortName() } // RepoFullName returns repo full name diff --git a/modules/repository/repo.go b/modules/repository/repo.go index a1dba8fc6..62e1f31b9 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -200,7 +200,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, mirrorModel.Interval = 0 mirrorModel.NextUpdateUnix = 0 } else if parsedInterval < setting.Mirror.MinInterval { - err := fmt.Errorf("Interval %s is set below Minimum Interval of %s", parsedInterval, setting.Mirror.MinInterval) + err := fmt.Errorf("interval %s is set below Minimum Interval of %s", parsedInterval, setting.Mirror.MinInterval) log.Error("Interval: %s is too frequent", opts.MirrorInterval) return repo, err } else { @@ -217,6 +217,15 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, if err = UpdateRepository(ctx, repo, false); err != nil { return nil, err } + + // this is necessary for sync local tags from remote + configName := fmt.Sprintf("remote.%s.fetch", mirrorModel.GetRemoteName()) + if stdout, _, err := git.NewCommand(ctx, "config"). + AddOptionValues("--add", configName, `+refs/tags/*:refs/tags/*`). + RunStdString(&git.RunOpts{Dir: repoPath}); err != nil { + log.Error("MigrateRepositoryGitData(git config --add +refs/tags/*:refs/tags/*) in %v: Stdout: %s\nError: %v", repo, stdout, err) + return repo, fmt.Errorf("error in MigrateRepositoryGitData(git config --add +refs/tags/*:refs/tags/*): %w", err) + } } else { if err = UpdateRepoSize(ctx, repo); err != nil { log.Error("Failed to update size for repository: %v", err) diff --git a/routers/api/actions/runner/utils.go b/routers/api/actions/runner/utils.go index 10f92c29f..77e660026 100644 --- a/routers/api/actions/runner/utils.go +++ b/routers/api/actions/runner/utils.go @@ -98,14 +98,8 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct { baseRef = pullPayload.PullRequest.Base.Ref headRef = pullPayload.PullRequest.Head.Ref } - refPrefix, refName := git.SplitRefName(t.Job.Run.Ref) - refType := "" - switch refPrefix { - case git.BranchPrefix: - refType = "branch" - case git.TagPrefix: - refType = "tag" - } + refName := git.RefName(t.Job.Run.Ref) + refType := refName.RefGroup() taskContext, _ := structpb.NewStruct(map[string]interface{}{ // standard contexts, see https://docs.github.com/en/actions/learn-github-actions/contexts#github-context diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index cfe20be10..0c9a2a10f 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -7,7 +7,6 @@ import ( "fmt" "net/http" "strconv" - "strings" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" @@ -47,7 +46,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // tags. Updates to other refs (eg, refs/notes, refs/changes, // or other less-standard refs spaces are ignored since there // may be a very large number of them). - if strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) { + if refFullName.IsBranch() || refFullName.IsTag() { if repo == nil { repo = loadRepository(ctx, ownerName, repoName) if ctx.Written() { @@ -67,7 +66,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { RepoName: repoName, } updates = append(updates, option) - if repo.IsEmpty && option.IsBranch() && (option.BranchName() == "master" || option.BranchName() == "main") { + if repo.IsEmpty && (refFullName.BranchName() == "master" || refFullName.BranchName() == "main") { // put the master/main branch first copy(updates[1:], updates) updates[0] = option @@ -79,7 +78,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { if err := repo_service.PushUpdates(updates); err != nil { log.Error("Failed to Update: %s/%s Total Updates: %d", ownerName, repoName, len(updates)) for i, update := range updates { - log.Error("Failed to Update: %s/%s Update: %d/%d: Branch: %s", ownerName, repoName, i, len(updates), update.BranchName()) + log.Error("Failed to Update: %s/%s Update: %d/%d: Branch: %s", ownerName, repoName, i, len(updates), update.RefFullName.BranchName()) } log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err) @@ -124,7 +123,8 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { newCommitID := opts.NewCommitIDs[i] // post update for agit pull request - if git.SupportProcReceive && strings.HasPrefix(refFullName, git.PullPrefix) { + // FIXME: use pr.Flow to test whether it's an Agit PR or a GH PR + if git.SupportProcReceive && refFullName.IsPull() { if repo == nil { repo = loadRepository(ctx, ownerName, repoName) if ctx.Written() { @@ -132,9 +132,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } } - pullIndexStr := strings.TrimPrefix(refFullName, git.PullPrefix) - pullIndexStr = strings.Split(pullIndexStr, "/")[0] - pullIndex, _ := strconv.ParseInt(pullIndexStr, 10, 64) + pullIndex, _ := strconv.ParseInt(refFullName.PullName(), 10, 64) if pullIndex <= 0 { continue } @@ -160,10 +158,8 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { continue } - branch := git.RefEndName(opts.RefFullNames[i]) - // If we've pushed a branch (and not deleted it) - if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) { + if newCommitID != git.EmptySHA && refFullName.IsBranch() { // First ensure we have the repository loaded, we're allowed pulls requests and we can get the base repo if repo == nil { @@ -197,6 +193,8 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } } + branch := refFullName.BranchName() + // If our branch is the default branch of an unforked repo - there's no PR to create or refer to if !repo.IsFork && branch == baseRepo.DefaultBranch { results = append(results, private.HookPostReceiveBranchResult{}) diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 63b4a8622..7f37d7379 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -7,7 +7,6 @@ import ( "fmt" "net/http" "os" - "strings" "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" @@ -119,12 +118,12 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { refFullName := opts.RefFullNames[i] switch { - case strings.HasPrefix(refFullName, git.BranchPrefix): + case refFullName.IsBranch(): preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName) - case strings.HasPrefix(refFullName, git.TagPrefix): + case refFullName.IsTag(): preReceiveTag(ourCtx, oldCommitID, newCommitID, refFullName) - case git.SupportProcReceive && strings.HasPrefix(refFullName, git.PullRequestPrefix): - preReceivePullRequest(ourCtx, oldCommitID, newCommitID, refFullName) + case git.SupportProcReceive && refFullName.IsFor(): + preReceiveFor(ourCtx, oldCommitID, newCommitID, refFullName) default: ourCtx.AssertCanWriteCode() } @@ -136,8 +135,8 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { ctx.PlainText(http.StatusOK, "ok") } -func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName string) { - branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) +func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, refFullName git.RefName) { + branchName := refFullName.BranchName() ctx.branchName = branchName if !ctx.AssertCanWriteCode() { @@ -369,12 +368,12 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN } } -func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName string) { +func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID string, refFullName git.RefName) { if !ctx.AssertCanWriteCode() { return } - tagName := strings.TrimPrefix(refFullName, git.TagPrefix) + tagName := refFullName.TagName() if !ctx.gotProtectedTags { var err error @@ -405,7 +404,7 @@ func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName } } -func preReceivePullRequest(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName string) { +func preReceiveFor(ctx *preReceiveContext, oldCommitID, newCommitID string, refFullName git.RefName) { if !ctx.AssertCreatePullRequest() { return } @@ -424,7 +423,7 @@ func preReceivePullRequest(ctx *preReceiveContext, oldCommitID, newCommitID, ref return } - baseBranchName := refFullName[len(git.PullRequestPrefix):] + baseBranchName := refFullName.ForBranchName() baseBranchExist := false if ctx.Repo.GitRepo.IsBranchExist(baseBranchName) { diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 9f2663431..ea2c01856 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -146,7 +146,7 @@ func RestoreBranchPost(ctx *context.Context) { // Don't return error below this if err := repo_service.PushUpdate( &repo_module.PushUpdateOptions{ - RefFullName: git.BranchPrefix + deletedBranch.Name, + RefFullName: git.RefNameFromBranch(deletedBranch.Name), OldCommitID: git.EmptySHA, NewCommitID: deletedBranch.Commit, PusherID: ctx.Doer.ID, diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 1448b772b..cbb2e2031 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -863,7 +863,7 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles ctx.Data["HasSelectedLabel"] = len(labelIDs) > 0 ctx.Data["label_ids"] = strings.Join(labelIDs, ",") ctx.Data["Reference"] = template.Ref - ctx.Data["RefEndName"] = git.RefEndName(template.Ref) + ctx.Data["RefEndName"] = git.RefName(template.Ref).ShortName() return templateErrs } return templateErrs @@ -1883,7 +1883,7 @@ func ViewIssue(ctx *context.Context) { ctx.Data["HasProjectsWritePermission"] = ctx.Repo.CanWrite(unit.TypeProjects) ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.Doer.IsAdmin) ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons - ctx.Data["RefEndName"] = git.RefEndName(issue.Ref) + ctx.Data["RefEndName"] = git.RefName(issue.Ref).ShortName() ctx.Data["NewPinAllowed"] = pinAllowed ctx.Data["PinEnabled"] = setting.Repository.Issue.MaxPinned != 0 diff --git a/services/actions/notifier.go b/services/actions/notifier.go index 4ac77276f..48eec5283 100644 --- a/services/actions/notifier.go +++ b/services/actions/notifier.go @@ -351,9 +351,9 @@ func (n *actionsNotifier) NotifyPushCommits(ctx context.Context, pusher *user_mo } newNotifyInput(repo, pusher, webhook_module.HookEventPush). - WithRef(opts.RefFullName). + WithRef(opts.RefFullName.String()). WithPayload(&api.PushPayload{ - Ref: opts.RefFullName, + Ref: opts.RefFullName.String(), Before: opts.OldCommitID, After: opts.NewCommitID, CompareURL: setting.AppURL + commits.CompareURL, @@ -366,37 +366,35 @@ func (n *actionsNotifier) NotifyPushCommits(ctx context.Context, pusher *user_mo Notify(ctx) } -func (n *actionsNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (n *actionsNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { ctx = withMethod(ctx, "NotifyCreateRef") apiPusher := convert.ToUser(ctx, pusher, nil) apiRepo := convert.ToRepo(ctx, repo, perm_model.AccessModeNone) - refName := git.RefEndName(refFullName) newNotifyInput(repo, pusher, webhook_module.HookEventCreate). - WithRef(refName). + WithRef(refFullName.ShortName()). // FIXME: should we use a full ref name WithPayload(&api.CreatePayload{ - Ref: refName, + Ref: refFullName.ShortName(), Sha: refID, - RefType: refType, + RefType: refFullName.RefGroup(), Repo: apiRepo, Sender: apiPusher, }). Notify(ctx) } -func (n *actionsNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (n *actionsNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { ctx = withMethod(ctx, "NotifyDeleteRef") apiPusher := convert.ToUser(ctx, pusher, nil) apiRepo := convert.ToRepo(ctx, repo, perm_model.AccessModeNone) - refName := git.RefEndName(refFullName) newNotifyInput(repo, pusher, webhook_module.HookEventDelete). - WithRef(refName). + WithRef(refFullName.ShortName()). // FIXME: should we use a full ref name WithPayload(&api.DeletePayload{ - Ref: refName, - RefType: refType, + Ref: refFullName.ShortName(), + RefType: refFullName.RefGroup(), PusherType: api.PusherTypeUser, Repo: apiRepo, Sender: apiPusher, @@ -415,9 +413,9 @@ func (n *actionsNotifier) NotifySyncPushCommits(ctx context.Context, pusher *use } newNotifyInput(repo, pusher, webhook_module.HookEventPush). - WithRef(opts.RefFullName). + WithRef(opts.RefFullName.String()). WithPayload(&api.PushPayload{ - Ref: opts.RefFullName, + Ref: opts.RefFullName.String(), Before: opts.OldCommitID, After: opts.NewCommitID, CompareURL: setting.AppURL + commits.CompareURL, @@ -431,14 +429,14 @@ func (n *actionsNotifier) NotifySyncPushCommits(ctx context.Context, pusher *use Notify(ctx) } -func (n *actionsNotifier) NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (n *actionsNotifier) NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { ctx = withMethod(ctx, "NotifySyncCreateRef") - n.NotifyCreateRef(ctx, pusher, repo, refType, refFullName, refID) + n.NotifyCreateRef(ctx, pusher, repo, refFullName, refID) } -func (n *actionsNotifier) NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (n *actionsNotifier) NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { ctx = withMethod(ctx, "NotifySyncDeleteRef") - n.NotifyDeleteRef(ctx, pusher, repo, refType, refFullName) + n.NotifyDeleteRef(ctx, pusher, repo, refFullName) } func (n *actionsNotifier) NotifyNewRelease(ctx context.Context, rel *repo_model.Release) { diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 376c9820f..5e41241d1 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -225,7 +225,7 @@ func notifyRelease(ctx context.Context, doer *user_model.User, rel *repo_model.R mode, _ := access_model.AccessLevel(ctx, doer, rel.Repo) newNotifyInput(rel.Repo, doer, webhook_module.HookEventRelease). - WithRef(git.TagPrefix + rel.TagName). + WithRef(git.RefNameFromTag(rel.TagName).String()). WithPayload(&api.ReleasePayload{ Action: action, Release: convert.ToRelease(ctx, rel), diff --git a/services/agit/agit.go b/services/agit/agit.go index 32fc3cba4..208ea109f 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -48,7 +48,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. continue } - if !strings.HasPrefix(opts.RefFullNames[i], git.PullRequestPrefix) { + if !opts.RefFullNames[i].IsFor() { results = append(results, private.HookProcReceiveRefResult{ IsNotMatched: true, OriginalRef: opts.RefFullNames[i], @@ -56,7 +56,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. continue } - baseBranchName := opts.RefFullNames[i][len(git.PullRequestPrefix):] + baseBranchName := opts.RefFullNames[i].ForBranchName() curentTopicBranch := "" if !gitRepo.IsBranchExist(baseBranchName) { // try match refs/for// diff --git a/services/issue/issue.go b/services/issue/issue.go index 06da47152..ce2b1c097 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -206,7 +206,7 @@ func GetRefEndNamesAndURLs(issues []*issues_model.Issue, repoLink string) (map[i issueRefURLs := make(map[int64]string, len(issues)) for _, issue := range issues { if issue.Ref != "" { - issueRefEndNames[issue.ID] = git.RefEndName(issue.Ref) + issueRefEndNames[issue.ID] = git.RefName(issue.Ref).ShortName() issueRefURLs[issue.ID] = git.RefURL(repoLink, issue.Ref) } } diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 60699294c..53ab632b0 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 000000000..8ad524b60 --- /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) +} diff --git a/services/release/release.go b/services/release/release.go index a9a523119..c1190305b 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -80,14 +80,15 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel commits.HeadCommit = repository.CommitToPushCommit(commit) commits.CompareURL = rel.Repo.ComposeCompareURL(git.EmptySHA, commit.ID.String()) + refFullName := git.RefNameFromTag(rel.TagName) notification.NotifyPushCommits( ctx, rel.Publisher, rel.Repo, &repository.PushUpdateOptions{ - RefFullName: git.TagPrefix + rel.TagName, + RefFullName: refFullName, OldCommitID: git.EmptySHA, NewCommitID: commit.ID.String(), }, commits) - notification.NotifyCreateRef(ctx, rel.Publisher, rel.Repo, "tag", git.TagPrefix+rel.TagName, commit.ID.String()) + notification.NotifyCreateRef(ctx, rel.Publisher, rel.Repo, refFullName, commit.ID.String()) rel.CreatedUnix = timeutil.TimeStampNow() } commit, err := gitRepo.GetTagCommit(rel.TagName) @@ -323,14 +324,15 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del return fmt.Errorf("git tag -d: %w", err) } + refName := git.RefNameFromTag(rel.TagName) notification.NotifyPushCommits( ctx, doer, repo, &repository.PushUpdateOptions{ - RefFullName: git.TagPrefix + rel.TagName, + RefFullName: refName, OldCommitID: rel.Sha1, NewCommitID: git.EmptySHA, }, repository.NewPushCommits()) - notification.NotifyDeleteRef(ctx, doer, repo, "tag", git.TagPrefix+rel.TagName) + notification.NotifyDeleteRef(ctx, doer, repo, refName) if err := repo_model.DeleteReleaseByID(ctx, id); err != nil { return fmt.Errorf("DeleteReleaseByID: %w", err) diff --git a/services/repository/branch.go b/services/repository/branch.go index cafad34ce..4027c75dc 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -139,13 +139,14 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_m }); err != nil { return "", err } - refID, err := gitRepo.GetRefCommitID(git.BranchPrefix + to) + refNameTo := git.RefNameFromBranch(to) + refID, err := gitRepo.GetRefCommitID(refNameTo.String()) if err != nil { return "", err } - notification.NotifyDeleteRef(ctx, doer, repo, "branch", git.BranchPrefix+from) - notification.NotifyCreateRef(ctx, doer, repo, "branch", git.BranchPrefix+to, refID) + notification.NotifyDeleteRef(ctx, doer, repo, git.RefNameFromBranch(from)) + notification.NotifyCreateRef(ctx, doer, repo, refNameTo, refID) return "", nil } @@ -187,7 +188,7 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R // Don't return error below this if err := PushUpdate( &repo_module.PushUpdateOptions{ - RefFullName: git.BranchPrefix + branchName, + RefFullName: git.RefNameFromBranch(branchName), OldCommitID: commit.ID.String(), NewCommitID: git.EmptySHA, PusherID: doer.ID, diff --git a/services/repository/cache.go b/services/repository/cache.go index 6fd4fa725..91351cbf4 100644 --- a/services/repository/cache.go +++ b/services/repository/cache.go @@ -5,7 +5,6 @@ package repository import ( "context" - "strings" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/cache" @@ -13,28 +12,19 @@ import ( "code.gitea.io/gitea/modules/setting" ) -func getRefName(fullRefName string) string { - if strings.HasPrefix(fullRefName, git.TagPrefix) { - return fullRefName[len(git.TagPrefix):] - } else if strings.HasPrefix(fullRefName, git.BranchPrefix) { - return fullRefName[len(git.BranchPrefix):] - } - return "" -} - // CacheRef cachhe last commit information of the branch or the tag -func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, fullRefName string) error { +func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, fullRefName git.RefName) error { if !setting.CacheService.LastCommit.Enabled { return nil } - commit, err := gitRepo.GetCommit(fullRefName) + commit, err := gitRepo.GetCommit(fullRefName.String()) if err != nil { return err } if gitRepo.LastCommitCache == nil { - commitsCount, err := cache.GetInt64(repo.GetCommitsCountCacheKey(getRefName(fullRefName), true), commit.CommitsCount) + commitsCount, err := cache.GetInt64(repo.GetCommitsCountCacheKey(fullRefName.ShortName(), true), commit.CommitsCount) if err != nil { return err } diff --git a/services/repository/push.go b/services/repository/push.go index c7ea8f336..f21394891 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -107,7 +107,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { if opts.IsNewRef() && opts.IsDelRef() { return fmt.Errorf("old and new revisions are both %s", git.EmptySHA) } - if opts.IsTag() { // If is tag reference + if opts.RefFullName.IsTag() { if pusher == nil || pusher.ID != opts.PusherID { if opts.PusherID == user_model.ActionsUserID { pusher = user_model.NewActionsUser() @@ -118,18 +118,18 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } } } - tagName := opts.TagName() + tagName := opts.RefFullName.TagName() if opts.IsDelRef() { notification.NotifyPushCommits( ctx, pusher, repo, &repo_module.PushUpdateOptions{ - RefFullName: git.TagPrefix + tagName, + RefFullName: git.RefNameFromTag(tagName), OldCommitID: opts.OldCommitID, NewCommitID: git.EmptySHA, }, repo_module.NewPushCommits()) delTags = append(delTags, tagName) - notification.NotifyDeleteRef(ctx, pusher, repo, "tag", opts.RefFullName) + notification.NotifyDeleteRef(ctx, pusher, repo, opts.RefFullName) } else { // is new tag newCommit, err := gitRepo.GetCommit(opts.NewCommitID) if err != nil { @@ -143,15 +143,15 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { notification.NotifyPushCommits( ctx, pusher, repo, &repo_module.PushUpdateOptions{ - RefFullName: git.TagPrefix + tagName, + RefFullName: opts.RefFullName, OldCommitID: git.EmptySHA, NewCommitID: opts.NewCommitID, }, commits) addTags = append(addTags, tagName) - notification.NotifyCreateRef(ctx, pusher, repo, "tag", opts.RefFullName, opts.NewCommitID) + notification.NotifyCreateRef(ctx, pusher, repo, opts.RefFullName, opts.NewCommitID) } - } else if opts.IsBranch() { // If is branch reference + } else if opts.RefFullName.IsBranch() { if pusher == nil || pusher.ID != opts.PusherID { if opts.PusherID == user_model.ActionsUserID { pusher = user_model.NewActionsUser() @@ -163,7 +163,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } } - branch := opts.BranchName() + branch := opts.RefFullName.BranchName() if !opts.IsDelRef() { log.Trace("TriggerTask '%s/%s' by %s", repo.Name, branch, pusher.Name) go pull_service.AddTestPullRequestTask(pusher, repo.ID, branch, true, opts.OldCommitID, opts.NewCommitID) @@ -198,7 +198,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { if err != nil { return fmt.Errorf("newCommit.CommitsBeforeLimit: %w", err) } - notification.NotifyCreateRef(ctx, pusher, repo, "branch", opts.RefFullName, opts.NewCommitID) + notification.NotifyCreateRef(ctx, pusher, repo, opts.RefFullName, opts.NewCommitID) } else { l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID) if err != nil { @@ -269,7 +269,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { log.Error("repo_module.CacheRef %s/%s failed: %v", repo.ID, branch, err) } } else { - notification.NotifyDeleteRef(ctx, pusher, repo, "branch", opts.RefFullName) + notification.NotifyDeleteRef(ctx, pusher, repo, opts.RefFullName) if err = pull_service.CloseBranchPulls(pusher, repo.ID, branch); err != nil { // close all related pulls log.Error("close related pull request failed: %v", err) diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index 99ee6e4d1..69fae0329 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -36,7 +36,7 @@ func (d *DingtalkPayload) JSONPayload() ([]byte, error) { // Create implements PayloadConvertor Create method func (d *DingtalkPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) return createDingtalkPayload(title, title, fmt.Sprintf("view ref %s", refName), p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName)), nil @@ -45,7 +45,7 @@ func (d *DingtalkPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // Delete implements PayloadConvertor Delete method func (d *DingtalkPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) return createDingtalkPayload(title, title, fmt.Sprintf("view ref %s", refName), p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName)), nil @@ -61,7 +61,7 @@ func (d *DingtalkPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { // Push implements PayloadConvertor Push method func (d *DingtalkPayload) Push(p *api.PushPayload) (api.Payloader, error) { var ( - branchName = git.RefEndName(p.Ref) + branchName = git.RefName(p.Ref).ShortName() commitDesc string ) diff --git a/services/webhook/discord.go b/services/webhook/discord.go index 02f0fb872..204587eca 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -112,7 +112,7 @@ var _ PayloadConvertor = &DiscordPayload{} // Create implements PayloadConvertor Create method func (d *DiscordPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName), greenColor), nil @@ -121,7 +121,7 @@ func (d *DiscordPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // Delete implements PayloadConvertor Delete method func (d *DiscordPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { // deleted tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName), redColor), nil @@ -137,7 +137,7 @@ func (d *DiscordPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { // Push implements PayloadConvertor Push method func (d *DiscordPayload) Push(p *api.PushPayload) (api.Payloader, error) { var ( - branchName = git.RefEndName(p.Ref) + branchName = git.RefName(p.Ref).ShortName() commitDesc string ) diff --git a/services/webhook/feishu.go b/services/webhook/feishu.go index 4fbf8f76a..885cde3bc 100644 --- a/services/webhook/feishu.go +++ b/services/webhook/feishu.go @@ -48,7 +48,7 @@ var _ PayloadConvertor = &FeishuPayload{} // Create implements PayloadConvertor Create method func (f *FeishuPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() text := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) return newFeishuTextPayload(text), nil @@ -57,7 +57,7 @@ func (f *FeishuPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // Delete implements PayloadConvertor Delete method func (f *FeishuPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() text := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) return newFeishuTextPayload(text), nil @@ -73,7 +73,7 @@ func (f *FeishuPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { // Push implements PayloadConvertor Push method func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) { var ( - branchName = git.RefEndName(p.Ref) + branchName = git.RefName(p.Ref).ShortName() commitDesc string ) diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index cf2b503cd..df97b43b6 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -73,7 +73,7 @@ func MatrixLinkFormatter(url, text string) string { // MatrixLinkToRef Matrix-formatter link to a repo ref func MatrixLinkToRef(repoURL, ref string) string { - refName := git.RefEndName(ref) + refName := git.RefName(ref).ShortName() switch { case strings.HasPrefix(ref, git.BranchPrefix): return MatrixLinkFormatter(repoURL+"/src/branch/"+util.PathEscapeSegments(refName), refName) @@ -95,7 +95,7 @@ func (m *MatrixPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // Delete composes Matrix payload for delete a branch or tag. func (m *MatrixPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() repoLink := MatrixLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName) text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName) diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index 60ef334de..6ad58a624 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -70,7 +70,7 @@ var _ PayloadConvertor = &MSTeamsPayload{} // Create implements PayloadConvertor Create method func (m *MSTeamsPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) return createMSTeamsPayload( @@ -87,7 +87,7 @@ func (m *MSTeamsPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // Delete implements PayloadConvertor Delete method func (m *MSTeamsPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { // deleted tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) return createMSTeamsPayload( @@ -119,7 +119,7 @@ func (m *MSTeamsPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { // Push implements PayloadConvertor Push method func (m *MSTeamsPayload) Push(p *api.PushPayload) (api.Payloader, error) { var ( - branchName = git.RefEndName(p.Ref) + branchName = git.RefName(p.Ref).ShortName() commitDesc string ) diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go index bd25e2080..e10c83e02 100644 --- a/services/webhook/notifier.go +++ b/services/webhook/notifier.go @@ -596,7 +596,7 @@ func (m *webhookNotifier) NotifyPushCommits(ctx context.Context, pusher *user_mo } if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{ - Ref: opts.RefFullName, + Ref: opts.RefFullName.String(), Before: opts.OldCommitID, After: opts.NewCommitID, CompareURL: setting.AppURL + commits.CompareURL, @@ -747,15 +747,15 @@ func (m *webhookNotifier) NotifyPullReviewRequest(ctx context.Context, doer *use } } -func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { +func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { apiPusher := convert.ToUser(ctx, pusher, nil) apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone) - refName := git.RefEndName(refFullName) + refName := refFullName.ShortName() if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventCreate, &api.CreatePayload{ - Ref: refName, + Ref: refName, // FIXME: should it be a full ref name? Sha: refID, - RefType: refType, + RefType: refFullName.RefGroup(), Repo: apiRepo, Sender: apiPusher, }); err != nil { @@ -784,19 +784,19 @@ func (m *webhookNotifier) NotifyPullRequestSynchronized(ctx context.Context, doe } } -func (m *webhookNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { +func (m *webhookNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { apiPusher := convert.ToUser(ctx, pusher, nil) apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone) - refName := git.RefEndName(refFullName) + refName := refFullName.ShortName() if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventDelete, &api.DeletePayload{ - Ref: refName, - RefType: refType, + Ref: refName, // FIXME: should it be a full ref name? + RefType: refFullName.RefGroup(), PusherType: api.PusherTypeUser, Repo: apiRepo, Sender: apiPusher, }); err != nil { - log.Error("PrepareWebhooks.(delete %s): %v", refType, err) + log.Error("PrepareWebhooks.(delete %s): %v", refFullName.RefGroup(), err) } } @@ -838,7 +838,7 @@ func (m *webhookNotifier) NotifySyncPushCommits(ctx context.Context, pusher *use } if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{ - Ref: opts.RefFullName, + Ref: opts.RefFullName.String(), Before: opts.OldCommitID, After: opts.NewCommitID, CompareURL: setting.AppURL + commits.CompareURL, @@ -853,12 +853,12 @@ func (m *webhookNotifier) NotifySyncPushCommits(ctx context.Context, pusher *use } } -func (m *webhookNotifier) NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { - m.NotifyCreateRef(ctx, pusher, repo, refType, refFullName, refID) +func (m *webhookNotifier) NotifySyncCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) { + m.NotifyCreateRef(ctx, pusher, repo, refFullName, refID) } -func (m *webhookNotifier) NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { - m.NotifyDeleteRef(ctx, pusher, repo, refType, refFullName) +func (m *webhookNotifier) NotifySyncDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) { + m.NotifyDeleteRef(ctx, pusher, repo, refFullName) } func (m *webhookNotifier) NotifyPackageCreate(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) { diff --git a/services/webhook/slack.go b/services/webhook/slack.go index c2d4a7731..0cb27bb3d 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -93,7 +93,7 @@ func SlackLinkFormatter(url, text string) string { // SlackLinkToRef slack-formatter link to a repo ref func SlackLinkToRef(repoURL, ref string) string { url := git.RefURL(repoURL, ref) - refName := git.RefEndName(ref) + refName := git.RefName(ref).ShortName() return SlackLinkFormatter(url, refName) } @@ -110,7 +110,7 @@ func (s *SlackPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // Delete composes Slack payload for delete a branch or tag. func (s *SlackPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName) text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName) diff --git a/services/webhook/telegram.go b/services/webhook/telegram.go index e5c731fc9..2d0484648 100644 --- a/services/webhook/telegram.go +++ b/services/webhook/telegram.go @@ -57,7 +57,7 @@ func (t *TelegramPayload) JSONPayload() ([]byte, error) { // Create implements PayloadConvertor Create method func (t *TelegramPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf(`[%s] %s %s created`, p.Repo.HTMLURL, p.Repo.FullName, p.RefType, p.Repo.HTMLURL+"/src/"+refName, refName) @@ -67,7 +67,7 @@ func (t *TelegramPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // Delete implements PayloadConvertor Delete method func (t *TelegramPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf(`[%s] %s %s deleted`, p.Repo.HTMLURL, p.Repo.FullName, p.RefType, p.Repo.HTMLURL+"/src/"+refName, refName) @@ -84,7 +84,7 @@ func (t *TelegramPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { // Push implements PayloadConvertor Push method func (t *TelegramPayload) Push(p *api.PushPayload) (api.Payloader, error) { var ( - branchName = git.RefEndName(p.Ref) + branchName = git.RefName(p.Ref).ShortName() commitDesc string ) diff --git a/services/webhook/wechatwork.go b/services/webhook/wechatwork.go index dc8810c4a..a7680f1c6 100644 --- a/services/webhook/wechatwork.go +++ b/services/webhook/wechatwork.go @@ -56,7 +56,7 @@ var _ PayloadConvertor = &WechatworkPayload{} // Create implements PayloadConvertor Create method func (f *WechatworkPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) return newWechatworkMarkdownPayload(title), nil @@ -65,7 +65,7 @@ func (f *WechatworkPayload) Create(p *api.CreatePayload) (api.Payloader, error) // Delete implements PayloadConvertor Delete method func (f *WechatworkPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { // created tag/branch - refName := git.RefEndName(p.Ref) + refName := git.RefName(p.Ref).ShortName() title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) return newWechatworkMarkdownPayload(title), nil @@ -81,7 +81,7 @@ func (f *WechatworkPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { // Push implements PayloadConvertor Push method func (f *WechatworkPayload) Push(p *api.PushPayload) (api.Payloader, error) { var ( - branchName = git.RefEndName(p.Ref) + branchName = git.RefName(p.Ref).ShortName() commitDesc string )