From 6da6ae02b0540897411b19fe5124c18049c17ac4 Mon Sep 17 00:00:00 2001 From: Tulskiy Aleksandr Date: Tue, 19 Dec 2023 22:07:07 +0300 Subject: [PATCH 1/5] Added PR redirection to a new branch if the target branch was deleted as a result of the PR merge --- routers/web/repo/pull.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index ec109ed665c4e..c14233d144fb9 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1305,6 +1305,31 @@ func MergePullRequest(ctx *context.Context) { return } + pullRequestsToHead, err := issues_model.GetUnmergedPullRequestsByBaseInfo(ctx, pr.HeadRepoID, pr.HeadBranch) + if err != nil { + ctx.ServerError("GetUnmergedPullRequestsByBaseInfo", err) + return + } + + for _, prToHead := range pullRequestsToHead { + if prToHead.BaseRepoID != pr.BaseRepoID { + continue + } + + err = prToHead.LoadIssue(ctx) + if err != nil { + ctx.ServerError(fmt.Sprintf("LoadIssueForPullRequest[%d]", prToHead.ID), err) + return + } + prToHead.Issue.Repo = ctx.Repo.Repository + + err = pull_service.ChangeTargetBranch(ctx, prToHead, ctx.Doer, pr.BaseBranch) + if err != nil { + ctx.ServerError(fmt.Sprintf("ChangeTargetBranch[%d]", prToHead.ID), err) + return + } + } + var headRepo *git.Repository if ctx.Repo != nil && ctx.Repo.Repository != nil && pr.HeadRepoID == ctx.Repo.Repository.ID && ctx.Repo.GitRepo != nil { headRepo = ctx.Repo.GitRepo From f1ec56c8bcb855f120cac7f591e389f0663a3c27 Mon Sep 17 00:00:00 2001 From: tulzke <62292054+tulzke@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:35:22 +0300 Subject: [PATCH 2/5] Update routers/web/repo/pull.go Co-authored-by: Denys Konovalov --- routers/web/repo/pull.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index ab79018b70815..6ac06b27825c7 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1324,8 +1324,7 @@ func MergePullRequest(ctx *context.Context) { continue } - err = prToHead.LoadIssue(ctx) - if err != nil { + if err := prToHead.LoadIssue(ctx); err != nil { ctx.ServerError(fmt.Sprintf("LoadIssueForPullRequest[%d]", prToHead.ID), err) return } From 19ffb87a3d4c048303f8efdfac7742bb05c5a694 Mon Sep 17 00:00:00 2001 From: tulzke <62292054+tulzke@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:35:34 +0300 Subject: [PATCH 3/5] Update routers/web/repo/pull.go Co-authored-by: Denys Konovalov --- routers/web/repo/pull.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 6ac06b27825c7..754dfdb728e60 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1330,8 +1330,7 @@ func MergePullRequest(ctx *context.Context) { } prToHead.Issue.Repo = ctx.Repo.Repository - err = pull_service.ChangeTargetBranch(ctx, prToHead, ctx.Doer, pr.BaseBranch) - if err != nil { + if err := pull_service.ChangeTargetBranch(ctx, prToHead, ctx.Doer, pr.BaseBranch); err != nil { ctx.ServerError(fmt.Sprintf("ChangeTargetBranch[%d]", prToHead.ID), err) return } From ce8886923bf17f107432b3a053576e4ea5dd99a2 Mon Sep 17 00:00:00 2001 From: Tulskiy Aleksandr Date: Tue, 2 Jan 2024 21:59:21 +0300 Subject: [PATCH 4/5] Added check of repoID. If repoID is different, LoadRepo is used --- routers/web/repo/pull.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 754dfdb728e60..7111e74ec8a6d 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1328,7 +1328,15 @@ func MergePullRequest(ctx *context.Context) { ctx.ServerError(fmt.Sprintf("LoadIssueForPullRequest[%d]", prToHead.ID), err) return } - prToHead.Issue.Repo = ctx.Repo.Repository + + if prToHead.Issue.RepoID == pr.Issue.RepoID { + prToHead.Issue.Repo = pr.Issue.Repo + } else { + if err := prToHead.Issue.LoadRepo(ctx); err != nil { + ctx.ServerError(fmt.Sprintf("LoadRepoForIssue[%d]", prToHead.IssueID), err) + return + } + } if err := pull_service.ChangeTargetBranch(ctx, prToHead, ctx.Doer, pr.BaseBranch); err != nil { ctx.ServerError(fmt.Sprintf("ChangeTargetBranch[%d]", prToHead.ID), err) From 9e4e6abb3adf0b930c6a4d443ea9cc8647993415 Mon Sep 17 00:00:00 2001 From: Tulskiy Aleksandr Date: Tue, 9 Jan 2024 13:22:26 +0300 Subject: [PATCH 5/5] The logic has been moved to the new function RedirectOpenPullsToBaseBranch. Added function call to api/v1 --- routers/api/v1/repo/pull.go | 5 +++++ routers/web/repo/pull.go | 30 ++---------------------------- services/pull/pull.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index d6b9dddd9d7ba..6ac1af69d0865 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -902,6 +902,11 @@ func MergePullRequest(ctx *context.APIContext) { return } + if err := pull_service.RedirectOpenPullsToBaseBranch(ctx, pr, ctx.Doer); err != nil { + ctx.ServerError("RedirectOpenPulls", err) + return + } + var headRepo *git.Repository if ctx.Repo != nil && ctx.Repo.Repository != nil && ctx.Repo.Repository.ID == pr.HeadRepoID && ctx.Repo.GitRepo != nil { headRepo = ctx.Repo.GitRepo diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 7111e74ec8a6d..b23c123817e40 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1313,37 +1313,11 @@ func MergePullRequest(ctx *context.Context) { return } - pullRequestsToHead, err := issues_model.GetUnmergedPullRequestsByBaseInfo(ctx, pr.HeadRepoID, pr.HeadBranch) - if err != nil { - ctx.ServerError("GetUnmergedPullRequestsByBaseInfo", err) + if err := pull_service.RedirectOpenPullsToBaseBranch(ctx, pr, ctx.Doer); err != nil { + ctx.ServerError("RedirectOpenPulls", err) return } - for _, prToHead := range pullRequestsToHead { - if prToHead.BaseRepoID != pr.BaseRepoID { - continue - } - - if err := prToHead.LoadIssue(ctx); err != nil { - ctx.ServerError(fmt.Sprintf("LoadIssueForPullRequest[%d]", prToHead.ID), err) - return - } - - if prToHead.Issue.RepoID == pr.Issue.RepoID { - prToHead.Issue.Repo = pr.Issue.Repo - } else { - if err := prToHead.Issue.LoadRepo(ctx); err != nil { - ctx.ServerError(fmt.Sprintf("LoadRepoForIssue[%d]", prToHead.IssueID), err) - return - } - } - - if err := pull_service.ChangeTargetBranch(ctx, prToHead, ctx.Doer, pr.BaseBranch); err != nil { - ctx.ServerError(fmt.Sprintf("ChangeTargetBranch[%d]", prToHead.ID), err) - return - } - } - var headRepo *git.Repository if ctx.Repo != nil && ctx.Repo.Repository != nil && pr.HeadRepoID == ctx.Repo.Repository.ID && ctx.Repo.GitRepo != nil { headRepo = ctx.Repo.GitRepo diff --git a/services/pull/pull.go b/services/pull/pull.go index 6094a4ed31b9e..d63d774cce0cf 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -953,3 +953,36 @@ func GetPullCommits(ctx *gitea_context.Context, issue *issues_model.Issue) ([]Co return commits, lastReviewCommitID, nil } + +// RedirectOpenPullsToBaseBranch redirects open pull requests to base branch of specified PR +func RedirectOpenPullsToBaseBranch(ctx context.Context, basePR *issues_model.PullRequest, doer *user_model.User) error { + pullRequestsToHead, err := issues_model.GetUnmergedPullRequestsByBaseInfo(ctx, basePR.HeadRepoID, basePR.HeadBranch) + if err != nil { + return fmt.Errorf("failed to get unmerged pull requests: %w", err) + } + + if err := issues_model.PullRequestList(pullRequestsToHead).LoadAttributes(ctx); err != nil { + return fmt.Errorf("failed to load attributes for pull requests: %w", err) + } + + for _, prToHead := range pullRequestsToHead { + if prToHead.BaseRepoID != basePR.BaseRepoID { + continue + } + + if prToHead.Issue.RepoID == basePR.Issue.RepoID { + prToHead.Issue.Repo = basePR.Issue.Repo + } else { + if err := prToHead.Issue.LoadRepo(ctx); err != nil { + return fmt.Errorf("failed to load repo for issue [%d]: %w", prToHead.IssueID, err) + } + } + + if err := ChangeTargetBranch(ctx, prToHead, doer, basePR.BaseBranch); err != nil && + !issues_model.IsErrPullRequestAlreadyExists(err) { + return fmt.Errorf("failed to change target branch for PR [%d]: %w", prToHead.ID, err) + } + } + + return nil +}