mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Kd/ci playwright go test (#20123)
* Add initial playwright config * Simplify Makefile * Simplify Makefile * Use correct config files * Update playwright settings * Fix package-lock file * Don't use test logger for e2e tests * fix frontend lint * Allow passing TEST_LOGGER variable * Init postgres database * use standard gitea env variables * Update playwright * update drone * Move empty env var to commands * Cleanup * Move integrations to subfolder * tests integrations to tests integraton * Run e2e tests with go test * Fix linting * install CI deps * Add files to ESlint * Fix drone typo * Don't log to console in CI * Use go test http server * Add build step before tests * Move shared init function to common package * fix drone * Clean up tests * Fix linting * Better mocking for page + version string * Cleanup test generation * Remove dependency on gitea binary * Fix linting * add initial support for running specific tests * Add ACCEPT_VISUAL variable * don't require git-lfs * Add initial documentation * Review feedback * Add logged in session test * Attempt fixing drone race * Cleanup and bump version * Bump deps * Review feedback * simplify installation * Fix ci * Update install docs
This commit is contained in:
		
							
								
								
									
										851
									
								
								tests/integration/git_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										851
									
								
								tests/integration/git_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,851 @@ | ||||
| // Copyright 2017 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. | ||||
|  | ||||
| package integration | ||||
|  | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"math/rand" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"code.gitea.io/gitea/models/db" | ||||
| 	issues_model "code.gitea.io/gitea/models/issues" | ||||
| 	"code.gitea.io/gitea/models/perm" | ||||
| 	repo_model "code.gitea.io/gitea/models/repo" | ||||
| 	"code.gitea.io/gitea/models/unittest" | ||||
| 	user_model "code.gitea.io/gitea/models/user" | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	"code.gitea.io/gitea/modules/lfs" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	api "code.gitea.io/gitea/modules/structs" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| 	"code.gitea.io/gitea/tests" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	littleSize = 1024              // 1ko | ||||
| 	bigSize    = 128 * 1024 * 1024 // 128Mo | ||||
| ) | ||||
|  | ||||
| func TestGit(t *testing.T) { | ||||
| 	onGiteaRun(t, testGit) | ||||
| } | ||||
|  | ||||
| func testGit(t *testing.T, u *url.URL) { | ||||
| 	username := "user2" | ||||
| 	baseAPITestContext := NewAPITestContext(t, username, "repo1") | ||||
|  | ||||
| 	u.Path = baseAPITestContext.GitPath() | ||||
|  | ||||
| 	forkedUserCtx := NewAPITestContext(t, "user4", "repo1") | ||||
|  | ||||
| 	t.Run("HTTP", func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		ensureAnonymousClone(t, u) | ||||
| 		httpContext := baseAPITestContext | ||||
| 		httpContext.Reponame = "repo-tmp-17" | ||||
| 		forkedUserCtx.Reponame = httpContext.Reponame | ||||
|  | ||||
| 		dstPath, err := os.MkdirTemp("", httpContext.Reponame) | ||||
| 		assert.NoError(t, err) | ||||
| 		defer util.RemoveAll(dstPath) | ||||
|  | ||||
| 		t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, false)) | ||||
| 		t.Run("AddUserAsCollaborator", doAPIAddCollaborator(forkedUserCtx, httpContext.Username, perm.AccessModeRead)) | ||||
|  | ||||
| 		t.Run("ForkFromDifferentUser", doAPIForkRepository(httpContext, forkedUserCtx.Username)) | ||||
|  | ||||
| 		u.Path = httpContext.GitPath() | ||||
| 		u.User = url.UserPassword(username, userPassword) | ||||
|  | ||||
| 		t.Run("Clone", doGitClone(dstPath, u)) | ||||
|  | ||||
| 		dstPath2, err := os.MkdirTemp("", httpContext.Reponame) | ||||
| 		assert.NoError(t, err) | ||||
| 		defer util.RemoveAll(dstPath2) | ||||
|  | ||||
| 		t.Run("Partial Clone", doPartialGitClone(dstPath2, u)) | ||||
|  | ||||
| 		little, big := standardCommitAndPushTest(t, dstPath) | ||||
| 		littleLFS, bigLFS := lfsCommitAndPushTest(t, dstPath) | ||||
| 		rawTest(t, &httpContext, little, big, littleLFS, bigLFS) | ||||
| 		mediaTest(t, &httpContext, little, big, littleLFS, bigLFS) | ||||
|  | ||||
| 		t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &httpContext, "master", "test/head")) | ||||
| 		t.Run("BranchProtectMerge", doBranchProtectPRMerge(&httpContext, dstPath)) | ||||
| 		t.Run("AutoMerge", doAutoPRMerge(&httpContext, dstPath)) | ||||
| 		t.Run("CreatePRAndSetManuallyMerged", doCreatePRAndSetManuallyMerged(httpContext, httpContext, dstPath, "master", "test-manually-merge")) | ||||
| 		t.Run("MergeFork", func(t *testing.T) { | ||||
| 			defer tests.PrintCurrentTest(t)() | ||||
| 			t.Run("CreatePRAndMerge", doMergeFork(httpContext, forkedUserCtx, "master", httpContext.Username+":master")) | ||||
| 			rawTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS) | ||||
| 			mediaTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS) | ||||
| 		}) | ||||
|  | ||||
| 		t.Run("PushCreate", doPushCreate(httpContext, u)) | ||||
| 	}) | ||||
| 	t.Run("SSH", func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		sshContext := baseAPITestContext | ||||
| 		sshContext.Reponame = "repo-tmp-18" | ||||
| 		keyname := "my-testing-key" | ||||
| 		forkedUserCtx.Reponame = sshContext.Reponame | ||||
| 		t.Run("CreateRepoInDifferentUser", doAPICreateRepository(forkedUserCtx, false)) | ||||
| 		t.Run("AddUserAsCollaborator", doAPIAddCollaborator(forkedUserCtx, sshContext.Username, perm.AccessModeRead)) | ||||
| 		t.Run("ForkFromDifferentUser", doAPIForkRepository(sshContext, forkedUserCtx.Username)) | ||||
|  | ||||
| 		// Setup key the user ssh key | ||||
| 		withKeyFile(t, keyname, func(keyFile string) { | ||||
| 			t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile)) | ||||
|  | ||||
| 			// Setup remote link | ||||
| 			// TODO: get url from api | ||||
| 			sshURL := createSSHUrl(sshContext.GitPath(), u) | ||||
|  | ||||
| 			// Setup clone folder | ||||
| 			dstPath, err := os.MkdirTemp("", sshContext.Reponame) | ||||
| 			assert.NoError(t, err) | ||||
| 			defer util.RemoveAll(dstPath) | ||||
|  | ||||
| 			t.Run("Clone", doGitClone(dstPath, sshURL)) | ||||
|  | ||||
| 			little, big := standardCommitAndPushTest(t, dstPath) | ||||
| 			littleLFS, bigLFS := lfsCommitAndPushTest(t, dstPath) | ||||
| 			rawTest(t, &sshContext, little, big, littleLFS, bigLFS) | ||||
| 			mediaTest(t, &sshContext, little, big, littleLFS, bigLFS) | ||||
|  | ||||
| 			t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &sshContext, "master", "test/head2")) | ||||
| 			t.Run("BranchProtectMerge", doBranchProtectPRMerge(&sshContext, dstPath)) | ||||
| 			t.Run("MergeFork", func(t *testing.T) { | ||||
| 				defer tests.PrintCurrentTest(t)() | ||||
| 				t.Run("CreatePRAndMerge", doMergeFork(sshContext, forkedUserCtx, "master", sshContext.Username+":master")) | ||||
| 				rawTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS) | ||||
| 				mediaTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS) | ||||
| 			}) | ||||
|  | ||||
| 			t.Run("PushCreate", doPushCreate(sshContext, sshURL)) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func ensureAnonymousClone(t *testing.T, u *url.URL) { | ||||
| 	dstLocalPath, err := os.MkdirTemp("", "repo1") | ||||
| 	assert.NoError(t, err) | ||||
| 	defer util.RemoveAll(dstLocalPath) | ||||
| 	t.Run("CloneAnonymous", doGitClone(dstLocalPath, u)) | ||||
| } | ||||
|  | ||||
| func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string) { | ||||
| 	t.Run("Standard", func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		little, big = commitAndPushTest(t, dstPath, "data-file-") | ||||
| 	}) | ||||
| 	return little, big | ||||
| } | ||||
|  | ||||
| func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) { | ||||
| 	t.Run("LFS", func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		prefix := "lfs-data-file-" | ||||
| 		err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath}) | ||||
| 		assert.NoError(t, err) | ||||
| 		_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track", prefix+"*").RunStdString(&git.RunOpts{Dir: dstPath}) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = git.AddChanges(dstPath, false, ".gitattributes") | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		err = git.CommitChangesWithArgs(dstPath, git.AllowLFSFiltersArgs(), 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()), | ||||
| 		}) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		littleLFS, bigLFS = commitAndPushTest(t, dstPath, prefix) | ||||
|  | ||||
| 		t.Run("Locks", func(t *testing.T) { | ||||
| 			defer tests.PrintCurrentTest(t)() | ||||
| 			lockTest(t, dstPath) | ||||
| 		}) | ||||
| 	}) | ||||
| 	return littleLFS, bigLFS | ||||
| } | ||||
|  | ||||
| func commitAndPushTest(t *testing.T, dstPath, prefix string) (little, big string) { | ||||
| 	t.Run("PushCommit", func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		t.Run("Little", func(t *testing.T) { | ||||
| 			defer tests.PrintCurrentTest(t)() | ||||
| 			little = doCommitAndPush(t, littleSize, dstPath, prefix) | ||||
| 		}) | ||||
| 		t.Run("Big", func(t *testing.T) { | ||||
| 			if testing.Short() { | ||||
| 				t.Skip("Skipping test in short mode.") | ||||
| 				return | ||||
| 			} | ||||
| 			defer tests.PrintCurrentTest(t)() | ||||
| 			big = doCommitAndPush(t, bigSize, dstPath, prefix) | ||||
| 		}) | ||||
| 	}) | ||||
| 	return little, big | ||||
| } | ||||
|  | ||||
| func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS string) { | ||||
| 	t.Run("Raw", func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		username := ctx.Username | ||||
| 		reponame := ctx.Reponame | ||||
|  | ||||
| 		session := loginUser(t, username) | ||||
|  | ||||
| 		// Request raw paths | ||||
| 		req := NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", little)) | ||||
| 		resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) | ||||
| 		assert.Equal(t, littleSize, resp.Length) | ||||
|  | ||||
| 		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.LessOrEqual(t, resp.Body.Len(), 1024) | ||||
| 			if resp.Body.Len() != littleSize && resp.Body.Len() <= 1024 { | ||||
| 				assert.Contains(t, resp.Body.String(), lfs.MetaFileIdentifier) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if !testing.Short() { | ||||
| 			req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/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, "/raw/branch/master/", bigLFS)) | ||||
| 				resp := session.MakeRequest(t, req, http.StatusOK) | ||||
| 				assert.NotEqual(t, bigSize, resp.Body.Len()) | ||||
| 				if resp.Body.Len() != bigSize && resp.Body.Len() <= 1024 { | ||||
| 					assert.Contains(t, resp.Body.String(), lfs.MetaFileIdentifier) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS string) { | ||||
| 	t.Run("Media", func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
|  | ||||
| 		username := ctx.Username | ||||
| 		reponame := ctx.Reponame | ||||
|  | ||||
| 		session := loginUser(t, username) | ||||
|  | ||||
| 		// Request media paths | ||||
| 		req := NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", little)) | ||||
| 		resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) | ||||
| 		assert.Equal(t, littleSize, resp.Length) | ||||
|  | ||||
| 		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) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func lockTest(t *testing.T, repoPath string) { | ||||
| 	lockFileTest(t, "README.md", repoPath) | ||||
| } | ||||
|  | ||||
| func lockFileTest(t *testing.T, filename, repoPath string) { | ||||
| 	_, _, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath}) | ||||
| 	assert.NoError(t, err) | ||||
| 	_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock", filename).RunStdString(&git.RunOpts{Dir: repoPath}) | ||||
| 	assert.NoError(t, err) | ||||
| 	_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath}) | ||||
| 	assert.NoError(t, err) | ||||
| 	_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock", filename).RunStdString(&git.RunOpts{Dir: repoPath}) | ||||
| 	assert.NoError(t, err) | ||||
| } | ||||
|  | ||||
| func doCommitAndPush(t *testing.T, size int, repoPath, prefix string) string { | ||||
| 	name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two", prefix) | ||||
| 	assert.NoError(t, err) | ||||
| 	_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunStdString(&git.RunOpts{Dir: repoPath}) // Push | ||||
| 	assert.NoError(t, err) | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| func generateCommitWithNewData(size int, repoPath, email, fullName, prefix string) (string, error) { | ||||
| 	// Generate random file | ||||
| 	bufSize := 4 * 1024 | ||||
| 	if bufSize > size { | ||||
| 		bufSize = size | ||||
| 	} | ||||
|  | ||||
| 	buffer := make([]byte, bufSize) | ||||
|  | ||||
| 	tmpFile, err := os.CreateTemp(repoPath, prefix) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	defer tmpFile.Close() | ||||
| 	written := 0 | ||||
| 	for written < size { | ||||
| 		n := size - written | ||||
| 		if n > bufSize { | ||||
| 			n = bufSize | ||||
| 		} | ||||
| 		_, err := rand.Read(buffer[:n]) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		n, err = tmpFile.Write(buffer[:n]) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		written += n | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	// Commit | ||||
| 	// Now here we should explicitly allow lfs filters to run | ||||
| 	globalArgs := git.AllowLFSFiltersArgs() | ||||
| 	err = git.AddChangesWithArgs(repoPath, globalArgs, false, filepath.Base(tmpFile.Name())) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	err = git.CommitChangesWithArgs(repoPath, globalArgs, git.CommitChangesOptions{ | ||||
| 		Committer: &git.Signature{ | ||||
| 			Email: email, | ||||
| 			Name:  fullName, | ||||
| 			When:  time.Now(), | ||||
| 		}, | ||||
| 		Author: &git.Signature{ | ||||
| 			Email: email, | ||||
| 			Name:  fullName, | ||||
| 			When:  time.Now(), | ||||
| 		}, | ||||
| 		Message: fmt.Sprintf("Testing commit @ %v", time.Now()), | ||||
| 	}) | ||||
| 	return filepath.Base(tmpFile.Name()), err | ||||
| } | ||||
|  | ||||
| func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		t.Run("CreateBranchProtected", doGitCreateBranch(dstPath, "protected")) | ||||
| 		t.Run("PushProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected")) | ||||
|  | ||||
| 		ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame) | ||||
| 		t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", "", "")) | ||||
| 		t.Run("GenerateCommit", func(t *testing.T) { | ||||
| 			_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-") | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 		t.Run("FailToPushToProtectedBranch", doGitPushTestRepositoryFail(dstPath, "origin", "protected")) | ||||
| 		t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected")) | ||||
| 		var pr api.PullRequest | ||||
| 		var err error | ||||
| 		t.Run("CreatePullRequest", func(t *testing.T) { | ||||
| 			pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, "protected", "unprotected")(t) | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 		t.Run("GenerateCommit", func(t *testing.T) { | ||||
| 			_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-") | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 		t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected-2")) | ||||
| 		var pr2 api.PullRequest | ||||
| 		t.Run("CreatePullRequest", func(t *testing.T) { | ||||
| 			pr2, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, "unprotected", "unprotected-2")(t) | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 		t.Run("MergePR2", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr2.Index)) | ||||
| 		t.Run("MergePR", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) | ||||
| 		t.Run("PullProtected", doGitPull(dstPath, "origin", "protected")) | ||||
|  | ||||
| 		t.Run("ProtectProtectedBranchUnprotectedFilePaths", doProtectBranch(ctx, "protected", "", "unprotected-file-*")) | ||||
| 		t.Run("GenerateCommit", func(t *testing.T) { | ||||
| 			_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "unprotected-file-") | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 		t.Run("PushUnprotectedFilesToProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected")) | ||||
|  | ||||
| 		t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username, "")) | ||||
|  | ||||
| 		t.Run("CheckoutMaster", doGitCheckoutBranch(dstPath, "master")) | ||||
| 		t.Run("CreateBranchForced", doGitCreateBranch(dstPath, "toforce")) | ||||
| 		t.Run("GenerateCommit", func(t *testing.T) { | ||||
| 			_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-") | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 		t.Run("FailToForcePushToProtectedBranch", doGitPushTestRepositoryFail(dstPath, "-f", "origin", "toforce:protected")) | ||||
| 		t.Run("MergeProtectedToToforce", doGitMerge(dstPath, "protected")) | ||||
| 		t.Run("PushToProtectedBranch", doGitPushTestRepository(dstPath, "origin", "toforce:protected")) | ||||
| 		t.Run("CheckoutMasterAgain", doGitCheckoutBranch(dstPath, "master")) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doProtectBranch(ctx APITestContext, branch, userToWhitelist, unprotectedFilePatterns string) func(t *testing.T) { | ||||
| 	// We are going to just use the owner to set the protection. | ||||
| 	return func(t *testing.T) { | ||||
| 		csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/settings/branches", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame))) | ||||
|  | ||||
| 		if userToWhitelist == "" { | ||||
| 			// Change branch to protected | ||||
| 			req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{ | ||||
| 				"_csrf":                     csrf, | ||||
| 				"protected":                 "on", | ||||
| 				"unprotected_file_patterns": unprotectedFilePatterns, | ||||
| 			}) | ||||
| 			ctx.Session.MakeRequest(t, req, http.StatusSeeOther) | ||||
| 		} else { | ||||
| 			user, err := user_model.GetUserByName(db.DefaultContext, userToWhitelist) | ||||
| 			assert.NoError(t, err) | ||||
| 			// Change branch to protected | ||||
| 			req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{ | ||||
| 				"_csrf":                     csrf, | ||||
| 				"protected":                 "on", | ||||
| 				"enable_push":               "whitelist", | ||||
| 				"enable_whitelist":          "on", | ||||
| 				"whitelist_users":           strconv.FormatInt(user.ID, 10), | ||||
| 				"unprotected_file_patterns": unprotectedFilePatterns, | ||||
| 			}) | ||||
| 			ctx.Session.MakeRequest(t, req, http.StatusSeeOther) | ||||
| 		} | ||||
| 		// Check if master branch has been locked successfully | ||||
| 		flashCookie := ctx.Session.GetCookie("macaron_flash") | ||||
| 		assert.NotNil(t, flashCookie) | ||||
| 		assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527"+url.QueryEscape(branch)+"%2527%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doMergeFork(ctx, baseCtx APITestContext, baseBranch, headBranch string) func(t *testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		var pr api.PullRequest | ||||
| 		var err error | ||||
|  | ||||
| 		// Create a test pullrequest | ||||
| 		t.Run("CreatePullRequest", func(t *testing.T) { | ||||
| 			pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, baseBranch, headBranch)(t) | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
|  | ||||
| 		// Ensure the PR page works | ||||
| 		t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr)) | ||||
|  | ||||
| 		// Then get the diff string | ||||
| 		var diffHash string | ||||
| 		var diffLength int | ||||
| 		t.Run("GetDiff", func(t *testing.T) { | ||||
| 			req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index)) | ||||
| 			resp := ctx.Session.MakeRequestNilResponseHashSumRecorder(t, req, http.StatusOK) | ||||
| 			diffHash = string(resp.Hash.Sum(nil)) | ||||
| 			diffLength = resp.Length | ||||
| 		}) | ||||
|  | ||||
| 		// Now: Merge the PR & make sure that doesn't break the PR page or change its diff | ||||
| 		t.Run("MergePR", doAPIMergePullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)) | ||||
| 		t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr)) | ||||
| 		t.Run("CheckPR", func(t *testing.T) { | ||||
| 			oldMergeBase := pr.MergeBase | ||||
| 			pr2, err := doAPIGetPullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, oldMergeBase, pr2.MergeBase) | ||||
| 		}) | ||||
| 		t.Run("EnsurDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength)) | ||||
|  | ||||
| 		// Then: Delete the head branch & make sure that doesn't break the PR page or change its diff | ||||
| 		t.Run("DeleteHeadBranch", doBranchDelete(baseCtx, baseCtx.Username, baseCtx.Reponame, headBranch)) | ||||
| 		t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr)) | ||||
| 		t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength)) | ||||
|  | ||||
| 		// Delete the head repository & make sure that doesn't break the PR page or change its diff | ||||
| 		t.Run("DeleteHeadRepository", doAPIDeleteRepository(ctx)) | ||||
| 		t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr)) | ||||
| 		t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doCreatePRAndSetManuallyMerged(ctx, baseCtx APITestContext, dstPath, baseBranch, headBranch string) func(t *testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
| 		var ( | ||||
| 			pr           api.PullRequest | ||||
| 			err          error | ||||
| 			lastCommitID string | ||||
| 		) | ||||
|  | ||||
| 		trueBool := true | ||||
| 		falseBool := false | ||||
|  | ||||
| 		t.Run("AllowSetManuallyMergedAndSwitchOffAutodetectManualMerge", doAPIEditRepository(baseCtx, &api.EditRepoOption{ | ||||
| 			HasPullRequests:       &trueBool, | ||||
| 			AllowManualMerge:      &trueBool, | ||||
| 			AutodetectManualMerge: &falseBool, | ||||
| 		})) | ||||
|  | ||||
| 		t.Run("CreateHeadBranch", doGitCreateBranch(dstPath, headBranch)) | ||||
| 		t.Run("PushToHeadBranch", doGitPushTestRepository(dstPath, "origin", headBranch)) | ||||
| 		t.Run("CreateEmptyPullRequest", func(t *testing.T) { | ||||
| 			pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, baseBranch, headBranch)(t) | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 		lastCommitID = pr.Base.Sha | ||||
| 		t.Run("ManuallyMergePR", doAPIManuallyMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, lastCommitID, pr.Index)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doEnsureCanSeePull(ctx APITestContext, pr api.PullRequest) func(t *testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index)) | ||||
| 		ctx.Session.MakeRequest(t, req, http.StatusOK) | ||||
| 		req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/files", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index)) | ||||
| 		ctx.Session.MakeRequest(t, req, http.StatusOK) | ||||
| 		req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index)) | ||||
| 		ctx.Session.MakeRequest(t, req, http.StatusOK) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doEnsureDiffNoChange(ctx APITestContext, pr api.PullRequest, diffHash string, diffLength int) func(t *testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index)) | ||||
| 		resp := ctx.Session.MakeRequestNilResponseHashSumRecorder(t, req, http.StatusOK) | ||||
| 		actual := string(resp.Hash.Sum(nil)) | ||||
| 		actualLength := resp.Length | ||||
|  | ||||
| 		equal := diffHash == actual | ||||
| 		assert.True(t, equal, "Unexpected change in the diff string: expected hash: %s size: %d but was actually: %s size: %d", hex.EncodeToString([]byte(diffHash)), diffLength, hex.EncodeToString([]byte(actual)), actualLength) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
|  | ||||
| 		// create a context for a currently non-existent repository | ||||
| 		ctx.Reponame = fmt.Sprintf("repo-tmp-push-create-%s", u.Scheme) | ||||
| 		u.Path = ctx.GitPath() | ||||
|  | ||||
| 		// Create a temporary directory | ||||
| 		tmpDir, err := os.MkdirTemp("", ctx.Reponame) | ||||
| 		assert.NoError(t, err) | ||||
| 		defer util.RemoveAll(tmpDir) | ||||
|  | ||||
| 		// Now create local repository to push as our test and set its origin | ||||
| 		t.Run("InitTestRepository", doGitInitTestRepository(tmpDir)) | ||||
| 		t.Run("AddRemote", doGitAddRemote(tmpDir, "origin", u)) | ||||
|  | ||||
| 		// Disable "Push To Create" and attempt to push | ||||
| 		setting.Repository.EnablePushCreateUser = false | ||||
| 		t.Run("FailToPushAndCreateTestRepository", doGitPushTestRepositoryFail(tmpDir, "origin", "master")) | ||||
|  | ||||
| 		// Enable "Push To Create" | ||||
| 		setting.Repository.EnablePushCreateUser = true | ||||
|  | ||||
| 		// Assert that cloning from a non-existent repository does not create it and that it definitely wasn't create above | ||||
| 		t.Run("FailToCloneFromNonExistentRepository", doGitCloneFail(u)) | ||||
|  | ||||
| 		// Then "Push To Create"x | ||||
| 		t.Run("SuccessfullyPushAndCreateTestRepository", doGitPushTestRepository(tmpDir, "origin", "master")) | ||||
|  | ||||
| 		// Finally, fetch repo from database and ensure the correct repository has been created | ||||
| 		repo, err := repo_model.GetRepositoryByOwnerAndName(ctx.Username, ctx.Reponame) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.False(t, repo.IsEmpty) | ||||
| 		assert.True(t, repo.IsPrivate) | ||||
|  | ||||
| 		// Now add a remote that is invalid to "Push To Create" | ||||
| 		invalidCtx := ctx | ||||
| 		invalidCtx.Reponame = fmt.Sprintf("invalid/repo-tmp-push-create-%s", u.Scheme) | ||||
| 		u.Path = invalidCtx.GitPath() | ||||
| 		t.Run("AddInvalidRemote", doGitAddRemote(tmpDir, "invalid", u)) | ||||
|  | ||||
| 		// Fail to "Push To Create" the invalid | ||||
| 		t.Run("FailToPushAndCreateInvalidTestRepository", doGitPushTestRepositoryFail(tmpDir, "invalid", "master")) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doBranchDelete(ctx APITestContext, owner, repo, branch string) func(*testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/branches", url.PathEscape(owner), url.PathEscape(repo))) | ||||
|  | ||||
| 		req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/branches/delete?name=%s", url.PathEscape(owner), url.PathEscape(repo), url.QueryEscape(branch)), map[string]string{ | ||||
| 			"_csrf": csrf, | ||||
| 		}) | ||||
| 		ctx.Session.MakeRequest(t, req, http.StatusOK) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
|  | ||||
| 		ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame) | ||||
|  | ||||
| 		t.Run("CheckoutProtected", doGitCheckoutBranch(dstPath, "protected")) | ||||
| 		t.Run("PullProtected", doGitPull(dstPath, "origin", "protected")) | ||||
| 		t.Run("GenerateCommit", func(t *testing.T) { | ||||
| 			_, err := generateCommitWithNewData(littleSize, dstPath, "user2@example.com", "User Two", "branch-data-file-") | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 		t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected3")) | ||||
| 		var pr api.PullRequest | ||||
| 		var err error | ||||
| 		t.Run("CreatePullRequest", func(t *testing.T) { | ||||
| 			pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, "protected", "unprotected3")(t) | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
|  | ||||
| 		// Request repository commits page | ||||
| 		req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits", baseCtx.Username, baseCtx.Reponame, pr.Index)) | ||||
| 		resp := ctx.Session.MakeRequest(t, req, http.StatusOK) | ||||
| 		doc := NewHTMLParser(t, resp.Body) | ||||
|  | ||||
| 		// Get first commit URL | ||||
| 		commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href") | ||||
| 		assert.True(t, exists) | ||||
| 		assert.NotEmpty(t, commitURL) | ||||
|  | ||||
| 		commitID := path.Base(commitURL) | ||||
|  | ||||
| 		// Call API to add Pending status for commit | ||||
| 		t.Run("CreateStatus", doAPICreateCommitStatus(ctx, commitID, api.CommitStatusPending)) | ||||
|  | ||||
| 		// Cancel not existing auto merge | ||||
| 		ctx.ExpectedCode = http.StatusNotFound | ||||
| 		t.Run("CancelAutoMergePR", doAPICancelAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) | ||||
|  | ||||
| 		// Add auto merge request | ||||
| 		ctx.ExpectedCode = http.StatusCreated | ||||
| 		t.Run("AutoMergePR", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) | ||||
|  | ||||
| 		// Can not create schedule twice | ||||
| 		ctx.ExpectedCode = http.StatusConflict | ||||
| 		t.Run("AutoMergePRTwice", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) | ||||
|  | ||||
| 		// Cancel auto merge request | ||||
| 		ctx.ExpectedCode = http.StatusNoContent | ||||
| 		t.Run("CancelAutoMergePR", doAPICancelAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) | ||||
|  | ||||
| 		// Add auto merge request | ||||
| 		ctx.ExpectedCode = http.StatusCreated | ||||
| 		t.Run("AutoMergePR", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) | ||||
|  | ||||
| 		// Check pr status | ||||
| 		ctx.ExpectedCode = 0 | ||||
| 		pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.False(t, pr.HasMerged) | ||||
|  | ||||
| 		// Call API to add Failure status for commit | ||||
| 		t.Run("CreateStatus", doAPICreateCommitStatus(ctx, commitID, api.CommitStatusFailure)) | ||||
|  | ||||
| 		// Check pr status | ||||
| 		pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.False(t, pr.HasMerged) | ||||
|  | ||||
| 		// Call API to add Success status for commit | ||||
| 		t.Run("CreateStatus", doAPICreateCommitStatus(ctx, commitID, api.CommitStatusSuccess)) | ||||
|  | ||||
| 		// wait to let gitea merge stuff | ||||
| 		time.Sleep(time.Second) | ||||
|  | ||||
| 		// test pr status | ||||
| 		pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.True(t, pr.HasMerged) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headBranch string) func(t *testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		defer tests.PrintCurrentTest(t)() | ||||
|  | ||||
| 		// skip this test if git version is low | ||||
| 		if git.CheckGitVersionAtLeast("2.29") != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		gitRepo, err := git.OpenRepository(git.DefaultContext, dstPath) | ||||
| 		if !assert.NoError(t, err) { | ||||
| 			return | ||||
| 		} | ||||
| 		defer gitRepo.Close() | ||||
|  | ||||
| 		var ( | ||||
| 			pr1, pr2 *issues_model.PullRequest | ||||
| 			commit   string | ||||
| 		) | ||||
| 		repo, err := repo_model.GetRepositoryByOwnerAndName(ctx.Username, ctx.Reponame) | ||||
| 		if !assert.NoError(t, err) { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		pullNum := unittest.GetCount(t, &issues_model.PullRequest{}) | ||||
|  | ||||
| 		t.Run("CreateHeadBranch", doGitCreateBranch(dstPath, headBranch)) | ||||
|  | ||||
| 		t.Run("AddCommit", func(t *testing.T) { | ||||
| 			err := os.WriteFile(path.Join(dstPath, "test_file"), []byte("## test content"), 0o666) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			err = git.AddChanges(dstPath, true) | ||||
| 			assert.NoError(t, err) | ||||
|  | ||||
| 			err = git.CommitChanges(dstPath, git.CommitChangesOptions{ | ||||
| 				Committer: &git.Signature{ | ||||
| 					Email: "user2@example.com", | ||||
| 					Name:  "user2", | ||||
| 					When:  time.Now(), | ||||
| 				}, | ||||
| 				Author: &git.Signature{ | ||||
| 					Email: "user2@example.com", | ||||
| 					Name:  "user2", | ||||
| 					When:  time.Now(), | ||||
| 				}, | ||||
| 				Message: "Testing commit 1", | ||||
| 			}) | ||||
| 			assert.NoError(t, err) | ||||
| 			commit, err = gitRepo.GetRefCommitID("HEAD") | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
|  | ||||
| 		t.Run("Push", func(t *testing.T) { | ||||
| 			err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath}) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
| 			unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+1) | ||||
| 			pr1 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ | ||||
| 				HeadRepoID: repo.ID, | ||||
| 				Flow:       issues_model.PullRequestFlowAGit, | ||||
| 			}) | ||||
| 			if !assert.NotEmpty(t, pr1) { | ||||
| 				return | ||||
| 			} | ||||
| 			prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
| 			assert.Equal(t, "user2/"+headBranch, pr1.HeadBranch) | ||||
| 			assert.Equal(t, false, prMsg.HasMerged) | ||||
| 			assert.Contains(t, "Testing commit 1", prMsg.Body) | ||||
| 			assert.Equal(t, commit, prMsg.Head.Sha) | ||||
|  | ||||
| 			_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath}) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
| 			unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2) | ||||
| 			pr2 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ | ||||
| 				HeadRepoID: repo.ID, | ||||
| 				Index:      pr1.Index + 1, | ||||
| 				Flow:       issues_model.PullRequestFlowAGit, | ||||
| 			}) | ||||
| 			if !assert.NotEmpty(t, pr2) { | ||||
| 				return | ||||
| 			} | ||||
| 			prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
| 			assert.Equal(t, "user2/test/"+headBranch, pr2.HeadBranch) | ||||
| 			assert.Equal(t, false, prMsg.HasMerged) | ||||
| 		}) | ||||
|  | ||||
| 		if pr1 == nil || pr2 == nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		t.Run("AddCommit2", func(t *testing.T) { | ||||
| 			err := os.WriteFile(path.Join(dstPath, "test_file"), []byte("## test content \n ## test content 2"), 0o666) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			err = git.AddChanges(dstPath, true) | ||||
| 			assert.NoError(t, err) | ||||
|  | ||||
| 			err = git.CommitChanges(dstPath, git.CommitChangesOptions{ | ||||
| 				Committer: &git.Signature{ | ||||
| 					Email: "user2@example.com", | ||||
| 					Name:  "user2", | ||||
| 					When:  time.Now(), | ||||
| 				}, | ||||
| 				Author: &git.Signature{ | ||||
| 					Email: "user2@example.com", | ||||
| 					Name:  "user2", | ||||
| 					When:  time.Now(), | ||||
| 				}, | ||||
| 				Message: "Testing commit 2", | ||||
| 			}) | ||||
| 			assert.NoError(t, err) | ||||
| 			commit, err = gitRepo.GetRefCommitID("HEAD") | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
|  | ||||
| 		t.Run("Push2", func(t *testing.T) { | ||||
| 			err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath}) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
| 			unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2) | ||||
| 			prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
| 			assert.Equal(t, false, prMsg.HasMerged) | ||||
| 			assert.Equal(t, commit, prMsg.Head.Sha) | ||||
|  | ||||
| 			_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath}) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
| 			unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2) | ||||
| 			prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t) | ||||
| 			if !assert.NoError(t, err) { | ||||
| 				return | ||||
| 			} | ||||
| 			assert.Equal(t, false, prMsg.HasMerged) | ||||
| 			assert.Equal(t, commit, prMsg.Head.Sha) | ||||
| 		}) | ||||
| 		t.Run("Merge", doAPIMergePullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)) | ||||
| 		t.Run("CheckoutMasterAgain", doGitCheckoutBranch(dstPath, "master")) | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user