Restore functionality for early gits (#7775)
* Change tests to make it possible to run TestGit with 1.7.2 * Make merge run on 1.7.2 * Fix tracking and staging branch name problem * Ensure that git 1.7.2 works on tests * ensure that there is no chance for conflicts * Fix-up missing merge issues * Final rm * Ensure LFS filters run on the tests * Do not sign commits from temp repo * Restore tracking fetch change * Apply suggestions from code review * Update modules/repofiles/temp_repo.go
This commit is contained in:
parent
ac3613b791
commit
5e759b60cc
12 changed files with 226 additions and 66 deletions
|
@ -12,7 +12,9 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -37,7 +39,12 @@ func withKeyFile(t *testing.T, keyname string, callback func(string)) {
|
|||
err = ssh.GenKeyPair(keyFile)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = ioutil.WriteFile(path.Join(tmpDir, "ssh"), []byte("#!/bin/bash\n"+
|
||||
"ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\" \"$@\""), 0700)
|
||||
assert.NoError(t, err)
|
||||
|
||||
//Setup ssh wrapper
|
||||
os.Setenv("GIT_SSH", path.Join(tmpDir, "ssh"))
|
||||
os.Setenv("GIT_SSH_COMMAND",
|
||||
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i \""+keyFile+"\"")
|
||||
os.Setenv("GIT_SSH_VARIANT", "ssh")
|
||||
|
@ -54,6 +61,24 @@ func createSSHUrl(gitPath string, u *url.URL) *url.URL {
|
|||
return &u2
|
||||
}
|
||||
|
||||
func allowLFSFilters() []string {
|
||||
// Now here we should explicitly allow lfs filters to run
|
||||
globalArgs := git.GlobalCommandArgs
|
||||
filteredLFSGlobalArgs := make([]string, len(git.GlobalCommandArgs))
|
||||
j := 0
|
||||
for _, arg := range git.GlobalCommandArgs {
|
||||
if strings.Contains(arg, "lfs") {
|
||||
j--
|
||||
} else {
|
||||
filteredLFSGlobalArgs[j] = arg
|
||||
j++
|
||||
}
|
||||
}
|
||||
filteredLFSGlobalArgs = filteredLFSGlobalArgs[:j]
|
||||
git.GlobalCommandArgs = filteredLFSGlobalArgs
|
||||
return globalArgs
|
||||
}
|
||||
|
||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) {
|
||||
prepareTestEnv(t, 1)
|
||||
s := http.Server{
|
||||
|
@ -79,7 +104,9 @@ func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL)) {
|
|||
|
||||
func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
oldGlobals := allowLFSFilters()
|
||||
assert.NoError(t, git.Clone(u.String(), dstLocalPath, git.CloneRepoOptions{}))
|
||||
git.GlobalCommandArgs = oldGlobals
|
||||
assert.True(t, com.IsExist(filepath.Join(dstLocalPath, "README.md")))
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +167,9 @@ func doGitCreateBranch(dstPath, branch string) func(*testing.T) {
|
|||
|
||||
func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
oldGlobals := allowLFSFilters()
|
||||
_, err := git.NewCommand(append([]string{"checkout"}, args...)...).RunInDir(dstPath)
|
||||
git.GlobalCommandArgs = oldGlobals
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +183,9 @@ func doGitMerge(dstPath string, args ...string) func(*testing.T) {
|
|||
|
||||
func doGitPull(dstPath string, args ...string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
oldGlobals := allowLFSFilters()
|
||||
_, err := git.NewCommand(append([]string{"pull"}, args...)...).RunInDir(dstPath)
|
||||
git.GlobalCommandArgs = oldGlobals
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -135,6 +136,11 @@ func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string
|
|||
func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) {
|
||||
t.Run("LFS", func(t *testing.T) {
|
||||
PrintCurrentTest(t)
|
||||
setting.CheckLFSVersion()
|
||||
if !setting.LFS.StartServer {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
prefix := "lfs-data-file-"
|
||||
_, err := git.NewCommand("lfs").AddArguments("install").RunInDir(dstPath)
|
||||
assert.NoError(t, err)
|
||||
|
@ -142,6 +148,21 @@ func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS strin
|
|||
assert.NoError(t, err)
|
||||
err = git.AddChanges(dstPath, false, ".gitattributes")
|
||||
assert.NoError(t, err)
|
||||
oldGlobals := allowLFSFilters()
|
||||
err = git.CommitChanges(dstPath, git.CommitChangesOptions{
|
||||
Committer: &git.Signature{
|
||||
Email: "user2@example.com",
|
||||
Name: "User Two",
|
||||
When: time.Now(),
|
||||
},
|
||||
Author: &git.Signature{
|
||||
Email: "user2@example.com",
|
||||
Name: "User Two",
|
||||
When: time.Now(),
|
||||
},
|
||||
Message: fmt.Sprintf("Testing commit @ %v", time.Now()),
|
||||
})
|
||||
git.GlobalCommandArgs = oldGlobals
|
||||
|
||||
littleLFS, bigLFS = commitAndPushTest(t, dstPath, prefix)
|
||||
|
||||
|
@ -185,21 +206,26 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s
|
|||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Body.Len())
|
||||
|
||||
setting.CheckLFSVersion()
|
||||
if setting.LFS.StartServer {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, littleSize, resp.Body.Len())
|
||||
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
|
||||
}
|
||||
|
||||
if !testing.Short() {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", big))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Body.Len())
|
||||
|
||||
if setting.LFS.StartServer {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", bigLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, bigSize, resp.Body.Len())
|
||||
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -217,19 +243,24 @@ func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS
|
|||
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Length)
|
||||
|
||||
setting.CheckLFSVersion()
|
||||
if setting.LFS.StartServer {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Length)
|
||||
}
|
||||
|
||||
if !testing.Short() {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
|
||||
if setting.LFS.StartServer {
|
||||
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", bigLFS))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -274,6 +305,8 @@ func generateCommitWithNewData(size int, repoPath, email, fullName, prefix strin
|
|||
}
|
||||
|
||||
//Commit
|
||||
// Now here we should explicitly allow lfs filters to run
|
||||
oldGlobals := allowLFSFilters()
|
||||
err = git.AddChanges(repoPath, false, filepath.Base(tmpFile.Name()))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -291,6 +324,7 @@ func generateCommitWithNewData(size int, repoPath, email, fullName, prefix strin
|
|||
},
|
||||
Message: fmt.Sprintf("Testing commit @ %v", time.Now()),
|
||||
})
|
||||
git.GlobalCommandArgs = oldGlobals
|
||||
return filepath.Base(tmpFile.Name()), err
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,11 @@ func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string
|
|||
|
||||
func doLfs(t *testing.T, content *[]byte, expectGzip bool) {
|
||||
prepareTestEnv(t)
|
||||
setting.CheckLFSVersion()
|
||||
if !setting.LFS.StartServer {
|
||||
t.Skip()
|
||||
return
|
||||
}
|
||||
repo, err := models.GetRepositoryByOwnerAndName("user2", "repo1")
|
||||
assert.NoError(t, err)
|
||||
oid := storeObjectInRepo(t, repo.ID, content)
|
||||
|
|
|
@ -1093,7 +1093,7 @@ func CleanUpMigrateInfo(repo *Repository) (*Repository, error) {
|
|||
}
|
||||
}
|
||||
|
||||
_, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath)
|
||||
_, err := git.NewCommand("remote", "rm", "origin").RunInDir(repoPath)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
||||
return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err)
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ func (repo *Repository) AddRemote(name, url string, fetch bool) error {
|
|||
|
||||
// RemoveRemote removes a remote from repository.
|
||||
func (repo *Repository) RemoveRemote(name string) error {
|
||||
_, err := NewCommand("remote", "remove", name).RunInDir(repo.Path)
|
||||
_, err := NewCommand("remote", "rm", name).RunInDir(repo.Path)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mcuadros/go-version"
|
||||
)
|
||||
|
||||
func (repo *Repository) getTree(id SHA1) (*Tree, error) {
|
||||
|
@ -61,6 +64,11 @@ type CommitTreeOpts struct {
|
|||
|
||||
// CommitTree creates a commit from a given tree id for the user with provided message
|
||||
func (repo *Repository) CommitTree(sig *Signature, tree *Tree, opts CommitTreeOpts) (SHA1, error) {
|
||||
binVersion, err := BinVersion()
|
||||
if err != nil {
|
||||
return SHA1{}, err
|
||||
}
|
||||
|
||||
commitTimeStr := time.Now().Format(time.RFC3339)
|
||||
|
||||
// Because this may call hooks we should pass in the environment
|
||||
|
@ -78,20 +86,24 @@ func (repo *Repository) CommitTree(sig *Signature, tree *Tree, opts CommitTreeOp
|
|||
cmd.AddArguments("-p", parent)
|
||||
}
|
||||
|
||||
cmd.AddArguments("-m", opts.Message)
|
||||
messageBytes := new(bytes.Buffer)
|
||||
_, _ = messageBytes.WriteString(opts.Message)
|
||||
_, _ = messageBytes.WriteString("\n")
|
||||
|
||||
if opts.KeyID != "" {
|
||||
cmd.AddArguments(fmt.Sprintf("-S%s", opts.KeyID))
|
||||
}
|
||||
|
||||
if opts.NoGPGSign {
|
||||
if version.Compare(binVersion, "2.0.0", ">=") && opts.NoGPGSign {
|
||||
cmd.AddArguments("--no-gpg-sign")
|
||||
}
|
||||
|
||||
res, err := cmd.RunInDirWithEnv(repo.Path, env)
|
||||
stdout := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
err = cmd.RunInDirTimeoutEnvFullPipeline(env, -1, repo.Path, stdout, stderr, messageBytes)
|
||||
|
||||
if err != nil {
|
||||
return SHA1{}, err
|
||||
return SHA1{}, concatenateError(err, stderr.String())
|
||||
}
|
||||
return NewIDFromString(strings.TrimSpace(res))
|
||||
return NewIDFromString(strings.TrimSpace(stdout.String()))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -9,6 +10,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -93,6 +95,14 @@ func (pm *Manager) ExecDir(timeout time.Duration, dir, desc, cmdName string, arg
|
|||
// Returns its complete stdout and stderr
|
||||
// outputs and an error, if any (including timeout)
|
||||
func (pm *Manager) ExecDirEnv(timeout time.Duration, dir, desc string, env []string, cmdName string, args ...string) (string, string, error) {
|
||||
return pm.ExecDirEnvStdIn(timeout, dir, desc, env, nil, cmdName, args...)
|
||||
}
|
||||
|
||||
// ExecDirEnvStdIn runs a command in given path and environment variables with provided stdIN, and waits for its completion
|
||||
// up to the given timeout (or DefaultTimeout if -1 is given).
|
||||
// Returns its complete stdout and stderr
|
||||
// outputs and an error, if any (including timeout)
|
||||
func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env []string, stdIn io.Reader, cmdName string, args ...string) (string, string, error) {
|
||||
if timeout == -1 {
|
||||
timeout = 60 * time.Second
|
||||
}
|
||||
|
@ -108,6 +118,10 @@ func (pm *Manager) ExecDirEnv(timeout time.Duration, dir, desc string, env []str
|
|||
cmd.Env = env
|
||||
cmd.Stdout = stdOut
|
||||
cmd.Stderr = stdErr
|
||||
if stdIn != nil {
|
||||
cmd.Stdin = stdIn
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ import (
|
|||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
|
||||
"github.com/mcuadros/go-version"
|
||||
)
|
||||
|
||||
// TemporaryUploadRepository is a type to wrap our upload repositories as a shallow clone
|
||||
|
@ -254,6 +256,11 @@ func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, t
|
|||
authorSig := author.NewGitSig()
|
||||
committerSig := committer.NewGitSig()
|
||||
|
||||
binVersion, err := git.BinVersion()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Unable to get git version: %v", err)
|
||||
}
|
||||
|
||||
// FIXME: Should we add SSH_ORIGINAL_COMMAND to this
|
||||
// Because this may call hooks we should pass in the environment
|
||||
env := append(os.Environ(),
|
||||
|
@ -264,11 +271,21 @@ func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, t
|
|||
"GIT_COMMITTER_EMAIL="+committerSig.Email,
|
||||
"GIT_COMMITTER_DATE="+commitTimeStr,
|
||||
)
|
||||
commitHash, stderr, err := process.GetManager().ExecDirEnv(5*time.Minute,
|
||||
messageBytes := new(bytes.Buffer)
|
||||
_, _ = messageBytes.WriteString(message)
|
||||
_, _ = messageBytes.WriteString("\n")
|
||||
|
||||
args := []string{"commit-tree", treeHash, "-p", "HEAD"}
|
||||
if version.Compare(binVersion, "2.0.0", ">=") {
|
||||
args = append(args, "--no-gpg-sign")
|
||||
}
|
||||
|
||||
commitHash, stderr, err := process.GetManager().ExecDirEnvStdIn(5*time.Minute,
|
||||
t.basePath,
|
||||
fmt.Sprintf("commitTree (git commit-tree): %s", t.basePath),
|
||||
env,
|
||||
git.GitExecutable, "commit-tree", treeHash, "-p", "HEAD", "-m", message)
|
||||
messageBytes,
|
||||
git.GitExecutable, args...)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("git commit-tree: %s", stderr)
|
||||
}
|
||||
|
@ -328,6 +345,12 @@ func (t *TemporaryUploadRepository) DiffIndex() (diff *gitdiff.Diff, err error)
|
|||
|
||||
// CheckAttribute checks the given attribute of the provided files
|
||||
func (t *TemporaryUploadRepository) CheckAttribute(attribute string, args ...string) (map[string]map[string]string, error) {
|
||||
binVersion, err := git.BinVersion()
|
||||
if err != nil {
|
||||
log.Error("Error retrieving git version: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stdOut := new(bytes.Buffer)
|
||||
stdErr := new(bytes.Buffer)
|
||||
|
||||
|
@ -335,7 +358,14 @@ func (t *TemporaryUploadRepository) CheckAttribute(attribute string, args ...str
|
|||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
cmdArgs := []string{"check-attr", "-z", attribute, "--cached", "--"}
|
||||
cmdArgs := []string{"check-attr", "-z", attribute}
|
||||
|
||||
// git check-attr --cached first appears in git 1.7.8
|
||||
if version.Compare(binVersion, "1.7.8", ">=") {
|
||||
cmdArgs = append(cmdArgs, "--cached")
|
||||
}
|
||||
cmdArgs = append(cmdArgs, "--")
|
||||
|
||||
for _, arg := range args {
|
||||
if arg != "" {
|
||||
cmdArgs = append(cmdArgs, arg)
|
||||
|
@ -353,7 +383,7 @@ func (t *TemporaryUploadRepository) CheckAttribute(attribute string, args ...str
|
|||
}
|
||||
|
||||
pid := process.GetManager().Add(desc, cmd)
|
||||
err := cmd.Wait()
|
||||
err = cmd.Wait()
|
||||
process.GetManager().Remove(pid)
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -313,12 +313,6 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
|
|||
}
|
||||
}
|
||||
|
||||
// Check there is no way this can return multiple infos
|
||||
filename2attribute2info, err := t.CheckAttribute("filter", treePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
content := opts.Content
|
||||
if bom {
|
||||
content = string(charset.UTF8BOM) + content
|
||||
|
@ -341,7 +335,14 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
|
|||
opts.Content = content
|
||||
var lfsMetaObject *models.LFSMetaObject
|
||||
|
||||
if setting.LFS.StartServer && filename2attribute2info[treePath] != nil && filename2attribute2info[treePath]["filter"] == "lfs" {
|
||||
if setting.LFS.StartServer {
|
||||
// Check there is no way this can return multiple infos
|
||||
filename2attribute2info, err := t.CheckAttribute("filter", treePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if filename2attribute2info[treePath] != nil && filename2attribute2info[treePath]["filter"] == "lfs" {
|
||||
// OK so we are supposed to LFS this data!
|
||||
oid, err := models.GenerateLFSOid(strings.NewReader(opts.Content))
|
||||
if err != nil {
|
||||
|
@ -350,7 +351,7 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
|
|||
lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: int64(len(opts.Content)), RepositoryID: repo.ID}
|
||||
content = lfsMetaObject.Pointer()
|
||||
}
|
||||
|
||||
}
|
||||
// Add the object to the database
|
||||
objectHash, err := t.HashObject(strings.NewReader(content))
|
||||
if err != nil {
|
||||
|
|
|
@ -74,10 +74,13 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
|
|||
infos[i] = uploadInfo{upload: upload}
|
||||
}
|
||||
|
||||
filename2attribute2info, err := t.CheckAttribute("filter", names...)
|
||||
var filename2attribute2info map[string]map[string]string
|
||||
if setting.LFS.StartServer {
|
||||
filename2attribute2info, err = t.CheckAttribute("filter", names...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Copy uploaded files into repository.
|
||||
for i, uploadInfo := range infos {
|
||||
|
@ -88,7 +91,7 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
|
|||
defer file.Close()
|
||||
|
||||
var objectHash string
|
||||
if filename2attribute2info[uploadInfo.upload.Name] != nil && filename2attribute2info[uploadInfo.upload.Name]["filter"] == "lfs" {
|
||||
if setting.LFS.StartServer && filename2attribute2info[uploadInfo.upload.Name] != nil && filename2attribute2info[uploadInfo.upload.Name]["filter"] == "lfs" {
|
||||
// Handle LFS
|
||||
// FIXME: Inefficient! this should probably happen in models.Upload
|
||||
oid, err := models.GenerateLFSOid(file)
|
||||
|
|
|
@ -91,7 +91,7 @@ func AddressNoCredentials(m *models.Mirror) string {
|
|||
func SaveAddress(m *models.Mirror, addr string) error {
|
||||
repoPath := m.Repo.RepoPath()
|
||||
// Remove old origin
|
||||
_, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath)
|
||||
_, err := git.NewCommand("remote", "rm", "origin").RunInDir(repoPath)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
@ -22,6 +21,8 @@ import (
|
|||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"github.com/mcuadros/go-version"
|
||||
)
|
||||
|
||||
// Merge merges pull request to base repository.
|
||||
|
@ -66,20 +67,17 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
|||
|
||||
headRepoPath := models.RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
|
||||
|
||||
if err := git.Clone(baseGitRepo.Path, tmpBasePath, git.CloneRepoOptions{
|
||||
Shared: true,
|
||||
NoCheckout: true,
|
||||
Branch: pr.BaseBranch,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("git clone: %v", err)
|
||||
if err := git.InitRepository(tmpBasePath, false); err != nil {
|
||||
return fmt.Errorf("git init: %v", err)
|
||||
}
|
||||
|
||||
remoteRepoName := "head_repo"
|
||||
baseBranch := "base"
|
||||
|
||||
// Add head repo remote.
|
||||
addCacheRepo := func(staging, cache string) error {
|
||||
p := filepath.Join(staging, ".git", "objects", "info", "alternates")
|
||||
f, err := os.OpenFile(p, os.O_APPEND|os.O_WRONLY, 0600)
|
||||
f, err := os.OpenFile(p, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -91,25 +89,41 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
|||
return nil
|
||||
}
|
||||
|
||||
if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil {
|
||||
if err := addCacheRepo(tmpBasePath, baseGitRepo.Path); err != nil {
|
||||
return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err)
|
||||
}
|
||||
|
||||
var errbuf strings.Builder
|
||||
if err := git.NewCommand("remote", "add", "-t", pr.BaseBranch, "-m", pr.BaseBranch, "origin", baseGitRepo.Path).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git remote add [%s -> %s]: %s", baseGitRepo.Path, tmpBasePath, errbuf.String())
|
||||
}
|
||||
|
||||
if err := git.NewCommand("fetch", "origin", "--no-tags", pr.BaseBranch+":"+baseBranch, pr.BaseBranch+":original_"+baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
|
||||
}
|
||||
|
||||
if err := git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git symbolic-ref HEAD base [%s]: %s", tmpBasePath, errbuf.String())
|
||||
}
|
||||
|
||||
if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil {
|
||||
return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err)
|
||||
}
|
||||
|
||||
if err := git.NewCommand("remote", "add", remoteRepoName, headRepoPath).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
|
||||
}
|
||||
|
||||
trackingBranch := "tracking"
|
||||
// Fetch head branch
|
||||
if err := git.NewCommand("fetch", remoteRepoName, fmt.Sprintf("%s:refs/remotes/%s/%s", pr.HeadBranch, remoteRepoName, pr.HeadBranch)).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := git.NewCommand("fetch", "--no-tags", remoteRepoName, pr.HeadBranch+":"+trackingBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
|
||||
}
|
||||
|
||||
trackingBranch := path.Join(remoteRepoName, pr.HeadBranch)
|
||||
stagingBranch := fmt.Sprintf("%s_%s", remoteRepoName, pr.HeadBranch)
|
||||
stagingBranch := "staging"
|
||||
|
||||
// Enable sparse-checkout
|
||||
sparseCheckoutList, err := getDiffTree(tmpBasePath, pr.BaseBranch, trackingBranch)
|
||||
sparseCheckoutList, err := getDiffTree(tmpBasePath, baseBranch, trackingBranch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getDiffTree: %v", err)
|
||||
}
|
||||
|
@ -123,21 +137,37 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
|||
return fmt.Errorf("Writing sparse-checkout file to %s: %v", sparseCheckoutListPath, err)
|
||||
}
|
||||
|
||||
gitConfigCommand := func() func() *git.Command {
|
||||
binVersion, err := git.BinVersion()
|
||||
if err != nil {
|
||||
log.Fatal("Error retrieving git version: %v", err)
|
||||
}
|
||||
|
||||
if version.Compare(binVersion, "1.8.0", ">=") {
|
||||
return func() *git.Command {
|
||||
return git.NewCommand("config", "--local")
|
||||
}
|
||||
}
|
||||
return func() *git.Command {
|
||||
return git.NewCommand("config")
|
||||
}
|
||||
}()
|
||||
|
||||
// Switch off LFS process (set required, clean and smudge here also)
|
||||
if err := git.NewCommand("config", "--local", "filter.lfs.process", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := gitConfigCommand().AddArguments("filter.lfs.process", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git config [filter.lfs.process -> <> ]: %v", errbuf.String())
|
||||
}
|
||||
if err := git.NewCommand("config", "--local", "filter.lfs.required", "false").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := gitConfigCommand().AddArguments("filter.lfs.required", "false").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git config [filter.lfs.required -> <false> ]: %v", errbuf.String())
|
||||
}
|
||||
if err := git.NewCommand("config", "--local", "filter.lfs.clean", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := gitConfigCommand().AddArguments("filter.lfs.clean", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git config [filter.lfs.clean -> <> ]: %v", errbuf.String())
|
||||
}
|
||||
if err := git.NewCommand("config", "--local", "filter.lfs.smudge", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := gitConfigCommand().AddArguments("filter.lfs.smudge", "").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git config [filter.lfs.smudge -> <> ]: %v", errbuf.String())
|
||||
}
|
||||
|
||||
if err := git.NewCommand("config", "--local", "core.sparseCheckout", "true").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := gitConfigCommand().AddArguments("core.sparseCheckout", "true").RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", errbuf.String())
|
||||
}
|
||||
|
||||
|
@ -163,11 +193,11 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
|||
return fmt.Errorf("git checkout: %s", errbuf.String())
|
||||
}
|
||||
// Rebase before merging
|
||||
if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := git.NewCommand("rebase", "-q", baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
|
||||
}
|
||||
// Checkout base branch again
|
||||
if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := git.NewCommand("checkout", baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git checkout: %s", errbuf.String())
|
||||
}
|
||||
// Merge fast forward
|
||||
|
@ -180,11 +210,11 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
|||
return fmt.Errorf("git checkout: %s", errbuf.String())
|
||||
}
|
||||
// Rebase before merging
|
||||
if err := git.NewCommand("rebase", "-q", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := git.NewCommand("rebase", "-q", baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
|
||||
}
|
||||
// Checkout base branch again
|
||||
if err := git.NewCommand("checkout", pr.BaseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := git.NewCommand("checkout", baseBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git checkout: %s", errbuf.String())
|
||||
}
|
||||
// Prepare merge with commit
|
||||
|
@ -216,7 +246,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
|||
if err != nil {
|
||||
return fmt.Errorf("Failed to get full commit id for HEAD: %v", err)
|
||||
}
|
||||
mergeBaseSHA, err := git.GetFullCommitID(tmpBasePath, "origin/"+pr.BaseBranch)
|
||||
mergeBaseSHA, err := git.GetFullCommitID(tmpBasePath, "original_"+baseBranch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get full commit id for origin/%s: %v", pr.BaseBranch, err)
|
||||
}
|
||||
|
@ -249,7 +279,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
|||
)
|
||||
|
||||
// Push back to upstream.
|
||||
if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {
|
||||
if err := git.NewCommand("push", "origin", baseBranch+":"+pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {
|
||||
return fmt.Errorf("git push: %s", errbuf.String())
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue