summaryrefslogtreecommitdiffstats
path: root/integrations/pull_merge_test.go
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2019-11-10 08:42:51 +0000
committerGitHub <noreply@github.com>2019-11-10 08:42:51 +0000
commit8eeb2877d5803d0501815466d651a519b32bbd3a (patch)
treeffd1abc59788797e0d99169b8a88655f51d4128f /integrations/pull_merge_test.go
parent31416a5f4e70d4972c351cde170b59d13fcbb77f (diff)
downloadgitea-8eeb2877d5803d0501815466d651a519b32bbd3a.tar.gz
gitea-8eeb2877d5803d0501815466d651a519b32bbd3a.zip
Adjust error reporting from merge failures and use LC_ALL=C for git (#8548)
There are two major components to this PR: * This PR handles merge and rebase failures from merging a little more nicely with Flash errors rather a 500. * All git commands are run in the LC_ALL="C" environment to ensure that error messages are in English. This DefaultLocale is defined in a way that if necessary (due to platform weirdness) it can be overridden at build time using LDFLAGS="-X "code.gitea.io/gitea/modules/git.DefaultLocale=C"" with C changed for the locale as necessary.
Diffstat (limited to 'integrations/pull_merge_test.go')
-rw-r--r--integrations/pull_merge_test.go137
1 files changed, 137 insertions, 0 deletions
diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go
index 27f9fc6bb9..a63e27e149 100644
--- a/integrations/pull_merge_test.go
+++ b/integrations/pull_merge_test.go
@@ -5,15 +5,22 @@
package integrations
import (
+ "bytes"
+ "fmt"
"net/http"
"net/http/httptest"
"net/url"
+ "os"
"path"
"strings"
"testing"
+ "time"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/git"
+ api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/services/pull"
"github.com/stretchr/testify/assert"
"github.com/unknwon/i18n"
@@ -202,3 +209,133 @@ func TestCantMergeWorkInProgress(t *testing.T) {
assert.Equal(t, replacer.Replace(expected), text, "Unable to find WIP text")
})
}
+
+func TestCantMergeConflict(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ prepareTestEnv(t)
+ session := loginUser(t, "user1")
+ testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
+ testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")
+ testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
+
+ // Use API to create a conflicting pr
+ token := getTokenForLoggedInUser(t, session)
+ req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", "user1", "repo1", token), &api.CreatePullRequestOption{
+ Head: "conflict",
+ Base: "base",
+ Title: "create a conflicting pr",
+ })
+ session.MakeRequest(t, req, 201)
+
+ // Now this PR will be marked conflict - or at least a race will do - so drop down to pure code at this point...
+ user1 := models.AssertExistsAndLoadBean(t, &models.User{
+ Name: "user1",
+ }).(*models.User)
+ repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{
+ OwnerID: user1.ID,
+ Name: "repo1",
+ }).(*models.Repository)
+
+ pr := models.AssertExistsAndLoadBean(t, &models.PullRequest{
+ HeadRepoID: repo1.ID,
+ BaseRepoID: repo1.ID,
+ HeadBranch: "conflict",
+ BaseBranch: "base",
+ }).(*models.PullRequest)
+
+ gitRepo, err := git.OpenRepository(models.RepoPath(user1.Name, repo1.Name))
+ assert.NoError(t, err)
+
+ err = pull.Merge(pr, user1, gitRepo, models.MergeStyleMerge, "CONFLICT")
+ assert.Error(t, err, "Merge should return an error due to conflict")
+ assert.True(t, models.IsErrMergeConflicts(err), "Merge error is not a conflict error")
+
+ err = pull.Merge(pr, user1, gitRepo, models.MergeStyleRebase, "CONFLICT")
+ assert.Error(t, err, "Merge should return an error due to conflict")
+ assert.True(t, models.IsErrRebaseConflicts(err), "Merge error is not a conflict error")
+ })
+}
+
+func TestCantMergeUnrelated(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ prepareTestEnv(t)
+ session := loginUser(t, "user1")
+ testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
+ testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
+
+ // Now we want to create a commit on a branch that is totally unrelated to our current head
+ // Drop down to pure code at this point
+ user1 := models.AssertExistsAndLoadBean(t, &models.User{
+ Name: "user1",
+ }).(*models.User)
+ repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{
+ OwnerID: user1.ID,
+ Name: "repo1",
+ }).(*models.Repository)
+ path := models.RepoPath(user1.Name, repo1.Name)
+
+ _, err := git.NewCommand("read-tree", "--empty").RunInDir(path)
+ assert.NoError(t, err)
+
+ stdin := bytes.NewBufferString("Unrelated File")
+ var stdout strings.Builder
+ err = git.NewCommand("hash-object", "-w", "--stdin").RunInDirFullPipeline(path, &stdout, nil, stdin)
+ assert.NoError(t, err)
+ sha := strings.TrimSpace(stdout.String())
+
+ _, err = git.NewCommand("update-index", "--add", "--replace", "--cacheinfo", "100644", sha, "somewher-over-the-rainbow").RunInDir(path)
+ assert.NoError(t, err)
+
+ treeSha, err := git.NewCommand("write-tree").RunInDir(path)
+ assert.NoError(t, err)
+ treeSha = strings.TrimSpace(treeSha)
+
+ commitTimeStr := time.Now().Format(time.RFC3339)
+ doerSig := user1.NewGitSig()
+ env := append(os.Environ(),
+ "GIT_AUTHOR_NAME="+doerSig.Name,
+ "GIT_AUTHOR_EMAIL="+doerSig.Email,
+ "GIT_AUTHOR_DATE="+commitTimeStr,
+ "GIT_COMMITTER_NAME="+doerSig.Name,
+ "GIT_COMMITTER_EMAIL="+doerSig.Email,
+ "GIT_COMMITTER_DATE="+commitTimeStr,
+ )
+
+ messageBytes := new(bytes.Buffer)
+ _, _ = messageBytes.WriteString("Unrelated")
+ _, _ = messageBytes.WriteString("\n")
+
+ stdout.Reset()
+ err = git.NewCommand("commit-tree", treeSha).RunInDirTimeoutEnvFullPipeline(env, -1, path, &stdout, nil, messageBytes)
+ assert.NoError(t, err)
+ commitSha := strings.TrimSpace(stdout.String())
+
+ _, err = git.NewCommand("branch", "unrelated", commitSha).RunInDir(path)
+ assert.NoError(t, err)
+
+ testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")
+
+ // Use API to create a conflicting pr
+ token := getTokenForLoggedInUser(t, session)
+ req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", "user1", "repo1", token), &api.CreatePullRequestOption{
+ Head: "unrelated",
+ Base: "base",
+ Title: "create an unrelated pr",
+ })
+ session.MakeRequest(t, req, 201)
+
+ // Now this PR could be marked conflict - or at least a race may occur - so drop down to pure code at this point...
+ gitRepo, err := git.OpenRepository(path)
+ assert.NoError(t, err)
+ pr := models.AssertExistsAndLoadBean(t, &models.PullRequest{
+ HeadRepoID: repo1.ID,
+ BaseRepoID: repo1.ID,
+ HeadBranch: "unrelated",
+ BaseBranch: "base",
+ }).(*models.PullRequest)
+
+ err = pull.Merge(pr, user1, gitRepo, models.MergeStyleMerge, "UNRELATED")
+ assert.Error(t, err, "Merge should return an error due to unrelated")
+ assert.True(t, models.IsErrMergeUnrelatedHistories(err), "Merge error is not a unrelated histories error")
+ })
+}