初始提交: Gitea 项目代码
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pull
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
issues_model "gitea.dev/models/issues"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/git"
|
||||
"gitea.dev/modules/git/gitcmd"
|
||||
"gitea.dev/modules/log"
|
||||
repo_module "gitea.dev/modules/repository"
|
||||
"gitea.dev/modules/setting"
|
||||
)
|
||||
|
||||
// updateHeadByRebaseOnToBase handles updating a PR's head branch by rebasing it on the PR current base branch
|
||||
func updateHeadByRebaseOnToBase(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) error {
|
||||
// "Clone" base repo and add the cache headers for the head repo and branch
|
||||
mergeCtx, cancel, err := createTemporaryRepoForMerge(ctx, pr, doer, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
// Determine the old merge-base before the rebase - we use this for LFS push later on
|
||||
oldMergeBase, _, _ := gitcmd.NewCommand("merge-base").AddDashesAndList(tmpRepoBaseBranch, tmpRepoTrackingBranch).
|
||||
WithDir(mergeCtx.tmpBasePath).RunStdString(ctx)
|
||||
oldMergeBase = strings.TrimSpace(oldMergeBase)
|
||||
|
||||
// Rebase the tracking branch on to the base as the staging branch
|
||||
if err := rebaseTrackingOnToBase(mergeCtx, repo_model.MergeStyleRebaseUpdate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if setting.LFS.StartServer {
|
||||
// Now we need to ensure that the head repository contains any LFS objects between the new base and the old mergebase
|
||||
// It's questionable about where this should go - either after or before the push
|
||||
// I think in the interests of data safety - failures to push to the lfs should prevent
|
||||
// the push as you can always re-rebase.
|
||||
if err := LFSPush(ctx, mergeCtx.tmpBasePath, tmpRepoBaseBranch, oldMergeBase, &issues_model.PullRequest{
|
||||
HeadRepoID: pr.BaseRepoID,
|
||||
BaseRepoID: pr.HeadRepoID,
|
||||
}); err != nil {
|
||||
log.Error("Unable to push lfs objects between %s and %s up to head branch in %-v: %v", tmpRepoBaseBranch, oldMergeBase, pr, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Now determine who the pushing author should be
|
||||
var headUser *user_model.User
|
||||
if err := pr.HeadRepo.LoadOwner(ctx); err != nil {
|
||||
if !user_model.IsErrUserNotExist(err) {
|
||||
log.Error("Can't find user: %d for head repository in %-v - %v", pr.HeadRepo.OwnerID, pr, err)
|
||||
return err
|
||||
}
|
||||
log.Error("Can't find user: %d for head repository in %-v - defaulting to doer: %-v - %v", pr.HeadRepo.OwnerID, pr, doer, err)
|
||||
headUser = doer
|
||||
} else {
|
||||
headUser = pr.HeadRepo.Owner
|
||||
}
|
||||
|
||||
pushCmd := gitcmd.NewCommand("push", "-f", "head_repo").
|
||||
AddDynamicArguments(tmpRepoStagingBranch + ":" + git.BranchPrefix + pr.HeadBranch)
|
||||
|
||||
// Push back to the head repository.
|
||||
// TODO: this cause an api call to "/api/internal/hook/post-receive/...",
|
||||
// that prevents us from doint the whole merge in one db transaction
|
||||
mergeCtx.outbuf.Reset()
|
||||
|
||||
if err := pushCmd.
|
||||
WithEnv(repo_module.FullPushingEnvironment(
|
||||
headUser,
|
||||
doer,
|
||||
pr.HeadRepo,
|
||||
pr.HeadRepo.Name,
|
||||
pr.ID,
|
||||
pr.Index,
|
||||
)).
|
||||
WithDir(mergeCtx.tmpBasePath).
|
||||
WithStdoutBuffer(mergeCtx.outbuf).
|
||||
RunWithStderr(ctx); err != nil {
|
||||
if strings.Contains(err.Stderr(), "non-fast-forward") {
|
||||
return &git.ErrPushOutOfDate{
|
||||
StdOut: mergeCtx.outbuf.String(),
|
||||
StdErr: err.Stderr(),
|
||||
Err: err,
|
||||
}
|
||||
} else if strings.Contains(err.Stderr(), "! [remote rejected]") {
|
||||
err := &git.ErrPushRejected{
|
||||
StdOut: mergeCtx.outbuf.String(),
|
||||
StdErr: err.Stderr(),
|
||||
Err: err,
|
||||
}
|
||||
err.GenerateMessage()
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("git push: %s", err.Stderr())
|
||||
}
|
||||
mergeCtx.outbuf.Reset()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user