diff options
Diffstat (limited to 'routers/private/hook.go')
-rw-r--r-- | routers/private/hook.go | 142 |
1 files changed, 141 insertions, 1 deletions
diff --git a/routers/private/hook.go b/routers/private/hook.go index 9f5579b6ae..4bed86f38a 100644 --- a/routers/private/hook.go +++ b/routers/private/hook.go @@ -23,6 +23,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/agit" pull_service "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" ) @@ -155,6 +156,56 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { private.GitQuarantinePath+"="+opts.GitQuarantinePath) } + if git.SupportProcReceive { + pusher, err := models.GetUserByID(opts.UserID) + if err != nil { + log.Error("models.GetUserByID:%v", err) + ctx.Error(http.StatusInternalServerError, "") + return + } + + perm, err := models.GetUserRepoPermission(repo, pusher) + if err != nil { + log.Error("models.GetUserRepoPermission:%v", err) + ctx.Error(http.StatusInternalServerError, "") + return + } + + canCreatePullRequest := perm.CanRead(models.UnitTypePullRequests) + + for _, refFullName := range opts.RefFullNames { + // if user want update other refs (branch or tag), + // should check code write permission because + // this check was delayed. + if !strings.HasPrefix(refFullName, git.PullRequestPrefix) { + if !perm.CanWrite(models.UnitTypeCode) { + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": "User permission denied.", + }) + return + } + + break + } else if repo.IsEmpty { + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": "Can't create pull request for an empty repository.", + }) + return + } else if !canCreatePullRequest { + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": "User permission denied.", + }) + return + } else if opts.IsWiki { + // TODO: maybe can do it ... + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": "not support send pull request to wiki.", + }) + return + } + } + } + protectedTags, err := repo.GetProtectedTags() if err != nil { log.Error("Unable to get protected tags for %-v Error: %v", repo, err) @@ -392,11 +443,35 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { }) return } + } else if git.SupportProcReceive && strings.HasPrefix(refFullName, git.PullRequestPrefix) { + baseBranchName := opts.RefFullNames[i][len(git.PullRequestPrefix):] + + baseBranchExist := false + if gitRepo.IsBranchExist(baseBranchName) { + baseBranchExist = true + } + + if !baseBranchExist { + for p, v := range baseBranchName { + if v == '/' && gitRepo.IsBranchExist(baseBranchName[:p]) && p != len(baseBranchName)-1 { + baseBranchExist = true + break + } + } + } + + if !baseBranchExist { + ctx.JSON(http.StatusForbidden, private.Response{ + Err: fmt.Sprintf("Unexpected ref: %s", refFullName), + }) + return + } } else { log.Error("Unexpected ref: %s", refFullName) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unexpected ref: %s", refFullName), }) + return } } @@ -537,7 +612,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { continue } - pr, err := models.GetUnmergedPullRequest(repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch) + pr, err := models.GetUnmergedPullRequest(repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch, models.PullRequestFlowGithub) if err != nil && !models.IsErrPullRequestNotExist(err) { log.Error("Failed to get active PR in: %-v Branch: %s to: %-v Branch: %s Error: %v", repo, branch, baseRepo, baseRepo.DefaultBranch, err) ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ @@ -574,6 +649,30 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { }) } +// HookProcReceive proc-receive hook +func HookProcReceive(ctx *gitea_context.PrivateContext) { + opts := web.GetForm(ctx).(*private.HookOptions) + if !git.SupportProcReceive { + ctx.Status(http.StatusNotFound) + return + } + + cancel := loadRepositoryAndGitRepoByParams(ctx) + if ctx.Written() { + return + } + defer cancel() + + results := agit.ProcRecive(ctx, opts) + if ctx.Written() { + return + } + + ctx.JSON(http.StatusOK, private.HockProcReceiveResult{ + Results: results, + }) +} + // SetDefaultBranch updates the default branch func SetDefaultBranch(ctx *gitea_context.PrivateContext) { ownerName := ctx.Params(":owner") @@ -618,3 +717,44 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) { } ctx.PlainText(http.StatusOK, []byte("success")) } + +func loadRepositoryAndGitRepoByParams(ctx *gitea_context.PrivateContext) context.CancelFunc { + ownerName := ctx.Params(":owner") + repoName := ctx.Params(":repo") + + repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) + if err != nil { + log.Error("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "Err": fmt.Sprintf("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err), + }) + return nil + } + if repo.OwnerName == "" { + repo.OwnerName = ownerName + } + + gitRepo, err := git.OpenRepository(repo.RepoPath()) + if err != nil { + log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "Err": fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err), + }) + return nil + } + + ctx.Repo = &gitea_context.Repository{ + Repository: repo, + GitRepo: gitRepo, + } + + // We opened it, we should close it + cancel := func() { + // If it's been set to nil then assume someone else has closed it. + if ctx.Repo.GitRepo != nil { + ctx.Repo.GitRepo.Close() + } + } + + return cancel +} |