From 37768f16aaf25d37854f9ff64b32e297f61dd168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=99=E2=97=A6=20The=20Tablet=20=E2=9D=80=20GamerGirla?= =?UTF-8?q?ndCo=20=E2=97=A6=E2=9D=A7?= Date: Mon, 18 Aug 2025 15:44:08 -0400 Subject: [PATCH] fix broken hooks --- cmd/hook.go | 17 ++--- models/issues/issue_xref.go | 2 +- models/repo/repo.go | 8 ++- modules/git/url/url.go | 33 +++++++--- modules/markup/html.go | 10 +-- modules/markup/html_codepreview.go | 11 +++- modules/markup/html_issue.go | 1 + modules/private/hook.go | 29 ++++++--- modules/references/references.go | 20 +++++- modules/repository/env.go | 1 + modules/repository/push.go | 1 + routers/api/v1/api.go | 2 +- routers/api/v1/org/team.go | 2 +- routers/api/v1/packages/package.go | 2 +- routers/api/v1/repo/action.go | 2 +- routers/api/v1/repo/issue_dependency.go | 2 +- routers/api/v1/repo/pull.go | 14 ++++- routers/private/actions.go | 2 +- routers/private/hook_post_receive.go | 10 +-- routers/private/internal.go | 4 ++ routers/private/internal_repo.go | 7 ++- routers/private/serv.go | 2 +- routers/web/goget.go | 5 +- routers/web/org/teams.go | 2 +- routers/web/repo/branch.go | 1 + routers/web/repo/editor_fork.go | 2 +- routers/web/repo/editor_util.go | 4 +- routers/web/repo/githttp.go | 2 +- routers/web/repo/star.go | 2 +- routers/web/repo/watch.go | 2 +- routers/web/shared/user/header.go | 2 +- routers/web/web.go | 44 ++++++------- services/context/repo.go | 7 ++- services/issue/commit.go | 2 +- services/lfs/locks.go | 11 ++-- services/lfs/server.go | 9 ++- services/markup/renderhelper_codepreview.go | 2 +- .../markup/renderhelper_issueicontitle.go | 2 +- services/packages/cargo/index.go | 4 +- services/repository/branch.go | 1 + services/repository/lfs_test.go | 2 +- services/repository/push.go | 2 +- tests/integration/actions_job_test.go | 4 +- tests/integration/actions_trigger_test.go | 8 +-- tests/integration/api_branch_test.go | 18 +++--- .../api_helper_for_declarative_test.go | 5 +- tests/integration/api_packages_cargo_test.go | 2 +- tests/integration/api_repo_lfs_test.go | 4 +- tests/integration/editor_test.go | 26 ++++---- tests/integration/git_general_test.go | 18 +++--- tests/integration/lfs_getobject_test.go | 4 +- tests/integration/repo_search_test.go | 4 +- tests/integration/repo_webhook_test.go | 62 +++++++++---------- 53 files changed, 270 insertions(+), 175 deletions(-) diff --git a/cmd/hook.go b/cmd/hook.go index 4a6c7c2905..4b4edd8936 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -200,6 +200,7 @@ Gitea or set your environment appropriately.`, "") // the environment is set by serv command isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki)) username := os.Getenv(repo_module.EnvRepoUsername) + groupID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvRepoGroupID), 10, 64) reponame := os.Getenv(repo_module.EnvRepoName) userID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64) prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64) @@ -271,7 +272,7 @@ Gitea or set your environment appropriately.`, "") hookOptions.OldCommitIDs = oldCommitIDs hookOptions.NewCommitIDs = newCommitIDs hookOptions.RefFullNames = refFullNames - extra := private.HookPreReceive(ctx, username, reponame, hookOptions) + extra := private.HookPreReceive(ctx, username, reponame, groupID, hookOptions) if extra.HasError() { return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error) } @@ -297,7 +298,7 @@ Gitea or set your environment appropriately.`, "") fmt.Fprintf(out, " Checking %d references\n", count) - extra := private.HookPreReceive(ctx, username, reponame, hookOptions) + extra := private.HookPreReceive(ctx, username, reponame, groupID, hookOptions) if extra.HasError() { return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error) } @@ -370,6 +371,7 @@ Gitea or set your environment appropriately.`, "") pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64) prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64) pusherName := os.Getenv(repo_module.EnvPusherName) + groupID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvRepoGroupID), 10, 64) hookOptions := private.HookOptions{ UserName: pusherName, @@ -417,7 +419,7 @@ Gitea or set your environment appropriately.`, "") hookOptions.OldCommitIDs = oldCommitIDs hookOptions.NewCommitIDs = newCommitIDs hookOptions.RefFullNames = refFullNames - resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions) + resp, extra := private.HookPostReceive(ctx, repoUser, repoName, groupID, hookOptions) if extra.HasError() { _ = dWriter.Close() hookPrintResults(results) @@ -437,7 +439,7 @@ Gitea or set your environment appropriately.`, "") if count == 0 { if wasEmpty && masterPushed { // We need to tell the repo to reset the default branch to master - extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master") + extra := private.SetDefaultBranch(ctx, repoUser, repoName, groupID, "master") if extra.HasError() { return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error) } @@ -455,7 +457,7 @@ Gitea or set your environment appropriately.`, "") fmt.Fprintf(out, " Processing %d references\n", count) - resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions) + resp, extra := private.HookPostReceive(ctx, repoUser, repoName, groupID, hookOptions) if resp == nil { _ = dWriter.Close() hookPrintResults(results) @@ -468,7 +470,7 @@ Gitea or set your environment appropriately.`, "") if wasEmpty && masterPushed { // We need to tell the repo to reset the default branch to master - extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master") + extra := private.SetDefaultBranch(ctx, repoUser, repoName, groupID, "master") if extra.HasError() { return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error) } @@ -537,6 +539,7 @@ Gitea or set your environment appropriately.`, "") repoName := os.Getenv(repo_module.EnvRepoName) pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64) pusherName := os.Getenv(repo_module.EnvPusherName) + groupID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvRepoGroupID), 10, 64) // 1. Version and features negotiation. // S: PKT-LINE(version=1\0push-options atomic...) / PKT-LINE(version=1\n) @@ -651,7 +654,7 @@ Gitea or set your environment appropriately.`, "") } // 3. run hook - resp, extra := private.HookProcReceive(ctx, repoUser, repoName, hookOptions) + resp, extra := private.HookProcReceive(ctx, repoUser, repoName, groupID, hookOptions) if extra.HasError() { return fail(ctx, extra.UserMsg, "HookProcReceive failed: %v", extra.Error) } diff --git a/models/issues/issue_xref.go b/models/issues/issue_xref.go index 41a867c892..3c21409bf6 100644 --- a/models/issues/issue_xref.go +++ b/models/issues/issue_xref.go @@ -148,7 +148,7 @@ func (issue *Issue) getCrossReferences(stdCtx context.Context, ctx *crossReferen refRepo = ctx.OrigIssue.Repo } else { // Issues in other repositories - refRepo, err = repo_model.GetRepositoryByOwnerAndName(stdCtx, ref.Owner, ref.Name) + refRepo, err = repo_model.GetRepositoryByOwnerAndName(stdCtx, ref.Owner, ref.Name, ref.GroupID) if err != nil { if repo_model.IsErrRepoNotExist(err) { continue diff --git a/models/repo/repo.go b/models/repo/repo.go index 84a4a5a2ed..efbd6812a1 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -807,11 +807,12 @@ func (err ErrRepoNotExist) Unwrap() error { } // GetRepositoryByOwnerAndName returns the repository by given owner name and repo name -func GetRepositoryByOwnerAndName(ctx context.Context, ownerName, repoName string) (*Repository, error) { +func GetRepositoryByOwnerAndName(ctx context.Context, ownerName, repoName string, groupID int64) (*Repository, error) { var repo Repository has, err := db.GetEngine(ctx).Table("repository").Select("repository.*"). Join("INNER", "`user`", "`user`.id = repository.owner_id"). Where("repository.lower_name = ?", strings.ToLower(repoName)). + And("`repository`.group_id = ?", groupID). And("`user`.lower_name = ?", strings.ToLower(ownerName)). Get(&repo) if err != nil { @@ -823,10 +824,11 @@ func GetRepositoryByOwnerAndName(ctx context.Context, ownerName, repoName string } // GetRepositoryByName returns the repository by given name under user if exists. -func GetRepositoryByName(ctx context.Context, ownerID int64, name string) (*Repository, error) { +func GetRepositoryByName(ctx context.Context, ownerID, groupID int64, name string) (*Repository, error) { var repo Repository has, err := db.GetEngine(ctx). Where("`owner_id`=?", ownerID). + And("`group_id`=?", groupID). And("`lower_name`=?", strings.ToLower(name)). NoAutoCondition(). Get(&repo) @@ -844,7 +846,7 @@ func GetRepositoryByURL(ctx context.Context, repoURL string) (*Repository, error if err != nil || ret.OwnerName == "" { return nil, errors.New("unknown or malformed repository URL") } - return GetRepositoryByOwnerAndName(ctx, ret.OwnerName, ret.RepoName) + return GetRepositoryByOwnerAndName(ctx, ret.OwnerName, ret.RepoName, ret.GroupID) } // GetRepositoryByURLRelax also accepts an SSH clone URL without user part diff --git a/modules/git/url/url.go b/modules/git/url/url.go index aa6fa31c5e..d137de8f5b 100644 --- a/modules/git/url/url.go +++ b/modules/git/url/url.go @@ -8,6 +8,7 @@ import ( "fmt" "net" stdurl "net/url" + "strconv" "strings" "code.gitea.io/gitea/modules/httplib" @@ -102,6 +103,7 @@ type RepositoryURL struct { // if the URL belongs to current Gitea instance, then the below fields have values OwnerName string + GroupID int64 RepoName string RemainingPath string } @@ -121,16 +123,25 @@ func ParseRepositoryURL(ctx context.Context, repoURL string) (*RepositoryURL, er ret := &RepositoryURL{} ret.GitURL = parsed - fillPathParts := func(s string) { + fillPathParts := func(s string) error { s = strings.TrimPrefix(s, "/") - fields := strings.SplitN(s, "/", 3) + fields := strings.SplitN(s, "/", 4) + var pathErr error if len(fields) >= 2 { ret.OwnerName = fields[0] - ret.RepoName = strings.TrimSuffix(fields[1], ".git") - if len(fields) == 3 { + if len(fields) >= 3 { + ret.GroupID, pathErr = strconv.ParseInt(fields[1], 10, 64) + if pathErr != nil { + return pathErr + } + ret.RepoName = strings.TrimSuffix(fields[2], ".git") + ret.RemainingPath = "/" + fields[3] + } else { + ret.RepoName = strings.TrimSuffix(fields[1], ".git") ret.RemainingPath = "/" + fields[2] } } + return nil } switch parsed.URL.Scheme { @@ -138,7 +149,9 @@ func ParseRepositoryURL(ctx context.Context, repoURL string) (*RepositoryURL, er if !httplib.IsCurrentGiteaSiteURL(ctx, repoURL) { return ret, nil } - fillPathParts(strings.TrimPrefix(parsed.URL.Path, setting.AppSubURL)) + if err = fillPathParts(strings.TrimPrefix(parsed.URL.Path, setting.AppSubURL)); err != nil { + return nil, err + } case "ssh", "git+ssh": domainSSH := setting.SSH.Domain domainCur := httplib.GuessCurrentHostDomain(ctx) @@ -152,7 +165,9 @@ func ParseRepositoryURL(ctx context.Context, repoURL string) (*RepositoryURL, er // check whether URL domain is current domain from context domainMatches = domainMatches || (domainCur != "" && domainCur == urlDomain) if domainMatches { - fillPathParts(parsed.URL.Path) + if err = fillPathParts(parsed.URL.Path); err != nil { + return nil, err + } } } return ret, nil @@ -161,7 +176,11 @@ func ParseRepositoryURL(ctx context.Context, repoURL string) (*RepositoryURL, er // MakeRepositoryWebLink generates a web link (http/https) for a git repository (by guessing sometimes) func MakeRepositoryWebLink(repoURL *RepositoryURL) string { if repoURL.OwnerName != "" { - return setting.AppSubURL + "/" + repoURL.OwnerName + "/" + repoURL.RepoName + var groupSegment string + if repoURL.GroupID > 0 { + groupSegment = strconv.FormatInt(repoURL.GroupID, 10) + "/" + } + return setting.AppSubURL + "/" + repoURL.OwnerName + "/" + groupSegment + repoURL.RepoName } // now, let's guess, for example: diff --git a/modules/markup/html.go b/modules/markup/html.go index 1c2ae6918d..b43ae83832 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -62,10 +62,10 @@ var globalVars = sync.OnceValue(func() *globalVarsType { v.shortLinkPattern = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`) // anyHashPattern splits url containing SHA into parts - v.anyHashPattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40,64})((\.\w+)*)(/[-+~%./\w]+)?(\?[-+~%.\w&=]+)?(#[-+~%.\w]+)?`) + v.anyHashPattern = regexp.MustCompile(`https?://(?:\S+/){4,6}([0-9a-f]{40,64})((\.\w+)*)(/[-+~%./\w]+)?(\?[-+~%.\w&=]+)?(#[-+~%.\w]+)?`) // comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash" - v.comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,64})(\.\.\.?)([0-9a-f]{7,64})?(#[-+~_%.a-zA-Z0-9]+)?`) + v.comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,6}([0-9a-f]{7,64})(\.\.\.?)([0-9a-f]{7,64})?(#[-+~_%.a-zA-Z0-9]+)?`) // fullURLPattern matches full URL like "mailto:...", "https://..." and "ssh+git://..." v.fullURLPattern = regexp.MustCompile(`^[a-z][-+\w]+:`) @@ -81,13 +81,13 @@ var globalVars = sync.OnceValue(func() *globalVarsType { v.emojiShortCodeRegex = regexp.MustCompile(`:[-+\w]+:`) // example: https://domain/org/repo/pulls/27#hash - v.issueFullPattern = regexp.MustCompile(`https?://(?:\S+/)[\w_.-]+/[\w_.-]+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#](\S+)?)?\b`) + v.issueFullPattern = regexp.MustCompile(`https?://(?:\S+/)[\w_.-]+/([\w_.-]+/)?[\w_.-]+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#](\S+)?)?\b`) // example: https://domain/org/repo/pulls/27/files#hash - v.filesChangedFullPattern = regexp.MustCompile(`https?://(?:\S+/)[\w_.-]+/[\w_.-]+/pulls/((?:\w{1,10}-)?[1-9][0-9]*)/files([\?|#](\S+)?)?\b`) + v.filesChangedFullPattern = regexp.MustCompile(`https?://(?:\S+/)[\w_.-]+/([\w_.-]+/)?[\w_.-]+/pulls/((?:\w{1,10}-)?[1-9][0-9]*)/files([\?|#](\S+)?)?\b`) // codePreviewPattern matches "http://domain/.../{owner}/{repo}/src/commit/{commit}/{filepath}#L10-L20" - v.codePreviewPattern = regexp.MustCompile(`https?://\S+/([^\s/]+)/([^\s/]+)/src/commit/([0-9a-f]{7,64})(/\S+)#(L\d+(-L\d+)?)`) + v.codePreviewPattern = regexp.MustCompile(`https?://\S+/([^\s/]+)/([^\s/]+/)?([^\s/]+)/src/commit/([0-9a-f]{7,64})(/\S+)#(L\d+(-L\d+)?)`) // cleans: "= 12 { + opts.GroupID, _ = strconv.ParseInt(node.Data[m[4]:m[5]], 10, 64) + opts.RepoName, opts.CommitID, opts.FilePath = node.Data[m[6]:m[7]], node.Data[m[8]:m[9]], node.Data[m[10]:m[11]] + } else { + opts.RepoName, opts.CommitID, opts.FilePath = node.Data[m[4]:m[5]], node.Data[m[6]:m[7]], node.Data[m[8]:m[9]] + } + if !httplib.IsCurrentGiteaSiteURL(ctx, opts.FullURL) { return 0, 0, "", nil } diff --git a/modules/markup/html_issue.go b/modules/markup/html_issue.go index a94abb3883..b3a1ab7e1d 100644 --- a/modules/markup/html_issue.go +++ b/modules/markup/html_issue.go @@ -23,6 +23,7 @@ import ( type RenderIssueIconTitleOptions struct { OwnerName string RepoName string + GroupID int64 LinkHref string IssueIndex int64 } diff --git a/modules/private/hook.go b/modules/private/hook.go index ce87ccd801..b8884d396e 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -82,8 +82,16 @@ type HookProcReceiveRefResult struct { HeadBranch string } -func newInternalRequestAPIForHooks(ctx context.Context, hookName, ownerName, repoName string, opts HookOptions) *httplib.Request { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/%s/%s/%s", hookName, url.PathEscape(ownerName), url.PathEscape(repoName)) +func genGroupSegment(groupID int64) string { + var groupSegment string + if groupID > 0 { + groupSegment = fmt.Sprintf("%d/", groupID) + } + return groupSegment +} + +func newInternalRequestAPIForHooks(ctx context.Context, hookName, ownerName, repoName string, groupID int64, opts HookOptions) *httplib.Request { + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/%s/%s/%s%s", hookName, url.PathEscape(ownerName), genGroupSegment(groupID), url.PathEscape(repoName)) req := newInternalRequestAPI(ctx, reqURL, "POST", opts) // This "timeout" applies to http.Client's timeout: A Timeout of zero means no timeout. // This "timeout" was previously set to `time.Duration(60+len(opts.OldCommitIDs))` seconds, but it caused unnecessary timeout failures. @@ -93,28 +101,29 @@ func newInternalRequestAPIForHooks(ctx context.Context, hookName, ownerName, rep } // HookPreReceive check whether the provided commits are allowed -func HookPreReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) ResponseExtra { - req := newInternalRequestAPIForHooks(ctx, "pre-receive", ownerName, repoName, opts) +func HookPreReceive(ctx context.Context, ownerName, repoName string, groupID int64, opts HookOptions) ResponseExtra { + req := newInternalRequestAPIForHooks(ctx, "pre-receive", ownerName, repoName, groupID, opts) _, extra := requestJSONResp(req, &ResponseText{}) return extra } // HookPostReceive updates services and users -func HookPostReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookPostReceiveResult, ResponseExtra) { - req := newInternalRequestAPIForHooks(ctx, "post-receive", ownerName, repoName, opts) +func HookPostReceive(ctx context.Context, ownerName, repoName string, groupID int64, opts HookOptions) (*HookPostReceiveResult, ResponseExtra) { + req := newInternalRequestAPIForHooks(ctx, "post-receive", ownerName, repoName, groupID, opts) return requestJSONResp(req, &HookPostReceiveResult{}) } // HookProcReceive proc-receive hook -func HookProcReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookProcReceiveResult, ResponseExtra) { - req := newInternalRequestAPIForHooks(ctx, "proc-receive", ownerName, repoName, opts) +func HookProcReceive(ctx context.Context, ownerName, repoName string, groupID int64, opts HookOptions) (*HookProcReceiveResult, ResponseExtra) { + req := newInternalRequestAPIForHooks(ctx, "proc-receive", ownerName, repoName, groupID, opts) return requestJSONResp(req, &HookProcReceiveResult{}) } // SetDefaultBranch will set the default branch to the provided branch for the provided repository -func SetDefaultBranch(ctx context.Context, ownerName, repoName, branch string) ResponseExtra { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/set-default-branch/%s/%s/%s", +func SetDefaultBranch(ctx context.Context, ownerName, repoName string, groupID int64, branch string) ResponseExtra { + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/set-default-branch/%s/%s/%s%s", url.PathEscape(ownerName), + genGroupSegment(groupID), url.PathEscape(repoName), url.PathEscape(branch), ) diff --git a/modules/references/references.go b/modules/references/references.go index ef3568ebea..79f977137d 100644 --- a/modules/references/references.go +++ b/modules/references/references.go @@ -35,7 +35,7 @@ var ( issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\'|,)`) // crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository // e.g. org/repo#12345 - crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) + crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/(?:\d+/)?[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) // crossReferenceCommitPattern matches a string that references a commit in a different repository // e.g. go-gitea/gitea@d8a994ef, go-gitea/gitea@d8a994ef243349f321568f9e36d5c3f444b99cae (7-40 characters) crossReferenceCommitPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+)@([0-9a-f]{7,64})(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) @@ -81,6 +81,7 @@ func (a XRefAction) String() string { type IssueReference struct { Index int64 Owner string + GroupID int64 Name string Action XRefAction TimeLog string @@ -93,6 +94,7 @@ type IssueReference struct { type RenderizableReference struct { Issue string Owner string + GroupID int64 Name string CommitSha string IsPull bool @@ -104,6 +106,7 @@ type RenderizableReference struct { type rawReference struct { index int64 owner string + groupID int64 name string isPull bool action XRefAction @@ -119,6 +122,7 @@ func rawToIssueReferenceList(reflist []*rawReference) []IssueReference { refarr[i] = IssueReference{ Index: r.index, Owner: r.owner, + GroupID: r.groupID, Name: r.name, Action: r.action, TimeLog: r.timeLog, @@ -563,10 +567,19 @@ func getCrossReference(content []byte, start, end int, fromLink, prOnly bool) *r } } parts := strings.Split(strings.ToLower(repo), "/") - if len(parts) != 2 { + var owner, rawGroup, name string + var gid int64 + if len(parts) > 3 { return nil } - owner, name := parts[0], parts[1] + if len(parts) == 3 { + owner, rawGroup, name = parts[0], parts[1], parts[2] + } else { + owner, name = parts[0], parts[1] + } + if rawGroup != "" { + gid, _ = strconv.ParseInt(rawGroup, 10, 64) + } if !validNamePattern.MatchString(owner) || !validNamePattern.MatchString(name) { return nil } @@ -574,6 +587,7 @@ func getCrossReference(content []byte, start, end int, fromLink, prOnly bool) *r return &rawReference{ index: index, owner: owner, + groupID: gid, name: name, action: action, issue: issue, diff --git a/modules/repository/env.go b/modules/repository/env.go index ed2c6fef81..a232d3a727 100644 --- a/modules/repository/env.go +++ b/modules/repository/env.go @@ -18,6 +18,7 @@ import ( const ( EnvRepoName = "GITEA_REPO_NAME" EnvRepoUsername = "GITEA_REPO_USER_NAME" + EnvRepoGroupID = "GITEA_REPO_GROUP_ID" EnvRepoID = "GITEA_REPO_ID" EnvRepoIsWiki = "GITEA_REPO_IS_WIKI" EnvPusherName = "GITEA_PUSHER_NAME" diff --git a/modules/repository/push.go b/modules/repository/push.go index cf047847b6..ddbcf9065f 100644 --- a/modules/repository/push.go +++ b/modules/repository/push.go @@ -12,6 +12,7 @@ type PushUpdateOptions struct { PusherID int64 PusherName string RepoUserName string + RepoGroupID int64 RepoName string RefFullName git.RefName // branch, tag or other name to push OldCommitID string diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 85b42b279f..27c32b6036 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -178,7 +178,7 @@ func repoAssignment() func(ctx *context.APIContext) { ctx.ContextUser = owner // Get repository. - repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, repoName) + repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, gid, repoName) if err != nil { if repo_model.IsErrRepoNotExist(err) { redirectRepoID, err := repo_model.LookupRedirect(ctx, owner.ID, repoName) diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index 659218e837..bcfd235e20 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -639,7 +639,7 @@ func GetTeamRepo(ctx *context.APIContext) { // getRepositoryByParams get repository by a team's organization ID and repo name func getRepositoryByParams(ctx *context.APIContext) *repo_model.Repository { - repo, err := repo_model.GetRepositoryByName(ctx, ctx.Org.Team.OrgID, ctx.PathParam("reponame")) + repo, err := repo_model.GetRepositoryByName(ctx, ctx.Org.Team.OrgID, ctx.PathParamInt64("group_id"), ctx.PathParam("reponame")) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.APIErrorNotFound() diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index cee0daccae..1d5a4dea13 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -355,7 +355,7 @@ func LinkPackage(ctx *context.APIContext) { return } - repo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, ctx.PathParam("repo_name")) + repo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, ctx.PathParamInt64("group_id"), ctx.PathParam("repo_name")) if err != nil { if errors.Is(err, util.ErrNotExist) { ctx.APIError(http.StatusNotFound, err) diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 3cbe13d018..50fcd4186d 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -1850,7 +1850,7 @@ func DownloadArtifact(ctx *context.APIContext) { // DownloadArtifactRaw Downloads a specific artifact for a workflow run directly. func DownloadArtifactRaw(ctx *context.APIContext) { // it doesn't use repoAssignment middleware, so it needs to prepare the repo and check permission (sig) by itself - repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ctx.PathParam("username"), ctx.PathParam("reponame")) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ctx.PathParam("username"), ctx.PathParam("reponame"), ctx.PathParamInt64("group_id")) if err != nil { if errors.Is(err, util.ErrNotExist) { ctx.APIErrorNotFound() diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index 28cdbb3091..2bbe947e8c 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -506,7 +506,7 @@ func getFormIssue(ctx *context.APIContext, form *api.IssueMeta) *issues_model.Is return nil } var err error - repo, err = repo_model.GetRepositoryByOwnerAndName(ctx, form.Owner, form.Name) + repo, err = repo_model.GetRepositoryByOwnerAndName(ctx, form.Owner, form.Name, ctx.PathParamInt64("group_id")) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.APIErrorNotFound("IsErrRepoNotExist", err) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index ef86f413b7..6ca3e255ae 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -255,15 +255,23 @@ func GetPullRequestByBaseHead(ctx *context.APIContext) { split := strings.SplitN(head, ":", 2) headBranch = split[1] var owner, name string + var gid int64 if strings.Contains(split[0], "/") { split = strings.Split(split[0], "/") - owner = split[0] - name = split[1] + if len(split) == 3 { + owner = split[0] + gid, _ = strconv.ParseInt(split[1], 10, 64) + name = split[2] + } else { + owner, name = split[0], split[1] + } + } else { owner = split[0] + gid = ctx.Repo.Repository.GroupID name = ctx.Repo.Repository.Name } - repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner, name) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner, name, gid) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.APIErrorNotFound() diff --git a/routers/private/actions.go b/routers/private/actions.go index 696634b5e7..06934128dc 100644 --- a/routers/private/actions.go +++ b/routers/private/actions.go @@ -83,7 +83,7 @@ func parseScope(ctx *context.PrivateContext, scope string) (ownerID, repoID int6 return ownerID, repoID, nil } - r, err := repo_model.GetRepositoryByName(ctx, u.ID, repoName) + r, err := repo_model.GetRepositoryByName(ctx, u.ID, ctx.PathParamInt64("group_id"), repoName) if err != nil { return ownerID, repoID, err } diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 3d070a18ab..738099bcd0 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -41,6 +41,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { ownerName := ctx.PathParam("owner") repoName := ctx.PathParam("repo") + groupID := ctx.PathParamInt64("group_id") // defer getting the repository at this point - as we should only retrieve it if we're going to call update var ( @@ -61,7 +62,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // may be a very large number of them). if refFullName.IsBranch() || refFullName.IsTag() { if repo == nil { - repo = loadRepository(ctx, ownerName, repoName) + repo = loadRepository(ctx, ownerName, repoName, groupID) if ctx.Written() { // Error handled in loadRepository return @@ -75,6 +76,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { NewCommitID: opts.NewCommitIDs[i], PusherID: opts.UserID, PusherName: opts.UserName, + RepoGroupID: groupID, RepoUserName: ownerName, RepoName: repoName, } @@ -98,7 +100,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { continue } if repo == nil { - repo = loadRepository(ctx, ownerName, repoName) + repo = loadRepository(ctx, ownerName, repoName, groupID) if ctx.Written() { return } @@ -176,7 +178,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { if isPrivate.Has() || isTemplate.Has() { // load the repository if repo == nil { - repo = loadRepository(ctx, ownerName, repoName) + repo = loadRepository(ctx, ownerName, repoName, groupID) if ctx.Written() { // Error handled in loadRepository return @@ -239,7 +241,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { if !git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() { // First ensure we have the repository loaded, we're allowed pulls requests and we can get the base repo if repo == nil { - repo = loadRepository(ctx, ownerName, repoName) + repo = loadRepository(ctx, ownerName, repoName, groupID) if ctx.Written() { return } diff --git a/routers/private/internal.go b/routers/private/internal.go index d4918455f1..dc965c6003 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -64,9 +64,13 @@ func Routes() *web.Router { r.Post("/ssh/authorized_keys", AuthorizedPublicKeyByContent) r.Post("/ssh/{id}/update/{repoid}", UpdatePublicKeyInRepo) r.Post("/ssh/log", bind(private.SSHLogOption{}), SSHLog) + r.Post("/hook/pre-receive/{owner}/{group_id}/{repo}", RepoAssignment, bind(private.HookOptions{}), HookPreReceive) r.Post("/hook/pre-receive/{owner}/{repo}", RepoAssignment, bind(private.HookOptions{}), HookPreReceive) + r.Post("/hook/post-receive/{owner}/{group_id}/{repo}", context.OverrideContext(), bind(private.HookOptions{}), HookPostReceive) r.Post("/hook/post-receive/{owner}/{repo}", context.OverrideContext(), bind(private.HookOptions{}), HookPostReceive) + r.Post("/hook/proc-receive/{owner}/{group_id}/{repo}", context.OverrideContext(), RepoAssignment, bind(private.HookOptions{}), HookProcReceive) r.Post("/hook/proc-receive/{owner}/{repo}", context.OverrideContext(), RepoAssignment, bind(private.HookOptions{}), HookProcReceive) + r.Post("/hook/set-default-branch/{owner}/{group_id}/{repo}/{branch}", RepoAssignment, SetDefaultBranch) r.Post("/hook/set-default-branch/{owner}/{repo}/{branch}", RepoAssignment, SetDefaultBranch) r.Get("/serv/none/{keyid}", ServNoCommand) r.Get("/serv/command/{keyid}/{owner}/{repo}", ServCommand) diff --git a/routers/private/internal_repo.go b/routers/private/internal_repo.go index e111d6689e..5f7f166944 100644 --- a/routers/private/internal_repo.go +++ b/routers/private/internal_repo.go @@ -20,8 +20,9 @@ import ( func RepoAssignment(ctx *gitea_context.PrivateContext) { ownerName := ctx.PathParam("owner") repoName := ctx.PathParam("repo") + gid := ctx.PathParamInt64("group_id") - repo := loadRepository(ctx, ownerName, repoName) + repo := loadRepository(ctx, ownerName, repoName, gid) if ctx.Written() { // Error handled in loadRepository return @@ -41,8 +42,8 @@ func RepoAssignment(ctx *gitea_context.PrivateContext) { } } -func loadRepository(ctx *gitea_context.PrivateContext, ownerName, repoName string) *repo_model.Repository { - repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName) +func loadRepository(ctx *gitea_context.PrivateContext, ownerName, repoName string, groupID int64) *repo_model.Repository { + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName, groupID) if err != nil { log.Error("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err) ctx.JSON(http.StatusInternalServerError, private.Response{ diff --git a/routers/private/serv.go b/routers/private/serv.go index 7c6eb907fa..4efaeafaf6 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -152,7 +152,7 @@ func ServCommand(ctx *context.PrivateContext) { // Now get the Repository and set the results section repoExist := true - repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, results.RepoName) + repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, ctx.PathParamInt64("group_id"), results.RepoName) if err != nil { if !repo_model.IsErrRepoNotExist(err) { log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err) diff --git a/routers/web/goget.go b/routers/web/goget.go index 6a769f973c..9321375c00 100644 --- a/routers/web/goget.go +++ b/routers/web/goget.go @@ -55,8 +55,8 @@ func goGet(ctx *context.Context) { return } branchName := setting.Repository.DefaultBranch - - repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName) + gid, _ := strconv.ParseInt(group, 10, 64) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName, gid) if err == nil && len(repo.DefaultBranch) > 0 { branchName = repo.DefaultBranch } @@ -76,7 +76,6 @@ func goGet(ctx *context.Context) { goGetImport := context.ComposeGoGetImport(ctx, ownerName, trimmedRepoName) var cloneURL string - gid, _ := strconv.ParseInt(group, 10, 64) if setting.Repository.GoGetCloneURLProtocol == "ssh" { cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, ownerName, repoName, gid) } else { diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 1e22a67032..3e64f800b0 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -236,7 +236,7 @@ func TeamsRepoAction(ctx *context.Context) { case "add": repoName := path.Base(ctx.FormString("repo_name")) var repo *repo_model.Repository - repo, err = repo_model.GetRepositoryByName(ctx, ctx.Org.Organization.ID, repoName) + repo, err = repo_model.GetRepositoryByName(ctx, ctx.Org.Organization.ID, ctx.PathParamInt64("group_id"), repoName) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.Flash.Error(ctx.Tr("org.teams.add_nonexistent_repo")) diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 5e5cfec5c2..45209d7be0 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -161,6 +161,7 @@ func RestoreBranchPost(ctx *context.Context) { PusherName: ctx.Doer.Name, RepoUserName: ctx.Repo.Owner.Name, RepoName: ctx.Repo.Repository.Name, + RepoGroupID: ctx.Repo.Repository.GroupID, }); err != nil { log.Error("RestoreBranch: Update: %v", err) } diff --git a/routers/web/repo/editor_fork.go b/routers/web/repo/editor_fork.go index b78a634c00..19fb42f0f5 100644 --- a/routers/web/repo/editor_fork.go +++ b/routers/web/repo/editor_fork.go @@ -20,7 +20,7 @@ func ForkToEdit(ctx *context.Context) { func ForkToEditPost(ctx *context.Context) { ForkRepoTo(ctx, ctx.Doer, repo_service.ForkRepoOptions{ BaseRepo: ctx.Repo.Repository, - Name: getUniqueRepositoryName(ctx, ctx.Doer.ID, ctx.Repo.Repository.Name), + Name: getUniqueRepositoryName(ctx, ctx.Doer.ID, 0, ctx.Repo.Repository.Name), Description: ctx.Repo.Repository.Description, SingleBranch: ctx.Repo.Repository.DefaultBranch, // maybe we only need the default branch in the fork? }) diff --git a/routers/web/repo/editor_util.go b/routers/web/repo/editor_util.go index 7155b6e99d..efdd3c5b56 100644 --- a/routers/web/repo/editor_util.go +++ b/routers/web/repo/editor_util.go @@ -114,10 +114,10 @@ func getParentTreeFields(treePath string) (treeNames, treePaths []string) { // getUniqueRepositoryName Gets a unique repository name for a user // It will append a - postfix if the name is already taken -func getUniqueRepositoryName(ctx context.Context, ownerID int64, name string) string { +func getUniqueRepositoryName(ctx context.Context, ownerID, groupID int64, name string) string { uniqueName := name for i := 1; i < 1000; i++ { - _, err := repo_model.GetRepositoryByName(ctx, ownerID, uniqueName) + _, err := repo_model.GetRepositoryByName(ctx, ownerID, groupID, uniqueName) if err != nil || repo_model.IsErrRepoNotExist(err) { return uniqueName } diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index 928c78a61f..a1262533f9 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -107,7 +107,7 @@ func httpBase(ctx *context.Context, optGitService ...string) *serviceHandler { } repoExist := true - repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, reponame) + repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, ctx.PathParamInt64("group_id"), reponame) if err != nil { if !repo_model.IsErrRepoNotExist(err) { ctx.ServerError("GetRepositoryByName", err) diff --git a/routers/web/repo/star.go b/routers/web/repo/star.go index 00c06b7d02..f9301e15d0 100644 --- a/routers/web/repo/star.go +++ b/routers/web/repo/star.go @@ -21,7 +21,7 @@ func ActionStar(ctx *context.Context) { } ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) - ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.Name) + ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.GroupID, ctx.Repo.Repository.Name) if err != nil { ctx.ServerError("GetRepositoryByName", err) return diff --git a/routers/web/repo/watch.go b/routers/web/repo/watch.go index 70c548b8ce..c00b1d1b1f 100644 --- a/routers/web/repo/watch.go +++ b/routers/web/repo/watch.go @@ -21,7 +21,7 @@ func ActionWatch(ctx *context.Context) { } ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) - ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.Name) + ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.GroupID, ctx.Repo.Repository.Name) if err != nil { ctx.ServerError("GetRepositoryByName", err) return diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go index 2ba45fc5a7..5638f9c31c 100644 --- a/routers/web/shared/user/header.go +++ b/routers/web/shared/user/header.go @@ -93,7 +93,7 @@ func prepareContextForProfileBigAvatar(ctx *context.Context) { func FindOwnerProfileReadme(ctx *context.Context, doer *user_model.User, optProfileRepoName ...string) (profileDbRepo *repo_model.Repository, profileReadmeBlob *git.Blob) { profileRepoName := util.OptionalArg(optProfileRepoName, RepoNameProfile) - profileDbRepo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, profileRepoName) + profileDbRepo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, ctx.PathParamInt64("group_id"), profileRepoName) if err != nil { if !repo_model.IsErrRepoNotExist(err) { log.Error("FindOwnerProfileReadme failed to GetRepositoryByName: %v", err) diff --git a/routers/web/web.go b/routers/web/web.go index 6656980766..e3d735095b 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1277,7 +1277,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get("/pulls/new/*", repo.PullsNewRedirect) } m.Group("/{username}/{reponame}", rootRepoFn, optSignIn, context.RepoAssignment, reqUnitCodeReader) - m.Group("/{username}/{group_id}{reponame}", rootRepoFn, optSignIn, context.RepoAssignment, reqUnitCodeReader) + m.Group("/{username}/{group_id}/{reponame}", rootRepoFn, optSignIn, context.RepoAssignment, reqUnitCodeReader) // end "/{username}/{group_id}/{reponame}": repo code: find, compare, list addIssuesPullsViewRoutes := func() { @@ -1295,10 +1295,10 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { }) } // FIXME: many "pulls" requests are sent to "issues" endpoints correctly, so the issue endpoints have to tolerate pull request permissions at the moment + m.Group("/{username}/{group_id}/{reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests)) m.Group("/{username}/{reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests)) - m.Group("/{username}/{group_id}/reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests)) - m.Group("/{username}/reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader) - m.Group("/{username}/{group_id}/reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader) + m.Group("/{username}/{group_id}/{reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader) + m.Group("/{username}/{reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader) repoIssueAttachmentFn := func() { m.Get("/comments/{id}/attachments", repo.GetCommentAttachments) @@ -1308,16 +1308,16 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get("/issues/suggestions", repo.IssueSuggestions) } - m.Group("/{username}/{reponame}", repoIssueAttachmentFn, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) // issue/pull attachments, labels, milestones m.Group("/{username}/{group_id}/{reponame}", repoIssueAttachmentFn, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) // issue/pull attachments, labels, milestones + m.Group("/{username}/{reponame}", repoIssueAttachmentFn, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) // issue/pull attachments, labels, milestones // end "/{username}/{group_id}/{reponame}": view milestone, label, issue, pull, etc issueViewFn := func() { m.Get("", repo.Issues) m.Get("/{index}", repo.ViewIssue) } - m.Group("/{username}/{reponame}/{type:issues}", issueViewFn, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypeExternalTracker)) m.Group("/{username}/{group_id}/{reponame}/{type:issues}", issueViewFn, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypeExternalTracker)) + m.Group("/{username}/{reponame}/{type:issues}", issueViewFn, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypeExternalTracker)) // end "/{username}/{group_id}/{reponame}": issue/pull list, issue/pull view, external tracker editIssueFn := func() { // edit issues, pulls, labels, milestones, etc @@ -1408,8 +1408,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { }, reqUnitPullsReader) m.Post("/pull/{index}/target_branch", reqUnitPullsReader, repo.UpdatePullRequestTarget) } - m.Group("/{username}/{reponame}", editIssueFn, reqSignIn, context.RepoAssignment, context.RepoMustNotBeArchived()) m.Group("/{username}/{group_id}/{reponame}", editIssueFn, reqSignIn, context.RepoAssignment, context.RepoMustNotBeArchived()) + m.Group("/{username}/{reponame}", editIssueFn, reqSignIn, context.RepoAssignment, context.RepoMustNotBeArchived()) // end "/{username}/{group_id}/{reponame}": create or edit issues, pulls, labels, milestones codeFn := func() { // repo code (at least "code reader") @@ -1461,8 +1461,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Combo("/fork").Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost) } - m.Group("/{username}/{reponame}", codeFn, reqSignIn, context.RepoAssignment, reqUnitCodeReader) m.Group("/{username}/{group_id}/{reponame}", codeFn, reqSignIn, context.RepoAssignment, reqUnitCodeReader) + m.Group("/{username}/{reponame}", codeFn, reqSignIn, context.RepoAssignment, reqUnitCodeReader) // end "/{username}/{group_id}/{reponame}": repo code repoTagFn := func() { // repo tags @@ -1474,8 +1474,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { }, ctxDataSet("EnableFeed", setting.Other.EnableFeed)) m.Post("/tags/delete", reqSignIn, reqRepoCodeWriter, context.RepoMustNotBeArchived(), repo.DeleteTag) } - m.Group("/{username}/{reponame}", repoTagFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqUnitCodeReader) m.Group("/{username}/{group_id}/{reponame}", repoTagFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqUnitCodeReader) + m.Group("/{username}/{reponame}", repoTagFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqUnitCodeReader) // end "/{username}/{group_id}/{reponame}": repo tags repoReleaseFn := func() { // repo releases @@ -1501,30 +1501,30 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost) }, reqSignIn, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, repo.CommitInfoCache) } - m.Group("/{username}/{reponame}", repoReleaseFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoReleaseReader) m.Group("/{username}/{group_id}/{reponame}", repoReleaseFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoReleaseReader) + m.Group("/{username}/{reponame}", repoReleaseFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoReleaseReader) // end "/{username}/{group_id}/{reponame}": repo releases repoAttachmentsFn := func() { // to maintain compatibility with old attachments m.Get("/attachments/{uuid}", webAuth.AllowBasic, webAuth.AllowOAuth2, repo.GetAttachment) } - m.Group("/{username}/{reponame}", repoAttachmentsFn, optSignIn, context.RepoAssignment) m.Group("/{username}/{group_id}/{reponame}", repoAttachmentsFn, optSignIn, context.RepoAssignment) + m.Group("/{username}/{reponame}", repoAttachmentsFn, optSignIn, context.RepoAssignment) // end "/{username}/{group_id}/{reponame}": compatibility with old attachments repoTopicFn := func() { m.Post("/topics", repo.TopicsPost) } - m.Group("/{username}/{reponame}", repoTopicFn, context.RepoAssignment, reqRepoAdmin, context.RepoMustNotBeArchived()) m.Group("/{username}/{group_id}/{reponame}", repoTopicFn, context.RepoAssignment, reqRepoAdmin, context.RepoMustNotBeArchived()) + m.Group("/{username}/{reponame}", repoTopicFn, context.RepoAssignment, reqRepoAdmin, context.RepoMustNotBeArchived()) repoPackageFn := func() { if setting.Packages.Enabled { m.Get("/packages", repo.Packages) } } - m.Group("/{username}/{reponame}", repoPackageFn, optSignIn, context.RepoAssignment) m.Group("/{username}/{group_id}/{reponame}", repoPackageFn, optSignIn, context.RepoAssignment) + m.Group("/{username}/{reponame}", repoPackageFn, optSignIn, context.RepoAssignment) repoProjectsFn := func() { m.Get("", repo.Projects) @@ -1551,8 +1551,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { }) }, reqRepoProjectsWriter, context.RepoMustNotBeArchived()) } - m.Group("/{username}/{reponame}/projects", repoProjectsFn, optSignIn, context.RepoAssignment, reqRepoProjectsReader, repo.MustEnableRepoProjects) m.Group("/{username}/{group_id}/{reponame}/projects", repoProjectsFn, optSignIn, context.RepoAssignment, reqRepoProjectsReader, repo.MustEnableRepoProjects) + m.Group("/{username}/{reponame}/projects", repoProjectsFn, optSignIn, context.RepoAssignment, reqRepoProjectsReader, repo.MustEnableRepoProjects) // end "/{username}/{group_id}/{reponame}/projects" repoActionsFn := func() { @@ -1587,8 +1587,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get("/badge.svg", webAuth.AllowBasic, webAuth.AllowOAuth2, actions.GetWorkflowBadge) }) } - m.Group("/{username}/{reponame}/actions", repoActionsFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoActionsReader, actions.MustEnableActions) m.Group("/{username}/{group_id}/{reponame}/actions", repoActionsFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoActionsReader, actions.MustEnableActions) + m.Group("/{username}/{reponame}/actions", repoActionsFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoActionsReader, actions.MustEnableActions) // end "/{username}/{group_id}/{reponame}/actions" repoWikiFn := func() { @@ -1603,11 +1603,11 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff) m.Get("/raw/*", repo.WikiRaw) } - m.Group("/{username}/{reponame}/wiki", repoWikiFn, optSignIn, context.RepoAssignment, repo.MustEnableWiki, reqUnitWikiReader, func(ctx *context.Context) { + m.Group("/{username}/{group_id}/{reponame}/wiki", repoWikiFn, optSignIn, context.RepoAssignment, repo.MustEnableWiki, reqUnitWikiReader, func(ctx *context.Context) { ctx.Data["PageIsWiki"] = true ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink(ctx, ctx.Doer) }) - m.Group("/{username}/{group_id}/{reponame}/wiki", repoWikiFn, optSignIn, context.RepoAssignment, repo.MustEnableWiki, reqUnitWikiReader, func(ctx *context.Context) { + m.Group("/{username}/{reponame}/wiki", repoWikiFn, optSignIn, context.RepoAssignment, repo.MustEnableWiki, reqUnitWikiReader, func(ctx *context.Context) { ctx.Data["PageIsWiki"] = true ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink(ctx, ctx.Doer) }) @@ -1633,11 +1633,11 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { }) }, reqUnitCodeReader) } - m.Group("/{username}/{reponame}/activity", activityFn, + m.Group("/{username}/{group_id}/{reponame}/activity", activityFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, context.RequireUnitReader(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases), ) - m.Group("/{username}/{group_id}/{reponame}/activity", activityFn, + m.Group("/{username}/{reponame}/activity", activityFn, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, context.RequireUnitReader(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases), ) @@ -1671,8 +1671,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { }) }) } - m.Group("/{username}/{reponame}", repoPullFn, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqUnitPullsReader) m.Group("/{username}/{group_id}/{reponame}", repoPullFn, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqUnitPullsReader) + m.Group("/{username}/{reponame}", repoPullFn, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqUnitPullsReader) // end "/{username}/{group_id}/{reponame}/pulls/{index}": repo pull request repoCodeFn := func() { @@ -1755,8 +1755,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, repo.RawDiff) m.Post("/lastcommit/*", context.RepoRefByType(git.RefTypeCommit), repo.LastCommit) } - m.Group("/{username}/{reponame}", repoCodeFn, optSignIn, context.RepoAssignment, reqUnitCodeReader) m.Group("/{username}/{group_id}/{reponame}", repoCodeFn, optSignIn, context.RepoAssignment, reqUnitCodeReader) + m.Group("/{username}/{reponame}", repoCodeFn, optSignIn, context.RepoAssignment, reqUnitCodeReader) // end "/{username}/{group_id}/{reponame}": repo code fn := func() { @@ -1767,8 +1767,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Post("/action/{action:watch|unwatch}", reqSignIn, repo.ActionWatch) m.Post("/action/{action:accept_transfer|reject_transfer}", reqSignIn, repo.ActionTransfer) } - m.Group("/{username}/{reponame}", fn, optSignIn, context.RepoAssignment) m.Group("/{username}/{group_id}/{reponame}", fn, optSignIn, context.RepoAssignment) + m.Group("/{username}/{reponame}", fn, optSignIn, context.RepoAssignment) // git lfs uses its own jwt key, and it handles the token & auth by itself, it conflicts with the general "OAuth2" auth method // pattern: "/{username}/{reponame}/{lfs-paths}": git-lfs support, see also addOwnerRepoGitHTTPRouters diff --git a/services/context/repo.go b/services/context/repo.go index 6183700762..ea87159ac5 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -12,6 +12,7 @@ import ( "net/http" "net/url" "path" + "regexp" "strconv" "strings" @@ -387,6 +388,8 @@ func EarlyResponseForGoGetMeta(ctx *Context) { ctx.PlainText(http.StatusOK, htmlMeta) } +var pathRegex = regexp.MustCompile(`(?i).*/[a-z\-0-9_]+/(\d+/)?[a-z\-0-9_]`) + // RedirectToRepo redirect to a differently-named repository func RedirectToRepo(ctx *Base, redirectRepoID int64) { ownerName := ctx.PathParam("username") @@ -398,6 +401,8 @@ func RedirectToRepo(ctx *Base, redirectRepoID int64) { ctx.HTTPError(http.StatusInternalServerError, "GetRepositoryByID") return } + pathRegex.ReplaceAllString(ctx.Req.URL.EscapedPath(), + url.PathEscape(repo.OwnerName)+"/$1"+url.PathEscape(repo.Name)) redirectPath := strings.Replace( ctx.Req.URL.EscapedPath(), @@ -542,7 +547,7 @@ func RepoAssignment(ctx *Context) { } // Get repository. - repo, err := repo_model.GetRepositoryByName(ctx, ctx.Repo.Owner.ID, repoName) + repo, err := repo_model.GetRepositoryByName(ctx, ctx.Repo.Owner.ID, gid, repoName) if err != nil { if repo_model.IsErrRepoNotExist(err) { redirectRepoID, err := repo_model.LookupRedirect(ctx, ctx.Repo.Owner.ID, repoName) diff --git a/services/issue/commit.go b/services/issue/commit.go index 68ccc906b6..58099e45b4 100644 --- a/services/issue/commit.go +++ b/services/issue/commit.go @@ -138,7 +138,7 @@ func UpdateIssuesCommit(ctx context.Context, doer *user_model.User, repo *repo_m for _, ref := range references.FindAllIssueReferences(c.Message) { // issue is from another repo if len(ref.Owner) > 0 && len(ref.Name) > 0 { - refRepo, err = repo_model.GetRepositoryByOwnerAndName(ctx, ref.Owner, ref.Name) + refRepo, err = repo_model.GetRepositoryByOwnerAndName(ctx, ref.Owner, ref.Name, ref.GroupID) if err != nil { if repo_model.IsErrRepoNotExist(err) { log.Warn("Repository referenced in commit but does not exist: %v", err) diff --git a/services/lfs/locks.go b/services/lfs/locks.go index c2279edaf0..a7285be4d1 100644 --- a/services/lfs/locks.go +++ b/services/lfs/locks.go @@ -48,7 +48,7 @@ func handleLockListOut(ctx *context.Context, repo *repo_model.Repository, lock * func GetListLockHandler(ctx *context.Context) { rv := getRequestContext(ctx) - repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, rv.User, rv.Repo) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, rv.User, rv.Repo, rv.GroupID) if err != nil { log.Debug("Could not find repository: %s/%s - %s", rv.User, rv.Repo, err) ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`) @@ -135,9 +135,10 @@ func GetListLockHandler(ctx *context.Context) { func PostLockHandler(ctx *context.Context) { userName := ctx.PathParam("username") repoName := strings.TrimSuffix(ctx.PathParam("reponame"), ".git") + groupID := ctx.PathParamInt64("group_id") authorization := ctx.Req.Header.Get("Authorization") - repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName, groupID) if err != nil { log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err) ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`) @@ -200,9 +201,10 @@ func PostLockHandler(ctx *context.Context) { func VerifyLockHandler(ctx *context.Context) { userName := ctx.PathParam("username") repoName := strings.TrimSuffix(ctx.PathParam("reponame"), ".git") + groupID := ctx.PathParamInt64("group_id") authorization := ctx.Req.Header.Get("Authorization") - repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName, groupID) if err != nil { log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err) ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`) @@ -268,9 +270,10 @@ func VerifyLockHandler(ctx *context.Context) { func UnLockHandler(ctx *context.Context) { userName := ctx.PathParam("username") repoName := strings.TrimSuffix(ctx.PathParam("reponame"), ".git") + groupID := ctx.PathParamInt64("group_id") authorization := ctx.Req.Header.Get("Authorization") - repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName, groupID) if err != nil { log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err) ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`) diff --git a/services/lfs/server.go b/services/lfs/server.go index 0d4243a47e..6ca24f4ced 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -32,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" "github.com/golang-jwt/jwt/v5" @@ -41,6 +42,7 @@ import ( type requestContext struct { User string Repo string + GroupID int64 Authorization string RepoGitURL string } @@ -422,11 +424,14 @@ func decodeJSON(req *http.Request, v any) error { func getRequestContext(ctx *context.Context) *requestContext { ownerName := ctx.PathParam("username") repoName := strings.TrimSuffix(ctx.PathParam("reponame"), ".git") + gid := ctx.PathParamInt64("group_id") + groupSegment := util.Iif(gid != 0, fmt.Sprintf("group/%d/", gid), "") return &requestContext{ User: ownerName, Repo: repoName, + GroupID: gid, Authorization: ctx.Req.Header.Get("Authorization"), - RepoGitURL: httplib.GuessCurrentAppURL(ctx) + url.PathEscape(ownerName) + "/" + url.PathEscape(repoName+".git"), + RepoGitURL: httplib.GuessCurrentAppURL(ctx) + url.PathEscape(ownerName) + "/" + groupSegment + url.PathEscape(repoName+".git"), } } @@ -453,7 +458,7 @@ func getAuthenticatedMeta(ctx *context.Context, rc *requestContext, p lfs_module } func getAuthenticatedRepository(ctx *context.Context, rc *requestContext, requireWrite bool) *repo_model.Repository { - repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, rc.User, rc.Repo) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, rc.User, rc.Repo, rc.GroupID) if err != nil { log.Error("Unable to get repository: %s/%s Error: %v", rc.User, rc.Repo, err) writeStatus(ctx, http.StatusNotFound) diff --git a/services/markup/renderhelper_codepreview.go b/services/markup/renderhelper_codepreview.go index 87c3bd1d48..ad2d54db46 100644 --- a/services/markup/renderhelper_codepreview.go +++ b/services/markup/renderhelper_codepreview.go @@ -31,7 +31,7 @@ func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePrevie opts.LineStop = opts.LineStart + lineCount } - dbRepo, err := repo.GetRepositoryByOwnerAndName(ctx, opts.OwnerName, opts.RepoName) + dbRepo, err := repo.GetRepositoryByOwnerAndName(ctx, opts.OwnerName, opts.RepoName, opts.GroupID) if err != nil { return "", err } diff --git a/services/markup/renderhelper_issueicontitle.go b/services/markup/renderhelper_issueicontitle.go index 651e2997e0..66a7dcadbe 100644 --- a/services/markup/renderhelper_issueicontitle.go +++ b/services/markup/renderhelper_issueicontitle.go @@ -27,7 +27,7 @@ func renderRepoIssueIconTitle(ctx context.Context, opts markup.RenderIssueIconTi textIssueIndex := fmt.Sprintf("(#%d)", opts.IssueIndex) dbRepo := webCtx.Repo.Repository if opts.OwnerName != "" { - dbRepo, err = repo.GetRepositoryByOwnerAndName(ctx, opts.OwnerName, opts.RepoName) + dbRepo, err = repo.GetRepositoryByOwnerAndName(ctx, opts.OwnerName, opts.RepoName, opts.GroupID) if err != nil { return "", err } diff --git a/services/packages/cargo/index.go b/services/packages/cargo/index.go index 580d84ebc2..eb4332b84d 100644 --- a/services/packages/cargo/index.go +++ b/services/packages/cargo/index.go @@ -109,7 +109,7 @@ func UpdatePackageIndexIfExists(ctx context.Context, doer, owner *user_model.Use // We do not want to force the creation of the repo here // cargo http index does not rely on the repo itself, // so if the repo does not exist, we just do nothing. - repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner.Name, IndexRepositoryName) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner.Name, IndexRepositoryName, 0) if err != nil { if errors.Is(err, util.ErrNotExist) { return nil @@ -208,7 +208,7 @@ func addOrUpdatePackageIndex(ctx context.Context, t *files_service.TemporaryUplo } func getOrCreateIndexRepository(ctx context.Context, doer, owner *user_model.User) (*repo_model.Repository, error) { - repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner.Name, IndexRepositoryName) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner.Name, IndexRepositoryName, 0) if err != nil { if errors.Is(err, util.ErrNotExist) { repo, err = repo_service.CreateRepositoryDirectly(ctx, doer, owner, repo_service.CreateRepoOptions{ diff --git a/services/repository/branch.go b/services/repository/branch.go index dc17e4f2fe..3e9e2165e7 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -648,6 +648,7 @@ func deleteBranchSuccessPostProcess(doer *user_model.User, repo *repo_model.Repo PusherID: doer.ID, PusherName: doer.Name, RepoUserName: repo.OwnerName, + RepoGroupID: repo.GroupID, RepoName: repo.Name, }); err != nil { log.Error("PushUpdateOptions: %v", err) diff --git a/services/repository/lfs_test.go b/services/repository/lfs_test.go index 1335d48cb1..fc9e8386ba 100644 --- a/services/repository/lfs_test.go +++ b/services/repository/lfs_test.go @@ -28,7 +28,7 @@ func TestGarbageCollectLFSMetaObjects(t *testing.T) { err := storage.Init() assert.NoError(t, err) - repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "repo1") + repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "repo1", 0) assert.NoError(t, err) // add lfs object diff --git a/services/repository/push.go b/services/repository/push.go index 7c68a7f176..7bf0eba1bf 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -82,7 +82,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PushUpdates: %s/%s", optsList[0].RepoUserName, optsList[0].RepoName)) defer finished() - repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, optsList[0].RepoUserName, optsList[0].RepoName) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, optsList[0].RepoUserName, optsList[0].RepoName, optsList[0].RepoGroupID) if err != nil { return fmt.Errorf("GetRepositoryByOwnerAndName failed: %w", err) } diff --git a/tests/integration/actions_job_test.go b/tests/integration/actions_job_test.go index 3adae7b3d8..40f67c8ec6 100644 --- a/tests/integration/actions_job_test.go +++ b/tests/integration/actions_job_test.go @@ -474,7 +474,7 @@ func TestActionsGiteaContext(t *testing.T) { apiBaseRepo := createActionsTestRepo(t, user2Token, "actions-gitea-context", false) baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiBaseRepo.ID}) - user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository) + user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, baseRepo.GroupID, auth_model.AccessTokenScopeWriteRepository) runner := newMockRunner() runner.registerAsRepoRunner(t, baseRepo.OwnerName, baseRepo.Name, "mock-runner", []string{"ubuntu-latest"}, false) @@ -558,7 +558,7 @@ func TestActionsGiteaContextEphemeral(t *testing.T) { apiBaseRepo := createActionsTestRepo(t, user2Token, "actions-gitea-context", false) baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiBaseRepo.ID}) - user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository) + user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, baseRepo.GroupID, auth_model.AccessTokenScopeWriteRepository) runner := newMockRunner() runner.registerAsRepoRunner(t, baseRepo.OwnerName, baseRepo.Name, "mock-runner", []string{"ubuntu-latest"}, true) diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index f1c0d79d6d..d42db0c681 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -61,7 +61,7 @@ func TestPullRequestTargetEvent(t *testing.T) { assert.NotEmpty(t, baseRepo) // add user4 as the collaborator - ctx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository) + ctx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, baseRepo.GroupID, auth_model.AccessTokenScopeWriteRepository) t.Run("AddUser4AsCollaboratorWithReadAccess", doAPIAddCollaborator(ctx, "user4", perm.AccessModeRead)) // create the forked repo @@ -487,7 +487,7 @@ func TestPullRequestCommitStatusEvent(t *testing.T) { assert.NotEmpty(t, repo) // add user4 as the collaborator - ctx := NewAPITestContext(t, repo.OwnerName, repo.Name, auth_model.AccessTokenScopeWriteRepository) + ctx := NewAPITestContext(t, repo.OwnerName, repo.Name, repo.GroupID, auth_model.AccessTokenScopeWriteRepository) t.Run("AddUser4AsCollaboratorWithReadAccess", doAPIAddCollaborator(ctx, "user4", perm.AccessModeRead)) // add the workflow file to the repo @@ -1542,7 +1542,7 @@ func TestClosePullRequestWithPath(t *testing.T) { // create the base repo apiBaseRepo := createActionsTestRepo(t, user2Token, "close-pull-request-with-path", false) baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiBaseRepo.ID}) - user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository) + user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, baseRepo.GroupID, auth_model.AccessTokenScopeWriteRepository) // init the workflow wfTreePath := ".gitea/workflows/pull.yml" @@ -1571,7 +1571,7 @@ jobs: var apiForkRepo api.Repository DecodeJSON(t, resp, &apiForkRepo) forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiForkRepo.ID}) - user4APICtx := NewAPITestContext(t, user4.Name, forkRepo.Name, auth_model.AccessTokenScopeWriteRepository) + user4APICtx := NewAPITestContext(t, user4.Name, forkRepo.Name, forkRepo.GroupID, auth_model.AccessTokenScopeWriteRepository) // user4 creates a pull request to add file "app/main.go" doAPICreateFile(user4APICtx, "app/main.go", &api.CreateFileOptions{ diff --git a/tests/integration/api_branch_test.go b/tests/integration/api_branch_test.go index f5f33dacf0..e55e0126ff 100644 --- a/tests/integration/api_branch_test.go +++ b/tests/integration/api_branch_test.go @@ -115,7 +115,7 @@ func TestAPICreateBranch(t *testing.T) { func testAPICreateBranches(t *testing.T, giteaURL *url.URL) { username := "user2" - ctx := NewAPITestContext(t, username, "my-noo-repo", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + ctx := NewAPITestContext(t, username, "my-noo-repo", 0, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) giteaURL.Path = ctx.GitPath() t.Run("CreateRepo", doAPICreateRepository(ctx, false)) @@ -166,14 +166,18 @@ func testAPICreateBranches(t *testing.T, giteaURL *url.URL) { for _, test := range testCases { session := ctx.Session t.Run(test.NewBranch, func(t *testing.T) { - testAPICreateBranch(t, session, "user2", "my-noo-repo", test.OldBranch, test.NewBranch, test.ExpectedHTTPStatus) + testAPICreateBranch(t, session, 0, "user2", "my-noo-repo", test.OldBranch, test.NewBranch, test.ExpectedHTTPStatus) }) } } -func testAPICreateBranch(t testing.TB, session *TestSession, user, repo, oldBranch, newBranch string, status int) bool { +func testAPICreateBranch(t testing.TB, session *TestSession, groupID int64, user, repo, oldBranch, newBranch string, status int) bool { token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - req := NewRequestWithJSON(t, "POST", "/api/v1/repos/"+user+"/"+repo+"/branches", &api.CreateBranchRepoOption{ + var groupSegment string + if groupID > 0 { + groupSegment = fmt.Sprintf("%d/", groupID) + } + req := NewRequestWithJSON(t, "POST", "/api/v1/repos/"+user+"/"+groupSegment+repo+"/branches", &api.CreateBranchRepoOption{ BranchName: newBranch, OldBranchName: oldBranch, }).AddTokenAuth(token) @@ -282,7 +286,7 @@ func TestAPIUpdateBranchReference(t *testing.T) { defer tests.PrepareTestEnv(t)() onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - ctx := NewAPITestContext(t, "user2", "update-branch", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + ctx := NewAPITestContext(t, "user2", "update-branch", 0, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) giteaURL.Path = ctx.GitPath() var defaultBranch string @@ -420,10 +424,10 @@ func TestAPICreateBranchWithSyncBranches(t *testing.T) { assert.NoError(t, err) onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + ctx := NewAPITestContext(t, "user2", "repo1", 0, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) giteaURL.Path = ctx.GitPath() - testAPICreateBranch(t, ctx.Session, "user2", "repo1", "", "new_branch", http.StatusCreated) + testAPICreateBranch(t, ctx.Session, 0, "user2", "repo1", "", "new_branch", http.StatusCreated) }) branches, err = db.Find[git_model.Branch](t.Context(), git_model.FindBranchOptions{ diff --git a/tests/integration/api_helper_for_declarative_test.go b/tests/integration/api_helper_for_declarative_test.go index b30cdfd0fc..c6266470eb 100644 --- a/tests/integration/api_helper_for_declarative_test.go +++ b/tests/integration/api_helper_for_declarative_test.go @@ -29,9 +29,10 @@ type APITestContext struct { Token string Username string ExpectedCode int + GroupID int64 } -func NewAPITestContext(t *testing.T, username, reponame string, scope ...auth.AccessTokenScope) APITestContext { +func NewAPITestContext(t *testing.T, username, reponame string, groupID int64, scope ...auth.AccessTokenScope) APITestContext { session := loginUser(t, username) if len(scope) == 0 { // FIXME: legacy logic: no scope means all @@ -41,6 +42,7 @@ func NewAPITestContext(t *testing.T, username, reponame string, scope ...auth.Ac return APITestContext{ Session: session, Token: token, + GroupID: groupID, Username: username, Reponame: reponame, } @@ -60,6 +62,7 @@ func doAPICreateRepository(ctx APITestContext, empty bool, callback ...func(*tes Template: true, Gitignores: "", License: "WTFPL", + GroupID: ctx.GroupID, Readme: "Default", } req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", createRepoOption). diff --git a/tests/integration/api_packages_cargo_test.go b/tests/integration/api_packages_cargo_test.go index d7a89e446d..be62300290 100644 --- a/tests/integration/api_packages_cargo_test.go +++ b/tests/integration/api_packages_cargo_test.go @@ -71,7 +71,7 @@ func testPackageCargo(t *testing.T, _ *neturl.URL) { err := cargo_service.InitializeIndexRepository(t.Context(), user, user) assert.NoError(t, err) - repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), user.Name, cargo_service.IndexRepositoryName) + repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), user.Name, cargo_service.IndexRepositoryName, 0) assert.NotNil(t, repo) assert.NoError(t, err) diff --git a/tests/integration/api_repo_lfs_test.go b/tests/integration/api_repo_lfs_test.go index 86d5f69b9c..e646f0c572 100644 --- a/tests/integration/api_repo_lfs_test.go +++ b/tests/integration/api_repo_lfs_test.go @@ -61,10 +61,10 @@ func TestAPILFSMediaType(t *testing.T) { } func createLFSTestRepository(t *testing.T, repoName string) *repo_model.Repository { - ctx := NewAPITestContext(t, "user2", repoName, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + ctx := NewAPITestContext(t, "user2", repoName, 0, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) t.Run("CreateRepo", doAPICreateRepository(ctx, false)) - repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", repoName) + repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", repoName, 0) require.NoError(t, err) return repo diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go index ac106bc776..2bc8a0e84e 100644 --- a/tests/integration/editor_test.go +++ b/tests/integration/editor_test.go @@ -37,8 +37,8 @@ func TestEditor(t *testing.T) { t.Run("DiffPreview", testEditorDiffPreview) t.Run("CreateFile", testEditorCreateFile) t.Run("EditFile", func(t *testing.T) { - testEditFile(t, sessionUser2, "user2", "repo1", "master", "README.md", "Hello, World (direct)\n") - testEditFileToNewBranch(t, sessionUser2, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (commit-to-new-branch)\n") + testEditFile(t, sessionUser2, 0, "user2", "repo1", "master", "README.md", "Hello, World (direct)\n") + testEditFileToNewBranch(t, sessionUser2, 0, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (commit-to-new-branch)\n") }) t.Run("PatchFile", testEditorPatchFile) t.Run("DeleteFile", func(t *testing.T) { @@ -57,7 +57,7 @@ func TestEditor(t *testing.T) { func testEditorCreateFile(t *testing.T) { session := loginUser(t, "user2") - testCreateFile(t, session, "user2", "repo1", "master", "", "test.txt", "Content") + testCreateFile(t, session, 0, "user2", "repo1", "master", "", "test.txt", "Content") testEditorActionPostRequestError(t, session, "/user2/repo1/_new/master/", map[string]string{ "tree_path": "test.txt", "commit_choice": "direct", @@ -70,12 +70,12 @@ func testEditorCreateFile(t *testing.T) { }, `Branch "master" already exists in this repository.`) } -func testCreateFile(t *testing.T, session *TestSession, user, repo, baseBranchName, newBranchName, filePath, content string) { +func testCreateFile(t *testing.T, session *TestSession, groupID int64, user, repo, baseBranchName, newBranchName, filePath, content string) { commitChoice := "direct" if newBranchName != "" && newBranchName != baseBranchName { commitChoice = "commit-to-new-branch" } - testEditorActionEdit(t, session, user, repo, "_new", baseBranchName, "", map[string]string{ + testEditorActionEdit(t, session, groupID, user, repo, "_new", baseBranchName, "", map[string]string{ "tree_path": filePath, "content": content, "commit_choice": commitChoice, @@ -118,10 +118,14 @@ func testEditorActionPostRequestError(t *testing.T, session *TestSession, reques assert.Equal(t, errorMessage, test.ParseJSONError(resp.Body.Bytes()).ErrorMessage) } -func testEditorActionEdit(t *testing.T, session *TestSession, user, repo, editorAction, branch, filePath string, params map[string]string) *httptest.ResponseRecorder { +func testEditorActionEdit(t *testing.T, session *TestSession, groupID int64, user, repo, editorAction, branch, filePath string, params map[string]string) *httptest.ResponseRecorder { params["tree_path"] = util.IfZero(params["tree_path"], filePath) newBranchName := util.Iif(params["commit_choice"] == "direct", branch, params["new_branch_name"]) - resp := testEditorActionPostRequest(t, session, fmt.Sprintf("/%s/%s/%s/%s/%s", user, repo, editorAction, branch, filePath), params) + var groupSegment string + if groupID > 0 { + groupSegment = fmt.Sprintf("%d/", groupID) + } + resp := testEditorActionPostRequest(t, session, fmt.Sprintf("/%s/%s%s/%s/%s/%s", user, groupSegment, repo, editorAction, branch, filePath), params) assert.Equal(t, http.StatusOK, resp.Code) assert.NotEmpty(t, test.RedirectURL(resp)) req := NewRequest(t, "GET", path.Join(user, repo, "raw/branch", newBranchName, params["tree_path"])) @@ -130,15 +134,15 @@ func testEditorActionEdit(t *testing.T, session *TestSession, user, repo, editor return resp } -func testEditFile(t *testing.T, session *TestSession, user, repo, branch, filePath, newContent string) { - testEditorActionEdit(t, session, user, repo, "_edit", branch, filePath, map[string]string{ +func testEditFile(t *testing.T, session *TestSession, groupID int64, user, repo, branch, filePath, newContent string) { + testEditorActionEdit(t, session, groupID, user, repo, "_edit", branch, filePath, map[string]string{ "content": newContent, "commit_choice": "direct", }) } -func testEditFileToNewBranch(t *testing.T, session *TestSession, user, repo, branch, targetBranch, filePath, newContent string) { - testEditorActionEdit(t, session, user, repo, "_edit", branch, filePath, map[string]string{ +func testEditFileToNewBranch(t *testing.T, session *TestSession, groupID int64, user, repo, branch, targetBranch, filePath, newContent string) { + testEditorActionEdit(t, session, groupID, user, repo, "_edit", branch, filePath, map[string]string{ "content": newContent, "commit_choice": "commit-to-new-branch", "new_branch_name": targetBranch, diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go index b82dd60021..e249e0173d 100644 --- a/tests/integration/git_general_test.go +++ b/tests/integration/git_general_test.go @@ -51,11 +51,11 @@ func TestGitGeneral(t *testing.T) { func testGitGeneral(t *testing.T, u *url.URL) { username := "user2" - baseAPITestContext := NewAPITestContext(t, username, "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + baseAPITestContext := NewAPITestContext(t, username, "repo1", 0, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) u.Path = baseAPITestContext.GitPath() - forkedUserCtx := NewAPITestContext(t, "user4", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + forkedUserCtx := NewAPITestContext(t, "user4", "repo1", 0, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) t.Run("HTTP", func(t *testing.T) { defer tests.PrintCurrentTest(t)() @@ -370,7 +370,7 @@ func generateCommitWithNewData(ctx context.Context, size int, repoPath, email, f func doCreateProtectedBranch(baseCtx *APITestContext, dstPath string) func(t *testing.T) { return func(t *testing.T) { defer tests.PrintCurrentTest(t)() - ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) + ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, 0, auth_model.AccessTokenScopeWriteRepository) t.Run("ProtectBranchWithFilePatterns", doProtectBranch(ctx, "release-*", baseCtx.Username, "", "", "config*")) @@ -401,7 +401,7 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes t.Run("CreateBranchProtected", doGitCreateBranch(dstPath, "protected")) t.Run("PushProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected")) - ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) + ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, 0, auth_model.AccessTokenScopeWriteRepository) // Protect branch without any whitelisting t.Run("ProtectBranchNoWhitelist", doProtectBranch(ctx, "protected", "", "", "", "")) @@ -673,7 +673,7 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) { t.Run("SuccessfullyPushAndCreateTestRepository", doGitPushTestRepository(tmpDir, "origin", "master")) // Finally, fetch repo from database and ensure the correct repository has been created - repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), ctx.Username, ctx.Reponame) + repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), ctx.Username, ctx.Reponame, ctx.GroupID) assert.NoError(t, err) assert.False(t, repo.IsEmpty) assert.True(t, repo.IsPrivate) @@ -700,9 +700,9 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { return func(t *testing.T) { defer tests.PrintCurrentTest(t)() - ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) - collaboratorCtx := NewAPITestContext(t, "user5", baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) - readOnlyCtx := NewAPITestContext(t, "user4", baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) + ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, 0, auth_model.AccessTokenScopeWriteRepository) + collaboratorCtx := NewAPITestContext(t, "user5", baseCtx.Reponame, 0, auth_model.AccessTokenScopeWriteRepository) + readOnlyCtx := NewAPITestContext(t, "user4", baseCtx.Reponame, 0, auth_model.AccessTokenScopeWriteRepository) t.Run("AddAutoMergeCollaborator", doAPIAddCollaborator(*baseCtx, collaboratorCtx.Username, perm.AccessModeWrite)) t.Run("AddReadOnlyAutoMergeCollaborator", doAPIAddCollaborator(*baseCtx, readOnlyCtx.Username, perm.AccessModeRead)) @@ -826,7 +826,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string pr1, pr2 *issues_model.PullRequest commit string ) - repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), ctx.Username, ctx.Reponame) + repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), ctx.Username, ctx.Reponame, ctx.GroupID) require.NoError(t, err) pullNum := unittest.GetCount(t, &issues_model.PullRequest{}) diff --git a/tests/integration/lfs_getobject_test.go b/tests/integration/lfs_getobject_test.go index 5f13229ba2..ca2897a3aa 100644 --- a/tests/integration/lfs_getobject_test.go +++ b/tests/integration/lfs_getobject_test.go @@ -41,7 +41,7 @@ func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string } func storeAndGetLfsToken(t *testing.T, content *[]byte, extraHeader *http.Header, expectedStatus int, ts ...auth.AccessTokenScope) *httptest.ResponseRecorder { - repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "repo1") + repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "repo1", 0) assert.NoError(t, err) oid := storeObjectInRepo(t, repo.ID, content) defer git_model.RemoveLFSMetaObjectByOid(t.Context(), repo.ID, oid) @@ -66,7 +66,7 @@ func storeAndGetLfsToken(t *testing.T, content *[]byte, extraHeader *http.Header } func storeAndGetLfs(t *testing.T, content *[]byte, extraHeader *http.Header, expectedStatus int) *httptest.ResponseRecorder { - repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "repo1") + repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "repo1", 0) assert.NoError(t, err) oid := storeObjectInRepo(t, repo.ID, content) defer git_model.RemoveLFSMetaObjectByOid(t.Context(), repo.ID, oid) diff --git a/tests/integration/repo_search_test.go b/tests/integration/repo_search_test.go index eafb600990..2c80aea337 100644 --- a/tests/integration/repo_search_test.go +++ b/tests/integration/repo_search_test.go @@ -28,7 +28,7 @@ func resultFilenames(doc *HTMLDoc) []string { func TestSearchRepo(t *testing.T) { defer tests.PrepareTestEnv(t)() - repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "repo1") + repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "repo1", 0) assert.NoError(t, err) code_indexer.UpdateRepoIndexer(repo) @@ -38,7 +38,7 @@ func TestSearchRepo(t *testing.T) { setting.Indexer.IncludePatterns = setting.IndexerGlobFromString("**.txt") setting.Indexer.ExcludePatterns = setting.IndexerGlobFromString("**/y/**") - repo, err = repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "glob") + repo, err = repo_model.GetRepositoryByOwnerAndName(t.Context(), "user2", "glob", 0) assert.NoError(t, err) code_indexer.UpdateRepoIndexer(repo) diff --git a/tests/integration/repo_webhook_test.go b/tests/integration/repo_webhook_test.go index 004465ed92..df5a5d014e 100644 --- a/tests/integration/repo_webhook_test.go +++ b/tests/integration/repo_webhook_test.go @@ -64,7 +64,7 @@ func TestNewWebHookLink(t *testing.T) { } } -func testAPICreateWebhookForRepo(t *testing.T, session *TestSession, userName, repoName, url, event string, branchFilter ...string) { +func testAPICreateWebhookForRepo(t *testing.T, session *TestSession, groupID int64, userName, repoName, url, event string, branchFilter ...string) { token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) var branchFilterString string if len(branchFilter) > 0 { @@ -153,10 +153,10 @@ func Test_WebhookCreate(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "create") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "create") // 2. trigger the webhook - testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) + testAPICreateBranch(t, session, 0, "user2", "repo1", "master", "master2", http.StatusCreated) // 3. validate the webhook is triggered assert.Len(t, payloads, 1) @@ -185,10 +185,10 @@ func Test_WebhookDelete(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "delete") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "delete") // 2. trigger the webhook - testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) + testAPICreateBranch(t, session, 0, "user2", "repo1", "master", "master2", http.StatusCreated) testAPIDeleteBranch(t, "master2", http.StatusNoContent) // 3. validate the webhook is triggered @@ -218,7 +218,7 @@ func Test_WebhookFork(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user1") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "fork") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "fork") // 2. trigger the webhook testRepoFork(t, session, "user2", "repo1", "user1", "repo1-fork", "master") @@ -250,7 +250,7 @@ func Test_WebhookIssueComment(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_comment") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "issue_comment") t.Run("create comment", func(t *testing.T) { // 2. trigger the webhook @@ -332,7 +332,7 @@ func Test_WebhookRelease(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "release") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "release") // 2. trigger the webhook createNewRelease(t, session, "/user2/repo1", "v0.0.99", "v0.0.99", false, false) @@ -365,10 +365,10 @@ func Test_WebhookPush(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "push") // 2. trigger the webhook - testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") + testCreateFile(t, session, 0, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") // 3. validate the webhook is triggered assert.Equal(t, "push", triggeredEvent) @@ -398,10 +398,10 @@ func Test_WebhookPushDevBranch(t *testing.T) { session := loginUser(t, "user2") // only for dev branch - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push", "develop") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "push", "develop") // 2. this should not trigger the webhook - testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") + testCreateFile(t, session, 0, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") assert.Empty(t, triggeredEvent) assert.Empty(t, payloads) @@ -414,7 +414,7 @@ func Test_WebhookPushDevBranch(t *testing.T) { assert.NoError(t, err) // 3. trigger the webhook - testCreateFile(t, session, "user2", "repo1", "develop", "", "test_webhook_push.md", "# a test file for webhook push") + testCreateFile(t, session, 0, "user2", "repo1", "develop", "", "test_webhook_push.md", "# a test file for webhook push") afterCommitID, err := gitRepo.GetBranchCommitID("develop") assert.NoError(t, err) @@ -454,7 +454,7 @@ func Test_WebhookPushToNewBranch(t *testing.T) { session := loginUser(t, "user2") // only for dev branch - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push", "new_branch") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "push", "new_branch") repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1) @@ -465,7 +465,7 @@ func Test_WebhookPushToNewBranch(t *testing.T) { assert.NoError(t, err) // 2. trigger the webhook - testCreateFile(t, session, "user2", "repo1", "master", "new_branch", "test_webhook_push.md", "# a new push from new branch") + testCreateFile(t, session, 0, "user2", "repo1", "master", "new_branch", "test_webhook_push.md", "# a new push from new branch") afterCommitID, err := gitRepo.GetBranchCommitID("new_branch") assert.NoError(t, err) @@ -505,7 +505,7 @@ func Test_WebhookIssue(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issues") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "issues") // 2. trigger the webhook testNewIssue(t, session, "user2", "repo1", "Title1", "Description1") @@ -539,7 +539,7 @@ func Test_WebhookIssueDelete(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issues") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "issues") issueURL := testNewIssue(t, session, "user2", "repo1", "Title1", "Description1") // 2. trigger the webhook @@ -576,7 +576,7 @@ func Test_WebhookIssueAssign(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request_assign") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "pull_request_assign") // 2. trigger the webhook, issue 2 is a pull request testIssueAssign(t, session, repo1.Link(), 2, user2.ID) @@ -610,7 +610,7 @@ func Test_WebhookIssueMilestone(t *testing.T) { // create a new webhook with special webhook for repo1 session := loginUser(t, "user2") repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_milestone") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "issue_milestone") t.Run("assign a milestone", func(t *testing.T) { // trigger the webhook @@ -688,9 +688,9 @@ func Test_WebhookPullRequest(t *testing.T) { sessionUser4 := loginUser(t, "user4") // ignore the possible review_requested event to keep the test deterministic - testAPICreateWebhookForRepo(t, sessionUser2, "user2", "repo1", provider.URL(), "pull_request_only") + testAPICreateWebhookForRepo(t, sessionUser2, 0, "user2", "repo1", provider.URL(), "pull_request_only") - testAPICreateBranch(t, sessionUser2, "user2", "repo1", "master", "master2", http.StatusCreated) + testAPICreateBranch(t, sessionUser2, 0, "user2", "repo1", "master", "master2", http.StatusCreated) // 2. trigger the webhook repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) testPullCreateDirectly(t, sessionUser4, createPullRequestOptions{ @@ -735,9 +735,9 @@ func Test_WebhookPullRequestDelete(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "pull_request") - testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) + testAPICreateBranch(t, session, 0, "user2", "repo1", "master", "master2", http.StatusCreated) repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) issueURL := testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request") @@ -774,10 +774,10 @@ func Test_WebhookPullRequestComment(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request_comment") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "pull_request_comment") // 2. trigger the webhook - testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) + testAPICreateBranch(t, session, 0, "user2", "repo1", "master", "master2", http.StatusCreated) repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) prID := testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request") @@ -812,7 +812,7 @@ func Test_WebhookWiki(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "wiki") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "wiki") // 2. trigger the webhook testAPICreateWikiPage(t, session, "user2", "repo1", "Test Wiki Page", http.StatusCreated) @@ -918,7 +918,7 @@ func Test_WebhookStatus(t *testing.T) { // 1. create a new webhook with special webhook for repo1 session := loginUser(t, "user2") - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "status") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "status") repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) @@ -962,7 +962,7 @@ func Test_WebhookStatus_NoWrongTrigger(t *testing.T) { testCreateWebhookForRepo(t, session, "gitea", "user2", "repo1", provider.URL(), "push_only") // 2. trigger the webhook with a push action - testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") + testCreateFile(t, session, 0, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push") // 3. validate the webhook is triggered with right event assert.Equal(t, "push", trigger) @@ -991,7 +991,7 @@ func Test_WebhookWorkflowJob(t *testing.T) { session := loginUser(t, "user2") token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "workflow_job") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", provider.URL(), "workflow_job") repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) @@ -1696,7 +1696,7 @@ func testWebhookWorkflowRun(t *testing.T, webhookData *workflowRunWebhook) { session := loginUser(t, "user2") token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", webhookData.URL, "workflow_run") repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) @@ -1797,7 +1797,7 @@ func testWebhookWorkflowRunDepthLimit(t *testing.T, webhookData *workflowRunWebh session := loginUser(t, "user2") token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run") + testAPICreateWebhookForRepo(t, session, 0, "user2", "repo1", webhookData.URL, "workflow_run") repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})