mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Remove local clones & make hooks run on merge/edit/upload (#6672)
* Add options to git.Clone to make it more capable * Begin the process of removing the local copy and tidy up * Remove Wiki LocalCopy Checkouts * Remove the last LocalRepo helpers * Remove WithTemporaryFile * Enable push-hooks for these routes * Ensure tests cope with hooks Signed-off-by: Andrew Thornton <art27@cantab.net> * Remove Repository.LocalCopyPath() * Move temporary repo to use the standard temporary path * Fix the tests Signed-off-by: Andrew Thornton <art27@cantab.net> * Remove LocalWikiPath * Fix missing remove Signed-off-by: Andrew Thornton <art27@cantab.net> * Use AppURL for Oauth user link (#6894) * Use AppURL for Oauth user link Fix #6843 * Update oauth.go * Update oauth.go * internal/ssh: ignore env command totally (#6825) * ssh: ignore env command totally * Remove commented code Needed fix described in issue #6889 * Escape the commit message on issues update and title in telegram hook (#6901) * update sdk to latest (#6903) * improve description of branch protection (fix #6886) (#6906) The branch protection description text were not quite accurate. * Fix logging documentation (#6904) * ENABLE_MACARON_REDIRECT should be REDIRECT_MACARON_LOG * Allow DISABLE_ROUTER_LOG to be set in the [log] section * [skip ci] Updated translations via Crowdin * Move sdk structs to modules/structs (#6905) * move sdk structs to moduels/structs * fix tests * fix fmt * fix swagger * fix vendor
This commit is contained in:
		@@ -108,7 +108,6 @@ func runPR() {
 | 
				
			|||||||
	models.LoadFixtures()
 | 
						models.LoadFixtures()
 | 
				
			||||||
	os.RemoveAll(setting.RepoRootPath)
 | 
						os.RemoveAll(setting.RepoRootPath)
 | 
				
			||||||
	os.RemoveAll(models.LocalCopyPath())
 | 
						os.RemoveAll(models.LocalCopyPath())
 | 
				
			||||||
	os.RemoveAll(models.LocalWikiPath())
 | 
					 | 
				
			||||||
	com.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath)
 | 
						com.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Printf("[PR] Setting up router\n")
 | 
						log.Printf("[PR] Setting up router\n")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package integrations
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,7 +41,10 @@ func getExpectedFileContentResponseForFileContents(branch string) *api.FileConte
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAPIGetFileContents(t *testing.T) {
 | 
					func TestAPIGetFileContents(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, testAPIGetFileContents)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testAPIGetFileContents(t *testing.T, u *url.URL) {
 | 
				
			||||||
	user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)               // owner of the repo1 & repo16
 | 
						user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)               // owner of the repo1 & repo16
 | 
				
			||||||
	user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)               // owner of the repo3, is an org
 | 
						user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)               // owner of the repo3, is an org
 | 
				
			||||||
	user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)               // owner of neither repos
 | 
						user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)               // owner of neither repos
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"encoding/base64"
 | 
						"encoding/base64"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,125 +92,126 @@ func getExpectedFileResponseForCreate(commitID, treePath string) *api.FileRespon
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAPICreateFile(t *testing.T) {
 | 
					func TestAPICreateFile(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
	user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)               // owner of the repo1 & repo16
 | 
							user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)               // owner of the repo1 & repo16
 | 
				
			||||||
	user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)               // owner of the repo3, is an org
 | 
							user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)               // owner of the repo3, is an org
 | 
				
			||||||
	user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)               // owner of neither repos
 | 
							user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)               // owner of neither repos
 | 
				
			||||||
	repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)   // public repo
 | 
							repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)   // public repo
 | 
				
			||||||
	repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)   // public repo
 | 
							repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)   // public repo
 | 
				
			||||||
	repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
 | 
							repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
 | 
				
			||||||
	fileID := 0
 | 
							fileID := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get user2's token
 | 
							// Get user2's token
 | 
				
			||||||
	session := loginUser(t, user2.Name)
 | 
							session := loginUser(t, user2.Name)
 | 
				
			||||||
	token2 := getTokenForLoggedInUser(t, session)
 | 
							token2 := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	session = emptyTestSession(t)
 | 
							session = emptyTestSession(t)
 | 
				
			||||||
	// Get user4's token
 | 
							// Get user4's token
 | 
				
			||||||
	session = loginUser(t, user4.Name)
 | 
							session = loginUser(t, user4.Name)
 | 
				
			||||||
	token4 := getTokenForLoggedInUser(t, session)
 | 
							token4 := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	session = emptyTestSession(t)
 | 
							session = emptyTestSession(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test creating a file in repo1 which user2 owns, try both with branch and empty branch
 | 
							// Test creating a file in repo1 which user2 owns, try both with branch and empty branch
 | 
				
			||||||
	for _, branch := range [...]string{
 | 
							for _, branch := range [...]string{
 | 
				
			||||||
		"master", // Branch
 | 
								"master", // Branch
 | 
				
			||||||
		"",       // Empty branch
 | 
								"",       // Empty branch
 | 
				
			||||||
	} {
 | 
							} {
 | 
				
			||||||
 | 
								createFileOptions := getCreateFileOptions()
 | 
				
			||||||
 | 
								createFileOptions.BranchName = branch
 | 
				
			||||||
 | 
								fileID++
 | 
				
			||||||
 | 
								treePath := fmt.Sprintf("new/file%d.txt", fileID)
 | 
				
			||||||
 | 
								url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
 | 
								req := NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
 | 
								resp := session.MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
 | 
								gitRepo, _ := git.OpenRepository(repo1.RepoPath())
 | 
				
			||||||
 | 
								commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
 | 
				
			||||||
 | 
								expectedFileResponse := getExpectedFileResponseForCreate(commitID, treePath)
 | 
				
			||||||
 | 
								var fileResponse api.FileResponse
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Test creating a file in a new branch
 | 
				
			||||||
		createFileOptions := getCreateFileOptions()
 | 
							createFileOptions := getCreateFileOptions()
 | 
				
			||||||
		createFileOptions.BranchName = branch
 | 
							createFileOptions.BranchName = repo1.DefaultBranch
 | 
				
			||||||
 | 
							createFileOptions.NewBranchName = "new_branch"
 | 
				
			||||||
		fileID++
 | 
							fileID++
 | 
				
			||||||
		treePath := fmt.Sprintf("new/file%d.txt", fileID)
 | 
							treePath := fmt.Sprintf("new/file%d.txt", fileID)
 | 
				
			||||||
		url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
		req := NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
							req := NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
		resp := session.MakeRequest(t, req, http.StatusCreated)
 | 
							resp := session.MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
		gitRepo, _ := git.OpenRepository(repo1.RepoPath())
 | 
					 | 
				
			||||||
		commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
 | 
					 | 
				
			||||||
		expectedFileResponse := getExpectedFileResponseForCreate(commitID, treePath)
 | 
					 | 
				
			||||||
		var fileResponse api.FileResponse
 | 
							var fileResponse api.FileResponse
 | 
				
			||||||
		DecodeJSON(t, resp, &fileResponse)
 | 
							DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
							expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
							expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/new/file%d.txt", fileID)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
							expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
 | 
							assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
 | 
							assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL)
 | 
				
			||||||
	}
 | 
							assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test creating a file in a new branch
 | 
							// Test trying to create a file that already exists, should fail
 | 
				
			||||||
	createFileOptions := getCreateFileOptions()
 | 
							createFileOptions = getCreateFileOptions()
 | 
				
			||||||
	createFileOptions.BranchName = repo1.DefaultBranch
 | 
							treePath = "README.md"
 | 
				
			||||||
	createFileOptions.NewBranchName = "new_branch"
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
	fileID++
 | 
							req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
	treePath := fmt.Sprintf("new/file%d.txt", fileID)
 | 
							resp = session.MakeRequest(t, req, http.StatusInternalServerError)
 | 
				
			||||||
	url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							expectedAPIError := context.APIError{
 | 
				
			||||||
	req := NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
								Message: "repository file already exists [path: " + treePath + "]",
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusCreated)
 | 
								URL:     base.DocURL,
 | 
				
			||||||
	var fileResponse api.FileResponse
 | 
							}
 | 
				
			||||||
	DecodeJSON(t, resp, &fileResponse)
 | 
							var apiError context.APIError
 | 
				
			||||||
	expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
 | 
							DecodeJSON(t, resp, &apiError)
 | 
				
			||||||
	expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/new/file%d.txt", fileID)
 | 
							assert.Equal(t, expectedAPIError, apiError)
 | 
				
			||||||
	expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test trying to create a file that already exists, should fail
 | 
							// Test creating a file in repo1 by user4 who does not have write access
 | 
				
			||||||
	createFileOptions = getCreateFileOptions()
 | 
							createFileOptions = getCreateFileOptions()
 | 
				
			||||||
	treePath = "README.md"
 | 
							fileID++
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusInternalServerError)
 | 
							req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
	expectedAPIError := context.APIError{
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
		Message: "repository file already exists [path: " + treePath + "]",
 | 
					 | 
				
			||||||
		URL:     base.DocURL,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var apiError context.APIError
 | 
					 | 
				
			||||||
	DecodeJSON(t, resp, &apiError)
 | 
					 | 
				
			||||||
	assert.Equal(t, expectedAPIError, apiError)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test creating a file in repo1 by user4 who does not have write access
 | 
							// Tests a repo with no token given so will fail
 | 
				
			||||||
	createFileOptions = getCreateFileOptions()
 | 
							createFileOptions = getCreateFileOptions()
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
							req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Tests a repo with no token given so will fail
 | 
							// Test using access token for a private repo that the user of the token owns
 | 
				
			||||||
	createFileOptions = getCreateFileOptions()
 | 
							createFileOptions = getCreateFileOptions()
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
							req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using access token for a private repo that the user of the token owns
 | 
							// Test using org repo "user3/repo3" where user2 is a collaborator
 | 
				
			||||||
	createFileOptions = getCreateFileOptions()
 | 
							createFileOptions = getCreateFileOptions()
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
							req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusCreated)
 | 
							session.MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using org repo "user3/repo3" where user2 is a collaborator
 | 
							// Test using org repo "user3/repo3" with no user token
 | 
				
			||||||
	createFileOptions = getCreateFileOptions()
 | 
							createFileOptions = getCreateFileOptions()
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
							req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusCreated)
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using org repo "user3/repo3" with no user token
 | 
							// Test using repo "user2/repo1" where user4 is a NOT collaborator
 | 
				
			||||||
	createFileOptions = getCreateFileOptions()
 | 
							createFileOptions = getCreateFileOptions()
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
							req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusForbidden)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
	// Test using repo "user2/repo1" where user4 is a NOT collaborator
 | 
					 | 
				
			||||||
	createFileOptions = getCreateFileOptions()
 | 
					 | 
				
			||||||
	fileID++
 | 
					 | 
				
			||||||
	treePath = fmt.Sprintf("new/file%d.txt", fileID)
 | 
					 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
 | 
					 | 
				
			||||||
	req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
					 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusForbidden)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package integrations
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
@@ -37,34 +38,50 @@ func getDeleteFileOptions() *api.DeleteFileOptions {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAPIDeleteFile(t *testing.T) {
 | 
					func TestAPIDeleteFile(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
	user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)               // owner of the repo1 & repo16
 | 
							user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)               // owner of the repo1 & repo16
 | 
				
			||||||
	user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)               // owner of the repo3, is an org
 | 
							user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)               // owner of the repo3, is an org
 | 
				
			||||||
	user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)               // owner of neither repos
 | 
							user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)               // owner of neither repos
 | 
				
			||||||
	repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)   // public repo
 | 
							repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)   // public repo
 | 
				
			||||||
	repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)   // public repo
 | 
							repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)   // public repo
 | 
				
			||||||
	repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
 | 
							repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
 | 
				
			||||||
	fileID := 0
 | 
							fileID := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get user2's token
 | 
							// Get user2's token
 | 
				
			||||||
	session := loginUser(t, user2.Name)
 | 
							session := loginUser(t, user2.Name)
 | 
				
			||||||
	token2 := getTokenForLoggedInUser(t, session)
 | 
							token2 := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	session = emptyTestSession(t)
 | 
							session = emptyTestSession(t)
 | 
				
			||||||
	// Get user4's token
 | 
							// Get user4's token
 | 
				
			||||||
	session = loginUser(t, user4.Name)
 | 
							session = loginUser(t, user4.Name)
 | 
				
			||||||
	token4 := getTokenForLoggedInUser(t, session)
 | 
							token4 := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	session = emptyTestSession(t)
 | 
							session = emptyTestSession(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test deleting a file in repo1 which user2 owns, try both with branch and empty branch
 | 
							// Test deleting a file in repo1 which user2 owns, try both with branch and empty branch
 | 
				
			||||||
	for _, branch := range [...]string{
 | 
							for _, branch := range [...]string{
 | 
				
			||||||
		"master", // Branch
 | 
								"master", // Branch
 | 
				
			||||||
		"",       // Empty branch
 | 
								"",       // Empty branch
 | 
				
			||||||
	} {
 | 
							} {
 | 
				
			||||||
 | 
								fileID++
 | 
				
			||||||
 | 
								treePath := fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
 | 
								createFile(user2, repo1, treePath)
 | 
				
			||||||
 | 
								deleteFileOptions := getDeleteFileOptions()
 | 
				
			||||||
 | 
								deleteFileOptions.BranchName = branch
 | 
				
			||||||
 | 
								url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
 | 
								req := NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
								var fileResponse api.FileResponse
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
 | 
								assert.NotNil(t, fileResponse)
 | 
				
			||||||
 | 
								assert.Nil(t, fileResponse.Content)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Test deleting file and making the delete in a new branch
 | 
				
			||||||
		fileID++
 | 
							fileID++
 | 
				
			||||||
		treePath := fmt.Sprintf("delete/file%d.txt", fileID)
 | 
							treePath := fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
		createFile(user2, repo1, treePath)
 | 
							createFile(user2, repo1, treePath)
 | 
				
			||||||
		deleteFileOptions := getDeleteFileOptions()
 | 
							deleteFileOptions := getDeleteFileOptions()
 | 
				
			||||||
		deleteFileOptions.BranchName = branch
 | 
							deleteFileOptions.BranchName = repo1.DefaultBranch
 | 
				
			||||||
 | 
							deleteFileOptions.NewBranchName = "new_branch"
 | 
				
			||||||
		url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
		req := NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
							req := NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
		resp := session.MakeRequest(t, req, http.StatusOK)
 | 
							resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
@@ -72,92 +89,77 @@ func TestAPIDeleteFile(t *testing.T) {
 | 
				
			|||||||
		DecodeJSON(t, resp, &fileResponse)
 | 
							DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
		assert.NotNil(t, fileResponse)
 | 
							assert.NotNil(t, fileResponse)
 | 
				
			||||||
		assert.Nil(t, fileResponse.Content)
 | 
							assert.Nil(t, fileResponse.Content)
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test deleting file and making the delete in a new branch
 | 
							// Test deleting a file with the wrong SHA
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath := fmt.Sprintf("delete/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo1, treePath)
 | 
							createFile(user2, repo1, treePath)
 | 
				
			||||||
	deleteFileOptions := getDeleteFileOptions()
 | 
							deleteFileOptions = getDeleteFileOptions()
 | 
				
			||||||
	deleteFileOptions.BranchName = repo1.DefaultBranch
 | 
							correctSHA := deleteFileOptions.SHA
 | 
				
			||||||
	deleteFileOptions.NewBranchName = "new_branch"
 | 
							deleteFileOptions.SHA = "badsha"
 | 
				
			||||||
	url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
	req := NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
							req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusInternalServerError)
 | 
				
			||||||
	var fileResponse api.FileResponse
 | 
							expectedAPIError := context.APIError{
 | 
				
			||||||
	DecodeJSON(t, resp, &fileResponse)
 | 
								Message: "sha does not match [given: " + deleteFileOptions.SHA + ", expected: " + correctSHA + "]",
 | 
				
			||||||
	assert.NotNil(t, fileResponse)
 | 
								URL:     base.DocURL,
 | 
				
			||||||
	assert.Nil(t, fileResponse.Content)
 | 
							}
 | 
				
			||||||
 | 
							var apiError context.APIError
 | 
				
			||||||
 | 
							DecodeJSON(t, resp, &apiError)
 | 
				
			||||||
 | 
							assert.Equal(t, expectedAPIError, apiError)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test deleting a file with the wrong SHA
 | 
							// Test creating a file in repo1 by user4 who does not have write access
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo1, treePath)
 | 
							createFile(user2, repo16, treePath)
 | 
				
			||||||
	deleteFileOptions = getDeleteFileOptions()
 | 
							deleteFileOptions = getDeleteFileOptions()
 | 
				
			||||||
	correctSHA := deleteFileOptions.SHA
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
 | 
				
			||||||
	deleteFileOptions.SHA = "badsha"
 | 
							req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
					 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusInternalServerError)
 | 
					 | 
				
			||||||
	expectedAPIError := context.APIError{
 | 
					 | 
				
			||||||
		Message: "sha does not match [given: " + deleteFileOptions.SHA + ", expected: " + correctSHA + "]",
 | 
					 | 
				
			||||||
		URL:     base.DocURL,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var apiError context.APIError
 | 
					 | 
				
			||||||
	DecodeJSON(t, resp, &apiError)
 | 
					 | 
				
			||||||
	assert.Equal(t, expectedAPIError, apiError)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test creating a file in repo1 by user4 who does not have write access
 | 
							// Tests a repo with no token given so will fail
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo16, treePath)
 | 
							createFile(user2, repo16, treePath)
 | 
				
			||||||
	deleteFileOptions = getDeleteFileOptions()
 | 
							deleteFileOptions = getDeleteFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
							req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Tests a repo with no token given so will fail
 | 
							// Test using access token for a private repo that the user of the token owns
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo16, treePath)
 | 
							createFile(user2, repo16, treePath)
 | 
				
			||||||
	deleteFileOptions = getDeleteFileOptions()
 | 
							deleteFileOptions = getDeleteFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
							req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using access token for a private repo that the user of the token owns
 | 
							// Test using org repo "user3/repo3" where user2 is a collaborator
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo16, treePath)
 | 
							createFile(user3, repo3, treePath)
 | 
				
			||||||
	deleteFileOptions = getDeleteFileOptions()
 | 
							deleteFileOptions = getDeleteFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
							req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusOK)
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using org repo "user3/repo3" where user2 is a collaborator
 | 
							// Test using org repo "user3/repo3" with no user token
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user3, repo3, treePath)
 | 
							createFile(user3, repo3, treePath)
 | 
				
			||||||
	deleteFileOptions = getDeleteFileOptions()
 | 
							deleteFileOptions = getDeleteFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
							req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusOK)
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using org repo "user3/repo3" with no user token
 | 
							// Test using repo "user2/repo1" where user4 is a NOT collaborator
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user3, repo3, treePath)
 | 
							createFile(user2, repo1, treePath)
 | 
				
			||||||
	deleteFileOptions = getDeleteFileOptions()
 | 
							deleteFileOptions = getDeleteFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
							req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusForbidden)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
	// Test using repo "user2/repo1" where user4 is a NOT collaborator
 | 
					 | 
				
			||||||
	fileID++
 | 
					 | 
				
			||||||
	treePath = fmt.Sprintf("delete/file%d.txt", fileID)
 | 
					 | 
				
			||||||
	createFile(user2, repo1, treePath)
 | 
					 | 
				
			||||||
	deleteFileOptions = getDeleteFileOptions()
 | 
					 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
 | 
					 | 
				
			||||||
	req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
 | 
					 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusForbidden)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"encoding/base64"
 | 
						"encoding/base64"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -79,156 +80,157 @@ func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileRespon
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAPIUpdateFile(t *testing.T) {
 | 
					func TestAPIUpdateFile(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
	user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)               // owner of the repo1 & repo16
 | 
							user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)               // owner of the repo1 & repo16
 | 
				
			||||||
	user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)               // owner of the repo3, is an org
 | 
							user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)               // owner of the repo3, is an org
 | 
				
			||||||
	user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)               // owner of neither repos
 | 
							user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)               // owner of neither repos
 | 
				
			||||||
	repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)   // public repo
 | 
							repo1 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)   // public repo
 | 
				
			||||||
	repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)   // public repo
 | 
							repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository)   // public repo
 | 
				
			||||||
	repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
 | 
							repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
 | 
				
			||||||
	fileID := 0
 | 
							fileID := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get user2's token
 | 
							// Get user2's token
 | 
				
			||||||
	session := loginUser(t, user2.Name)
 | 
							session := loginUser(t, user2.Name)
 | 
				
			||||||
	token2 := getTokenForLoggedInUser(t, session)
 | 
							token2 := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	session = emptyTestSession(t)
 | 
							session = emptyTestSession(t)
 | 
				
			||||||
	// Get user4's token
 | 
							// Get user4's token
 | 
				
			||||||
	session = loginUser(t, user4.Name)
 | 
							session = loginUser(t, user4.Name)
 | 
				
			||||||
	token4 := getTokenForLoggedInUser(t, session)
 | 
							token4 := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	session = emptyTestSession(t)
 | 
							session = emptyTestSession(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test updating a file in repo1 which user2 owns, try both with branch and empty branch
 | 
							// Test updating a file in repo1 which user2 owns, try both with branch and empty branch
 | 
				
			||||||
	for _, branch := range [...]string{
 | 
							for _, branch := range [...]string{
 | 
				
			||||||
		"master", // Branch
 | 
								"master", // Branch
 | 
				
			||||||
		"",       // Empty branch
 | 
								"",       // Empty branch
 | 
				
			||||||
	} {
 | 
							} {
 | 
				
			||||||
 | 
								fileID++
 | 
				
			||||||
 | 
								treePath := fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
 | 
								createFile(user2, repo1, treePath)
 | 
				
			||||||
 | 
								updateFileOptions := getUpdateFileOptions()
 | 
				
			||||||
 | 
								updateFileOptions.BranchName = branch
 | 
				
			||||||
 | 
								url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
 | 
								req := NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
								gitRepo, _ := git.OpenRepository(repo1.RepoPath())
 | 
				
			||||||
 | 
								commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName)
 | 
				
			||||||
 | 
								expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath)
 | 
				
			||||||
 | 
								var fileResponse api.FileResponse
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
 | 
				
			||||||
 | 
								assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Test updating a file in a new branch
 | 
				
			||||||
 | 
							updateFileOptions := getUpdateFileOptions()
 | 
				
			||||||
 | 
							updateFileOptions.BranchName = repo1.DefaultBranch
 | 
				
			||||||
 | 
							updateFileOptions.NewBranchName = "new_branch"
 | 
				
			||||||
		fileID++
 | 
							fileID++
 | 
				
			||||||
		treePath := fmt.Sprintf("update/file%d.txt", fileID)
 | 
							treePath := fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
		createFile(user2, repo1, treePath)
 | 
							createFile(user2, repo1, treePath)
 | 
				
			||||||
		updateFileOptions := getUpdateFileOptions()
 | 
					 | 
				
			||||||
		updateFileOptions.BranchName = branch
 | 
					 | 
				
			||||||
		url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
		req := NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
							req := NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
		resp := session.MakeRequest(t, req, http.StatusOK)
 | 
							resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
		gitRepo, _ := git.OpenRepository(repo1.RepoPath())
 | 
					 | 
				
			||||||
		commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName)
 | 
					 | 
				
			||||||
		expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath)
 | 
					 | 
				
			||||||
		var fileResponse api.FileResponse
 | 
							var fileResponse api.FileResponse
 | 
				
			||||||
		DecodeJSON(t, resp, &fileResponse)
 | 
							DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
							expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136"
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
							expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/update/file%d.txt", fileID)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
							expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
 | 
							assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
 | 
							assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL)
 | 
				
			||||||
	}
 | 
							assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test updating a file in a new branch
 | 
							// Test updating a file and renaming it
 | 
				
			||||||
	updateFileOptions := getUpdateFileOptions()
 | 
							updateFileOptions = getUpdateFileOptions()
 | 
				
			||||||
	updateFileOptions.BranchName = repo1.DefaultBranch
 | 
							updateFileOptions.BranchName = repo1.DefaultBranch
 | 
				
			||||||
	updateFileOptions.NewBranchName = "new_branch"
 | 
							fileID++
 | 
				
			||||||
	fileID++
 | 
							treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
	treePath := fmt.Sprintf("update/file%d.txt", fileID)
 | 
							createFile(user2, repo1, treePath)
 | 
				
			||||||
	createFile(user2, repo1, treePath)
 | 
							updateFileOptions.FromPath = treePath
 | 
				
			||||||
	url := fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							treePath = "rename/" + treePath
 | 
				
			||||||
	req := NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
							req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
	var fileResponse api.FileResponse
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &fileResponse)
 | 
							DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
	expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136"
 | 
							expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136"
 | 
				
			||||||
	expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/update/file%d.txt", fileID)
 | 
							expectedHTMLURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/master/rename/update/file%d.txt", fileID)
 | 
				
			||||||
	expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID)
 | 
							expectedDownloadURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID)
 | 
				
			||||||
	assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
 | 
							assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
 | 
				
			||||||
	assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL)
 | 
							assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL)
 | 
				
			||||||
	assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL)
 | 
							assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test updating a file and renaming it
 | 
							// Test updating a file with the wrong SHA
 | 
				
			||||||
	updateFileOptions = getUpdateFileOptions()
 | 
							fileID++
 | 
				
			||||||
	updateFileOptions.BranchName = repo1.DefaultBranch
 | 
							treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
	fileID++
 | 
							createFile(user2, repo1, treePath)
 | 
				
			||||||
	treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
							updateFileOptions = getUpdateFileOptions()
 | 
				
			||||||
	createFile(user2, repo1, treePath)
 | 
							correctSHA := updateFileOptions.SHA
 | 
				
			||||||
	updateFileOptions.FromPath = treePath
 | 
							updateFileOptions.SHA = "badsha"
 | 
				
			||||||
	treePath = "rename/" + treePath
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
							resp = session.MakeRequest(t, req, http.StatusInternalServerError)
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							expectedAPIError := context.APIError{
 | 
				
			||||||
	DecodeJSON(t, resp, &fileResponse)
 | 
								Message: "sha does not match [given: " + updateFileOptions.SHA + ", expected: " + correctSHA + "]",
 | 
				
			||||||
	expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136"
 | 
								URL:     base.DocURL,
 | 
				
			||||||
	expectedHTMLURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/master/rename/update/file%d.txt", fileID)
 | 
							}
 | 
				
			||||||
	expectedDownloadURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID)
 | 
							var apiError context.APIError
 | 
				
			||||||
	assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
 | 
							DecodeJSON(t, resp, &apiError)
 | 
				
			||||||
	assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL)
 | 
							assert.Equal(t, expectedAPIError, apiError)
 | 
				
			||||||
	assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test updating a file with the wrong SHA
 | 
							// Test creating a file in repo1 by user4 who does not have write access
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo1, treePath)
 | 
							createFile(user2, repo16, treePath)
 | 
				
			||||||
	updateFileOptions = getUpdateFileOptions()
 | 
							updateFileOptions = getUpdateFileOptions()
 | 
				
			||||||
	correctSHA := updateFileOptions.SHA
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
 | 
				
			||||||
	updateFileOptions.SHA = "badsha"
 | 
							req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
					 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusInternalServerError)
 | 
					 | 
				
			||||||
	expectedAPIError := context.APIError{
 | 
					 | 
				
			||||||
		Message: "sha does not match [given: " + updateFileOptions.SHA + ", expected: " + correctSHA + "]",
 | 
					 | 
				
			||||||
		URL:     base.DocURL,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var apiError context.APIError
 | 
					 | 
				
			||||||
	DecodeJSON(t, resp, &apiError)
 | 
					 | 
				
			||||||
	assert.Equal(t, expectedAPIError, apiError)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test creating a file in repo1 by user4 who does not have write access
 | 
							// Tests a repo with no token given so will fail
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo16, treePath)
 | 
							createFile(user2, repo16, treePath)
 | 
				
			||||||
	updateFileOptions = getUpdateFileOptions()
 | 
							updateFileOptions = getUpdateFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
							req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Tests a repo with no token given so will fail
 | 
							// Test using access token for a private repo that the user of the token owns
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo16, treePath)
 | 
							createFile(user2, repo16, treePath)
 | 
				
			||||||
	updateFileOptions = getUpdateFileOptions()
 | 
							updateFileOptions = getUpdateFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
							req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using access token for a private repo that the user of the token owns
 | 
							// Test using org repo "user3/repo3" where user2 is a collaborator
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user2, repo16, treePath)
 | 
							createFile(user3, repo3, treePath)
 | 
				
			||||||
	updateFileOptions = getUpdateFileOptions()
 | 
							updateFileOptions = getUpdateFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
							req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusOK)
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using org repo "user3/repo3" where user2 is a collaborator
 | 
							// Test using org repo "user3/repo3" with no user token
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user3, repo3, treePath)
 | 
							createFile(user3, repo3, treePath)
 | 
				
			||||||
	updateFileOptions = getUpdateFileOptions()
 | 
							updateFileOptions = getUpdateFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
							req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusOK)
 | 
							session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test using org repo "user3/repo3" with no user token
 | 
							// Test using repo "user2/repo1" where user4 is a NOT collaborator
 | 
				
			||||||
	fileID++
 | 
							fileID++
 | 
				
			||||||
	treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
							treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
				
			||||||
	createFile(user3, repo3, treePath)
 | 
							createFile(user2, repo1, treePath)
 | 
				
			||||||
	updateFileOptions = getUpdateFileOptions()
 | 
							updateFileOptions = getUpdateFileOptions()
 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
 | 
							url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
 | 
				
			||||||
	req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
							req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
							session.MakeRequest(t, req, http.StatusForbidden)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
	// Test using repo "user2/repo1" where user4 is a NOT collaborator
 | 
					 | 
				
			||||||
	fileID++
 | 
					 | 
				
			||||||
	treePath = fmt.Sprintf("update/file%d.txt", fileID)
 | 
					 | 
				
			||||||
	createFile(user2, repo1, treePath)
 | 
					 | 
				
			||||||
	updateFileOptions = getUpdateFileOptions()
 | 
					 | 
				
			||||||
	url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token4)
 | 
					 | 
				
			||||||
	req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
					 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusForbidden)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package integrations
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,80 +15,79 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateFile(t *testing.T) {
 | 
					func TestCreateFile(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							session := loginUser(t, "user2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
							// Request editor page
 | 
				
			||||||
 | 
							req := NewRequest(t, "GET", "/user2/repo1/_new/master/")
 | 
				
			||||||
 | 
							resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Request editor page
 | 
							doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
	req := NewRequest(t, "GET", "/user2/repo1/_new/master/")
 | 
							lastCommit := doc.GetInputValueByName("last_commit")
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
							assert.NotEmpty(t, lastCommit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	doc := NewHTMLParser(t, resp.Body)
 | 
							// Save new file to master branch
 | 
				
			||||||
	lastCommit := doc.GetInputValueByName("last_commit")
 | 
							req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
 | 
				
			||||||
	assert.NotEmpty(t, lastCommit)
 | 
								"_csrf":         doc.GetCSRF(),
 | 
				
			||||||
 | 
								"last_commit":   lastCommit,
 | 
				
			||||||
	// Save new file to master branch
 | 
								"tree_path":     "test.txt",
 | 
				
			||||||
	req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
 | 
								"content":       "Content",
 | 
				
			||||||
		"_csrf":         doc.GetCSRF(),
 | 
								"commit_choice": "direct",
 | 
				
			||||||
		"last_commit":   lastCommit,
 | 
							})
 | 
				
			||||||
		"tree_path":     "test.txt",
 | 
							resp = session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
		"content":       "Content",
 | 
					 | 
				
			||||||
		"commit_choice": "direct",
 | 
					 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusFound)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateFileOnProtectedBranch(t *testing.T) {
 | 
					func TestCreateFileOnProtectedBranch(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							session := loginUser(t, "user2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
							csrf := GetCSRF(t, session, "/user2/repo1/settings/branches")
 | 
				
			||||||
 | 
							// Change master branch to protected
 | 
				
			||||||
 | 
							req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/master", map[string]string{
 | 
				
			||||||
 | 
								"_csrf":     csrf,
 | 
				
			||||||
 | 
								"protected": "on",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							resp := session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
							// Check if master branch has been locked successfully
 | 
				
			||||||
 | 
							flashCookie := session.GetCookie("macaron_flash")
 | 
				
			||||||
 | 
							assert.NotNil(t, flashCookie)
 | 
				
			||||||
 | 
							assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527master%2527%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	csrf := GetCSRF(t, session, "/user2/repo1/settings/branches")
 | 
							// Request editor page
 | 
				
			||||||
	// Change master branch to protected
 | 
							req = NewRequest(t, "GET", "/user2/repo1/_new/master/")
 | 
				
			||||||
	req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/master", map[string]string{
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
		"_csrf":     csrf,
 | 
					
 | 
				
			||||||
		"protected": "on",
 | 
							doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
							lastCommit := doc.GetInputValueByName("last_commit")
 | 
				
			||||||
 | 
							assert.NotEmpty(t, lastCommit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Save new file to master branch
 | 
				
			||||||
 | 
							req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
 | 
				
			||||||
 | 
								"_csrf":         doc.GetCSRF(),
 | 
				
			||||||
 | 
								"last_commit":   lastCommit,
 | 
				
			||||||
 | 
								"tree_path":     "test.txt",
 | 
				
			||||||
 | 
								"content":       "Content",
 | 
				
			||||||
 | 
								"commit_choice": "direct",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
							// Check body for error message
 | 
				
			||||||
 | 
							assert.Contains(t, resp.Body.String(), "Cannot commit to protected branch 'master'.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// remove the protected branch
 | 
				
			||||||
 | 
							csrf = GetCSRF(t, session, "/user2/repo1/settings/branches")
 | 
				
			||||||
 | 
							// Change master branch to protected
 | 
				
			||||||
 | 
							req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/master", map[string]string{
 | 
				
			||||||
 | 
								"_csrf":     csrf,
 | 
				
			||||||
 | 
								"protected": "off",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							resp = session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
							// Check if master branch has been locked successfully
 | 
				
			||||||
 | 
							flashCookie = session.GetCookie("macaron_flash")
 | 
				
			||||||
 | 
							assert.NotNil(t, flashCookie)
 | 
				
			||||||
 | 
							assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527master%2527%2Bhas%2Bbeen%2Bdisabled.", flashCookie.Value)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusFound)
 | 
					 | 
				
			||||||
	// Check if master branch has been locked successfully
 | 
					 | 
				
			||||||
	flashCookie := session.GetCookie("macaron_flash")
 | 
					 | 
				
			||||||
	assert.NotNil(t, flashCookie)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527master%2527%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Request editor page
 | 
					 | 
				
			||||||
	req = NewRequest(t, "GET", "/user2/repo1/_new/master/")
 | 
					 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	doc := NewHTMLParser(t, resp.Body)
 | 
					 | 
				
			||||||
	lastCommit := doc.GetInputValueByName("last_commit")
 | 
					 | 
				
			||||||
	assert.NotEmpty(t, lastCommit)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Save new file to master branch
 | 
					 | 
				
			||||||
	req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
 | 
					 | 
				
			||||||
		"_csrf":         doc.GetCSRF(),
 | 
					 | 
				
			||||||
		"last_commit":   lastCommit,
 | 
					 | 
				
			||||||
		"tree_path":     "test.txt",
 | 
					 | 
				
			||||||
		"content":       "Content",
 | 
					 | 
				
			||||||
		"commit_choice": "direct",
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
					 | 
				
			||||||
	// Check body for error message
 | 
					 | 
				
			||||||
	assert.Contains(t, resp.Body.String(), "Cannot commit to protected branch 'master'.")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// remove the protected branch
 | 
					 | 
				
			||||||
	csrf = GetCSRF(t, session, "/user2/repo1/settings/branches")
 | 
					 | 
				
			||||||
	// Change master branch to protected
 | 
					 | 
				
			||||||
	req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/master", map[string]string{
 | 
					 | 
				
			||||||
		"_csrf":     csrf,
 | 
					 | 
				
			||||||
		"protected": "off",
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusFound)
 | 
					 | 
				
			||||||
	// Check if master branch has been locked successfully
 | 
					 | 
				
			||||||
	flashCookie = session.GetCookie("macaron_flash")
 | 
					 | 
				
			||||||
	assert.NotNil(t, flashCookie)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Bbranch%2B%2527master%2527%2Bhas%2Bbeen%2Bdisabled.", flashCookie.Value)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testEditFile(t *testing.T, session *TestSession, user, repo, branch, filePath, newContent string) *httptest.ResponseRecorder {
 | 
					func testEditFile(t *testing.T, session *TestSession, user, repo, branch, filePath, newContent string) *httptest.ResponseRecorder {
 | 
				
			||||||
@@ -151,13 +151,15 @@ func testEditFileToNewBranch(t *testing.T, session *TestSession, user, repo, bra
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestEditFile(t *testing.T) {
 | 
					func TestEditFile(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
							session := loginUser(t, "user2")
 | 
				
			||||||
	testEditFile(t, session, "user2", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user2", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestEditFileToNewBranch(t *testing.T) {
 | 
					func TestEditFileToNewBranch(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
							session := loginUser(t, "user2")
 | 
				
			||||||
	testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -178,7 +178,6 @@ func prepareTestEnv(t testing.TB, skip ...int) {
 | 
				
			|||||||
	assert.NoError(t, models.LoadFixtures())
 | 
						assert.NoError(t, models.LoadFixtures())
 | 
				
			||||||
	assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
 | 
						assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
 | 
				
			||||||
	assert.NoError(t, os.RemoveAll(models.LocalCopyPath()))
 | 
						assert.NoError(t, os.RemoveAll(models.LocalCopyPath()))
 | 
				
			||||||
	assert.NoError(t, os.RemoveAll(models.LocalWikiPath()))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.NoError(t, com.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"),
 | 
						assert.NoError(t, com.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"),
 | 
				
			||||||
		setting.RepoRootPath))
 | 
							setting.RepoRootPath))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package integrations
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
@@ -43,63 +44,65 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo, branch, titl
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullCreate(t *testing.T) {
 | 
					func TestPullCreate(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// check the redirected URL
 | 
							// check the redirected URL
 | 
				
			||||||
	url := resp.HeaderMap.Get("Location")
 | 
							url := resp.HeaderMap.Get("Location")
 | 
				
			||||||
	assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
 | 
							assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// check .diff can be accessed and matches performed change
 | 
							// check .diff can be accessed and matches performed change
 | 
				
			||||||
	req := NewRequest(t, "GET", url+".diff")
 | 
							req := NewRequest(t, "GET", url+".diff")
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	assert.Regexp(t, `\+Hello, World \(Edited\)`, resp.Body)
 | 
							assert.Regexp(t, `\+Hello, World \(Edited\)`, resp.Body)
 | 
				
			||||||
	assert.Regexp(t, "^diff", resp.Body)
 | 
							assert.Regexp(t, "^diff", resp.Body)
 | 
				
			||||||
	assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
 | 
							assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// check .patch can be accessed and matches performed change
 | 
							// check .patch can be accessed and matches performed change
 | 
				
			||||||
	req = NewRequest(t, "GET", url+".patch")
 | 
							req = NewRequest(t, "GET", url+".patch")
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	assert.Regexp(t, `\+Hello, World \(Edited\)`, resp.Body)
 | 
							assert.Regexp(t, `\+Hello, World \(Edited\)`, resp.Body)
 | 
				
			||||||
	assert.Regexp(t, "diff", resp.Body)
 | 
							assert.Regexp(t, "diff", resp.Body)
 | 
				
			||||||
	assert.Regexp(t, `Subject: \[PATCH\] Update 'README.md'`, resp.Body)
 | 
							assert.Regexp(t, `Subject: \[PATCH\] Update 'README.md'`, resp.Body)
 | 
				
			||||||
	assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
 | 
							assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullCreate_TitleEscape(t *testing.T) {
 | 
					func TestPullCreate_TitleEscape(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "master", "<i>XSS PR</i>")
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master", "<i>XSS PR</i>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// check the redirected URL
 | 
							// check the redirected URL
 | 
				
			||||||
	url := resp.HeaderMap.Get("Location")
 | 
							url := resp.HeaderMap.Get("Location")
 | 
				
			||||||
	assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
 | 
							assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Edit title
 | 
							// Edit title
 | 
				
			||||||
	req := NewRequest(t, "GET", url)
 | 
							req := NewRequest(t, "GET", url)
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	htmlDoc := NewHTMLParser(t, resp.Body)
 | 
							htmlDoc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
	editTestTitleURL, exists := htmlDoc.doc.Find("#save-edit-title").First().Attr("data-update-url")
 | 
							editTestTitleURL, exists := htmlDoc.doc.Find("#save-edit-title").First().Attr("data-update-url")
 | 
				
			||||||
	assert.True(t, exists, "The template has changed")
 | 
							assert.True(t, exists, "The template has changed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{
 | 
							req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{
 | 
				
			||||||
		"_csrf": htmlDoc.GetCSRF(),
 | 
								"_csrf": htmlDoc.GetCSRF(),
 | 
				
			||||||
		"title": "<u>XSS PR</u>",
 | 
								"title": "<u>XSS PR</u>",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							req = NewRequest(t, "GET", url)
 | 
				
			||||||
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
							htmlDoc = NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
							titleHTML, err := htmlDoc.doc.Find(".comments .event .text b").First().Html()
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							assert.Equal(t, "<i>XSS PR</i>", titleHTML)
 | 
				
			||||||
 | 
							titleHTML, err = htmlDoc.doc.Find(".comments .event .text b").Next().Html()
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							assert.Equal(t, "<u>XSS PR</u>", titleHTML)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusOK)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req = NewRequest(t, "GET", url)
 | 
					 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
					 | 
				
			||||||
	htmlDoc = NewHTMLParser(t, resp.Body)
 | 
					 | 
				
			||||||
	titleHTML, err := htmlDoc.doc.Find(".comments .event .text b").First().Html()
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Equal(t, "<i>XSS PR</i>", titleHTML)
 | 
					 | 
				
			||||||
	titleHTML, err = htmlDoc.doc.Find(".comments .event .text b").Next().Html()
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.Equal(t, "<u>XSS PR</u>", titleHTML)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package integrations
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
@@ -52,108 +53,118 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullMerge(t *testing.T) {
 | 
					func TestPullMerge(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
	assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
	testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullRebase(t *testing.T) {
 | 
					func TestPullRebase(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
	assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
	testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullRebaseMerge(t *testing.T) {
 | 
					func TestPullRebaseMerge(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							prepareTestEnv(t)
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
	assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
	testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebaseMerge)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebaseMerge)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullSquash(t *testing.T) {
 | 
					func TestPullSquash(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							prepareTestEnv(t)
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
	assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
	testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullCleanUpAfterMerge(t *testing.T) {
 | 
					func TestPullCleanUpAfterMerge(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							prepareTestEnv(t)
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
 | 
							testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "feature/test", "This is a pull title")
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "feature/test", "This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
	assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
	testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check PR branch deletion
 | 
							// Check PR branch deletion
 | 
				
			||||||
	resp = testPullCleanUp(t, session, elem[1], elem[2], elem[4])
 | 
							resp = testPullCleanUp(t, session, elem[1], elem[2], elem[4])
 | 
				
			||||||
	respJSON := struct {
 | 
							respJSON := struct {
 | 
				
			||||||
		Redirect string
 | 
								Redirect string
 | 
				
			||||||
	}{}
 | 
							}{}
 | 
				
			||||||
	DecodeJSON(t, resp, &respJSON)
 | 
							DecodeJSON(t, resp, &respJSON)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.NotEmpty(t, respJSON.Redirect, "Redirected URL is not found")
 | 
							assert.NotEmpty(t, respJSON.Redirect, "Redirected URL is not found")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elem = strings.Split(respJSON.Redirect, "/")
 | 
							elem = strings.Split(respJSON.Redirect, "/")
 | 
				
			||||||
	assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check branch deletion result
 | 
							// Check branch deletion result
 | 
				
			||||||
	req := NewRequest(t, "GET", respJSON.Redirect)
 | 
							req := NewRequest(t, "GET", respJSON.Redirect)
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	htmlDoc := NewHTMLParser(t, resp.Body)
 | 
							htmlDoc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
	resultMsg := htmlDoc.doc.Find(".ui.message>p").Text()
 | 
							resultMsg := htmlDoc.doc.Find(".ui.message>p").Text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, "Branch 'user1/feature/test' has been deleted.", resultMsg)
 | 
							assert.EqualValues(t, "Branch 'user1/feature/test' has been deleted.", resultMsg)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCantMergeWorkInProgress(t *testing.T) {
 | 
					func TestCantMergeWorkInProgress(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							prepareTestEnv(t)
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "master", "[wip] This is a pull title")
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master", "[wip] This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req := NewRequest(t, "GET", resp.Header().Get("Location"))
 | 
							req := NewRequest(t, "GET", resp.Header().Get("Location"))
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	htmlDoc := NewHTMLParser(t, resp.Body)
 | 
							htmlDoc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
	text := strings.TrimSpace(htmlDoc.doc.Find(".merge.segment > .text.grey").Text())
 | 
							text := strings.TrimSpace(htmlDoc.doc.Find(".merge.segment > .text.grey").Text())
 | 
				
			||||||
	assert.NotEmpty(t, text, "Can't find WIP text")
 | 
							assert.NotEmpty(t, text, "Can't find WIP text")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// remove <strong /> from lang
 | 
							// remove <strong /> from lang
 | 
				
			||||||
	expected := i18n.Tr("en", "repo.pulls.cannot_merge_work_in_progress", "[wip]")
 | 
							expected := i18n.Tr("en", "repo.pulls.cannot_merge_work_in_progress", "[wip]")
 | 
				
			||||||
	replacer := strings.NewReplacer("<strong>", "", "</strong>", "")
 | 
							replacer := strings.NewReplacer("<strong>", "", "</strong>", "")
 | 
				
			||||||
	assert.Equal(t, replacer.Replace(expected), text, "Unable to find WIP text")
 | 
							assert.Equal(t, replacer.Replace(expected), text, "Unable to find WIP text")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package integrations
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -16,78 +17,79 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullCreate_CommitStatus(t *testing.T) {
 | 
					func TestPullCreate_CommitStatus(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
	testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
 | 
							testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	url := path.Join("user1", "repo1", "compare", "master...status1")
 | 
							url := path.Join("user1", "repo1", "compare", "master...status1")
 | 
				
			||||||
	req := NewRequestWithValues(t, "POST", url,
 | 
							req := NewRequestWithValues(t, "POST", url,
 | 
				
			||||||
		map[string]string{
 | 
								map[string]string{
 | 
				
			||||||
			"_csrf": GetCSRF(t, session, url),
 | 
									"_csrf": GetCSRF(t, session, url),
 | 
				
			||||||
			"title": "pull request from status1",
 | 
									"title": "pull request from status1",
 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusFound)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req = NewRequest(t, "GET", "/user1/repo1/pulls")
 | 
					 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
					 | 
				
			||||||
	doc := NewHTMLParser(t, resp.Body)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Request repository commits page
 | 
					 | 
				
			||||||
	req = NewRequest(t, "GET", "/user1/repo1/pulls/1/commits")
 | 
					 | 
				
			||||||
	resp = 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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	statusList := []models.CommitStatusState{
 | 
					 | 
				
			||||||
		models.CommitStatusPending,
 | 
					 | 
				
			||||||
		models.CommitStatusError,
 | 
					 | 
				
			||||||
		models.CommitStatusFailure,
 | 
					 | 
				
			||||||
		models.CommitStatusWarning,
 | 
					 | 
				
			||||||
		models.CommitStatusSuccess,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	statesIcons := map[models.CommitStatusState]string{
 | 
					 | 
				
			||||||
		models.CommitStatusPending: "circle icon yellow",
 | 
					 | 
				
			||||||
		models.CommitStatusSuccess: "check icon green",
 | 
					 | 
				
			||||||
		models.CommitStatusError:   "warning icon red",
 | 
					 | 
				
			||||||
		models.CommitStatusFailure: "remove icon red",
 | 
					 | 
				
			||||||
		models.CommitStatusWarning: "warning sign icon yellow",
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Update commit status, and check if icon is updated as well
 | 
					 | 
				
			||||||
	for _, status := range statusList {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Call API to add status for commit
 | 
					 | 
				
			||||||
		token := getTokenForLoggedInUser(t, session)
 | 
					 | 
				
			||||||
		req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/user1/repo1/statuses/%s?token=%s", commitID, token),
 | 
					 | 
				
			||||||
			api.CreateStatusOption{
 | 
					 | 
				
			||||||
				State:       api.StatusState(status),
 | 
					 | 
				
			||||||
				TargetURL:   "http://test.ci/",
 | 
					 | 
				
			||||||
				Description: "",
 | 
					 | 
				
			||||||
				Context:     "testci",
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		session.MakeRequest(t, req, http.StatusCreated)
 | 
							session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		req = NewRequestf(t, "GET", "/user1/repo1/pulls/1/commits")
 | 
							req = NewRequest(t, "GET", "/user1/repo1/pulls")
 | 
				
			||||||
 | 
							resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
							doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Request repository commits page
 | 
				
			||||||
 | 
							req = NewRequest(t, "GET", "/user1/repo1/pulls/1/commits")
 | 
				
			||||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
		doc = NewHTMLParser(t, resp.Body)
 | 
							doc = NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		commitURL, exists = doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href")
 | 
							// Get first commit URL
 | 
				
			||||||
 | 
							commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href")
 | 
				
			||||||
		assert.True(t, exists)
 | 
							assert.True(t, exists)
 | 
				
			||||||
		assert.NotEmpty(t, commitURL)
 | 
							assert.NotEmpty(t, commitURL)
 | 
				
			||||||
		assert.EqualValues(t, commitID, path.Base(commitURL))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cls, ok := doc.doc.Find("#commits-table tbody tr td.message i.commit-status").Last().Attr("class")
 | 
							commitID := path.Base(commitURL)
 | 
				
			||||||
		assert.True(t, ok)
 | 
					
 | 
				
			||||||
		assert.EqualValues(t, "commit-status "+statesIcons[status], cls)
 | 
							statusList := []models.CommitStatusState{
 | 
				
			||||||
	}
 | 
								models.CommitStatusPending,
 | 
				
			||||||
 | 
								models.CommitStatusError,
 | 
				
			||||||
 | 
								models.CommitStatusFailure,
 | 
				
			||||||
 | 
								models.CommitStatusWarning,
 | 
				
			||||||
 | 
								models.CommitStatusSuccess,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							statesIcons := map[models.CommitStatusState]string{
 | 
				
			||||||
 | 
								models.CommitStatusPending: "circle icon yellow",
 | 
				
			||||||
 | 
								models.CommitStatusSuccess: "check icon green",
 | 
				
			||||||
 | 
								models.CommitStatusError:   "warning icon red",
 | 
				
			||||||
 | 
								models.CommitStatusFailure: "remove icon red",
 | 
				
			||||||
 | 
								models.CommitStatusWarning: "warning sign icon yellow",
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Update commit status, and check if icon is updated as well
 | 
				
			||||||
 | 
							for _, status := range statusList {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Call API to add status for commit
 | 
				
			||||||
 | 
								token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
								req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/user1/repo1/statuses/%s?token=%s", commitID, token),
 | 
				
			||||||
 | 
									api.CreateStatusOption{
 | 
				
			||||||
 | 
										State:       api.StatusState(status),
 | 
				
			||||||
 | 
										TargetURL:   "http://test.ci/",
 | 
				
			||||||
 | 
										Description: "",
 | 
				
			||||||
 | 
										Context:     "testci",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
								session.MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req = NewRequestf(t, "GET", "/user1/repo1/pulls/1/commits")
 | 
				
			||||||
 | 
								resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
								doc = NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								commitURL, exists = doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href")
 | 
				
			||||||
 | 
								assert.True(t, exists)
 | 
				
			||||||
 | 
								assert.NotEmpty(t, commitURL)
 | 
				
			||||||
 | 
								assert.EqualValues(t, commitID, path.Base(commitURL))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								cls, ok := doc.doc.Find("#commits-table tbody tr td.message i.commit-status").Last().Attr("class")
 | 
				
			||||||
 | 
								assert.True(t, ok)
 | 
				
			||||||
 | 
								assert.EqualValues(t, "commit-status "+statesIcons[status], cls)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package integrations
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -16,49 +17,51 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRepoActivity(t *testing.T) {
 | 
					func TestRepoActivity(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create PRs (1 merged & 2 proposed)
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
	testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
					 | 
				
			||||||
	testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
					 | 
				
			||||||
	resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
					 | 
				
			||||||
	elem := strings.Split(test.RedirectURL(resp), "/")
 | 
					 | 
				
			||||||
	assert.EqualValues(t, "pulls", elem[3])
 | 
					 | 
				
			||||||
	testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/better_readme", "README.md", "Hello, World (Edited Again)\n")
 | 
							// Create PRs (1 merged & 2 proposed)
 | 
				
			||||||
	testPullCreate(t, session, "user1", "repo1", "feat/better_readme", "This is a pull title")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
 | 
				
			||||||
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/much_better_readme", "README.md", "Hello, World (Edited More)\n")
 | 
							testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/better_readme", "README.md", "Hello, World (Edited Again)\n")
 | 
				
			||||||
	testPullCreate(t, session, "user1", "repo1", "feat/much_better_readme", "This is a pull title")
 | 
							testPullCreate(t, session, "user1", "repo1", "feat/better_readme", "This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create issues (3 new issues)
 | 
							testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/much_better_readme", "README.md", "Hello, World (Edited More)\n")
 | 
				
			||||||
	testNewIssue(t, session, "user2", "repo1", "Issue 1", "Description 1")
 | 
							testPullCreate(t, session, "user1", "repo1", "feat/much_better_readme", "This is a pull title")
 | 
				
			||||||
	testNewIssue(t, session, "user2", "repo1", "Issue 2", "Description 2")
 | 
					 | 
				
			||||||
	testNewIssue(t, session, "user2", "repo1", "Issue 3", "Description 3")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create releases (1 new release)
 | 
							// Create issues (3 new issues)
 | 
				
			||||||
	createNewRelease(t, session, "/user2/repo1", "v1.0.0", "v1.0.0", false, false)
 | 
							testNewIssue(t, session, "user2", "repo1", "Issue 1", "Description 1")
 | 
				
			||||||
 | 
							testNewIssue(t, session, "user2", "repo1", "Issue 2", "Description 2")
 | 
				
			||||||
 | 
							testNewIssue(t, session, "user2", "repo1", "Issue 3", "Description 3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Open Activity page and check stats
 | 
							// Create releases (1 new release)
 | 
				
			||||||
	req := NewRequest(t, "GET", "/user2/repo1/activity")
 | 
							createNewRelease(t, session, "/user2/repo1", "v1.0.0", "v1.0.0", false, false)
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
					 | 
				
			||||||
	htmlDoc := NewHTMLParser(t, resp.Body)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Should be 1 published release
 | 
							// Open Activity page and check stats
 | 
				
			||||||
	list := htmlDoc.doc.Find("#published-releases").Next().Find("p.desc")
 | 
							req := NewRequest(t, "GET", "/user2/repo1/activity")
 | 
				
			||||||
	assert.Len(t, list.Nodes, 1)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
							htmlDoc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Should be 1 merged pull request
 | 
							// Should be 1 published release
 | 
				
			||||||
	list = htmlDoc.doc.Find("#merged-pull-requests").Next().Find("p.desc")
 | 
							list := htmlDoc.doc.Find("#published-releases").Next().Find("p.desc")
 | 
				
			||||||
	assert.Len(t, list.Nodes, 1)
 | 
							assert.Len(t, list.Nodes, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Should be 2 merged proposed pull requests
 | 
							// Should be 1 merged pull request
 | 
				
			||||||
	list = htmlDoc.doc.Find("#proposed-pull-requests").Next().Find("p.desc")
 | 
							list = htmlDoc.doc.Find("#merged-pull-requests").Next().Find("p.desc")
 | 
				
			||||||
	assert.Len(t, list.Nodes, 2)
 | 
							assert.Len(t, list.Nodes, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Should be 3 new issues
 | 
							// Should be 2 merged proposed pull requests
 | 
				
			||||||
	list = htmlDoc.doc.Find("#new-issues").Next().Find("p.desc")
 | 
							list = htmlDoc.doc.Find("#proposed-pull-requests").Next().Find("p.desc")
 | 
				
			||||||
	assert.Len(t, list.Nodes, 3)
 | 
							assert.Len(t, list.Nodes, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Should be 3 new issues
 | 
				
			||||||
 | 
							list = htmlDoc.doc.Find("#new-issues").Next().Find("p.desc")
 | 
				
			||||||
 | 
							assert.Len(t, list.Nodes, 3)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package integrations
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
@@ -35,6 +36,10 @@ func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubU
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateBranch(t *testing.T) {
 | 
					func TestCreateBranch(t *testing.T) {
 | 
				
			||||||
 | 
						onGiteaRun(t, testCreateBranches)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testCreateBranches(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		OldRefSubURL   string
 | 
							OldRefSubURL   string
 | 
				
			||||||
		NewBranch      string
 | 
							NewBranch      string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,20 +2,22 @@
 | 
				
			|||||||
// Use of this source code is governed by a MIT-style
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
// license that can be found in the LICENSE file.
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package repofiles
 | 
					package integrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/repofiles"
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/test"
 | 
						"code.gitea.io/gitea/modules/test"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getDeleteRepoFileOptions(repo *models.Repository) *DeleteRepoFileOptions {
 | 
					func getDeleteRepoFileOptions(repo *models.Repository) *repofiles.DeleteRepoFileOptions {
 | 
				
			||||||
	return &DeleteRepoFileOptions{
 | 
						return &repofiles.DeleteRepoFileOptions{
 | 
				
			||||||
		LastCommitID: "",
 | 
							LastCommitID: "",
 | 
				
			||||||
		OldBranch:    repo.DefaultBranch,
 | 
							OldBranch:    repo.DefaultBranch,
 | 
				
			||||||
		NewBranch:    repo.DefaultBranch,
 | 
							NewBranch:    repo.DefaultBranch,
 | 
				
			||||||
@@ -27,15 +29,15 @@ func getDeleteRepoFileOptions(repo *models.Repository) *DeleteRepoFileOptions {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getExpectedDeleteFileResponse() *api.FileResponse {
 | 
					func getExpectedDeleteFileResponse(u *url.URL) *api.FileResponse {
 | 
				
			||||||
	return &api.FileResponse{
 | 
						return &api.FileResponse{
 | 
				
			||||||
		Content: nil,
 | 
							Content: nil,
 | 
				
			||||||
		Commit: &api.FileCommitResponse{
 | 
							Commit: &api.FileCommitResponse{
 | 
				
			||||||
			CommitMeta: api.CommitMeta{
 | 
								CommitMeta: api.CommitMeta{
 | 
				
			||||||
				URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
									URL: u.String() + "api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
				SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
									SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			HTMLURL: "https://try.gitea.io/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
								HTMLURL: u.String() + "user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
			Author: &api.CommitUser{
 | 
								Author: &api.CommitUser{
 | 
				
			||||||
				Identity: api.Identity{
 | 
									Identity: api.Identity{
 | 
				
			||||||
					Name:  "user1",
 | 
										Name:  "user1",
 | 
				
			||||||
@@ -53,7 +55,7 @@ func getExpectedDeleteFileResponse() *api.FileResponse {
 | 
				
			|||||||
			Parents: []*api.CommitMeta{},
 | 
								Parents: []*api.CommitMeta{},
 | 
				
			||||||
			Message: "Initial commit\n",
 | 
								Message: "Initial commit\n",
 | 
				
			||||||
			Tree: &api.CommitMeta{
 | 
								Tree: &api.CommitMeta{
 | 
				
			||||||
				URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/trees/2a2f1d4670728a2e10049e345bd7a276468beab6",
 | 
									URL: u.String() + "api/v1/repos/user2/repo1/git/trees/2a2f1d4670728a2e10049e345bd7a276468beab6",
 | 
				
			||||||
				SHA: "2a2f1d4670728a2e10049e345bd7a276468beab6",
 | 
									SHA: "2a2f1d4670728a2e10049e345bd7a276468beab6",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -67,6 +69,10 @@ func getExpectedDeleteFileResponse() *api.FileResponse {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDeleteRepoFile(t *testing.T) {
 | 
					func TestDeleteRepoFile(t *testing.T) {
 | 
				
			||||||
 | 
						onGiteaRun(t, testDeleteRepoFile)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testDeleteRepoFile(t *testing.T, u *url.URL) {
 | 
				
			||||||
	// setup
 | 
						// setup
 | 
				
			||||||
	models.PrepareTestEnv(t)
 | 
						models.PrepareTestEnv(t)
 | 
				
			||||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
						ctx := test.MockContext(t, "user2/repo1")
 | 
				
			||||||
@@ -80,14 +86,14 @@ func TestDeleteRepoFile(t *testing.T) {
 | 
				
			|||||||
	opts := getDeleteRepoFileOptions(repo)
 | 
						opts := getDeleteRepoFileOptions(repo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("Delete README.md file", func(t *testing.T) {
 | 
						t.Run("Delete README.md file", func(t *testing.T) {
 | 
				
			||||||
		fileResponse, err := DeleteRepoFile(repo, doer, opts)
 | 
							fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
 | 
				
			||||||
		assert.Nil(t, err)
 | 
							assert.Nil(t, err)
 | 
				
			||||||
		expectedFileResponse := getExpectedDeleteFileResponse()
 | 
							expectedFileResponse := getExpectedDeleteFileResponse(u)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse, fileResponse)
 | 
							assert.EqualValues(t, expectedFileResponse, fileResponse)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("Verify README.md has been deleted", func(t *testing.T) {
 | 
						t.Run("Verify README.md has been deleted", func(t *testing.T) {
 | 
				
			||||||
		fileResponse, err := DeleteRepoFile(repo, doer, opts)
 | 
							fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
							assert.Nil(t, fileResponse)
 | 
				
			||||||
		expectedError := "repository file does not exist [path: " + opts.TreePath + "]"
 | 
							expectedError := "repository file does not exist [path: " + opts.TreePath + "]"
 | 
				
			||||||
		assert.EqualError(t, err, expectedError)
 | 
							assert.EqualError(t, err, expectedError)
 | 
				
			||||||
@@ -96,6 +102,10 @@ func TestDeleteRepoFile(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Test opts with branch names removed, same results
 | 
					// Test opts with branch names removed, same results
 | 
				
			||||||
func TestDeleteRepoFileWithoutBranchNames(t *testing.T) {
 | 
					func TestDeleteRepoFileWithoutBranchNames(t *testing.T) {
 | 
				
			||||||
 | 
						onGiteaRun(t, testDeleteRepoFileWithoutBranchNames)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testDeleteRepoFileWithoutBranchNames(t *testing.T, u *url.URL) {
 | 
				
			||||||
	// setup
 | 
						// setup
 | 
				
			||||||
	models.PrepareTestEnv(t)
 | 
						models.PrepareTestEnv(t)
 | 
				
			||||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
						ctx := test.MockContext(t, "user2/repo1")
 | 
				
			||||||
@@ -111,9 +121,9 @@ func TestDeleteRepoFileWithoutBranchNames(t *testing.T) {
 | 
				
			|||||||
	opts.NewBranch = ""
 | 
						opts.NewBranch = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("Delete README.md without Branch Name", func(t *testing.T) {
 | 
						t.Run("Delete README.md without Branch Name", func(t *testing.T) {
 | 
				
			||||||
		fileResponse, err := DeleteRepoFile(repo, doer, opts)
 | 
							fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
 | 
				
			||||||
		assert.Nil(t, err)
 | 
							assert.Nil(t, err)
 | 
				
			||||||
		expectedFileResponse := getExpectedDeleteFileResponse()
 | 
							expectedFileResponse := getExpectedDeleteFileResponse(u)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse, fileResponse)
 | 
							assert.EqualValues(t, expectedFileResponse, fileResponse)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -133,7 +143,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
 | 
				
			|||||||
	t.Run("Bad branch", func(t *testing.T) {
 | 
						t.Run("Bad branch", func(t *testing.T) {
 | 
				
			||||||
		opts := getDeleteRepoFileOptions(repo)
 | 
							opts := getDeleteRepoFileOptions(repo)
 | 
				
			||||||
		opts.OldBranch = "bad_branch"
 | 
							opts.OldBranch = "bad_branch"
 | 
				
			||||||
		fileResponse, err := DeleteRepoFile(repo, doer, opts)
 | 
							fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
 | 
				
			||||||
		assert.Error(t, err)
 | 
							assert.Error(t, err)
 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
							assert.Nil(t, fileResponse)
 | 
				
			||||||
		expectedError := "branch does not exist [name: " + opts.OldBranch + "]"
 | 
							expectedError := "branch does not exist [name: " + opts.OldBranch + "]"
 | 
				
			||||||
@@ -144,7 +154,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
 | 
				
			|||||||
		opts := getDeleteRepoFileOptions(repo)
 | 
							opts := getDeleteRepoFileOptions(repo)
 | 
				
			||||||
		origSHA := opts.SHA
 | 
							origSHA := opts.SHA
 | 
				
			||||||
		opts.SHA = "bad_sha"
 | 
							opts.SHA = "bad_sha"
 | 
				
			||||||
		fileResponse, err := DeleteRepoFile(repo, doer, opts)
 | 
							fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
							assert.Nil(t, fileResponse)
 | 
				
			||||||
		assert.Error(t, err)
 | 
							assert.Error(t, err)
 | 
				
			||||||
		expectedError := "sha does not match [given: " + opts.SHA + ", expected: " + origSHA + "]"
 | 
							expectedError := "sha does not match [given: " + opts.SHA + ", expected: " + origSHA + "]"
 | 
				
			||||||
@@ -154,7 +164,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
 | 
				
			|||||||
	t.Run("New branch already exists", func(t *testing.T) {
 | 
						t.Run("New branch already exists", func(t *testing.T) {
 | 
				
			||||||
		opts := getDeleteRepoFileOptions(repo)
 | 
							opts := getDeleteRepoFileOptions(repo)
 | 
				
			||||||
		opts.NewBranch = "develop"
 | 
							opts.NewBranch = "develop"
 | 
				
			||||||
		fileResponse, err := DeleteRepoFile(repo, doer, opts)
 | 
							fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
							assert.Nil(t, fileResponse)
 | 
				
			||||||
		assert.Error(t, err)
 | 
							assert.Error(t, err)
 | 
				
			||||||
		expectedError := "branch already exists [name: " + opts.NewBranch + "]"
 | 
							expectedError := "branch already exists [name: " + opts.NewBranch + "]"
 | 
				
			||||||
@@ -164,7 +174,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
 | 
				
			|||||||
	t.Run("TreePath is empty:", func(t *testing.T) {
 | 
						t.Run("TreePath is empty:", func(t *testing.T) {
 | 
				
			||||||
		opts := getDeleteRepoFileOptions(repo)
 | 
							opts := getDeleteRepoFileOptions(repo)
 | 
				
			||||||
		opts.TreePath = ""
 | 
							opts.TreePath = ""
 | 
				
			||||||
		fileResponse, err := DeleteRepoFile(repo, doer, opts)
 | 
							fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
							assert.Nil(t, fileResponse)
 | 
				
			||||||
		assert.Error(t, err)
 | 
							assert.Error(t, err)
 | 
				
			||||||
		expectedError := "path contains a malformed path component [path: ]"
 | 
							expectedError := "path contains a malformed path component [path: ]"
 | 
				
			||||||
@@ -174,7 +184,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
 | 
				
			|||||||
	t.Run("TreePath is a git directory:", func(t *testing.T) {
 | 
						t.Run("TreePath is a git directory:", func(t *testing.T) {
 | 
				
			||||||
		opts := getDeleteRepoFileOptions(repo)
 | 
							opts := getDeleteRepoFileOptions(repo)
 | 
				
			||||||
		opts.TreePath = ".git"
 | 
							opts.TreePath = ".git"
 | 
				
			||||||
		fileResponse, err := DeleteRepoFile(repo, doer, opts)
 | 
							fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
							assert.Nil(t, fileResponse)
 | 
				
			||||||
		assert.Error(t, err)
 | 
							assert.Error(t, err)
 | 
				
			||||||
		expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]"
 | 
							expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]"
 | 
				
			||||||
							
								
								
									
										365
									
								
								integrations/repofiles_update_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								integrations/repofiles_update_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,365 @@
 | 
				
			|||||||
 | 
					// 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package integrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/repofiles"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/test"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getCreateRepoFileOptions(repo *models.Repository) *repofiles.UpdateRepoFileOptions {
 | 
				
			||||||
 | 
						return &repofiles.UpdateRepoFileOptions{
 | 
				
			||||||
 | 
							OldBranch: repo.DefaultBranch,
 | 
				
			||||||
 | 
							NewBranch: repo.DefaultBranch,
 | 
				
			||||||
 | 
							TreePath:  "new/file.txt",
 | 
				
			||||||
 | 
							Message:   "Creates new/file.txt",
 | 
				
			||||||
 | 
							Content:   "This is a NEW file",
 | 
				
			||||||
 | 
							IsNewFile: true,
 | 
				
			||||||
 | 
							Author:    nil,
 | 
				
			||||||
 | 
							Committer: nil,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getUpdateRepoFileOptions(repo *models.Repository) *repofiles.UpdateRepoFileOptions {
 | 
				
			||||||
 | 
						return &repofiles.UpdateRepoFileOptions{
 | 
				
			||||||
 | 
							OldBranch: repo.DefaultBranch,
 | 
				
			||||||
 | 
							NewBranch: repo.DefaultBranch,
 | 
				
			||||||
 | 
							TreePath:  "README.md",
 | 
				
			||||||
 | 
							Message:   "Updates README.md",
 | 
				
			||||||
 | 
							SHA:       "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
 | 
				
			||||||
 | 
							Content:   "This is UPDATED content for the README file",
 | 
				
			||||||
 | 
							IsNewFile: false,
 | 
				
			||||||
 | 
							Author:    nil,
 | 
				
			||||||
 | 
							Committer: nil,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileResponse {
 | 
				
			||||||
 | 
						return &api.FileResponse{
 | 
				
			||||||
 | 
							Content: &api.FileContentResponse{
 | 
				
			||||||
 | 
								Name:        "file.txt",
 | 
				
			||||||
 | 
								Path:        "new/file.txt",
 | 
				
			||||||
 | 
								SHA:         "103ff9234cefeee5ec5361d22b49fbb04d385885",
 | 
				
			||||||
 | 
								Size:        18,
 | 
				
			||||||
 | 
								URL:         setting.AppURL + "api/v1/repos/user2/repo1/contents/new/file.txt",
 | 
				
			||||||
 | 
								HTMLURL:     setting.AppURL + "user2/repo1/blob/master/new/file.txt",
 | 
				
			||||||
 | 
								GitURL:      setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/103ff9234cefeee5ec5361d22b49fbb04d385885",
 | 
				
			||||||
 | 
								DownloadURL: setting.AppURL + "user2/repo1/raw/branch/master/new/file.txt",
 | 
				
			||||||
 | 
								Type:        "blob",
 | 
				
			||||||
 | 
								Links: &api.FileLinksResponse{
 | 
				
			||||||
 | 
									Self:    setting.AppURL + "api/v1/repos/user2/repo1/contents/new/file.txt",
 | 
				
			||||||
 | 
									GitURL:  setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/103ff9234cefeee5ec5361d22b49fbb04d385885",
 | 
				
			||||||
 | 
									HTMLURL: setting.AppURL + "user2/repo1/blob/master/new/file.txt",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Commit: &api.FileCommitResponse{
 | 
				
			||||||
 | 
								CommitMeta: api.CommitMeta{
 | 
				
			||||||
 | 
									URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/" + commitID,
 | 
				
			||||||
 | 
									SHA: commitID,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								HTMLURL: setting.AppURL + "user2/repo1/commit/" + commitID,
 | 
				
			||||||
 | 
								Author: &api.CommitUser{
 | 
				
			||||||
 | 
									Identity: api.Identity{
 | 
				
			||||||
 | 
										Name:  "User Two",
 | 
				
			||||||
 | 
										Email: "user2@noreply.example.org",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Date: time.Now().UTC().Format(time.RFC3339),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Committer: &api.CommitUser{
 | 
				
			||||||
 | 
									Identity: api.Identity{
 | 
				
			||||||
 | 
										Name:  "User Two",
 | 
				
			||||||
 | 
										Email: "user2@noreply.example.org",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Date: time.Now().UTC().Format(time.RFC3339),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Parents: []*api.CommitMeta{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
 | 
										SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Message: "Updates README.md\n",
 | 
				
			||||||
 | 
								Tree: &api.CommitMeta{
 | 
				
			||||||
 | 
									URL: setting.AppURL + "api/v1/repos/user2/repo1/git/trees/f93e3a1a1525fb5b91020da86e44810c87a2d7bc",
 | 
				
			||||||
 | 
									SHA: "f93e3a1a1525fb5b91020git dda86e44810c87a2d7bc",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Verification: &api.PayloadCommitVerification{
 | 
				
			||||||
 | 
								Verified:  false,
 | 
				
			||||||
 | 
								Reason:    "unsigned",
 | 
				
			||||||
 | 
								Signature: "",
 | 
				
			||||||
 | 
								Payload:   "",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getExpectedFileResponseForRepofilesUpdate(commitID string) *api.FileResponse {
 | 
				
			||||||
 | 
						return &api.FileResponse{
 | 
				
			||||||
 | 
							Content: &api.FileContentResponse{
 | 
				
			||||||
 | 
								Name:        "README.md",
 | 
				
			||||||
 | 
								Path:        "README.md",
 | 
				
			||||||
 | 
								SHA:         "dbf8d00e022e05b7e5cf7e535de857de57925647",
 | 
				
			||||||
 | 
								Size:        43,
 | 
				
			||||||
 | 
								URL:         setting.AppURL + "api/v1/repos/user2/repo1/contents/README.md",
 | 
				
			||||||
 | 
								HTMLURL:     setting.AppURL + "user2/repo1/blob/master/README.md",
 | 
				
			||||||
 | 
								GitURL:      setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/dbf8d00e022e05b7e5cf7e535de857de57925647",
 | 
				
			||||||
 | 
								DownloadURL: setting.AppURL + "user2/repo1/raw/branch/master/README.md",
 | 
				
			||||||
 | 
								Type:        "blob",
 | 
				
			||||||
 | 
								Links: &api.FileLinksResponse{
 | 
				
			||||||
 | 
									Self:    setting.AppURL + "api/v1/repos/user2/repo1/contents/README.md",
 | 
				
			||||||
 | 
									GitURL:  setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/dbf8d00e022e05b7e5cf7e535de857de57925647",
 | 
				
			||||||
 | 
									HTMLURL: setting.AppURL + "user2/repo1/blob/master/README.md",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Commit: &api.FileCommitResponse{
 | 
				
			||||||
 | 
								CommitMeta: api.CommitMeta{
 | 
				
			||||||
 | 
									URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/" + commitID,
 | 
				
			||||||
 | 
									SHA: commitID,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								HTMLURL: setting.AppURL + "user2/repo1/commit/" + commitID,
 | 
				
			||||||
 | 
								Author: &api.CommitUser{
 | 
				
			||||||
 | 
									Identity: api.Identity{
 | 
				
			||||||
 | 
										Name:  "User Two",
 | 
				
			||||||
 | 
										Email: "user2@noreply.example.org",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Date: time.Now().UTC().Format(time.RFC3339),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Committer: &api.CommitUser{
 | 
				
			||||||
 | 
									Identity: api.Identity{
 | 
				
			||||||
 | 
										Name:  "User Two",
 | 
				
			||||||
 | 
										Email: "user2@noreply.example.org",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Date: time.Now().UTC().Format(time.RFC3339),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Parents: []*api.CommitMeta{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
 | 
										SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Message: "Updates README.md\n",
 | 
				
			||||||
 | 
								Tree: &api.CommitMeta{
 | 
				
			||||||
 | 
									URL: setting.AppURL + "api/v1/repos/user2/repo1/git/trees/f93e3a1a1525fb5b91020da86e44810c87a2d7bc",
 | 
				
			||||||
 | 
									SHA: "f93e3a1a1525fb5b91020da86e44810c87a2d7bc",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Verification: &api.PayloadCommitVerification{
 | 
				
			||||||
 | 
								Verified:  false,
 | 
				
			||||||
 | 
								Reason:    "unsigned",
 | 
				
			||||||
 | 
								Signature: "",
 | 
				
			||||||
 | 
								Payload:   "",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCreateOrUpdateRepoFileForCreate(t *testing.T) {
 | 
				
			||||||
 | 
						// setup
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							ctx := test.MockContext(t, "user2/repo1")
 | 
				
			||||||
 | 
							ctx.SetParams(":id", "1")
 | 
				
			||||||
 | 
							test.LoadRepo(t, ctx, 1)
 | 
				
			||||||
 | 
							test.LoadRepoCommit(t, ctx)
 | 
				
			||||||
 | 
							test.LoadUser(t, ctx, 2)
 | 
				
			||||||
 | 
							test.LoadGitRepo(t, ctx)
 | 
				
			||||||
 | 
							repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
							doer := ctx.User
 | 
				
			||||||
 | 
							opts := getCreateRepoFileOptions(repo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// test
 | 
				
			||||||
 | 
							fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// asserts
 | 
				
			||||||
 | 
							assert.Nil(t, err)
 | 
				
			||||||
 | 
							gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
				
			||||||
 | 
							commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCreateOrUpdateRepoFileForUpdate(t *testing.T) {
 | 
				
			||||||
 | 
						// setup
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							ctx := test.MockContext(t, "user2/repo1")
 | 
				
			||||||
 | 
							ctx.SetParams(":id", "1")
 | 
				
			||||||
 | 
							test.LoadRepo(t, ctx, 1)
 | 
				
			||||||
 | 
							test.LoadRepoCommit(t, ctx)
 | 
				
			||||||
 | 
							test.LoadUser(t, ctx, 2)
 | 
				
			||||||
 | 
							test.LoadGitRepo(t, ctx)
 | 
				
			||||||
 | 
							repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
							doer := ctx.User
 | 
				
			||||||
 | 
							opts := getUpdateRepoFileOptions(repo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// test
 | 
				
			||||||
 | 
							fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// asserts
 | 
				
			||||||
 | 
							assert.Nil(t, err)
 | 
				
			||||||
 | 
							gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
				
			||||||
 | 
							commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCreateOrUpdateRepoFileForUpdateWithFileMove(t *testing.T) {
 | 
				
			||||||
 | 
						// setup
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							ctx := test.MockContext(t, "user2/repo1")
 | 
				
			||||||
 | 
							ctx.SetParams(":id", "1")
 | 
				
			||||||
 | 
							test.LoadRepo(t, ctx, 1)
 | 
				
			||||||
 | 
							test.LoadRepoCommit(t, ctx)
 | 
				
			||||||
 | 
							test.LoadUser(t, ctx, 2)
 | 
				
			||||||
 | 
							test.LoadGitRepo(t, ctx)
 | 
				
			||||||
 | 
							repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
							doer := ctx.User
 | 
				
			||||||
 | 
							opts := getUpdateRepoFileOptions(repo)
 | 
				
			||||||
 | 
							suffix := "_new"
 | 
				
			||||||
 | 
							opts.FromTreePath = "README.md"
 | 
				
			||||||
 | 
							opts.TreePath = "README.md" + suffix // new file name, README.md_new
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// test
 | 
				
			||||||
 | 
							fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// asserts
 | 
				
			||||||
 | 
							assert.Nil(t, err)
 | 
				
			||||||
 | 
							gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
				
			||||||
 | 
							commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String())
 | 
				
			||||||
 | 
							// assert that the old file no longer exists in the last commit of the branch
 | 
				
			||||||
 | 
							fromEntry, err := commit.GetTreeEntryByPath(opts.FromTreePath)
 | 
				
			||||||
 | 
							toEntry, err := commit.GetTreeEntryByPath(opts.TreePath)
 | 
				
			||||||
 | 
							assert.Nil(t, fromEntry)  // Should no longer exist here
 | 
				
			||||||
 | 
							assert.NotNil(t, toEntry) // Should exist here
 | 
				
			||||||
 | 
							// assert SHA has remained the same but paths use the new file name
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Content.SHA, fileResponse.Content.SHA)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Content.Name+suffix, fileResponse.Content.Name)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Content.Path+suffix, fileResponse.Content.Path)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Content.URL+suffix, fileResponse.Content.URL)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test opts with branch names removed, should get same results as above test
 | 
				
			||||||
 | 
					func TestCreateOrUpdateRepoFileWithoutBranchNames(t *testing.T) {
 | 
				
			||||||
 | 
						// setup
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							ctx := test.MockContext(t, "user2/repo1")
 | 
				
			||||||
 | 
							ctx.SetParams(":id", "1")
 | 
				
			||||||
 | 
							test.LoadRepo(t, ctx, 1)
 | 
				
			||||||
 | 
							test.LoadRepoCommit(t, ctx)
 | 
				
			||||||
 | 
							test.LoadUser(t, ctx, 2)
 | 
				
			||||||
 | 
							test.LoadGitRepo(t, ctx)
 | 
				
			||||||
 | 
							repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
							doer := ctx.User
 | 
				
			||||||
 | 
							opts := getUpdateRepoFileOptions(repo)
 | 
				
			||||||
 | 
							opts.OldBranch = ""
 | 
				
			||||||
 | 
							opts.NewBranch = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// test
 | 
				
			||||||
 | 
							fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// asserts
 | 
				
			||||||
 | 
							assert.Nil(t, err)
 | 
				
			||||||
 | 
							gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
				
			||||||
 | 
							commitID, _ := gitRepo.GetBranchCommitID(repo.DefaultBranch)
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID)
 | 
				
			||||||
 | 
							assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCreateOrUpdateRepoFileErrors(t *testing.T) {
 | 
				
			||||||
 | 
						// setup
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							ctx := test.MockContext(t, "user2/repo1")
 | 
				
			||||||
 | 
							ctx.SetParams(":id", "1")
 | 
				
			||||||
 | 
							test.LoadRepo(t, ctx, 1)
 | 
				
			||||||
 | 
							test.LoadRepoCommit(t, ctx)
 | 
				
			||||||
 | 
							test.LoadUser(t, ctx, 2)
 | 
				
			||||||
 | 
							test.LoadGitRepo(t, ctx)
 | 
				
			||||||
 | 
							repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
							doer := ctx.User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("bad branch", func(t *testing.T) {
 | 
				
			||||||
 | 
								opts := getUpdateRepoFileOptions(repo)
 | 
				
			||||||
 | 
								opts.OldBranch = "bad_branch"
 | 
				
			||||||
 | 
								fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
								assert.Error(t, err)
 | 
				
			||||||
 | 
								assert.Nil(t, fileResponse)
 | 
				
			||||||
 | 
								expectedError := "branch does not exist [name: " + opts.OldBranch + "]"
 | 
				
			||||||
 | 
								assert.EqualError(t, err, expectedError)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("bad SHA", func(t *testing.T) {
 | 
				
			||||||
 | 
								opts := getUpdateRepoFileOptions(repo)
 | 
				
			||||||
 | 
								origSHA := opts.SHA
 | 
				
			||||||
 | 
								opts.SHA = "bad_sha"
 | 
				
			||||||
 | 
								fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
								assert.Nil(t, fileResponse)
 | 
				
			||||||
 | 
								assert.Error(t, err)
 | 
				
			||||||
 | 
								expectedError := "sha does not match [given: " + opts.SHA + ", expected: " + origSHA + "]"
 | 
				
			||||||
 | 
								assert.EqualError(t, err, expectedError)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("new branch already exists", func(t *testing.T) {
 | 
				
			||||||
 | 
								opts := getUpdateRepoFileOptions(repo)
 | 
				
			||||||
 | 
								opts.NewBranch = "develop"
 | 
				
			||||||
 | 
								fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
								assert.Nil(t, fileResponse)
 | 
				
			||||||
 | 
								assert.Error(t, err)
 | 
				
			||||||
 | 
								expectedError := "branch already exists [name: " + opts.NewBranch + "]"
 | 
				
			||||||
 | 
								assert.EqualError(t, err, expectedError)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("treePath is empty:", func(t *testing.T) {
 | 
				
			||||||
 | 
								opts := getUpdateRepoFileOptions(repo)
 | 
				
			||||||
 | 
								opts.TreePath = ""
 | 
				
			||||||
 | 
								fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
								assert.Nil(t, fileResponse)
 | 
				
			||||||
 | 
								assert.Error(t, err)
 | 
				
			||||||
 | 
								expectedError := "path contains a malformed path component [path: ]"
 | 
				
			||||||
 | 
								assert.EqualError(t, err, expectedError)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("treePath is a git directory:", func(t *testing.T) {
 | 
				
			||||||
 | 
								opts := getUpdateRepoFileOptions(repo)
 | 
				
			||||||
 | 
								opts.TreePath = ".git"
 | 
				
			||||||
 | 
								fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
								assert.Nil(t, fileResponse)
 | 
				
			||||||
 | 
								assert.Error(t, err)
 | 
				
			||||||
 | 
								expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]"
 | 
				
			||||||
 | 
								assert.EqualError(t, err, expectedError)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							t.Run("create file that already exists", func(t *testing.T) {
 | 
				
			||||||
 | 
								opts := getCreateRepoFileOptions(repo)
 | 
				
			||||||
 | 
								opts.TreePath = "README.md" //already exists
 | 
				
			||||||
 | 
								fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts)
 | 
				
			||||||
 | 
								assert.Nil(t, fileResponse)
 | 
				
			||||||
 | 
								assert.Error(t, err)
 | 
				
			||||||
 | 
								expectedError := "repository file already exists [path: " + opts.TreePath + "]"
 | 
				
			||||||
 | 
								assert.EqualError(t, err, expectedError)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										45
									
								
								models/helper_directory.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								models/helper_directory.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					// 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/Unknwon/com"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LocalCopyPath returns the local repository temporary copy path.
 | 
				
			||||||
 | 
					func LocalCopyPath() string {
 | 
				
			||||||
 | 
						if filepath.IsAbs(setting.Repository.Local.LocalCopyPath) {
 | 
				
			||||||
 | 
							return setting.Repository.Local.LocalCopyPath
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return path.Join(setting.AppDataPath, setting.Repository.Local.LocalCopyPath)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CreateTemporaryPath creates a temporary path
 | 
				
			||||||
 | 
					func CreateTemporaryPath(prefix string) (string, error) {
 | 
				
			||||||
 | 
						timeStr := com.ToStr(time.Now().Nanosecond()) // SHOULD USE SOMETHING UNIQUE
 | 
				
			||||||
 | 
						basePath := path.Join(LocalCopyPath(), prefix+"-"+timeStr+".git")
 | 
				
			||||||
 | 
						if err := os.MkdirAll(filepath.Dir(basePath), os.ModePerm); err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to create temporary directory: %s (%v)", basePath, err)
 | 
				
			||||||
 | 
							return "", fmt.Errorf("Failed to create dir %s: %v", basePath, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return basePath, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoveTemporaryPath removes the temporary path
 | 
				
			||||||
 | 
					func RemoveTemporaryPath(basePath string) error {
 | 
				
			||||||
 | 
						if _, err := os.Stat(basePath); !os.IsNotExist(err) {
 | 
				
			||||||
 | 
							return os.RemoveAll(basePath)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								models/helper_environment.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								models/helper_environment.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					// 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PushingEnvironment returns an os environment to allow hooks to work on push
 | 
				
			||||||
 | 
					func PushingEnvironment(doer *User, repo *Repository) []string {
 | 
				
			||||||
 | 
						isWiki := "false"
 | 
				
			||||||
 | 
						if strings.HasSuffix(repo.Name, ".wiki") {
 | 
				
			||||||
 | 
							isWiki = "true"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sig := doer.NewGitSig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return append(os.Environ(),
 | 
				
			||||||
 | 
							"GIT_AUTHOR_NAME="+sig.Name,
 | 
				
			||||||
 | 
							"GIT_AUTHOR_EMAIL="+sig.Email,
 | 
				
			||||||
 | 
							"GIT_COMMITTER_NAME="+sig.Name,
 | 
				
			||||||
 | 
							"GIT_COMMITTER_EMAIL="+sig.Email,
 | 
				
			||||||
 | 
							EnvRepoName+"="+repo.Name,
 | 
				
			||||||
 | 
							EnvRepoUsername+"="+repo.OwnerName,
 | 
				
			||||||
 | 
							EnvRepoIsWiki+"="+isWiki,
 | 
				
			||||||
 | 
							EnvPusherName+"="+doer.Name,
 | 
				
			||||||
 | 
							EnvPusherID+"="+fmt.Sprintf("%d", doer.ID),
 | 
				
			||||||
 | 
							ProtectedBranchRepoID+"="+fmt.Sprintf("%d", repo.ID),
 | 
				
			||||||
 | 
							"SSH_ORIGINAL_COMMAND=gitea-internal",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -418,22 +418,21 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 | 
				
			|||||||
		go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
 | 
							go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Clone base repo.
 | 
				
			||||||
 | 
						tmpBasePath, err := CreateTemporaryPath("merge")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer RemoveTemporaryPath(tmpBasePath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
 | 
						headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Clone base repo.
 | 
						if err := git.Clone(baseGitRepo.Path, tmpBasePath, git.CloneRepoOptions{
 | 
				
			||||||
	tmpBasePath := path.Join(LocalCopyPath(), "merge-"+com.ToStr(time.Now().Nanosecond())+".git")
 | 
							Shared:     true,
 | 
				
			||||||
 | 
							NoCheckout: true,
 | 
				
			||||||
	if err := os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm); err != nil {
 | 
							Branch:     pr.BaseBranch,
 | 
				
			||||||
		return fmt.Errorf("Failed to create dir %s: %v", tmpBasePath, err)
 | 
						}); err != nil {
 | 
				
			||||||
	}
 | 
							return fmt.Errorf("git clone: %v", err)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	defer os.RemoveAll(tmpBasePath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var stderr string
 | 
					 | 
				
			||||||
	if _, stderr, err = process.GetManager().ExecTimeout(5*time.Minute,
 | 
					 | 
				
			||||||
		fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath),
 | 
					 | 
				
			||||||
		"git", "clone", "-s", "--no-checkout", "-b", pr.BaseBranch, baseGitRepo.Path, tmpBasePath); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("git clone: %s", stderr)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	remoteRepoName := "head_repo"
 | 
						remoteRepoName := "head_repo"
 | 
				
			||||||
@@ -456,14 +455,14 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 | 
				
			|||||||
	if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil {
 | 
						if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil {
 | 
				
			||||||
		return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err)
 | 
							return fmt.Errorf("addCacheRepo [%s -> %s]: %v", headRepoPath, tmpBasePath, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
						if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
		fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath),
 | 
							fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath),
 | 
				
			||||||
		"git", "remote", "add", remoteRepoName, headRepoPath); err != nil {
 | 
							"git", "remote", "add", remoteRepoName, headRepoPath); err != nil {
 | 
				
			||||||
		return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
							return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Fetch head branch
 | 
						// Fetch head branch
 | 
				
			||||||
	if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
						if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
		fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath),
 | 
							fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath),
 | 
				
			||||||
		"git", "fetch", remoteRepoName); err != nil {
 | 
							"git", "fetch", remoteRepoName); err != nil {
 | 
				
			||||||
		return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
							return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
				
			||||||
@@ -487,14 +486,14 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 | 
				
			|||||||
		return fmt.Errorf("Writing sparse-checkout file to %s: %v", sparseCheckoutListPath, err)
 | 
							return fmt.Errorf("Writing sparse-checkout file to %s: %v", sparseCheckoutListPath, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
						if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
		fmt.Sprintf("PullRequest.Merge (git config): %s", tmpBasePath),
 | 
							fmt.Sprintf("PullRequest.Merge (git config): %s", tmpBasePath),
 | 
				
			||||||
		"git", "config", "--local", "core.sparseCheckout", "true"); err != nil {
 | 
							"git", "config", "--local", "core.sparseCheckout", "true"); err != nil {
 | 
				
			||||||
		return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", stderr)
 | 
							return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", stderr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Read base branch index
 | 
						// Read base branch index
 | 
				
			||||||
	if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
						if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
		fmt.Sprintf("PullRequest.Merge (git read-tree): %s", tmpBasePath),
 | 
							fmt.Sprintf("PullRequest.Merge (git read-tree): %s", tmpBasePath),
 | 
				
			||||||
		"git", "read-tree", "HEAD"); err != nil {
 | 
							"git", "read-tree", "HEAD"); err != nil {
 | 
				
			||||||
		return fmt.Errorf("git read-tree HEAD: %s", stderr)
 | 
							return fmt.Errorf("git read-tree HEAD: %s", stderr)
 | 
				
			||||||
@@ -503,14 +502,14 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 | 
				
			|||||||
	// Merge commits.
 | 
						// Merge commits.
 | 
				
			||||||
	switch mergeStyle {
 | 
						switch mergeStyle {
 | 
				
			||||||
	case MergeStyleMerge:
 | 
						case MergeStyleMerge:
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath),
 | 
				
			||||||
			"git", "merge", "--no-ff", "--no-commit", trackingBranch); err != nil {
 | 
								"git", "merge", "--no-ff", "--no-commit", trackingBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr)
 | 
								return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sig := doer.NewGitSig()
 | 
							sig := doer.NewGitSig()
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
 | 
				
			||||||
			"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
 | 
								"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
 | 
				
			||||||
			"-m", message); err != nil {
 | 
								"-m", message); err != nil {
 | 
				
			||||||
@@ -518,50 +517,50 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	case MergeStyleRebase:
 | 
						case MergeStyleRebase:
 | 
				
			||||||
		// Checkout head branch
 | 
							// Checkout head branch
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
 | 
				
			||||||
			"git", "checkout", "-b", stagingBranch, trackingBranch); err != nil {
 | 
								"git", "checkout", "-b", stagingBranch, trackingBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git checkout: %s", stderr)
 | 
								return fmt.Errorf("git checkout: %s", stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Rebase before merging
 | 
							// Rebase before merging
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
 | 
				
			||||||
			"git", "rebase", "-q", pr.BaseBranch); err != nil {
 | 
								"git", "rebase", "-q", pr.BaseBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
								return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Checkout base branch again
 | 
							// Checkout base branch again
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
 | 
				
			||||||
			"git", "checkout", pr.BaseBranch); err != nil {
 | 
								"git", "checkout", pr.BaseBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git checkout: %s", stderr)
 | 
								return fmt.Errorf("git checkout: %s", stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Merge fast forward
 | 
							// Merge fast forward
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
 | 
				
			||||||
			"git", "merge", "--ff-only", "-q", stagingBranch); err != nil {
 | 
								"git", "merge", "--ff-only", "-q", stagingBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
								return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case MergeStyleRebaseMerge:
 | 
						case MergeStyleRebaseMerge:
 | 
				
			||||||
		// Checkout head branch
 | 
							// Checkout head branch
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
 | 
				
			||||||
			"git", "checkout", "-b", stagingBranch, trackingBranch); err != nil {
 | 
								"git", "checkout", "-b", stagingBranch, trackingBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git checkout: %s", stderr)
 | 
								return fmt.Errorf("git checkout: %s", stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Rebase before merging
 | 
							// Rebase before merging
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
 | 
				
			||||||
			"git", "rebase", "-q", pr.BaseBranch); err != nil {
 | 
								"git", "rebase", "-q", pr.BaseBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
								return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Checkout base branch again
 | 
							// Checkout base branch again
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
 | 
				
			||||||
			"git", "checkout", pr.BaseBranch); err != nil {
 | 
								"git", "checkout", pr.BaseBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git checkout: %s", stderr)
 | 
								return fmt.Errorf("git checkout: %s", stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Prepare merge with commit
 | 
							// Prepare merge with commit
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
 | 
				
			||||||
			"git", "merge", "--no-ff", "--no-commit", "-q", stagingBranch); err != nil {
 | 
								"git", "merge", "--no-ff", "--no-commit", "-q", stagingBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git merge --no-ff [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
								return fmt.Errorf("git merge --no-ff [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
				
			||||||
@@ -569,7 +568,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Set custom message and author and create merge commit
 | 
							// Set custom message and author and create merge commit
 | 
				
			||||||
		sig := doer.NewGitSig()
 | 
							sig := doer.NewGitSig()
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git commit): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git commit): %s", tmpBasePath),
 | 
				
			||||||
			"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
 | 
								"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
 | 
				
			||||||
			"-m", message); err != nil {
 | 
								"-m", message); err != nil {
 | 
				
			||||||
@@ -578,13 +577,13 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	case MergeStyleSquash:
 | 
						case MergeStyleSquash:
 | 
				
			||||||
		// Merge with squash
 | 
							// Merge with squash
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git squash): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git squash): %s", tmpBasePath),
 | 
				
			||||||
			"git", "merge", "-q", "--squash", trackingBranch); err != nil {
 | 
								"git", "merge", "-q", "--squash", trackingBranch); err != nil {
 | 
				
			||||||
			return fmt.Errorf("git merge --squash [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
								return fmt.Errorf("git merge --squash [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		sig := pr.Issue.Poster.NewGitSig()
 | 
							sig := pr.Issue.Poster.NewGitSig()
 | 
				
			||||||
		if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
							if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
 | 
				
			||||||
			fmt.Sprintf("PullRequest.Merge (git squash): %s", tmpBasePath),
 | 
								fmt.Sprintf("PullRequest.Merge (git squash): %s", tmpBasePath),
 | 
				
			||||||
			"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
 | 
								"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
 | 
				
			||||||
			"-m", message); err != nil {
 | 
								"-m", message); err != nil {
 | 
				
			||||||
@@ -594,10 +593,12 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 | 
				
			|||||||
		return ErrInvalidMergeStyle{pr.BaseRepo.ID, mergeStyle}
 | 
							return ErrInvalidMergeStyle{pr.BaseRepo.ID, mergeStyle}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						env := PushingEnvironment(doer, pr.BaseRepo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Push back to upstream.
 | 
						// Push back to upstream.
 | 
				
			||||||
	if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
 | 
						if _, stderr, err := process.GetManager().ExecDirEnv(-1, tmpBasePath,
 | 
				
			||||||
		fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
 | 
							fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
 | 
				
			||||||
		"git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
 | 
							env, "git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
 | 
				
			||||||
		return fmt.Errorf("git push: %s", stderr)
 | 
							return fmt.Errorf("git push: %s", stderr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -518,7 +518,7 @@ func (repo *Repository) DeleteWiki() error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (repo *Repository) deleteWiki(e Engine) error {
 | 
					func (repo *Repository) deleteWiki(e Engine) error {
 | 
				
			||||||
	wikiPaths := []string{repo.WikiPath(), repo.LocalWikiPath()}
 | 
						wikiPaths := []string{repo.WikiPath()}
 | 
				
			||||||
	for _, wikiPath := range wikiPaths {
 | 
						for _, wikiPath := range wikiPaths {
 | 
				
			||||||
		removeAllWithNotice(e, "Delete repository wiki", wikiPath)
 | 
							removeAllWithNotice(e, "Delete repository wiki", wikiPath)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -749,56 +749,6 @@ func (repo *Repository) DescriptionHTML() template.HTML {
 | 
				
			|||||||
	return template.HTML(markup.Sanitize(string(desc)))
 | 
						return template.HTML(markup.Sanitize(string(desc)))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// LocalCopyPath returns the local repository copy path.
 | 
					 | 
				
			||||||
func LocalCopyPath() string {
 | 
					 | 
				
			||||||
	if filepath.IsAbs(setting.Repository.Local.LocalCopyPath) {
 | 
					 | 
				
			||||||
		return setting.Repository.Local.LocalCopyPath
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return path.Join(setting.AppDataPath, setting.Repository.Local.LocalCopyPath)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// LocalCopyPath returns the local repository copy path for the given repo.
 | 
					 | 
				
			||||||
func (repo *Repository) LocalCopyPath() string {
 | 
					 | 
				
			||||||
	return path.Join(LocalCopyPath(), com.ToStr(repo.ID))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// UpdateLocalCopyBranch pulls latest changes of given branch from repoPath to localPath.
 | 
					 | 
				
			||||||
// It creates a new clone if local copy does not exist.
 | 
					 | 
				
			||||||
// This function checks out target branch by default, it is safe to assume subsequent
 | 
					 | 
				
			||||||
// operations are operating against target branch when caller has confidence for no race condition.
 | 
					 | 
				
			||||||
func UpdateLocalCopyBranch(repoPath, localPath, branch string) error {
 | 
					 | 
				
			||||||
	if !com.IsExist(localPath) {
 | 
					 | 
				
			||||||
		if err := git.Clone(repoPath, localPath, git.CloneRepoOptions{
 | 
					 | 
				
			||||||
			Timeout: time.Duration(setting.Git.Timeout.Clone) * time.Second,
 | 
					 | 
				
			||||||
			Branch:  branch,
 | 
					 | 
				
			||||||
		}); err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("git clone %s: %v", branch, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		_, err := git.NewCommand("fetch", "origin").RunInDir(localPath)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("git fetch origin: %v", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(branch) > 0 {
 | 
					 | 
				
			||||||
			if err := git.Checkout(localPath, git.CheckoutOptions{
 | 
					 | 
				
			||||||
				Branch: branch,
 | 
					 | 
				
			||||||
			}); err != nil {
 | 
					 | 
				
			||||||
				return fmt.Errorf("git checkout %s: %v", branch, err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if err := git.ResetHEAD(localPath, true, "origin/"+branch); err != nil {
 | 
					 | 
				
			||||||
				return fmt.Errorf("git reset --hard origin/%s: %v", branch, err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// UpdateLocalCopyBranch makes sure local copy of repository in given branch is up-to-date.
 | 
					 | 
				
			||||||
func (repo *Repository) UpdateLocalCopyBranch(branch string) error {
 | 
					 | 
				
			||||||
	return UpdateLocalCopyBranch(repo.RepoPath(), repo.LocalCopyPath(), branch)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// PatchPath returns corresponding patch file path of repository by given issue ID.
 | 
					// PatchPath returns corresponding patch file path of repository by given issue ID.
 | 
				
			||||||
func (repo *Repository) PatchPath(index int64) (string, error) {
 | 
					func (repo *Repository) PatchPath(index int64) (string, error) {
 | 
				
			||||||
	return repo.patchPath(x, index)
 | 
						return repo.patchPath(x, index)
 | 
				
			||||||
@@ -1583,12 +1533,10 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
 | 
				
			|||||||
	if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
 | 
						if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
 | 
				
			||||||
		return fmt.Errorf("rename repository directory: %v", err)
 | 
							return fmt.Errorf("rename repository directory: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	removeAllWithNotice(sess, "Delete repository local copy", repo.LocalCopyPath())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Rename remote wiki repository to new path and delete local copy.
 | 
						// Rename remote wiki repository to new path and delete local copy.
 | 
				
			||||||
	wikiPath := WikiPath(owner.Name, repo.Name)
 | 
						wikiPath := WikiPath(owner.Name, repo.Name)
 | 
				
			||||||
	if com.IsExist(wikiPath) {
 | 
						if com.IsExist(wikiPath) {
 | 
				
			||||||
		removeAllWithNotice(sess, "Delete repository wiki local copy", repo.LocalWikiPath())
 | 
					 | 
				
			||||||
		if err = os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil {
 | 
							if err = os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil {
 | 
				
			||||||
			return fmt.Errorf("rename repository wiki: %v", err)
 | 
								return fmt.Errorf("rename repository wiki: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -1633,20 +1581,11 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
 | 
				
			|||||||
		return fmt.Errorf("rename repository directory: %v", err)
 | 
							return fmt.Errorf("rename repository directory: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	localPath := repo.LocalCopyPath()
 | 
					 | 
				
			||||||
	if com.IsExist(localPath) {
 | 
					 | 
				
			||||||
		_, err := git.NewCommand("remote", "set-url", "origin", newRepoPath).RunInDir(localPath)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("git remote set-url origin %s: %v", newRepoPath, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wikiPath := repo.WikiPath()
 | 
						wikiPath := repo.WikiPath()
 | 
				
			||||||
	if com.IsExist(wikiPath) {
 | 
						if com.IsExist(wikiPath) {
 | 
				
			||||||
		if err = os.Rename(wikiPath, WikiPath(u.Name, newRepoName)); err != nil {
 | 
							if err = os.Rename(wikiPath, WikiPath(u.Name, newRepoName)); err != nil {
 | 
				
			||||||
			return fmt.Errorf("rename repository wiki: %v", err)
 | 
								return fmt.Errorf("rename repository wiki: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sess := x.NewSession()
 | 
						sess := x.NewSession()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,86 +7,11 @@ package models
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/Unknwon/com"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// discardLocalRepoBranchChanges discards local commits/changes of
 | 
					 | 
				
			||||||
// given branch to make sure it is even to remote branch.
 | 
					 | 
				
			||||||
func discardLocalRepoBranchChanges(localPath, branch string) error {
 | 
					 | 
				
			||||||
	if !com.IsExist(localPath) {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// No need to check if nothing in the repository.
 | 
					 | 
				
			||||||
	if !git.IsBranchExist(localPath, branch) {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refName := "origin/" + branch
 | 
					 | 
				
			||||||
	if err := git.ResetHEAD(localPath, true, refName); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("git reset --hard %s: %v", refName, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// DiscardLocalRepoBranchChanges discards the local repository branch changes
 | 
					 | 
				
			||||||
func (repo *Repository) DiscardLocalRepoBranchChanges(branch string) error {
 | 
					 | 
				
			||||||
	return discardLocalRepoBranchChanges(repo.LocalCopyPath(), branch)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// checkoutNewBranch checks out to a new branch from the a branch name.
 | 
					 | 
				
			||||||
func checkoutNewBranch(repoPath, localPath, oldBranch, newBranch string) error {
 | 
					 | 
				
			||||||
	if err := git.Checkout(localPath, git.CheckoutOptions{
 | 
					 | 
				
			||||||
		Timeout:   time.Duration(setting.Git.Timeout.Pull) * time.Second,
 | 
					 | 
				
			||||||
		Branch:    newBranch,
 | 
					 | 
				
			||||||
		OldBranch: oldBranch,
 | 
					 | 
				
			||||||
	}); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("git checkout -b %s %s: %v", newBranch, oldBranch, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// CheckoutNewBranch checks out a new branch
 | 
					 | 
				
			||||||
func (repo *Repository) CheckoutNewBranch(oldBranch, newBranch string) error {
 | 
					 | 
				
			||||||
	return checkoutNewBranch(repo.RepoPath(), repo.LocalCopyPath(), oldBranch, newBranch)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// deleteLocalBranch deletes a branch from a local repo cache
 | 
					 | 
				
			||||||
// First checks out default branch to avoid trying to delete the currently checked out branch
 | 
					 | 
				
			||||||
func deleteLocalBranch(localPath, defaultBranch, deleteBranch string) error {
 | 
					 | 
				
			||||||
	if !com.IsExist(localPath) {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !git.IsBranchExist(localPath, deleteBranch) {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Must NOT have branch currently checked out
 | 
					 | 
				
			||||||
	// Checkout default branch first
 | 
					 | 
				
			||||||
	if err := git.Checkout(localPath, git.CheckoutOptions{
 | 
					 | 
				
			||||||
		Timeout: time.Duration(setting.Git.Timeout.Pull) * time.Second,
 | 
					 | 
				
			||||||
		Branch:  defaultBranch,
 | 
					 | 
				
			||||||
	}); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("git checkout %s: %v", defaultBranch, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd := git.NewCommand("branch")
 | 
					 | 
				
			||||||
	cmd.AddArguments("-D")
 | 
					 | 
				
			||||||
	cmd.AddArguments(deleteBranch)
 | 
					 | 
				
			||||||
	_, err := cmd.RunInDir(localPath)
 | 
					 | 
				
			||||||
	return err
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// DeleteLocalBranch deletes a branch from the local repo
 | 
					 | 
				
			||||||
func (repo *Repository) DeleteLocalBranch(branchName string) error {
 | 
					 | 
				
			||||||
	return deleteLocalBranch(repo.LocalCopyPath(), repo.DefaultBranch, branchName)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// CanCreateBranch returns true if repository meets the requirements for creating new branches.
 | 
					// CanCreateBranch returns true if repository meets the requirements for creating new branches.
 | 
				
			||||||
func (repo *Repository) CanCreateBranch() bool {
 | 
					func (repo *Repository) CanCreateBranch() bool {
 | 
				
			||||||
	return !repo.IsMirror
 | 
						return !repo.IsMirror
 | 
				
			||||||
@@ -137,29 +62,44 @@ func (repo *Repository) CheckBranchName(name string) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// CreateNewBranch creates a new repository branch
 | 
					// CreateNewBranch creates a new repository branch
 | 
				
			||||||
func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName string) (err error) {
 | 
					func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName string) (err error) {
 | 
				
			||||||
	repoWorkingPool.CheckIn(com.ToStr(repo.ID))
 | 
					 | 
				
			||||||
	defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Check if branch name can be used
 | 
						// Check if branch name can be used
 | 
				
			||||||
	if err := repo.CheckBranchName(branchName); err != nil {
 | 
						if err := repo.CheckBranchName(branchName); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	localPath := repo.LocalCopyPath()
 | 
						if !git.IsBranchExist(repo.RepoPath(), oldBranchName) {
 | 
				
			||||||
 | 
							return fmt.Errorf("OldBranch: %s does not exist. Cannot create new branch from this", oldBranchName)
 | 
				
			||||||
	if err = discardLocalRepoBranchChanges(localPath, oldBranchName); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("discardLocalRepoChanges: %v", err)
 | 
					 | 
				
			||||||
	} else if err = repo.UpdateLocalCopyBranch(oldBranchName); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("UpdateLocalCopyBranch: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = repo.CheckoutNewBranch(oldBranchName, branchName); err != nil {
 | 
						basePath, err := CreateTemporaryPath("branch-maker")
 | 
				
			||||||
		return fmt.Errorf("CreateNewBranch: %v", err)
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer RemoveTemporaryPath(basePath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{
 | 
				
			||||||
 | 
							Bare:   true,
 | 
				
			||||||
 | 
							Shared: true,
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = git.Push(localPath, git.PushOptions{
 | 
						gitRepo, err := git.OpenRepository(basePath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = gitRepo.CreateBranch(branchName, oldBranchName); err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to create branch: %s from %s. (%v)", branchName, oldBranchName, err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Unable to create branch: %s from %s. (%v)", branchName, oldBranchName, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = git.Push(basePath, git.PushOptions{
 | 
				
			||||||
		Remote: "origin",
 | 
							Remote: "origin",
 | 
				
			||||||
		Branch: branchName,
 | 
							Branch: branchName,
 | 
				
			||||||
 | 
							Env:    PushingEnvironment(doer, repo),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -167,62 +107,41 @@ func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName st
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// updateLocalCopyToCommit pulls latest changes of given commit from repoPath to localPath.
 | 
					 | 
				
			||||||
// It creates a new clone if local copy does not exist.
 | 
					 | 
				
			||||||
// This function checks out target commit by default, it is safe to assume subsequent
 | 
					 | 
				
			||||||
// operations are operating against target commit when caller has confidence for no race condition.
 | 
					 | 
				
			||||||
func updateLocalCopyToCommit(repoPath, localPath, commit string) error {
 | 
					 | 
				
			||||||
	if !com.IsExist(localPath) {
 | 
					 | 
				
			||||||
		if err := git.Clone(repoPath, localPath, git.CloneRepoOptions{
 | 
					 | 
				
			||||||
			Timeout: time.Duration(setting.Git.Timeout.Clone) * time.Second,
 | 
					 | 
				
			||||||
		}); err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("git clone: %v", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		_, err := git.NewCommand("fetch", "origin").RunInDir(localPath)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("git fetch origin: %v", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err := git.ResetHEAD(localPath, true, "HEAD"); err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("git reset --hard HEAD: %v", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := git.Checkout(localPath, git.CheckoutOptions{
 | 
					 | 
				
			||||||
		Branch: commit,
 | 
					 | 
				
			||||||
	}); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("git checkout %s: %v", commit, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// updateLocalCopyToCommit makes sure local copy of repository is at given commit.
 | 
					 | 
				
			||||||
func (repo *Repository) updateLocalCopyToCommit(commit string) error {
 | 
					 | 
				
			||||||
	return updateLocalCopyToCommit(repo.RepoPath(), repo.LocalCopyPath(), commit)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// CreateNewBranchFromCommit creates a new repository branch
 | 
					// CreateNewBranchFromCommit creates a new repository branch
 | 
				
			||||||
func (repo *Repository) CreateNewBranchFromCommit(doer *User, commit, branchName string) (err error) {
 | 
					func (repo *Repository) CreateNewBranchFromCommit(doer *User, commit, branchName string) (err error) {
 | 
				
			||||||
	repoWorkingPool.CheckIn(com.ToStr(repo.ID))
 | 
					 | 
				
			||||||
	defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Check if branch name can be used
 | 
						// Check if branch name can be used
 | 
				
			||||||
	if err := repo.CheckBranchName(branchName); err != nil {
 | 
						if err := repo.CheckBranchName(branchName); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						basePath, err := CreateTemporaryPath("branch-maker")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer RemoveTemporaryPath(basePath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	localPath := repo.LocalCopyPath()
 | 
						if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{
 | 
				
			||||||
 | 
							Bare:   true,
 | 
				
			||||||
	if err = repo.updateLocalCopyToCommit(commit); err != nil {
 | 
							Shared: true,
 | 
				
			||||||
		return fmt.Errorf("UpdateLocalCopyBranch: %v", err)
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = repo.CheckoutNewBranch(commit, branchName); err != nil {
 | 
						gitRepo, err := git.OpenRepository(basePath)
 | 
				
			||||||
		return fmt.Errorf("CheckoutNewBranch: %v", err)
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = git.Push(localPath, git.PushOptions{
 | 
						if err = gitRepo.CreateBranch(branchName, commit); err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to create branch: %s from %s. (%v)", branchName, commit, err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Unable to create branch: %s from %s. (%v)", branchName, commit, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = git.Push(basePath, git.PushOptions{
 | 
				
			||||||
		Remote: "origin",
 | 
							Remote: "origin",
 | 
				
			||||||
		Branch: branchName,
 | 
							Branch: branchName,
 | 
				
			||||||
 | 
							Env:    PushingEnvironment(doer, repo),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,11 +5,9 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/markup"
 | 
						"code.gitea.io/gitea/modules/markup"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Unknwon/com"
 | 
						"github.com/Unknwon/com"
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
@@ -138,25 +136,6 @@ func TestRepoAPIURL(t *testing.T) {
 | 
				
			|||||||
	assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL())
 | 
						assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRepoLocalCopyPath(t *testing.T) {
 | 
					 | 
				
			||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	repo, err := GetRepositoryByID(10)
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
					 | 
				
			||||||
	assert.NotNil(t, repo)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// test default
 | 
					 | 
				
			||||||
	repoID := com.ToStr(repo.ID)
 | 
					 | 
				
			||||||
	expected := path.Join(setting.AppDataPath, setting.Repository.Local.LocalCopyPath, repoID)
 | 
					 | 
				
			||||||
	assert.Equal(t, expected, repo.LocalCopyPath())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// test absolute setting
 | 
					 | 
				
			||||||
	tempPath := "/tmp/gitea/local-copy-path"
 | 
					 | 
				
			||||||
	expected = path.Join(tempPath, repoID)
 | 
					 | 
				
			||||||
	setting.Repository.Local.LocalCopyPath = tempPath
 | 
					 | 
				
			||||||
	assert.Equal(t, expected, repo.LocalCopyPath())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestTransferOwnership(t *testing.T) {
 | 
					func TestTransferOwnership(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -943,17 +943,6 @@ func ChangeUserName(u *User, newUserName string) (err error) {
 | 
				
			|||||||
		return fmt.Errorf("ChangeUsernameInPullRequests: %v", err)
 | 
							return fmt.Errorf("ChangeUsernameInPullRequests: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Delete all local copies of repository wiki that user owns.
 | 
					 | 
				
			||||||
	if err = x.BufferSize(setting.IterateBufferSize).
 | 
					 | 
				
			||||||
		Where("owner_id=?", u.ID).
 | 
					 | 
				
			||||||
		Iterate(new(Repository), func(idx int, bean interface{}) error {
 | 
					 | 
				
			||||||
			repo := bean.(*Repository)
 | 
					 | 
				
			||||||
			RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
 | 
					 | 
				
			||||||
			return nil
 | 
					 | 
				
			||||||
		}); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("Delete repository wiki local copy: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Do not fail if directory does not exist
 | 
						// Do not fail if directory does not exist
 | 
				
			||||||
	if err = os.Rename(UserPath(u.Name), UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
 | 
						if err = os.Rename(UserPath(u.Name), UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
 | 
				
			||||||
		return fmt.Errorf("Rename user directory: %v", err)
 | 
							return fmt.Errorf("Rename user directory: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										231
									
								
								models/wiki.go
									
									
									
									
									
								
							
							
						
						
									
										231
									
								
								models/wiki.go
									
									
									
									
									
								
							@@ -6,15 +6,13 @@ package models
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io/ioutil"
 | 
					 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/sync"
 | 
						"code.gitea.io/gitea/modules/sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Unknwon/com"
 | 
						"github.com/Unknwon/com"
 | 
				
			||||||
@@ -89,34 +87,6 @@ func (repo *Repository) InitWiki() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// LocalWikiPath returns the local wiki repository copy path.
 | 
					 | 
				
			||||||
func LocalWikiPath() string {
 | 
					 | 
				
			||||||
	if filepath.IsAbs(setting.Repository.Local.LocalWikiPath) {
 | 
					 | 
				
			||||||
		return setting.Repository.Local.LocalWikiPath
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return path.Join(setting.AppDataPath, setting.Repository.Local.LocalWikiPath)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// LocalWikiPath returns the path to the local wiki repository (?).
 | 
					 | 
				
			||||||
func (repo *Repository) LocalWikiPath() string {
 | 
					 | 
				
			||||||
	return path.Join(LocalWikiPath(), com.ToStr(repo.ID))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
 | 
					 | 
				
			||||||
func (repo *Repository) updateLocalWiki() error {
 | 
					 | 
				
			||||||
	// Don't pass branch name here because it fails to clone and
 | 
					 | 
				
			||||||
	// checkout to a specific branch when wiki is an empty repository.
 | 
					 | 
				
			||||||
	var branch = ""
 | 
					 | 
				
			||||||
	if com.IsExist(repo.LocalWikiPath()) {
 | 
					 | 
				
			||||||
		branch = "master"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return UpdateLocalCopyBranch(repo.WikiPath(), repo.LocalWikiPath(), branch)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func discardLocalWikiChanges(localPath string) error {
 | 
					 | 
				
			||||||
	return discardLocalRepoBranchChanges(localPath, "master")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// nameAllowed checks if a wiki name is allowed
 | 
					// nameAllowed checks if a wiki name is allowed
 | 
				
			||||||
func nameAllowed(name string) error {
 | 
					func nameAllowed(name string) error {
 | 
				
			||||||
	for _, reservedName := range reservedWikiNames {
 | 
						for _, reservedName := range reservedWikiNames {
 | 
				
			||||||
@@ -132,7 +102,6 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 | 
				
			|||||||
	if err = nameAllowed(newWikiName); err != nil {
 | 
						if err = nameAllowed(newWikiName); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
 | 
						wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
 | 
				
			||||||
	defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
 | 
						defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -140,54 +109,113 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 | 
				
			|||||||
		return fmt.Errorf("InitWiki: %v", err)
 | 
							return fmt.Errorf("InitWiki: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	localPath := repo.LocalWikiPath()
 | 
						hasMasterBranch := git.IsBranchExist(repo.WikiPath(), "master")
 | 
				
			||||||
	if err = discardLocalWikiChanges(localPath); err != nil {
 | 
					
 | 
				
			||||||
		return fmt.Errorf("discardLocalWikiChanges: %v", err)
 | 
						basePath, err := CreateTemporaryPath("update-wiki")
 | 
				
			||||||
	} else if err = repo.updateLocalWiki(); err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("UpdateLocalWiki: %v", err)
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer RemoveTemporaryPath(basePath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cloneOpts := git.CloneRepoOptions{
 | 
				
			||||||
 | 
							Bare:   true,
 | 
				
			||||||
 | 
							Shared: true,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	newWikiPath := path.Join(localPath, WikiNameToFilename(newWikiName))
 | 
						if hasMasterBranch {
 | 
				
			||||||
 | 
							cloneOpts.Branch = "master"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If not a new file, show perform update not create.
 | 
						if err := git.Clone(repo.WikiPath(), basePath, cloneOpts); err != nil {
 | 
				
			||||||
 | 
							log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gitRepo, err := git.OpenRepository(basePath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if hasMasterBranch {
 | 
				
			||||||
 | 
							if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil {
 | 
				
			||||||
 | 
								log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err)
 | 
				
			||||||
 | 
								return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						newWikiPath := WikiNameToFilename(newWikiName)
 | 
				
			||||||
	if isNew {
 | 
						if isNew {
 | 
				
			||||||
		if com.IsExist(newWikiPath) {
 | 
							filesInIndex, err := gitRepo.LsFiles(newWikiPath)
 | 
				
			||||||
			return ErrWikiAlreadyExist{newWikiPath}
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Error("%v", err)
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, file := range filesInIndex {
 | 
				
			||||||
 | 
								if file == newWikiPath {
 | 
				
			||||||
 | 
									return ErrWikiAlreadyExist{newWikiPath}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		oldWikiPath := path.Join(localPath, WikiNameToFilename(oldWikiName))
 | 
							oldWikiPath := WikiNameToFilename(oldWikiName)
 | 
				
			||||||
		if err := os.Remove(oldWikiPath); err != nil {
 | 
							filesInIndex, err := gitRepo.LsFiles(oldWikiPath)
 | 
				
			||||||
			return fmt.Errorf("Failed to remove %s: %v", oldWikiPath, err)
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Error("%v", err)
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							found := false
 | 
				
			||||||
 | 
							for _, file := range filesInIndex {
 | 
				
			||||||
 | 
								if file == oldWikiPath {
 | 
				
			||||||
 | 
									found = true
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if found {
 | 
				
			||||||
 | 
								err := gitRepo.RemoveFilesFromIndex(oldWikiPath)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									log.Error("%v", err)
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// SECURITY: if new file is a symlink to non-exist critical file,
 | 
						// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
 | 
				
			||||||
	// attack content can be written to the target file (e.g. authorized_keys2)
 | 
					
 | 
				
			||||||
	// as a new page operation.
 | 
						objectHash, err := gitRepo.HashObject(strings.NewReader(content))
 | 
				
			||||||
	// So we want to make sure the symlink is removed before write anything.
 | 
						if err != nil {
 | 
				
			||||||
	// The new file we created will be in normal text format.
 | 
							log.Error("%v", err)
 | 
				
			||||||
	if err = os.RemoveAll(newWikiPath); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = ioutil.WriteFile(newWikiPath, []byte(content), 0666); err != nil {
 | 
						if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil {
 | 
				
			||||||
		return fmt.Errorf("WriteFile: %v", err)
 | 
							log.Error("%v", err)
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(message) == 0 {
 | 
						tree, err := gitRepo.WriteTree()
 | 
				
			||||||
		message = "Update page '" + newWikiName + "'"
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("%v", err)
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err = git.AddChanges(localPath, true); err != nil {
 | 
					
 | 
				
			||||||
		return fmt.Errorf("AddChanges: %v", err)
 | 
						commitTreeOpts := git.CommitTreeOpts{
 | 
				
			||||||
	} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
 | 
							Message: message,
 | 
				
			||||||
		Committer: doer.NewGitSig(),
 | 
						}
 | 
				
			||||||
		Message:   message,
 | 
						if hasMasterBranch {
 | 
				
			||||||
	}); err != nil {
 | 
							commitTreeOpts.Parents = []string{"HEAD"}
 | 
				
			||||||
		return fmt.Errorf("CommitChanges: %v", err)
 | 
						}
 | 
				
			||||||
	} else if err = git.Push(localPath, git.PushOptions{
 | 
						commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, commitTreeOpts)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("%v", err)
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := git.Push(basePath, git.PushOptions{
 | 
				
			||||||
		Remote: "origin",
 | 
							Remote: "origin",
 | 
				
			||||||
		Branch: "master",
 | 
							Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
 | 
				
			||||||
 | 
							Env:    PushingEnvironment(doer, repo),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							log.Error("%v", err)
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -210,31 +238,74 @@ func (repo *Repository) DeleteWikiPage(doer *User, wikiName string) (err error)
 | 
				
			|||||||
	wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
 | 
						wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
 | 
				
			||||||
	defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
 | 
						defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	localPath := repo.LocalWikiPath()
 | 
						if err = repo.InitWiki(); err != nil {
 | 
				
			||||||
	if err = discardLocalWikiChanges(localPath); err != nil {
 | 
							return fmt.Errorf("InitWiki: %v", err)
 | 
				
			||||||
		return fmt.Errorf("discardLocalWikiChanges: %v", err)
 | 
					 | 
				
			||||||
	} else if err = repo.updateLocalWiki(); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("UpdateLocalWiki: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	filename := path.Join(localPath, WikiNameToFilename(wikiName))
 | 
						basePath, err := CreateTemporaryPath("update-wiki")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer RemoveTemporaryPath(basePath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := os.Remove(filename); err != nil {
 | 
						if err := git.Clone(repo.WikiPath(), basePath, git.CloneRepoOptions{
 | 
				
			||||||
		return fmt.Errorf("Failed to remove %s: %v", filename, err)
 | 
							Bare:   true,
 | 
				
			||||||
 | 
							Shared: true,
 | 
				
			||||||
 | 
							Branch: "master",
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gitRepo, err := git.OpenRepository(basePath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err)
 | 
				
			||||||
 | 
							return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wikiPath := WikiNameToFilename(wikiName)
 | 
				
			||||||
 | 
						filesInIndex, err := gitRepo.LsFiles(wikiPath)
 | 
				
			||||||
 | 
						found := false
 | 
				
			||||||
 | 
						for _, file := range filesInIndex {
 | 
				
			||||||
 | 
							if file == wikiPath {
 | 
				
			||||||
 | 
								found = true
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if found {
 | 
				
			||||||
 | 
							err := gitRepo.RemoveFilesFromIndex(wikiPath)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return os.ErrNotExist
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tree, err := gitRepo.WriteTree()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	message := "Delete page '" + wikiName + "'"
 | 
						message := "Delete page '" + wikiName + "'"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = git.AddChanges(localPath, true); err != nil {
 | 
						commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, git.CommitTreeOpts{
 | 
				
			||||||
		return fmt.Errorf("AddChanges: %v", err)
 | 
							Message: message,
 | 
				
			||||||
	} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
 | 
							Parents: []string{"HEAD"},
 | 
				
			||||||
		Committer: doer.NewGitSig(),
 | 
						})
 | 
				
			||||||
		Message:   message,
 | 
						if err != nil {
 | 
				
			||||||
	}); err != nil {
 | 
							return err
 | 
				
			||||||
		return fmt.Errorf("CommitChanges: %v", err)
 | 
						}
 | 
				
			||||||
	} else if err = git.Push(localPath, git.PushOptions{
 | 
					
 | 
				
			||||||
 | 
						if err := git.Push(basePath, git.PushOptions{
 | 
				
			||||||
		Remote: "origin",
 | 
							Remote: "origin",
 | 
				
			||||||
		Branch: "master",
 | 
							Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
 | 
				
			||||||
 | 
							Env:    PushingEnvironment(doer, repo),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,13 +5,12 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Unknwon/com"
 | 
					 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -145,13 +144,6 @@ func TestRepository_InitWiki(t *testing.T) {
 | 
				
			|||||||
	assert.True(t, repo2.HasWiki())
 | 
						assert.True(t, repo2.HasWiki())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRepository_LocalWikiPath(t *testing.T) {
 | 
					 | 
				
			||||||
	PrepareTestEnv(t)
 | 
					 | 
				
			||||||
	repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
					 | 
				
			||||||
	expected := filepath.Join(setting.AppDataPath, setting.Repository.Local.LocalWikiPath, "1")
 | 
					 | 
				
			||||||
	assert.Equal(t, expected, repo.LocalWikiPath())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestRepository_AddWikiPage(t *testing.T) {
 | 
					func TestRepository_AddWikiPage(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
	const wikiContent = "This is the wiki content"
 | 
						const wikiContent = "This is the wiki content"
 | 
				
			||||||
@@ -166,8 +158,15 @@ func TestRepository_AddWikiPage(t *testing.T) {
 | 
				
			|||||||
		t.Run("test wiki exist: "+wikiName, func(t *testing.T) {
 | 
							t.Run("test wiki exist: "+wikiName, func(t *testing.T) {
 | 
				
			||||||
			t.Parallel()
 | 
								t.Parallel()
 | 
				
			||||||
			assert.NoError(t, repo.AddWikiPage(doer, wikiName, wikiContent, commitMsg))
 | 
								assert.NoError(t, repo.AddWikiPage(doer, wikiName, wikiContent, commitMsg))
 | 
				
			||||||
			expectedPath := path.Join(repo.LocalWikiPath(), WikiNameToFilename(wikiName))
 | 
								// Now need to show that the page has been added:
 | 
				
			||||||
			assert.True(t, com.IsExist(expectedPath))
 | 
								gitRepo, err := git.OpenRepository(repo.WikiPath())
 | 
				
			||||||
 | 
								assert.NoError(t, err)
 | 
				
			||||||
 | 
								masterTree, err := gitRepo.GetTree("master")
 | 
				
			||||||
 | 
								assert.NoError(t, err)
 | 
				
			||||||
 | 
								wikiPath := WikiNameToFilename(wikiName)
 | 
				
			||||||
 | 
								entry, err := masterTree.GetTreeEntryByPath(wikiPath)
 | 
				
			||||||
 | 
								assert.NoError(t, err)
 | 
				
			||||||
 | 
								assert.Equal(t, wikiPath, entry.Name(), "%s not addded correctly", wikiName)
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -200,11 +199,20 @@ func TestRepository_EditWikiPage(t *testing.T) {
 | 
				
			|||||||
	} {
 | 
						} {
 | 
				
			||||||
		PrepareTestEnv(t)
 | 
							PrepareTestEnv(t)
 | 
				
			||||||
		assert.NoError(t, repo.EditWikiPage(doer, "Home", newWikiName, newWikiContent, commitMsg))
 | 
							assert.NoError(t, repo.EditWikiPage(doer, "Home", newWikiName, newWikiContent, commitMsg))
 | 
				
			||||||
		newPath := path.Join(repo.LocalWikiPath(), WikiNameToFilename(newWikiName))
 | 
					
 | 
				
			||||||
		assert.True(t, com.IsExist(newPath))
 | 
							// Now need to show that the page has been added:
 | 
				
			||||||
 | 
							gitRepo, err := git.OpenRepository(repo.WikiPath())
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							masterTree, err := gitRepo.GetTree("master")
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							wikiPath := WikiNameToFilename(newWikiName)
 | 
				
			||||||
 | 
							entry, err := masterTree.GetTreeEntryByPath(wikiPath)
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							assert.Equal(t, wikiPath, entry.Name(), "%s not editted correctly", newWikiName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if newWikiName != "Home" {
 | 
							if newWikiName != "Home" {
 | 
				
			||||||
			oldPath := path.Join(repo.LocalWikiPath(), "Home.md")
 | 
								_, err := masterTree.GetTreeEntryByPath("Home.md")
 | 
				
			||||||
			assert.False(t, com.IsExist(oldPath))
 | 
								assert.Error(t, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -214,6 +222,13 @@ func TestRepository_DeleteWikiPage(t *testing.T) {
 | 
				
			|||||||
	repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
						repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
				
			||||||
	doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
 | 
						doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
 | 
				
			||||||
	assert.NoError(t, repo.DeleteWikiPage(doer, "Home"))
 | 
						assert.NoError(t, repo.DeleteWikiPage(doer, "Home"))
 | 
				
			||||||
	wikiPath := path.Join(repo.LocalWikiPath(), "Home.md")
 | 
					
 | 
				
			||||||
	assert.False(t, com.IsExist(wikiPath))
 | 
						// Now need to show that the page has been added:
 | 
				
			||||||
 | 
						gitRepo, err := git.OpenRepository(repo.WikiPath())
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						masterTree, err := gitRepo.GetTree("master")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						wikiPath := WikiNameToFilename("Home")
 | 
				
			||||||
 | 
						_, err = masterTree.GetTreeEntryByPath(wikiPath)
 | 
				
			||||||
 | 
						assert.Error(t, err)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,9 +52,15 @@ func (c *Command) AddArguments(args ...string) *Command {
 | 
				
			|||||||
	return c
 | 
						return c
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RunInDirTimeoutPipeline executes the command in given directory with given timeout,
 | 
					// RunInDirTimeoutEnvPipeline executes the command in given directory with given timeout,
 | 
				
			||||||
// it pipes stdout and stderr to given io.Writer.
 | 
					// it pipes stdout and stderr to given io.Writer.
 | 
				
			||||||
func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer) error {
 | 
					func (c *Command) RunInDirTimeoutEnvPipeline(env []string, timeout time.Duration, dir string, stdout, stderr io.Writer) error {
 | 
				
			||||||
 | 
						return c.RunInDirTimeoutEnvFullPipeline(env, timeout, dir, stdout, stderr, nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RunInDirTimeoutEnvFullPipeline executes the command in given directory with given timeout,
 | 
				
			||||||
 | 
					// it pipes stdout and stderr to given io.Writer and passes in an io.Reader as stdin.
 | 
				
			||||||
 | 
					func (c *Command) RunInDirTimeoutEnvFullPipeline(env []string, timeout time.Duration, dir string, stdout, stderr io.Writer, stdin io.Reader) error {
 | 
				
			||||||
	if timeout == -1 {
 | 
						if timeout == -1 {
 | 
				
			||||||
		timeout = DefaultCommandExecutionTimeout
 | 
							timeout = DefaultCommandExecutionTimeout
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -69,9 +75,11 @@ func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, std
 | 
				
			|||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := exec.CommandContext(ctx, c.name, c.args...)
 | 
						cmd := exec.CommandContext(ctx, c.name, c.args...)
 | 
				
			||||||
 | 
						cmd.Env = env
 | 
				
			||||||
	cmd.Dir = dir
 | 
						cmd.Dir = dir
 | 
				
			||||||
	cmd.Stdout = stdout
 | 
						cmd.Stdout = stdout
 | 
				
			||||||
	cmd.Stderr = stderr
 | 
						cmd.Stderr = stderr
 | 
				
			||||||
 | 
						cmd.Stdin = stdin
 | 
				
			||||||
	if err := cmd.Start(); err != nil {
 | 
						if err := cmd.Start(); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -83,12 +91,30 @@ func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, std
 | 
				
			|||||||
	return ctx.Err()
 | 
						return ctx.Err()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RunInDirTimeoutPipeline executes the command in given directory with given timeout,
 | 
				
			||||||
 | 
					// it pipes stdout and stderr to given io.Writer.
 | 
				
			||||||
 | 
					func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer) error {
 | 
				
			||||||
 | 
						return c.RunInDirTimeoutEnvPipeline(nil, timeout, dir, stdout, stderr)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RunInDirTimeoutFullPipeline executes the command in given directory with given timeout,
 | 
				
			||||||
 | 
					// it pipes stdout and stderr to given io.Writer, and stdin from the given io.Reader
 | 
				
			||||||
 | 
					func (c *Command) RunInDirTimeoutFullPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer, stdin io.Reader) error {
 | 
				
			||||||
 | 
						return c.RunInDirTimeoutEnvFullPipeline(nil, timeout, dir, stdout, stderr, stdin)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RunInDirTimeout executes the command in given directory with given timeout,
 | 
					// RunInDirTimeout executes the command in given directory with given timeout,
 | 
				
			||||||
// and returns stdout in []byte and error (combined with stderr).
 | 
					// and returns stdout in []byte and error (combined with stderr).
 | 
				
			||||||
func (c *Command) RunInDirTimeout(timeout time.Duration, dir string) ([]byte, error) {
 | 
					func (c *Command) RunInDirTimeout(timeout time.Duration, dir string) ([]byte, error) {
 | 
				
			||||||
 | 
						return c.RunInDirTimeoutEnv(nil, timeout, dir)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RunInDirTimeoutEnv executes the command in given directory with given timeout,
 | 
				
			||||||
 | 
					// and returns stdout in []byte and error (combined with stderr).
 | 
				
			||||||
 | 
					func (c *Command) RunInDirTimeoutEnv(env []string, timeout time.Duration, dir string) ([]byte, error) {
 | 
				
			||||||
	stdout := new(bytes.Buffer)
 | 
						stdout := new(bytes.Buffer)
 | 
				
			||||||
	stderr := new(bytes.Buffer)
 | 
						stderr := new(bytes.Buffer)
 | 
				
			||||||
	if err := c.RunInDirTimeoutPipeline(timeout, dir, stdout, stderr); err != nil {
 | 
						if err := c.RunInDirTimeoutEnvPipeline(env, timeout, dir, stdout, stderr); err != nil {
 | 
				
			||||||
		return nil, concatenateError(err, stderr.String())
 | 
							return nil, concatenateError(err, stderr.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -101,7 +127,13 @@ func (c *Command) RunInDirTimeout(timeout time.Duration, dir string) ([]byte, er
 | 
				
			|||||||
// RunInDirPipeline executes the command in given directory,
 | 
					// RunInDirPipeline executes the command in given directory,
 | 
				
			||||||
// it pipes stdout and stderr to given io.Writer.
 | 
					// it pipes stdout and stderr to given io.Writer.
 | 
				
			||||||
func (c *Command) RunInDirPipeline(dir string, stdout, stderr io.Writer) error {
 | 
					func (c *Command) RunInDirPipeline(dir string, stdout, stderr io.Writer) error {
 | 
				
			||||||
	return c.RunInDirTimeoutPipeline(-1, dir, stdout, stderr)
 | 
						return c.RunInDirFullPipeline(dir, stdout, stderr, nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RunInDirFullPipeline executes the command in given directory,
 | 
				
			||||||
 | 
					// it pipes stdout and stderr to given io.Writer.
 | 
				
			||||||
 | 
					func (c *Command) RunInDirFullPipeline(dir string, stdout, stderr io.Writer, stdin io.Reader) error {
 | 
				
			||||||
 | 
						return c.RunInDirTimeoutFullPipeline(-1, dir, stdout, stderr, stdin)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RunInDirBytes executes the command in given directory
 | 
					// RunInDirBytes executes the command in given directory
 | 
				
			||||||
@@ -113,7 +145,13 @@ func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
 | 
				
			|||||||
// RunInDir executes the command in given directory
 | 
					// RunInDir executes the command in given directory
 | 
				
			||||||
// and returns stdout in string and error (combined with stderr).
 | 
					// and returns stdout in string and error (combined with stderr).
 | 
				
			||||||
func (c *Command) RunInDir(dir string) (string, error) {
 | 
					func (c *Command) RunInDir(dir string) (string, error) {
 | 
				
			||||||
	stdout, err := c.RunInDirTimeout(-1, dir)
 | 
						return c.RunInDirWithEnv(dir, nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RunInDirWithEnv executes the command in given directory
 | 
				
			||||||
 | 
					// and returns stdout in string and error (combined with stderr).
 | 
				
			||||||
 | 
					func (c *Command) RunInDirWithEnv(dir string, env []string) (string, error) {
 | 
				
			||||||
 | 
						stdout, err := c.RunInDirTimeoutEnv(env, -1, dir)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,11 +109,13 @@ func OpenRepository(repoPath string) (*Repository, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// CloneRepoOptions options when clone a repository
 | 
					// CloneRepoOptions options when clone a repository
 | 
				
			||||||
type CloneRepoOptions struct {
 | 
					type CloneRepoOptions struct {
 | 
				
			||||||
	Timeout time.Duration
 | 
						Timeout    time.Duration
 | 
				
			||||||
	Mirror  bool
 | 
						Mirror     bool
 | 
				
			||||||
	Bare    bool
 | 
						Bare       bool
 | 
				
			||||||
	Quiet   bool
 | 
						Quiet      bool
 | 
				
			||||||
	Branch  string
 | 
						Branch     string
 | 
				
			||||||
 | 
						Shared     bool
 | 
				
			||||||
 | 
						NoCheckout bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Clone clones original repository to target path.
 | 
					// Clone clones original repository to target path.
 | 
				
			||||||
@@ -133,10 +135,17 @@ func Clone(from, to string, opts CloneRepoOptions) (err error) {
 | 
				
			|||||||
	if opts.Quiet {
 | 
						if opts.Quiet {
 | 
				
			||||||
		cmd.AddArguments("--quiet")
 | 
							cmd.AddArguments("--quiet")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if opts.Shared {
 | 
				
			||||||
 | 
							cmd.AddArguments("-s")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if opts.NoCheckout {
 | 
				
			||||||
 | 
							cmd.AddArguments("--no-checkout")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(opts.Branch) > 0 {
 | 
						if len(opts.Branch) > 0 {
 | 
				
			||||||
		cmd.AddArguments("-b", opts.Branch)
 | 
							cmd.AddArguments("-b", opts.Branch)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cmd.AddArguments(from, to)
 | 
						cmd.AddArguments("--", from, to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.Timeout <= 0 {
 | 
						if opts.Timeout <= 0 {
 | 
				
			||||||
		opts.Timeout = -1
 | 
							opts.Timeout = -1
 | 
				
			||||||
@@ -181,6 +190,7 @@ type PushOptions struct {
 | 
				
			|||||||
	Remote string
 | 
						Remote string
 | 
				
			||||||
	Branch string
 | 
						Branch string
 | 
				
			||||||
	Force  bool
 | 
						Force  bool
 | 
				
			||||||
 | 
						Env    []string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Push pushs local commits to given remote branch.
 | 
					// Push pushs local commits to given remote branch.
 | 
				
			||||||
@@ -190,7 +200,7 @@ func Push(repoPath string, opts PushOptions) error {
 | 
				
			|||||||
		cmd.AddArguments("-f")
 | 
							cmd.AddArguments("-f")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cmd.AddArguments(opts.Remote, opts.Branch)
 | 
						cmd.AddArguments(opts.Remote, opts.Branch)
 | 
				
			||||||
	_, err := cmd.RunInDir(repoPath)
 | 
						_, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ const BranchPrefix = "refs/heads/"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// IsReferenceExist returns true if given reference exists in the repository.
 | 
					// IsReferenceExist returns true if given reference exists in the repository.
 | 
				
			||||||
func IsReferenceExist(repoPath, name string) bool {
 | 
					func IsReferenceExist(repoPath, name string) bool {
 | 
				
			||||||
	_, err := NewCommand("show-ref", "--verify", name).RunInDir(repoPath)
 | 
						_, err := NewCommand("show-ref", "--verify", "--", name).RunInDir(repoPath)
 | 
				
			||||||
	return err == nil
 | 
						return err == nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -145,9 +145,9 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CreateBranch create a new branch
 | 
					// CreateBranch create a new branch
 | 
				
			||||||
func (repo *Repository) CreateBranch(branch, newBranch string) error {
 | 
					func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
 | 
				
			||||||
	cmd := NewCommand("branch")
 | 
						cmd := NewCommand("branch")
 | 
				
			||||||
	cmd.AddArguments(branch, newBranch)
 | 
						cmd.AddArguments("--", branch, oldbranchOrCommit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := cmd.RunInDir(repo.Path)
 | 
						_, err := cmd.RunInDir(repo.Path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										98
									
								
								modules/git/repo_index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								modules/git/repo_index.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					// 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReadTreeToIndex reads a treeish to the index
 | 
				
			||||||
 | 
					func (repo *Repository) ReadTreeToIndex(treeish string) error {
 | 
				
			||||||
 | 
						if len(treeish) != 40 {
 | 
				
			||||||
 | 
							res, err := NewCommand("rev-parse", treeish).RunInDir(repo.Path)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(res) > 0 {
 | 
				
			||||||
 | 
								treeish = res[:len(res)-1]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						id, err := NewIDFromString(treeish)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return repo.readTreeToIndex(id)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (repo *Repository) readTreeToIndex(id SHA1) error {
 | 
				
			||||||
 | 
						_, err := NewCommand("read-tree", id.String()).RunInDir(repo.Path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EmptyIndex empties the index
 | 
				
			||||||
 | 
					func (repo *Repository) EmptyIndex() error {
 | 
				
			||||||
 | 
						_, err := NewCommand("read-tree", "--empty").RunInDir(repo.Path)
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LsFiles checks if the given filenames are in the index
 | 
				
			||||||
 | 
					func (repo *Repository) LsFiles(filenames ...string) ([]string, error) {
 | 
				
			||||||
 | 
						cmd := NewCommand("ls-files", "-z", "--")
 | 
				
			||||||
 | 
						for _, arg := range filenames {
 | 
				
			||||||
 | 
							if arg != "" {
 | 
				
			||||||
 | 
								cmd.AddArguments(arg)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						res, err := cmd.RunInDirBytes(repo.Path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						filelist := make([]string, 0, len(filenames))
 | 
				
			||||||
 | 
						for _, line := range bytes.Split(res, []byte{'\000'}) {
 | 
				
			||||||
 | 
							filelist = append(filelist, string(line))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return filelist, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoveFilesFromIndex removes given filenames from the index - it does not check whether they are present.
 | 
				
			||||||
 | 
					func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
 | 
				
			||||||
 | 
						cmd := NewCommand("update-index", "--remove", "-z", "--index-info")
 | 
				
			||||||
 | 
						stdout := new(bytes.Buffer)
 | 
				
			||||||
 | 
						stderr := new(bytes.Buffer)
 | 
				
			||||||
 | 
						buffer := new(bytes.Buffer)
 | 
				
			||||||
 | 
						for _, file := range filenames {
 | 
				
			||||||
 | 
							if file != "" {
 | 
				
			||||||
 | 
								buffer.WriteString("0 0000000000000000000000000000000000000000\t")
 | 
				
			||||||
 | 
								buffer.WriteString(file)
 | 
				
			||||||
 | 
								buffer.WriteByte('\000')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return cmd.RunInDirFullPipeline(repo.Path, stdout, stderr, bytes.NewReader(buffer.Bytes()))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddObjectToIndex adds the provided object hash to the index at the provided filename
 | 
				
			||||||
 | 
					func (repo *Repository) AddObjectToIndex(mode string, object SHA1, filename string) error {
 | 
				
			||||||
 | 
						cmd := NewCommand("update-index", "--add", "--replace", "--cacheinfo", mode, object.String(), filename)
 | 
				
			||||||
 | 
						_, err := cmd.RunInDir(repo.Path)
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WriteTree writes the current index as a tree to the object db and returns its hash
 | 
				
			||||||
 | 
					func (repo *Repository) WriteTree() (*Tree, error) {
 | 
				
			||||||
 | 
						res, err := NewCommand("write-tree").RunInDir(repo.Path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						id, err := NewIDFromString(strings.TrimSpace(res))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NewTree(repo, id), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,6 +4,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package git
 | 
					package git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ObjectType git object type
 | 
					// ObjectType git object type
 | 
				
			||||||
type ObjectType string
 | 
					type ObjectType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,3 +23,24 @@ const (
 | 
				
			|||||||
	// ObjectTag tag object type
 | 
						// ObjectTag tag object type
 | 
				
			||||||
	ObjectTag ObjectType = "tag"
 | 
						ObjectTag ObjectType = "tag"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HashObject takes a reader and returns SHA1 hash for that reader
 | 
				
			||||||
 | 
					func (repo *Repository) HashObject(reader io.Reader) (SHA1, error) {
 | 
				
			||||||
 | 
						idStr, err := repo.hashObject(reader)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return SHA1{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NewIDFromString(idStr)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (repo *Repository) hashObject(reader io.Reader) (string, error) {
 | 
				
			||||||
 | 
						cmd := NewCommand("hash-object", "-w", "--stdin")
 | 
				
			||||||
 | 
						stdout := new(bytes.Buffer)
 | 
				
			||||||
 | 
						stderr := new(bytes.Buffer)
 | 
				
			||||||
 | 
						err := cmd.RunInDirFullPipeline(repo.Path, stdout, stderr, reader)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return strings.TrimSpace(stdout.String()), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,11 @@
 | 
				
			|||||||
package git
 | 
					package git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gopkg.in/src-d/go-git.v4/plumbing"
 | 
						"gopkg.in/src-d/go-git.v4/plumbing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,3 +52,48 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
 | 
				
			|||||||
	treeObject.ResolvedID = resolvedID
 | 
						treeObject.ResolvedID = resolvedID
 | 
				
			||||||
	return treeObject, nil
 | 
						return treeObject, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CommitTreeOpts represents the possible options to CommitTree
 | 
				
			||||||
 | 
					type CommitTreeOpts struct {
 | 
				
			||||||
 | 
						Parents   []string
 | 
				
			||||||
 | 
						Message   string
 | 
				
			||||||
 | 
						KeyID     string
 | 
				
			||||||
 | 
						NoGPGSign bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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) {
 | 
				
			||||||
 | 
						commitTimeStr := time.Now().Format(time.UnixDate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Because this may call hooks we should pass in the environment
 | 
				
			||||||
 | 
						env := append(os.Environ(),
 | 
				
			||||||
 | 
							"GIT_AUTHOR_NAME="+sig.Name,
 | 
				
			||||||
 | 
							"GIT_AUTHOR_EMAIL="+sig.Email,
 | 
				
			||||||
 | 
							"GIT_AUTHOR_DATE="+commitTimeStr,
 | 
				
			||||||
 | 
							"GIT_COMMITTER_NAME="+sig.Name,
 | 
				
			||||||
 | 
							"GIT_COMMITTER_EMAIL="+sig.Email,
 | 
				
			||||||
 | 
							"GIT_COMMITTER_DATE="+commitTimeStr,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						cmd := NewCommand("commit-tree", tree.ID.String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, parent := range opts.Parents {
 | 
				
			||||||
 | 
							cmd.AddArguments("-p", parent)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd.AddArguments("-m", opts.Message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.KeyID != "" {
 | 
				
			||||||
 | 
							cmd.AddArguments(fmt.Sprintf("-S%s", opts.KeyID))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.NoGPGSign {
 | 
				
			||||||
 | 
							cmd.AddArguments("--no-gpg-sign")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res, err := cmd.RunInDirWithEnv(repo.Path, env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return SHA1{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NewIDFromString(strings.TrimSpace(res))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,17 +11,15 @@ import (
 | 
				
			|||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/process"
 | 
						"code.gitea.io/gitea/modules/process"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/Unknwon/com"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TemporaryUploadRepository is a type to wrap our upload repositories as a shallow clone
 | 
					// TemporaryUploadRepository is a type to wrap our upload repositories as a shallow clone
 | 
				
			||||||
@@ -33,13 +31,9 @@ type TemporaryUploadRepository struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// NewTemporaryUploadRepository creates a new temporary upload repository
 | 
					// NewTemporaryUploadRepository creates a new temporary upload repository
 | 
				
			||||||
func NewTemporaryUploadRepository(repo *models.Repository) (*TemporaryUploadRepository, error) {
 | 
					func NewTemporaryUploadRepository(repo *models.Repository) (*TemporaryUploadRepository, error) {
 | 
				
			||||||
	timeStr := com.ToStr(time.Now().Nanosecond()) // SHOULD USE SOMETHING UNIQUE
 | 
						basePath, err := models.CreateTemporaryPath("upload")
 | 
				
			||||||
	basePath := path.Join(models.LocalCopyPath(), "upload-"+timeStr+".git")
 | 
						if err != nil {
 | 
				
			||||||
	if err := os.MkdirAll(path.Dir(basePath), os.ModePerm); err != nil {
 | 
							return nil, err
 | 
				
			||||||
		return nil, fmt.Errorf("failed to create dir %s: %v", basePath, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if repo.RepoPath() == "" {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("no path to repository on system")
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	t := &TemporaryUploadRepository{repo: repo, basePath: basePath}
 | 
						t := &TemporaryUploadRepository{repo: repo, basePath: basePath}
 | 
				
			||||||
	return t, nil
 | 
						return t, nil
 | 
				
			||||||
@@ -47,8 +41,8 @@ func NewTemporaryUploadRepository(repo *models.Repository) (*TemporaryUploadRepo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Close the repository cleaning up all files
 | 
					// Close the repository cleaning up all files
 | 
				
			||||||
func (t *TemporaryUploadRepository) Close() {
 | 
					func (t *TemporaryUploadRepository) Close() {
 | 
				
			||||||
	if _, err := os.Stat(t.basePath); !os.IsNotExist(err) {
 | 
						if err := models.RemoveTemporaryPath(t.basePath); err != nil {
 | 
				
			||||||
		os.RemoveAll(t.basePath)
 | 
							log.Error("Failed to remove temporary path %s: %v", t.basePath, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -282,27 +276,8 @@ func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, t
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Push the provided commitHash to the repository branch by the provided user
 | 
					// Push the provided commitHash to the repository branch by the provided user
 | 
				
			||||||
func (t *TemporaryUploadRepository) Push(doer *models.User, commitHash string, branch string) error {
 | 
					func (t *TemporaryUploadRepository) Push(doer *models.User, commitHash string, branch string) error {
 | 
				
			||||||
	isWiki := "false"
 | 
					 | 
				
			||||||
	if strings.HasSuffix(t.repo.Name, ".wiki") {
 | 
					 | 
				
			||||||
		isWiki = "true"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sig := doer.NewGitSig()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// FIXME: Should we add SSH_ORIGINAL_COMMAND to this
 | 
					 | 
				
			||||||
	// Because calls hooks we need to pass in the environment
 | 
						// Because calls hooks we need to pass in the environment
 | 
				
			||||||
	env := append(os.Environ(),
 | 
						env := models.PushingEnvironment(doer, t.repo)
 | 
				
			||||||
		"GIT_AUTHOR_NAME="+sig.Name,
 | 
					 | 
				
			||||||
		"GIT_AUTHOR_EMAIL="+sig.Email,
 | 
					 | 
				
			||||||
		"GIT_COMMITTER_NAME="+sig.Name,
 | 
					 | 
				
			||||||
		"GIT_COMMITTER_EMAIL="+sig.Email,
 | 
					 | 
				
			||||||
		models.EnvRepoName+"="+t.repo.Name,
 | 
					 | 
				
			||||||
		models.EnvRepoUsername+"="+t.repo.OwnerName,
 | 
					 | 
				
			||||||
		models.EnvRepoIsWiki+"="+isWiki,
 | 
					 | 
				
			||||||
		models.EnvPusherName+"="+doer.Name,
 | 
					 | 
				
			||||||
		models.EnvPusherID+"="+fmt.Sprintf("%d", doer.ID),
 | 
					 | 
				
			||||||
		models.ProtectedBranchRepoID+"="+fmt.Sprintf("%d", t.repo.ID),
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, stderr, err := process.GetManager().ExecDirEnv(5*time.Minute,
 | 
						if _, stderr, err := process.GetManager().ExecDirEnv(5*time.Minute,
 | 
				
			||||||
		t.basePath,
 | 
							t.basePath,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,357 +0,0 @@
 | 
				
			|||||||
// 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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package repofiles
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"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"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getCreateRepoFileOptions(repo *models.Repository) *UpdateRepoFileOptions {
 | 
					 | 
				
			||||||
	return &UpdateRepoFileOptions{
 | 
					 | 
				
			||||||
		OldBranch: repo.DefaultBranch,
 | 
					 | 
				
			||||||
		NewBranch: repo.DefaultBranch,
 | 
					 | 
				
			||||||
		TreePath:  "new/file.txt",
 | 
					 | 
				
			||||||
		Message:   "Creates new/file.txt",
 | 
					 | 
				
			||||||
		Content:   "This is a NEW file",
 | 
					 | 
				
			||||||
		IsNewFile: true,
 | 
					 | 
				
			||||||
		Author:    nil,
 | 
					 | 
				
			||||||
		Committer: nil,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getUpdateRepoFileOptions(repo *models.Repository) *UpdateRepoFileOptions {
 | 
					 | 
				
			||||||
	return &UpdateRepoFileOptions{
 | 
					 | 
				
			||||||
		OldBranch: repo.DefaultBranch,
 | 
					 | 
				
			||||||
		NewBranch: repo.DefaultBranch,
 | 
					 | 
				
			||||||
		TreePath:  "README.md",
 | 
					 | 
				
			||||||
		Message:   "Updates README.md",
 | 
					 | 
				
			||||||
		SHA:       "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
 | 
					 | 
				
			||||||
		Content:   "This is UPDATED content for the README file",
 | 
					 | 
				
			||||||
		IsNewFile: false,
 | 
					 | 
				
			||||||
		Author:    nil,
 | 
					 | 
				
			||||||
		Committer: nil,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getExpectedFileResponseForCreate(commitID string) *api.FileResponse {
 | 
					 | 
				
			||||||
	return &api.FileResponse{
 | 
					 | 
				
			||||||
		Content: &api.FileContentResponse{
 | 
					 | 
				
			||||||
			Name:        "file.txt",
 | 
					 | 
				
			||||||
			Path:        "new/file.txt",
 | 
					 | 
				
			||||||
			SHA:         "103ff9234cefeee5ec5361d22b49fbb04d385885",
 | 
					 | 
				
			||||||
			Size:        18,
 | 
					 | 
				
			||||||
			URL:         "https://try.gitea.io/api/v1/repos/user2/repo1/contents/new/file.txt",
 | 
					 | 
				
			||||||
			HTMLURL:     "https://try.gitea.io/user2/repo1/blob/master/new/file.txt",
 | 
					 | 
				
			||||||
			GitURL:      "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/103ff9234cefeee5ec5361d22b49fbb04d385885",
 | 
					 | 
				
			||||||
			DownloadURL: "https://try.gitea.io/user2/repo1/raw/branch/master/new/file.txt",
 | 
					 | 
				
			||||||
			Type:        "blob",
 | 
					 | 
				
			||||||
			Links: &api.FileLinksResponse{
 | 
					 | 
				
			||||||
				Self:    "https://try.gitea.io/api/v1/repos/user2/repo1/contents/new/file.txt",
 | 
					 | 
				
			||||||
				GitURL:  "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/103ff9234cefeee5ec5361d22b49fbb04d385885",
 | 
					 | 
				
			||||||
				HTMLURL: "https://try.gitea.io/user2/repo1/blob/master/new/file.txt",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Commit: &api.FileCommitResponse{
 | 
					 | 
				
			||||||
			CommitMeta: api.CommitMeta{
 | 
					 | 
				
			||||||
				URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/commits/" + commitID,
 | 
					 | 
				
			||||||
				SHA: commitID,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			HTMLURL: "https://try.gitea.io/user2/repo1/commit/" + commitID,
 | 
					 | 
				
			||||||
			Author: &api.CommitUser{
 | 
					 | 
				
			||||||
				Identity: api.Identity{
 | 
					 | 
				
			||||||
					Name:  "User Two",
 | 
					 | 
				
			||||||
					Email: "user2@",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				Date: time.Now().UTC().Format(time.RFC3339),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Committer: &api.CommitUser{
 | 
					 | 
				
			||||||
				Identity: api.Identity{
 | 
					 | 
				
			||||||
					Name:  "User Two",
 | 
					 | 
				
			||||||
					Email: "user2@",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				Date: time.Now().UTC().Format(time.RFC3339),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Parents: []*api.CommitMeta{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
					 | 
				
			||||||
					SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Message: "Updates README.md\n",
 | 
					 | 
				
			||||||
			Tree: &api.CommitMeta{
 | 
					 | 
				
			||||||
				URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/trees/f93e3a1a1525fb5b91020da86e44810c87a2d7bc",
 | 
					 | 
				
			||||||
				SHA: "f93e3a1a1525fb5b91020git dda86e44810c87a2d7bc",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Verification: &api.PayloadCommitVerification{
 | 
					 | 
				
			||||||
			Verified:  false,
 | 
					 | 
				
			||||||
			Reason:    "unsigned",
 | 
					 | 
				
			||||||
			Signature: "",
 | 
					 | 
				
			||||||
			Payload:   "",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getExpectedFileResponseForUpdate(commitID string) *api.FileResponse {
 | 
					 | 
				
			||||||
	return &api.FileResponse{
 | 
					 | 
				
			||||||
		Content: &api.FileContentResponse{
 | 
					 | 
				
			||||||
			Name:        "README.md",
 | 
					 | 
				
			||||||
			Path:        "README.md",
 | 
					 | 
				
			||||||
			SHA:         "dbf8d00e022e05b7e5cf7e535de857de57925647",
 | 
					 | 
				
			||||||
			Size:        43,
 | 
					 | 
				
			||||||
			URL:         "https://try.gitea.io/api/v1/repos/user2/repo1/contents/README.md",
 | 
					 | 
				
			||||||
			HTMLURL:     "https://try.gitea.io/user2/repo1/blob/master/README.md",
 | 
					 | 
				
			||||||
			GitURL:      "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/dbf8d00e022e05b7e5cf7e535de857de57925647",
 | 
					 | 
				
			||||||
			DownloadURL: "https://try.gitea.io/user2/repo1/raw/branch/master/README.md",
 | 
					 | 
				
			||||||
			Type:        "blob",
 | 
					 | 
				
			||||||
			Links: &api.FileLinksResponse{
 | 
					 | 
				
			||||||
				Self:    "https://try.gitea.io/api/v1/repos/user2/repo1/contents/README.md",
 | 
					 | 
				
			||||||
				GitURL:  "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/dbf8d00e022e05b7e5cf7e535de857de57925647",
 | 
					 | 
				
			||||||
				HTMLURL: "https://try.gitea.io/user2/repo1/blob/master/README.md",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Commit: &api.FileCommitResponse{
 | 
					 | 
				
			||||||
			CommitMeta: api.CommitMeta{
 | 
					 | 
				
			||||||
				URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/commits/" + commitID,
 | 
					 | 
				
			||||||
				SHA: commitID,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			HTMLURL: "https://try.gitea.io/user2/repo1/commit/" + commitID,
 | 
					 | 
				
			||||||
			Author: &api.CommitUser{
 | 
					 | 
				
			||||||
				Identity: api.Identity{
 | 
					 | 
				
			||||||
					Name:  "User Two",
 | 
					 | 
				
			||||||
					Email: "user2@",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				Date: time.Now().UTC().Format(time.RFC3339),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Committer: &api.CommitUser{
 | 
					 | 
				
			||||||
				Identity: api.Identity{
 | 
					 | 
				
			||||||
					Name:  "User Two",
 | 
					 | 
				
			||||||
					Email: "user2@",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				Date: time.Now().UTC().Format(time.RFC3339),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Parents: []*api.CommitMeta{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
					 | 
				
			||||||
					SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			Message: "Updates README.md\n",
 | 
					 | 
				
			||||||
			Tree: &api.CommitMeta{
 | 
					 | 
				
			||||||
				URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/trees/f93e3a1a1525fb5b91020da86e44810c87a2d7bc",
 | 
					 | 
				
			||||||
				SHA: "f93e3a1a1525fb5b91020da86e44810c87a2d7bc",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Verification: &api.PayloadCommitVerification{
 | 
					 | 
				
			||||||
			Verified:  false,
 | 
					 | 
				
			||||||
			Reason:    "unsigned",
 | 
					 | 
				
			||||||
			Signature: "",
 | 
					 | 
				
			||||||
			Payload:   "",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCreateOrUpdateRepoFileForCreate(t *testing.T) {
 | 
					 | 
				
			||||||
	// setup
 | 
					 | 
				
			||||||
	models.PrepareTestEnv(t)
 | 
					 | 
				
			||||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
					 | 
				
			||||||
	ctx.SetParams(":id", "1")
 | 
					 | 
				
			||||||
	test.LoadRepo(t, ctx, 1)
 | 
					 | 
				
			||||||
	test.LoadRepoCommit(t, ctx)
 | 
					 | 
				
			||||||
	test.LoadUser(t, ctx, 2)
 | 
					 | 
				
			||||||
	test.LoadGitRepo(t, ctx)
 | 
					 | 
				
			||||||
	repo := ctx.Repo.Repository
 | 
					 | 
				
			||||||
	doer := ctx.User
 | 
					 | 
				
			||||||
	opts := getCreateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// test
 | 
					 | 
				
			||||||
	fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// asserts
 | 
					 | 
				
			||||||
	assert.Nil(t, err)
 | 
					 | 
				
			||||||
	gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
					 | 
				
			||||||
	commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
 | 
					 | 
				
			||||||
	expectedFileResponse := getExpectedFileResponseForCreate(commitID)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCreateOrUpdateRepoFileForUpdate(t *testing.T) {
 | 
					 | 
				
			||||||
	// setup
 | 
					 | 
				
			||||||
	models.PrepareTestEnv(t)
 | 
					 | 
				
			||||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
					 | 
				
			||||||
	ctx.SetParams(":id", "1")
 | 
					 | 
				
			||||||
	test.LoadRepo(t, ctx, 1)
 | 
					 | 
				
			||||||
	test.LoadRepoCommit(t, ctx)
 | 
					 | 
				
			||||||
	test.LoadUser(t, ctx, 2)
 | 
					 | 
				
			||||||
	test.LoadGitRepo(t, ctx)
 | 
					 | 
				
			||||||
	repo := ctx.Repo.Repository
 | 
					 | 
				
			||||||
	doer := ctx.User
 | 
					 | 
				
			||||||
	opts := getUpdateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// test
 | 
					 | 
				
			||||||
	fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// asserts
 | 
					 | 
				
			||||||
	assert.Nil(t, err)
 | 
					 | 
				
			||||||
	gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
					 | 
				
			||||||
	commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
 | 
					 | 
				
			||||||
	expectedFileResponse := getExpectedFileResponseForUpdate(commitID)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCreateOrUpdateRepoFileForUpdateWithFileMove(t *testing.T) {
 | 
					 | 
				
			||||||
	// setup
 | 
					 | 
				
			||||||
	models.PrepareTestEnv(t)
 | 
					 | 
				
			||||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
					 | 
				
			||||||
	ctx.SetParams(":id", "1")
 | 
					 | 
				
			||||||
	test.LoadRepo(t, ctx, 1)
 | 
					 | 
				
			||||||
	test.LoadRepoCommit(t, ctx)
 | 
					 | 
				
			||||||
	test.LoadUser(t, ctx, 2)
 | 
					 | 
				
			||||||
	test.LoadGitRepo(t, ctx)
 | 
					 | 
				
			||||||
	repo := ctx.Repo.Repository
 | 
					 | 
				
			||||||
	doer := ctx.User
 | 
					 | 
				
			||||||
	opts := getUpdateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
	suffix := "_new"
 | 
					 | 
				
			||||||
	opts.FromTreePath = "README.md"
 | 
					 | 
				
			||||||
	opts.TreePath = "README.md" + suffix // new file name, README.md_new
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// test
 | 
					 | 
				
			||||||
	fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// asserts
 | 
					 | 
				
			||||||
	assert.Nil(t, err)
 | 
					 | 
				
			||||||
	gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
					 | 
				
			||||||
	commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
 | 
					 | 
				
			||||||
	expectedFileResponse := getExpectedFileResponseForUpdate(commit.ID.String())
 | 
					 | 
				
			||||||
	// assert that the old file no longer exists in the last commit of the branch
 | 
					 | 
				
			||||||
	fromEntry, err := commit.GetTreeEntryByPath(opts.FromTreePath)
 | 
					 | 
				
			||||||
	toEntry, err := commit.GetTreeEntryByPath(opts.TreePath)
 | 
					 | 
				
			||||||
	assert.Nil(t, fromEntry)  // Should no longer exist here
 | 
					 | 
				
			||||||
	assert.NotNil(t, toEntry) // Should exist here
 | 
					 | 
				
			||||||
	// assert SHA has remained the same but paths use the new file name
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Content.SHA, fileResponse.Content.SHA)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Content.Name+suffix, fileResponse.Content.Name)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Content.Path+suffix, fileResponse.Content.Path)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Content.URL+suffix, fileResponse.Content.URL)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Test opts with branch names removed, should get same results as above test
 | 
					 | 
				
			||||||
func TestCreateOrUpdateRepoFileWithoutBranchNames(t *testing.T) {
 | 
					 | 
				
			||||||
	// setup
 | 
					 | 
				
			||||||
	models.PrepareTestEnv(t)
 | 
					 | 
				
			||||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
					 | 
				
			||||||
	ctx.SetParams(":id", "1")
 | 
					 | 
				
			||||||
	test.LoadRepo(t, ctx, 1)
 | 
					 | 
				
			||||||
	test.LoadRepoCommit(t, ctx)
 | 
					 | 
				
			||||||
	test.LoadUser(t, ctx, 2)
 | 
					 | 
				
			||||||
	test.LoadGitRepo(t, ctx)
 | 
					 | 
				
			||||||
	repo := ctx.Repo.Repository
 | 
					 | 
				
			||||||
	doer := ctx.User
 | 
					 | 
				
			||||||
	opts := getUpdateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
	opts.OldBranch = ""
 | 
					 | 
				
			||||||
	opts.NewBranch = ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// test
 | 
					 | 
				
			||||||
	fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// asserts
 | 
					 | 
				
			||||||
	assert.Nil(t, err)
 | 
					 | 
				
			||||||
	gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
					 | 
				
			||||||
	commitID, _ := gitRepo.GetBranchCommitID(repo.DefaultBranch)
 | 
					 | 
				
			||||||
	expectedFileResponse := getExpectedFileResponseForUpdate(commitID)
 | 
					 | 
				
			||||||
	assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCreateOrUpdateRepoFileErrors(t *testing.T) {
 | 
					 | 
				
			||||||
	// setup
 | 
					 | 
				
			||||||
	models.PrepareTestEnv(t)
 | 
					 | 
				
			||||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
					 | 
				
			||||||
	ctx.SetParams(":id", "1")
 | 
					 | 
				
			||||||
	test.LoadRepo(t, ctx, 1)
 | 
					 | 
				
			||||||
	test.LoadRepoCommit(t, ctx)
 | 
					 | 
				
			||||||
	test.LoadUser(t, ctx, 2)
 | 
					 | 
				
			||||||
	test.LoadGitRepo(t, ctx)
 | 
					 | 
				
			||||||
	repo := ctx.Repo.Repository
 | 
					 | 
				
			||||||
	doer := ctx.User
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t.Run("bad branch", func(t *testing.T) {
 | 
					 | 
				
			||||||
		opts := getUpdateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
		opts.OldBranch = "bad_branch"
 | 
					 | 
				
			||||||
		fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
		assert.Error(t, err)
 | 
					 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
					 | 
				
			||||||
		expectedError := "branch does not exist [name: " + opts.OldBranch + "]"
 | 
					 | 
				
			||||||
		assert.EqualError(t, err, expectedError)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t.Run("bad SHA", func(t *testing.T) {
 | 
					 | 
				
			||||||
		opts := getUpdateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
		origSHA := opts.SHA
 | 
					 | 
				
			||||||
		opts.SHA = "bad_sha"
 | 
					 | 
				
			||||||
		fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
					 | 
				
			||||||
		assert.Error(t, err)
 | 
					 | 
				
			||||||
		expectedError := "sha does not match [given: " + opts.SHA + ", expected: " + origSHA + "]"
 | 
					 | 
				
			||||||
		assert.EqualError(t, err, expectedError)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t.Run("new branch already exists", func(t *testing.T) {
 | 
					 | 
				
			||||||
		opts := getUpdateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
		opts.NewBranch = "develop"
 | 
					 | 
				
			||||||
		fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
					 | 
				
			||||||
		assert.Error(t, err)
 | 
					 | 
				
			||||||
		expectedError := "branch already exists [name: " + opts.NewBranch + "]"
 | 
					 | 
				
			||||||
		assert.EqualError(t, err, expectedError)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t.Run("treePath is empty:", func(t *testing.T) {
 | 
					 | 
				
			||||||
		opts := getUpdateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
		opts.TreePath = ""
 | 
					 | 
				
			||||||
		fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
					 | 
				
			||||||
		assert.Error(t, err)
 | 
					 | 
				
			||||||
		expectedError := "path contains a malformed path component [path: ]"
 | 
					 | 
				
			||||||
		assert.EqualError(t, err, expectedError)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t.Run("treePath is a git directory:", func(t *testing.T) {
 | 
					 | 
				
			||||||
		opts := getUpdateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
		opts.TreePath = ".git"
 | 
					 | 
				
			||||||
		fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
					 | 
				
			||||||
		assert.Error(t, err)
 | 
					 | 
				
			||||||
		expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]"
 | 
					 | 
				
			||||||
		assert.EqualError(t, err, expectedError)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t.Run("create file that already exists", func(t *testing.T) {
 | 
					 | 
				
			||||||
		opts := getCreateRepoFileOptions(repo)
 | 
					 | 
				
			||||||
		opts.TreePath = "README.md" //already exists
 | 
					 | 
				
			||||||
		fileResponse, err := CreateOrUpdateRepoFile(repo, doer, opts)
 | 
					 | 
				
			||||||
		assert.Nil(t, fileResponse)
 | 
					 | 
				
			||||||
		assert.Error(t, err)
 | 
					 | 
				
			||||||
		expectedError := "repository file already exists [path: " + opts.TreePath + "]"
 | 
					 | 
				
			||||||
		assert.EqualError(t, err, expectedError)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -53,7 +53,6 @@ var (
 | 
				
			|||||||
		// Repository local settings
 | 
							// Repository local settings
 | 
				
			||||||
		Local struct {
 | 
							Local struct {
 | 
				
			||||||
			LocalCopyPath string
 | 
								LocalCopyPath string
 | 
				
			||||||
			LocalWikiPath string
 | 
					 | 
				
			||||||
		} `ini:"-"`
 | 
							} `ini:"-"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Pull request settings
 | 
							// Pull request settings
 | 
				
			||||||
@@ -105,10 +104,8 @@ var (
 | 
				
			|||||||
		// Repository local settings
 | 
							// Repository local settings
 | 
				
			||||||
		Local: struct {
 | 
							Local: struct {
 | 
				
			||||||
			LocalCopyPath string
 | 
								LocalCopyPath string
 | 
				
			||||||
			LocalWikiPath string
 | 
					 | 
				
			||||||
		}{
 | 
							}{
 | 
				
			||||||
			LocalCopyPath: "tmp/local-repo",
 | 
								LocalCopyPath: "tmp/local-repo",
 | 
				
			||||||
			LocalWikiPath: "tmp/local-wiki",
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Pull request settings
 | 
							// Pull request settings
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,12 +74,6 @@ func DeleteBranchPost(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Delete branch in local copy if it exists
 | 
					 | 
				
			||||||
	if err := ctx.Repo.Repository.DeleteLocalBranch(branchName); err != nil {
 | 
					 | 
				
			||||||
		ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", branchName))
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.Flash.Success(ctx.Tr("repo.branch.deletion_success", branchName))
 | 
						ctx.Flash.Success(ctx.Tr("repo.branch.deletion_success", branchName))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user