diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go
index bc393da13..607a50318 100644
--- a/contrib/pr/checkout.go
+++ b/contrib/pr/checkout.go
@@ -108,7 +108,6 @@ func runPR() {
models.LoadFixtures()
os.RemoveAll(setting.RepoRootPath)
os.RemoveAll(models.LocalCopyPath())
- os.RemoveAll(models.LocalWikiPath())
com.CopyDir(path.Join(curDir, "integrations/gitea-repositories-meta"), setting.RepoRootPath)
log.Printf("[PR] Setting up router\n")
diff --git a/integrations/api_repo_file_content_test.go b/integrations/api_repo_file_content_test.go
index 1f535ef3a..896d81108 100644
--- a/integrations/api_repo_file_content_test.go
+++ b/integrations/api_repo_file_content_test.go
@@ -6,6 +6,7 @@ package integrations
import (
"net/http"
+ "net/url"
"path/filepath"
"testing"
@@ -40,7 +41,10 @@ func getExpectedFileContentResponseForFileContents(branch string) *api.FileConte
}
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
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
diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go
index a43855b06..28097179a 100644
--- a/integrations/api_repo_file_create_test.go
+++ b/integrations/api_repo_file_create_test.go
@@ -8,6 +8,7 @@ import (
"encoding/base64"
"fmt"
"net/http"
+ "net/url"
"path/filepath"
"testing"
@@ -91,125 +92,126 @@ func getExpectedFileResponseForCreate(commitID, treePath string) *api.FileRespon
}
func TestAPICreateFile(t *testing.T) {
- prepareTestEnv(t)
- 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
- 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
- repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo
- repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
- fileID := 0
-
- // Get user2's token
- session := loginUser(t, user2.Name)
- token2 := getTokenForLoggedInUser(t, session)
- session = emptyTestSession(t)
- // Get user4's token
- session = loginUser(t, user4.Name)
- token4 := getTokenForLoggedInUser(t, session)
- session = emptyTestSession(t)
-
- // Test creating a file in repo1 which user2 owns, try both with branch and empty branch
- for _, branch := range [...]string{
- "master", // Branch
- "", // Empty branch
- } {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ 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
+ 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
+ repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo
+ repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
+ fileID := 0
+
+ // Get user2's token
+ session := loginUser(t, user2.Name)
+ token2 := getTokenForLoggedInUser(t, session)
+ session = emptyTestSession(t)
+ // Get user4's token
+ session = loginUser(t, user4.Name)
+ token4 := getTokenForLoggedInUser(t, session)
+ session = emptyTestSession(t)
+
+ // Test creating a file in repo1 which user2 owns, try both with branch and empty branch
+ for _, branch := range [...]string{
+ "master", // 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.BranchName = branch
+ createFileOptions.BranchName = repo1.DefaultBranch
+ createFileOptions.NewBranchName = "new_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)
- }
+ expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
+ expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/new/file%d.txt", fileID)
+ 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
+ createFileOptions = getCreateFileOptions()
+ treePath = "README.md"
+ 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.StatusInternalServerError)
+ expectedAPIError := context.APIError{
+ 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
+ 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, repo16.Name, treePath, token4)
+ req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
- // Test creating a file in a new branch
- createFileOptions := getCreateFileOptions()
- createFileOptions.BranchName = repo1.DefaultBranch
- createFileOptions.NewBranchName = "new_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)
- var fileResponse api.FileResponse
- DecodeJSON(t, resp, &fileResponse)
- expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
- expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/new/file%d.txt", fileID)
- 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
- createFileOptions = getCreateFileOptions()
- treePath = "README.md"
- 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.StatusInternalServerError)
- expectedAPIError := context.APIError{
- 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
- 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, repo16.Name, treePath, token4)
- req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // Tests a repo with no token given so will fail
- createFileOptions = getCreateFileOptions()
- fileID++
- treePath = fmt.Sprintf("new/file%d.txt", fileID)
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
- req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // Test using access token for a private repo that the user of the token owns
- 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, repo16.Name, treePath, token2)
- req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
- session.MakeRequest(t, req, http.StatusCreated)
-
- // Test using org repo "user3/repo3" where user2 is a collaborator
- createFileOptions = getCreateFileOptions()
- 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)
- req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
- session.MakeRequest(t, req, http.StatusCreated)
-
- // Test using org repo "user3/repo3" with no user token
- createFileOptions = getCreateFileOptions()
- fileID++
- treePath = fmt.Sprintf("new/file%d.txt", fileID)
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
- req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // 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)
+ // Tests a repo with no token given so will fail
+ createFileOptions = getCreateFileOptions()
+ fileID++
+ treePath = fmt.Sprintf("new/file%d.txt", fileID)
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
+ req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // Test using access token for a private repo that the user of the token owns
+ 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, repo16.Name, treePath, token2)
+ req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
+ session.MakeRequest(t, req, http.StatusCreated)
+
+ // Test using org repo "user3/repo3" where user2 is a collaborator
+ createFileOptions = getCreateFileOptions()
+ 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)
+ req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
+ session.MakeRequest(t, req, http.StatusCreated)
+
+ // Test using org repo "user3/repo3" with no user token
+ createFileOptions = getCreateFileOptions()
+ fileID++
+ treePath = fmt.Sprintf("new/file%d.txt", fileID)
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
+ req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // 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)
+ })
}
diff --git a/integrations/api_repo_file_delete_test.go b/integrations/api_repo_file_delete_test.go
index b619f9c43..57e2539e1 100644
--- a/integrations/api_repo_file_delete_test.go
+++ b/integrations/api_repo_file_delete_test.go
@@ -7,6 +7,7 @@ package integrations
import (
"fmt"
"net/http"
+ "net/url"
"testing"
"code.gitea.io/gitea/models"
@@ -37,34 +38,50 @@ func getDeleteFileOptions() *api.DeleteFileOptions {
}
func TestAPIDeleteFile(t *testing.T) {
- prepareTestEnv(t)
- 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
- 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
- repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo
- repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
- fileID := 0
-
- // Get user2's token
- session := loginUser(t, user2.Name)
- token2 := getTokenForLoggedInUser(t, session)
- session = emptyTestSession(t)
- // Get user4's token
- session = loginUser(t, user4.Name)
- token4 := getTokenForLoggedInUser(t, session)
- session = emptyTestSession(t)
-
- // Test deleting a file in repo1 which user2 owns, try both with branch and empty branch
- for _, branch := range [...]string{
- "master", // Branch
- "", // Empty branch
- } {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ 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
+ 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
+ repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo
+ repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
+ fileID := 0
+
+ // Get user2's token
+ session := loginUser(t, user2.Name)
+ token2 := getTokenForLoggedInUser(t, session)
+ session = emptyTestSession(t)
+ // Get user4's token
+ session = loginUser(t, user4.Name)
+ token4 := getTokenForLoggedInUser(t, session)
+ session = emptyTestSession(t)
+
+ // Test deleting a file in repo1 which user2 owns, try both with branch and empty branch
+ for _, branch := range [...]string{
+ "master", // 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++
treePath := fmt.Sprintf("delete/file%d.txt", fileID)
createFile(user2, repo1, treePath)
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)
req := NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
resp := session.MakeRequest(t, req, http.StatusOK)
@@ -72,92 +89,77 @@ func TestAPIDeleteFile(t *testing.T) {
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++
- treePath := fmt.Sprintf("delete/file%d.txt", fileID)
- createFile(user2, repo1, treePath)
- deleteFileOptions := getDeleteFileOptions()
- 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)
- 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 a file with the wrong SHA
- fileID++
- treePath = fmt.Sprintf("delete/file%d.txt", fileID)
- createFile(user2, repo1, treePath)
- deleteFileOptions = getDeleteFileOptions()
- correctSHA := deleteFileOptions.SHA
- deleteFileOptions.SHA = "badsha"
- 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.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
- fileID++
- treePath = fmt.Sprintf("delete/file%d.txt", fileID)
- createFile(user2, repo16, treePath)
- deleteFileOptions = getDeleteFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
- req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // Tests a repo with no token given so will fail
- fileID++
- treePath = fmt.Sprintf("delete/file%d.txt", fileID)
- createFile(user2, repo16, treePath)
- deleteFileOptions = getDeleteFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
- req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // Test using access token for a private repo that the user of the token owns
- fileID++
- treePath = fmt.Sprintf("delete/file%d.txt", fileID)
- createFile(user2, repo16, treePath)
- deleteFileOptions = getDeleteFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
- req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
- session.MakeRequest(t, req, http.StatusOK)
-
- // Test using org repo "user3/repo3" where user2 is a collaborator
- fileID++
- treePath = fmt.Sprintf("delete/file%d.txt", fileID)
- createFile(user3, repo3, treePath)
- deleteFileOptions = getDeleteFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
- req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
- session.MakeRequest(t, req, http.StatusOK)
-
- // Test using org repo "user3/repo3" with no user token
- fileID++
- treePath = fmt.Sprintf("delete/file%d.txt", fileID)
- createFile(user3, repo3, treePath)
- deleteFileOptions = getDeleteFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
- req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // 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)
+ // Test deleting a file with the wrong SHA
+ fileID++
+ treePath = fmt.Sprintf("delete/file%d.txt", fileID)
+ createFile(user2, repo1, treePath)
+ deleteFileOptions = getDeleteFileOptions()
+ correctSHA := deleteFileOptions.SHA
+ deleteFileOptions.SHA = "badsha"
+ 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.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
+ fileID++
+ treePath = fmt.Sprintf("delete/file%d.txt", fileID)
+ createFile(user2, repo16, treePath)
+ deleteFileOptions = getDeleteFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
+ req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // Tests a repo with no token given so will fail
+ fileID++
+ treePath = fmt.Sprintf("delete/file%d.txt", fileID)
+ createFile(user2, repo16, treePath)
+ deleteFileOptions = getDeleteFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
+ req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // Test using access token for a private repo that the user of the token owns
+ fileID++
+ treePath = fmt.Sprintf("delete/file%d.txt", fileID)
+ createFile(user2, repo16, treePath)
+ deleteFileOptions = getDeleteFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
+ req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
+ session.MakeRequest(t, req, http.StatusOK)
+
+ // Test using org repo "user3/repo3" where user2 is a collaborator
+ fileID++
+ treePath = fmt.Sprintf("delete/file%d.txt", fileID)
+ createFile(user3, repo3, treePath)
+ deleteFileOptions = getDeleteFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
+ req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
+ session.MakeRequest(t, req, http.StatusOK)
+
+ // Test using org repo "user3/repo3" with no user token
+ fileID++
+ treePath = fmt.Sprintf("delete/file%d.txt", fileID)
+ createFile(user3, repo3, treePath)
+ deleteFileOptions = getDeleteFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
+ req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // 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)
+ })
}
diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go
index 71994564f..37438339b 100644
--- a/integrations/api_repo_file_update_test.go
+++ b/integrations/api_repo_file_update_test.go
@@ -8,6 +8,7 @@ import (
"encoding/base64"
"fmt"
"net/http"
+ "net/url"
"path/filepath"
"testing"
@@ -79,156 +80,157 @@ func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileRespon
}
func TestAPIUpdateFile(t *testing.T) {
- prepareTestEnv(t)
- 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
- 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
- repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo
- repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
- fileID := 0
-
- // Get user2's token
- session := loginUser(t, user2.Name)
- token2 := getTokenForLoggedInUser(t, session)
- session = emptyTestSession(t)
- // Get user4's token
- session = loginUser(t, user4.Name)
- token4 := getTokenForLoggedInUser(t, session)
- session = emptyTestSession(t)
-
- // Test updating a file in repo1 which user2 owns, try both with branch and empty branch
- for _, branch := range [...]string{
- "master", // Branch
- "", // Empty branch
- } {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ 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
+ 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
+ repo3 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 3}).(*models.Repository) // public repo
+ repo16 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) // private repo
+ fileID := 0
+
+ // Get user2's token
+ session := loginUser(t, user2.Name)
+ token2 := getTokenForLoggedInUser(t, session)
+ session = emptyTestSession(t)
+ // Get user4's token
+ session = loginUser(t, user4.Name)
+ token4 := getTokenForLoggedInUser(t, session)
+ session = emptyTestSession(t)
+
+ // Test updating a file in repo1 which user2 owns, try both with branch and empty branch
+ for _, branch := range [...]string{
+ "master", // 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++
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++
- treePath := fmt.Sprintf("update/file%d.txt", fileID)
- createFile(user2, repo1, treePath)
- 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)
- var fileResponse api.FileResponse
- DecodeJSON(t, resp, &fileResponse)
- expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136"
- expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/update/file%d.txt", fileID)
- expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/update/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 updating a file and renaming it
- updateFileOptions = getUpdateFileOptions()
- updateFileOptions.BranchName = repo1.DefaultBranch
- fileID++
- treePath = fmt.Sprintf("update/file%d.txt", fileID)
- createFile(user2, repo1, treePath)
- updateFileOptions.FromPath = treePath
- treePath = "rename/" + treePath
- 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)
- DecodeJSON(t, resp, &fileResponse)
- expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136"
- 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)
- assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
- assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL)
- assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL)
-
- // Test updating a file with the wrong SHA
- fileID++
- treePath = fmt.Sprintf("update/file%d.txt", fileID)
- createFile(user2, repo1, treePath)
- updateFileOptions = getUpdateFileOptions()
- correctSHA := updateFileOptions.SHA
- updateFileOptions.SHA = "badsha"
- 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.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
- fileID++
- treePath = fmt.Sprintf("update/file%d.txt", fileID)
- createFile(user2, repo16, treePath)
- updateFileOptions = getUpdateFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
- req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // Tests a repo with no token given so will fail
- fileID++
- treePath = fmt.Sprintf("update/file%d.txt", fileID)
- createFile(user2, repo16, treePath)
- updateFileOptions = getUpdateFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
- req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // Test using access token for a private repo that the user of the token owns
- fileID++
- treePath = fmt.Sprintf("update/file%d.txt", fileID)
- createFile(user2, repo16, treePath)
- updateFileOptions = getUpdateFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
- req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
- session.MakeRequest(t, req, http.StatusOK)
-
- // Test using org repo "user3/repo3" where user2 is a collaborator
- fileID++
- treePath = fmt.Sprintf("update/file%d.txt", fileID)
- createFile(user3, repo3, treePath)
- updateFileOptions = getUpdateFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
- req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
- session.MakeRequest(t, req, http.StatusOK)
-
- // Test using org repo "user3/repo3" with no user token
- fileID++
- treePath = fmt.Sprintf("update/file%d.txt", fileID)
- createFile(user3, repo3, treePath)
- updateFileOptions = getUpdateFileOptions()
- url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
- req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
- session.MakeRequest(t, req, http.StatusNotFound)
-
- // 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)
+ expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136"
+ expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/update/file%d.txt", fileID)
+ expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/update/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 updating a file and renaming it
+ updateFileOptions = getUpdateFileOptions()
+ updateFileOptions.BranchName = repo1.DefaultBranch
+ fileID++
+ treePath = fmt.Sprintf("update/file%d.txt", fileID)
+ createFile(user2, repo1, treePath)
+ updateFileOptions.FromPath = treePath
+ treePath = "rename/" + treePath
+ 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)
+ DecodeJSON(t, resp, &fileResponse)
+ expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136"
+ 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)
+ assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
+ assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL)
+ assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL)
+
+ // Test updating a file with the wrong SHA
+ fileID++
+ treePath = fmt.Sprintf("update/file%d.txt", fileID)
+ createFile(user2, repo1, treePath)
+ updateFileOptions = getUpdateFileOptions()
+ correctSHA := updateFileOptions.SHA
+ updateFileOptions.SHA = "badsha"
+ 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.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
+ fileID++
+ treePath = fmt.Sprintf("update/file%d.txt", fileID)
+ createFile(user2, repo16, treePath)
+ updateFileOptions = getUpdateFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)
+ req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // Tests a repo with no token given so will fail
+ fileID++
+ treePath = fmt.Sprintf("update/file%d.txt", fileID)
+ createFile(user2, repo16, treePath)
+ updateFileOptions = getUpdateFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath)
+ req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // Test using access token for a private repo that the user of the token owns
+ fileID++
+ treePath = fmt.Sprintf("update/file%d.txt", fileID)
+ createFile(user2, repo16, treePath)
+ updateFileOptions = getUpdateFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token2)
+ req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
+ session.MakeRequest(t, req, http.StatusOK)
+
+ // Test using org repo "user3/repo3" where user2 is a collaborator
+ fileID++
+ treePath = fmt.Sprintf("update/file%d.txt", fileID)
+ createFile(user3, repo3, treePath)
+ updateFileOptions = getUpdateFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user3.Name, repo3.Name, treePath, token2)
+ req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
+ session.MakeRequest(t, req, http.StatusOK)
+
+ // Test using org repo "user3/repo3" with no user token
+ fileID++
+ treePath = fmt.Sprintf("update/file%d.txt", fileID)
+ createFile(user3, repo3, treePath)
+ updateFileOptions = getUpdateFileOptions()
+ url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user3.Name, repo3.Name, treePath)
+ req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // 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)
+ })
}
diff --git a/integrations/editor_test.go b/integrations/editor_test.go
index e2dd2e1dc..8e6effe7e 100644
--- a/integrations/editor_test.go
+++ b/integrations/editor_test.go
@@ -7,6 +7,7 @@ package integrations
import (
"net/http"
"net/http/httptest"
+ "net/url"
"path"
"testing"
@@ -14,80 +15,79 @@ import (
)
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
- 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)
+ 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",
+ // 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.StatusFound)
})
- resp = session.MakeRequest(t, req, http.StatusFound)
}
func TestCreateFileOnProtectedBranch(t *testing.T) {
- prepareTestEnv(t)
-
- 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)
-
- // 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",
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ 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)
+
+ // 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)
})
- 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 {
@@ -151,13 +151,15 @@ func testEditFileToNewBranch(t *testing.T, session *TestSession, user, repo, bra
}
func TestEditFile(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user2")
- testEditFile(t, session, "user2", "repo1", "master", "README.md", "Hello, World (Edited)\n")
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ session := loginUser(t, "user2")
+ testEditFile(t, session, "user2", "repo1", "master", "README.md", "Hello, World (Edited)\n")
+ })
}
func TestEditFileToNewBranch(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user2")
- testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ session := loginUser(t, "user2")
+ testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
+ })
}
diff --git a/integrations/integration_test.go b/integrations/integration_test.go
index 566859518..93dacaf78 100644
--- a/integrations/integration_test.go
+++ b/integrations/integration_test.go
@@ -178,7 +178,6 @@ func prepareTestEnv(t testing.TB, skip ...int) {
assert.NoError(t, models.LoadFixtures())
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
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"),
setting.RepoRootPath))
diff --git a/integrations/pull_create_test.go b/integrations/pull_create_test.go
index ed553bf16..8f39e8b02 100644
--- a/integrations/pull_create_test.go
+++ b/integrations/pull_create_test.go
@@ -7,6 +7,7 @@ package integrations
import (
"net/http"
"net/http/httptest"
+ "net/url"
"path"
"strings"
"testing"
@@ -43,63 +44,65 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo, branch, titl
}
func TestPullCreate(t *testing.T) {
- prepareTestEnv(t)
- 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")
-
- // check the redirected URL
- url := resp.HeaderMap.Get("Location")
- assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
-
- // check .diff can be accessed and matches performed change
- req := NewRequest(t, "GET", url+".diff")
- resp = session.MakeRequest(t, req, http.StatusOK)
- assert.Regexp(t, `\+Hello, World \(Edited\)`, resp.Body)
- assert.Regexp(t, "^diff", resp.Body)
- assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
-
- // check .patch can be accessed and matches performed change
- req = NewRequest(t, "GET", url+".patch")
- resp = session.MakeRequest(t, req, http.StatusOK)
- assert.Regexp(t, `\+Hello, World \(Edited\)`, resp.Body)
- assert.Regexp(t, "diff", resp.Body)
- assert.Regexp(t, `Subject: \[PATCH\] Update 'README.md'`, resp.Body)
- assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ 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")
+
+ // check the redirected URL
+ url := resp.HeaderMap.Get("Location")
+ assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
+
+ // check .diff can be accessed and matches performed change
+ req := NewRequest(t, "GET", url+".diff")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Regexp(t, `\+Hello, World \(Edited\)`, resp.Body)
+ assert.Regexp(t, "^diff", resp.Body)
+ assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
+
+ // check .patch can be accessed and matches performed change
+ req = NewRequest(t, "GET", url+".patch")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Regexp(t, `\+Hello, World \(Edited\)`, resp.Body)
+ assert.Regexp(t, "diff", resp.Body)
+ assert.Regexp(t, `Subject: \[PATCH\] Update 'README.md'`, resp.Body)
+ assert.NotRegexp(t, "diff.*diff", resp.Body) // not two diffs, just one
+ })
}
func TestPullCreate_TitleEscape(t *testing.T) {
- prepareTestEnv(t)
- 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", "XSS PR")
-
- // check the redirected URL
- url := resp.HeaderMap.Get("Location")
- assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
-
- // Edit title
- req := NewRequest(t, "GET", url)
- resp = session.MakeRequest(t, req, http.StatusOK)
- htmlDoc := NewHTMLParser(t, resp.Body)
- editTestTitleURL, exists := htmlDoc.doc.Find("#save-edit-title").First().Attr("data-update-url")
- assert.True(t, exists, "The template has changed")
-
- req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{
- "_csrf": htmlDoc.GetCSRF(),
- "title": "XSS PR",
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ 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", "XSS PR")
+
+ // check the redirected URL
+ url := resp.HeaderMap.Get("Location")
+ assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
+
+ // Edit title
+ req := NewRequest(t, "GET", url)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ editTestTitleURL, exists := htmlDoc.doc.Find("#save-edit-title").First().Attr("data-update-url")
+ assert.True(t, exists, "The template has changed")
+
+ req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{
+ "_csrf": htmlDoc.GetCSRF(),
+ "title": "XSS PR",
+ })
+ 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)
}
diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go
index f466515eb..1f0ad27a0 100644
--- a/integrations/pull_merge_test.go
+++ b/integrations/pull_merge_test.go
@@ -7,6 +7,7 @@ package integrations
import (
"net/http"
"net/http/httptest"
+ "net/url"
"path"
"strings"
"testing"
@@ -52,108 +53,118 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
}
func TestPullMerge(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user1")
- testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
- testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ 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")
+ 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)
+ elem := strings.Split(test.RedirectURL(resp), "/")
+ assert.EqualValues(t, "pulls", elem[3])
+ testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
+ })
}
func TestPullRebase(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user1")
- testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
- testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ 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")
+ 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.MergeStyleRebase)
+ elem := strings.Split(test.RedirectURL(resp), "/")
+ assert.EqualValues(t, "pulls", elem[3])
+ testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
+ })
}
func TestPullRebaseMerge(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user1")
- testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
- testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ prepareTestEnv(t)
+ 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")
+ 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.MergeStyleRebaseMerge)
+ elem := strings.Split(test.RedirectURL(resp), "/")
+ assert.EqualValues(t, "pulls", elem[3])
+ testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebaseMerge)
+ })
}
func TestPullSquash(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user1")
- 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")
-
- elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
- testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ prepareTestEnv(t)
+ session := loginUser(t, "user1")
+ 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")
+
+ elem := strings.Split(test.RedirectURL(resp), "/")
+ assert.EqualValues(t, "pulls", elem[3])
+ testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
+ })
}
func TestPullCleanUpAfterMerge(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user1")
- testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
- testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ prepareTestEnv(t)
+ session := loginUser(t, "user1")
+ testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
+ testEditFileToNewBranch(t, session, "user1", "repo1", "master", "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), "/")
- assert.EqualValues(t, "pulls", elem[3])
- testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
+ elem := strings.Split(test.RedirectURL(resp), "/")
+ assert.EqualValues(t, "pulls", elem[3])
+ testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
- // Check PR branch deletion
- resp = testPullCleanUp(t, session, elem[1], elem[2], elem[4])
- respJSON := struct {
- Redirect string
- }{}
- DecodeJSON(t, resp, &respJSON)
+ // Check PR branch deletion
+ resp = testPullCleanUp(t, session, elem[1], elem[2], elem[4])
+ respJSON := struct {
+ Redirect string
+ }{}
+ 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, "/")
- assert.EqualValues(t, "pulls", elem[3])
+ elem = strings.Split(respJSON.Redirect, "/")
+ assert.EqualValues(t, "pulls", elem[3])
- // Check branch deletion result
- req := NewRequest(t, "GET", respJSON.Redirect)
- resp = session.MakeRequest(t, req, http.StatusOK)
+ // Check branch deletion result
+ req := NewRequest(t, "GET", respJSON.Redirect)
+ resp = session.MakeRequest(t, req, http.StatusOK)
- htmlDoc := NewHTMLParser(t, resp.Body)
- resultMsg := htmlDoc.doc.Find(".ui.message>p").Text()
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ 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) {
- prepareTestEnv(t)
- 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", "[wip] This is a pull title")
-
- req := NewRequest(t, "GET", resp.Header().Get("Location"))
- resp = session.MakeRequest(t, req, http.StatusOK)
- htmlDoc := NewHTMLParser(t, resp.Body)
- text := strings.TrimSpace(htmlDoc.doc.Find(".merge.segment > .text.grey").Text())
- assert.NotEmpty(t, text, "Can't find WIP text")
-
- // remove from lang
- expected := i18n.Tr("en", "repo.pulls.cannot_merge_work_in_progress", "[wip]")
- replacer := strings.NewReplacer("", "", "", "")
- assert.Equal(t, replacer.Replace(expected), text, "Unable to find WIP text")
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ prepareTestEnv(t)
+ 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", "[wip] This is a pull title")
+
+ req := NewRequest(t, "GET", resp.Header().Get("Location"))
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ text := strings.TrimSpace(htmlDoc.doc.Find(".merge.segment > .text.grey").Text())
+ assert.NotEmpty(t, text, "Can't find WIP text")
+
+ // remove from lang
+ expected := i18n.Tr("en", "repo.pulls.cannot_merge_work_in_progress", "[wip]")
+ replacer := strings.NewReplacer("", "", "", "")
+ assert.Equal(t, replacer.Replace(expected), text, "Unable to find WIP text")
+ })
}
diff --git a/integrations/pull_status_test.go b/integrations/pull_status_test.go
index 238144467..2a4d8e0b6 100644
--- a/integrations/pull_status_test.go
+++ b/integrations/pull_status_test.go
@@ -6,6 +6,7 @@ package integrations
import (
"fmt"
"net/http"
+ "net/url"
"path"
"testing"
@@ -16,78 +17,79 @@ import (
)
func TestPullCreate_CommitStatus(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user1")
- testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
- testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
-
- url := path.Join("user1", "repo1", "compare", "master...status1")
- req := NewRequestWithValues(t, "POST", url,
- map[string]string{
- "_csrf": GetCSRF(t, session, url),
- "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",
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ session := loginUser(t, "user1")
+ testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
+ testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
+
+ url := path.Join("user1", "repo1", "compare", "master...status1")
+ req := NewRequestWithValues(t, "POST", url,
+ map[string]string{
+ "_csrf": GetCSRF(t, session, url),
+ "title": "pull request from status1",
},
)
- 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)
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.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)
- }
+ 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)
+
+ 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)
+ }
+ })
}
diff --git a/integrations/repo_activity_test.go b/integrations/repo_activity_test.go
index fcdbda2c8..cec5c79c4 100644
--- a/integrations/repo_activity_test.go
+++ b/integrations/repo_activity_test.go
@@ -6,6 +6,7 @@ package integrations
import (
"net/http"
+ "net/url"
"strings"
"testing"
@@ -16,49 +17,51 @@ import (
)
func TestRepoActivity(t *testing.T) {
- prepareTestEnv(t)
- session := loginUser(t, "user1")
-
- // Create PRs (1 merged & 2 proposed)
- 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")
- testPullCreate(t, session, "user1", "repo1", "feat/better_readme", "This is a pull title")
-
- testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/much_better_readme", "README.md", "Hello, World (Edited More)\n")
- testPullCreate(t, session, "user1", "repo1", "feat/much_better_readme", "This is a pull title")
-
- // Create issues (3 new issues)
- 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")
-
- // Create releases (1 new release)
- createNewRelease(t, session, "/user2/repo1", "v1.0.0", "v1.0.0", false, false)
-
- // Open Activity page and check stats
- req := NewRequest(t, "GET", "/user2/repo1/activity")
- resp = session.MakeRequest(t, req, http.StatusOK)
- htmlDoc := NewHTMLParser(t, resp.Body)
-
- // Should be 1 published release
- list := htmlDoc.doc.Find("#published-releases").Next().Find("p.desc")
- assert.Len(t, list.Nodes, 1)
-
- // Should be 1 merged pull request
- list = htmlDoc.doc.Find("#merged-pull-requests").Next().Find("p.desc")
- assert.Len(t, list.Nodes, 1)
-
- // Should be 2 merged proposed pull requests
- list = htmlDoc.doc.Find("#proposed-pull-requests").Next().Find("p.desc")
- 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)
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+
+ session := loginUser(t, "user1")
+
+ // Create PRs (1 merged & 2 proposed)
+ 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")
+ testPullCreate(t, session, "user1", "repo1", "feat/better_readme", "This is a pull title")
+
+ testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/much_better_readme", "README.md", "Hello, World (Edited More)\n")
+ testPullCreate(t, session, "user1", "repo1", "feat/much_better_readme", "This is a pull title")
+
+ // Create issues (3 new issues)
+ 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")
+
+ // Create releases (1 new release)
+ createNewRelease(t, session, "/user2/repo1", "v1.0.0", "v1.0.0", false, false)
+
+ // Open Activity page and check stats
+ req := NewRequest(t, "GET", "/user2/repo1/activity")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+
+ // Should be 1 published release
+ list := htmlDoc.doc.Find("#published-releases").Next().Find("p.desc")
+ assert.Len(t, list.Nodes, 1)
+
+ // Should be 1 merged pull request
+ list = htmlDoc.doc.Find("#merged-pull-requests").Next().Find("p.desc")
+ assert.Len(t, list.Nodes, 1)
+
+ // Should be 2 merged proposed pull requests
+ list = htmlDoc.doc.Find("#proposed-pull-requests").Next().Find("p.desc")
+ 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)
+ })
}
diff --git a/integrations/repo_branch_test.go b/integrations/repo_branch_test.go
index 3101dc4c0..a5447cfb6 100644
--- a/integrations/repo_branch_test.go
+++ b/integrations/repo_branch_test.go
@@ -6,6 +6,7 @@ package integrations
import (
"net/http"
+ "net/url"
"path"
"strings"
"testing"
@@ -35,6 +36,10 @@ func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubU
}
func TestCreateBranch(t *testing.T) {
+ onGiteaRun(t, testCreateBranches)
+}
+
+func testCreateBranches(t *testing.T, giteaURL *url.URL) {
tests := []struct {
OldRefSubURL string
NewBranch string
diff --git a/modules/repofiles/delete_test.go b/integrations/repofiles_delete_test.go
similarity index 76%
rename from modules/repofiles/delete_test.go
rename to integrations/repofiles_delete_test.go
index 9d034066f..c3bb18ec9 100644
--- a/modules/repofiles/delete_test.go
+++ b/integrations/repofiles_delete_test.go
@@ -2,20 +2,22 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package repofiles
+package integrations
import (
+ "net/url"
"testing"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/repofiles"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
-func getDeleteRepoFileOptions(repo *models.Repository) *DeleteRepoFileOptions {
- return &DeleteRepoFileOptions{
+func getDeleteRepoFileOptions(repo *models.Repository) *repofiles.DeleteRepoFileOptions {
+ return &repofiles.DeleteRepoFileOptions{
LastCommitID: "",
OldBranch: 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{
Content: nil,
Commit: &api.FileCommitResponse{
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",
},
- HTMLURL: "https://try.gitea.io/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
+ HTMLURL: u.String() + "user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
Author: &api.CommitUser{
Identity: api.Identity{
Name: "user1",
@@ -53,7 +55,7 @@ func getExpectedDeleteFileResponse() *api.FileResponse {
Parents: []*api.CommitMeta{},
Message: "Initial commit\n",
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",
},
},
@@ -67,6 +69,10 @@ func getExpectedDeleteFileResponse() *api.FileResponse {
}
func TestDeleteRepoFile(t *testing.T) {
+ onGiteaRun(t, testDeleteRepoFile)
+}
+
+func testDeleteRepoFile(t *testing.T, u *url.URL) {
// setup
models.PrepareTestEnv(t)
ctx := test.MockContext(t, "user2/repo1")
@@ -80,14 +86,14 @@ func TestDeleteRepoFile(t *testing.T) {
opts := getDeleteRepoFileOptions(repo)
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)
- expectedFileResponse := getExpectedDeleteFileResponse()
+ expectedFileResponse := getExpectedDeleteFileResponse(u)
assert.EqualValues(t, expectedFileResponse, fileResponse)
})
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)
expectedError := "repository file does not exist [path: " + opts.TreePath + "]"
assert.EqualError(t, err, expectedError)
@@ -96,6 +102,10 @@ func TestDeleteRepoFile(t *testing.T) {
// Test opts with branch names removed, same results
func TestDeleteRepoFileWithoutBranchNames(t *testing.T) {
+ onGiteaRun(t, testDeleteRepoFileWithoutBranchNames)
+}
+
+func testDeleteRepoFileWithoutBranchNames(t *testing.T, u *url.URL) {
// setup
models.PrepareTestEnv(t)
ctx := test.MockContext(t, "user2/repo1")
@@ -111,9 +121,9 @@ func TestDeleteRepoFileWithoutBranchNames(t *testing.T) {
opts.NewBranch = ""
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)
- expectedFileResponse := getExpectedDeleteFileResponse()
+ expectedFileResponse := getExpectedDeleteFileResponse(u)
assert.EqualValues(t, expectedFileResponse, fileResponse)
})
}
@@ -133,7 +143,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
t.Run("Bad branch", func(t *testing.T) {
opts := getDeleteRepoFileOptions(repo)
opts.OldBranch = "bad_branch"
- fileResponse, err := DeleteRepoFile(repo, doer, opts)
+ fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
assert.Error(t, err)
assert.Nil(t, fileResponse)
expectedError := "branch does not exist [name: " + opts.OldBranch + "]"
@@ -144,7 +154,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
opts := getDeleteRepoFileOptions(repo)
origSHA := opts.SHA
opts.SHA = "bad_sha"
- fileResponse, err := DeleteRepoFile(repo, doer, opts)
+ fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
assert.Nil(t, fileResponse)
assert.Error(t, err)
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) {
opts := getDeleteRepoFileOptions(repo)
opts.NewBranch = "develop"
- fileResponse, err := DeleteRepoFile(repo, doer, opts)
+ fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
assert.Nil(t, fileResponse)
assert.Error(t, err)
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) {
opts := getDeleteRepoFileOptions(repo)
opts.TreePath = ""
- fileResponse, err := DeleteRepoFile(repo, doer, opts)
+ fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
assert.Nil(t, fileResponse)
assert.Error(t, err)
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) {
opts := getDeleteRepoFileOptions(repo)
opts.TreePath = ".git"
- fileResponse, err := DeleteRepoFile(repo, doer, opts)
+ fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts)
assert.Nil(t, fileResponse)
assert.Error(t, err)
expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]"
diff --git a/integrations/repofiles_update_test.go b/integrations/repofiles_update_test.go
new file mode 100644
index 000000000..02a9bbeb1
--- /dev/null
+++ b/integrations/repofiles_update_test.go
@@ -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)
+ })
+ })
+}
diff --git a/models/helper_directory.go b/models/helper_directory.go
new file mode 100644
index 000000000..417402b41
--- /dev/null
+++ b/models/helper_directory.go
@@ -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
+}
diff --git a/models/helper_environment.go b/models/helper_environment.go
new file mode 100644
index 000000000..283584cc5
--- /dev/null
+++ b/models/helper_environment.go
@@ -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",
+ )
+
+}
diff --git a/models/pull.go b/models/pull.go
index 7382cbd12..6f37145d9 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -418,22 +418,21 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
}()
- headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
-
// Clone base repo.
- tmpBasePath := path.Join(LocalCopyPath(), "merge-"+com.ToStr(time.Now().Nanosecond())+".git")
-
- if err := os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm); err != nil {
- return fmt.Errorf("Failed to create dir %s: %v", tmpBasePath, err)
+ tmpBasePath, err := CreateTemporaryPath("merge")
+ if err != nil {
+ return err
}
+ defer RemoveTemporaryPath(tmpBasePath)
- defer os.RemoveAll(tmpBasePath)
+ headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
- 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)
+ if err := git.Clone(baseGitRepo.Path, tmpBasePath, git.CloneRepoOptions{
+ Shared: true,
+ NoCheckout: true,
+ Branch: pr.BaseBranch,
+ }); err != nil {
+ return fmt.Errorf("git clone: %v", err)
}
remoteRepoName := "head_repo"
@@ -456,14 +455,14 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
if err := addCacheRepo(tmpBasePath, headRepoPath); err != nil {
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),
"git", "remote", "add", remoteRepoName, headRepoPath); err != nil {
return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
}
// 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),
"git", "fetch", remoteRepoName); err != nil {
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)
}
- if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
+ if _, stderr, err := process.GetManager().ExecDir(-1, tmpBasePath,
fmt.Sprintf("PullRequest.Merge (git config): %s", tmpBasePath),
"git", "config", "--local", "core.sparseCheckout", "true"); err != nil {
return fmt.Errorf("git config [core.sparsecheckout -> true]: %v", stderr)
}
// 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),
"git", "read-tree", "HEAD"); err != nil {
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.
switch mergeStyle {
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),
"git", "merge", "--no-ff", "--no-commit", trackingBranch); err != nil {
return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr)
}
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),
"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
"-m", message); err != nil {
@@ -518,50 +517,50 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
}
case MergeStyleRebase:
// 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),
"git", "checkout", "-b", stagingBranch, trackingBranch); err != nil {
return fmt.Errorf("git checkout: %s", stderr)
}
// 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),
"git", "rebase", "-q", pr.BaseBranch); err != nil {
return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
}
// 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),
"git", "checkout", pr.BaseBranch); err != nil {
return fmt.Errorf("git checkout: %s", stderr)
}
// 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),
"git", "merge", "--ff-only", "-q", stagingBranch); err != nil {
return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
}
case MergeStyleRebaseMerge:
// 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),
"git", "checkout", "-b", stagingBranch, trackingBranch); err != nil {
return fmt.Errorf("git checkout: %s", stderr)
}
// 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),
"git", "rebase", "-q", pr.BaseBranch); err != nil {
return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
}
// 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),
"git", "checkout", pr.BaseBranch); err != nil {
return fmt.Errorf("git checkout: %s", stderr)
}
// 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),
"git", "merge", "--no-ff", "--no-commit", "-q", stagingBranch); err != nil {
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
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),
"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
"-m", message); err != nil {
@@ -578,13 +577,13 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
case MergeStyleSquash:
// 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),
"git", "merge", "-q", "--squash", trackingBranch); err != nil {
return fmt.Errorf("git merge --squash [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
}
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),
"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
"-m", message); err != nil {
@@ -594,10 +593,12 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
return ErrInvalidMergeStyle{pr.BaseRepo.ID, mergeStyle}
}
+ env := PushingEnvironment(doer, pr.BaseRepo)
+
// 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),
- "git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
+ env, "git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
return fmt.Errorf("git push: %s", stderr)
}
diff --git a/models/repo.go b/models/repo.go
index 66c1bdbab..2f87e2f51 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -518,7 +518,7 @@ func (repo *Repository) DeleteWiki() error {
}
func (repo *Repository) deleteWiki(e Engine) error {
- wikiPaths := []string{repo.WikiPath(), repo.LocalWikiPath()}
+ wikiPaths := []string{repo.WikiPath()}
for _, wikiPath := range wikiPaths {
removeAllWithNotice(e, "Delete repository wiki", wikiPath)
}
@@ -749,56 +749,6 @@ func (repo *Repository) DescriptionHTML() template.HTML {
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.
func (repo *Repository) PatchPath(index int64) (string, error) {
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 {
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.
wikiPath := WikiPath(owner.Name, repo.Name)
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 {
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)
}
- 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()
if com.IsExist(wikiPath) {
if err = os.Rename(wikiPath, WikiPath(u.Name, newRepoName)); err != nil {
return fmt.Errorf("rename repository wiki: %v", err)
}
- RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
}
sess := x.NewSession()
diff --git a/models/repo_branch.go b/models/repo_branch.go
index 0958e2397..08c881fc2 100644
--- a/models/repo_branch.go
+++ b/models/repo_branch.go
@@ -7,86 +7,11 @@ package models
import (
"fmt"
- "time"
"code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/setting"
-
- "github.com/Unknwon/com"
+ "code.gitea.io/gitea/modules/log"
)
-// 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.
func (repo *Repository) CanCreateBranch() bool {
return !repo.IsMirror
@@ -137,92 +62,86 @@ func (repo *Repository) CheckBranchName(name string) error {
// CreateNewBranch creates a new repository branch
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
if err := repo.CheckBranchName(branchName); err != nil {
return err
}
- localPath := repo.LocalCopyPath()
-
- 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 !git.IsBranchExist(repo.RepoPath(), oldBranchName) {
+ return fmt.Errorf("OldBranch: %s does not exist. Cannot create new branch from this", oldBranchName)
}
- if err = repo.CheckoutNewBranch(oldBranchName, branchName); err != nil {
- return fmt.Errorf("CreateNewBranch: %v", err)
+ basePath, err := CreateTemporaryPath("branch-maker")
+ if err != nil {
+ return err
}
+ defer RemoveTemporaryPath(basePath)
- if err = git.Push(localPath, git.PushOptions{
- Remote: "origin",
- Branch: branchName,
+ if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{
+ Bare: true,
+ Shared: true,
}); err != nil {
- return fmt.Errorf("Push: %v", err)
+ log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
+ return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
}
- return nil
-}
+ 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)
+ }
-// 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 = 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.Checkout(localPath, git.CheckoutOptions{
- Branch: commit,
+
+ if err = git.Push(basePath, git.PushOptions{
+ Remote: "origin",
+ Branch: branchName,
+ Env: PushingEnvironment(doer, repo),
}); err != nil {
- return fmt.Errorf("git checkout %s: %v", commit, err)
+ return fmt.Errorf("Push: %v", 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)
+ return nil
}
// CreateNewBranchFromCommit creates a new repository branch
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
if err := repo.CheckBranchName(branchName); err != nil {
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,
+ 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 = repo.updateLocalCopyToCommit(commit); err != nil {
- return fmt.Errorf("UpdateLocalCopyBranch: %v", 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 = repo.CheckoutNewBranch(commit, branchName); err != nil {
- return fmt.Errorf("CheckoutNewBranch: %v", err)
+ 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(localPath, git.PushOptions{
+ if err = git.Push(basePath, git.PushOptions{
Remote: "origin",
Branch: branchName,
+ Env: PushingEnvironment(doer, repo),
}); err != nil {
return fmt.Errorf("Push: %v", err)
}
diff --git a/models/repo_test.go b/models/repo_test.go
index a5b8cce9b..eee399786 100644
--- a/models/repo_test.go
+++ b/models/repo_test.go
@@ -5,11 +5,9 @@
package models
import (
- "path"
"testing"
"code.gitea.io/gitea/modules/markup"
- "code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
"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())
}
-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) {
assert.NoError(t, PrepareTestDatabase())
diff --git a/models/user.go b/models/user.go
index 0c445b5af..90ca189ef 100644
--- a/models/user.go
+++ b/models/user.go
@@ -943,17 +943,6 @@ func ChangeUserName(u *User, newUserName string) (err error) {
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
if err = os.Rename(UserPath(u.Name), UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("Rename user directory: %v", err)
diff --git a/models/wiki.go b/models/wiki.go
index 0f5cdc20b..bcf97c076 100644
--- a/models/wiki.go
+++ b/models/wiki.go
@@ -6,15 +6,13 @@ package models
import (
"fmt"
- "io/ioutil"
"net/url"
"os"
- "path"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/sync"
"github.com/Unknwon/com"
@@ -89,34 +87,6 @@ func (repo *Repository) InitWiki() error {
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
func nameAllowed(name string) error {
for _, reservedName := range reservedWikiNames {
@@ -132,7 +102,6 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
if err = nameAllowed(newWikiName); err != nil {
return err
}
-
wikiWorkingPool.CheckIn(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)
}
- localPath := repo.LocalWikiPath()
- if err = discardLocalWikiChanges(localPath); err != nil {
- return fmt.Errorf("discardLocalWikiChanges: %v", err)
- } else if err = repo.updateLocalWiki(); err != nil {
- return fmt.Errorf("UpdateLocalWiki: %v", err)
+ hasMasterBranch := git.IsBranchExist(repo.WikiPath(), "master")
+
+ basePath, err := CreateTemporaryPath("update-wiki")
+ if err != nil {
+ return err
}
+ defer RemoveTemporaryPath(basePath)
- newWikiPath := path.Join(localPath, WikiNameToFilename(newWikiName))
+ cloneOpts := git.CloneRepoOptions{
+ Bare: true,
+ Shared: true,
+ }
+
+ 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 com.IsExist(newWikiPath) {
- return ErrWikiAlreadyExist{newWikiPath}
+ filesInIndex, err := gitRepo.LsFiles(newWikiPath)
+ if err != nil {
+ log.Error("%v", err)
+ return err
+ }
+ for _, file := range filesInIndex {
+ if file == newWikiPath {
+ return ErrWikiAlreadyExist{newWikiPath}
+ }
}
} else {
- oldWikiPath := path.Join(localPath, WikiNameToFilename(oldWikiName))
- if err := os.Remove(oldWikiPath); err != nil {
- return fmt.Errorf("Failed to remove %s: %v", oldWikiPath, err)
+ oldWikiPath := WikiNameToFilename(oldWikiName)
+ filesInIndex, err := gitRepo.LsFiles(oldWikiPath)
+ 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,
- // attack content can be written to the target file (e.g. authorized_keys2)
- // as a new page operation.
- // So we want to make sure the symlink is removed before write anything.
- // The new file we created will be in normal text format.
- if err = os.RemoveAll(newWikiPath); err != nil {
+ // FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
+
+ objectHash, err := gitRepo.HashObject(strings.NewReader(content))
+ if err != nil {
+ log.Error("%v", err)
return err
}
- if err = ioutil.WriteFile(newWikiPath, []byte(content), 0666); err != nil {
- return fmt.Errorf("WriteFile: %v", err)
+ if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil {
+ log.Error("%v", err)
+ return err
}
- if len(message) == 0 {
- message = "Update page '" + newWikiName + "'"
+ tree, err := gitRepo.WriteTree()
+ if err != nil {
+ log.Error("%v", err)
+ return err
}
- if err = git.AddChanges(localPath, true); err != nil {
- return fmt.Errorf("AddChanges: %v", err)
- } else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
- Committer: doer.NewGitSig(),
- Message: message,
- }); err != nil {
- return fmt.Errorf("CommitChanges: %v", err)
- } else if err = git.Push(localPath, git.PushOptions{
+
+ commitTreeOpts := git.CommitTreeOpts{
+ Message: message,
+ }
+ if hasMasterBranch {
+ commitTreeOpts.Parents = []string{"HEAD"}
+ }
+ 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",
- Branch: "master",
+ Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
+ Env: PushingEnvironment(doer, repo),
}); err != nil {
+ log.Error("%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))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
- localPath := repo.LocalWikiPath()
- if err = discardLocalWikiChanges(localPath); err != nil {
- return fmt.Errorf("discardLocalWikiChanges: %v", err)
- } else if err = repo.updateLocalWiki(); err != nil {
- return fmt.Errorf("UpdateLocalWiki: %v", err)
+ if err = repo.InitWiki(); err != nil {
+ return fmt.Errorf("InitWiki: %v", err)
+ }
+
+ basePath, err := CreateTemporaryPath("update-wiki")
+ if err != nil {
+ return err
}
+ defer RemoveTemporaryPath(basePath)
- filename := path.Join(localPath, WikiNameToFilename(wikiName))
+ if err := git.Clone(repo.WikiPath(), basePath, git.CloneRepoOptions{
+ 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)
+ }
- if err := os.Remove(filename); err != nil {
- return fmt.Errorf("Failed to remove %s: %v", filename, 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 + "'"
- if err = git.AddChanges(localPath, true); err != nil {
- return fmt.Errorf("AddChanges: %v", err)
- } else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
- Committer: doer.NewGitSig(),
- Message: message,
- }); err != nil {
- return fmt.Errorf("CommitChanges: %v", err)
- } else if err = git.Push(localPath, git.PushOptions{
+ commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, git.CommitTreeOpts{
+ Message: message,
+ Parents: []string{"HEAD"},
+ })
+ if err != nil {
+ return err
+ }
+
+ if err := git.Push(basePath, git.PushOptions{
Remote: "origin",
- Branch: "master",
+ Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
+ Env: PushingEnvironment(doer, repo),
}); err != nil {
return fmt.Errorf("Push: %v", err)
}
diff --git a/models/wiki_test.go b/models/wiki_test.go
index 5280b3ea0..991a3d95b 100644
--- a/models/wiki_test.go
+++ b/models/wiki_test.go
@@ -5,13 +5,12 @@
package models
import (
- "path"
"path/filepath"
"testing"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
- "github.com/Unknwon/com"
"github.com/stretchr/testify/assert"
)
@@ -145,13 +144,6 @@ func TestRepository_InitWiki(t *testing.T) {
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) {
assert.NoError(t, PrepareTestDatabase())
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.Parallel()
assert.NoError(t, repo.AddWikiPage(doer, wikiName, wikiContent, commitMsg))
- expectedPath := path.Join(repo.LocalWikiPath(), WikiNameToFilename(wikiName))
- assert.True(t, com.IsExist(expectedPath))
+ // 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(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)
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" {
- oldPath := path.Join(repo.LocalWikiPath(), "Home.md")
- assert.False(t, com.IsExist(oldPath))
+ _, err := masterTree.GetTreeEntryByPath("Home.md")
+ assert.Error(t, err)
}
}
}
@@ -214,6 +222,13 @@ func TestRepository_DeleteWikiPage(t *testing.T) {
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
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)
}
diff --git a/modules/git/command.go b/modules/git/command.go
index 360271770..d6221ce26 100644
--- a/modules/git/command.go
+++ b/modules/git/command.go
@@ -52,9 +52,15 @@ func (c *Command) AddArguments(args ...string) *Command {
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.
-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 {
timeout = DefaultCommandExecutionTimeout
}
@@ -69,9 +75,11 @@ func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, std
defer cancel()
cmd := exec.CommandContext(ctx, c.name, c.args...)
+ cmd.Env = env
cmd.Dir = dir
cmd.Stdout = stdout
cmd.Stderr = stderr
+ cmd.Stdin = stdin
if err := cmd.Start(); err != nil {
return err
}
@@ -83,12 +91,30 @@ func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, std
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,
// and returns stdout in []byte and error (combined with stderr).
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)
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())
}
@@ -101,7 +127,13 @@ func (c *Command) RunInDirTimeout(timeout time.Duration, dir string) ([]byte, er
// RunInDirPipeline executes the command in given directory,
// it pipes stdout and stderr to given io.Writer.
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
@@ -113,7 +145,13 @@ func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
// RunInDir executes the command in given directory
// and returns stdout in string and error (combined with stderr).
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 {
return "", err
}
diff --git a/modules/git/repo.go b/modules/git/repo.go
index 8355f8811..4be316413 100644
--- a/modules/git/repo.go
+++ b/modules/git/repo.go
@@ -109,11 +109,13 @@ func OpenRepository(repoPath string) (*Repository, error) {
// CloneRepoOptions options when clone a repository
type CloneRepoOptions struct {
- Timeout time.Duration
- Mirror bool
- Bare bool
- Quiet bool
- Branch string
+ Timeout time.Duration
+ Mirror bool
+ Bare bool
+ Quiet bool
+ Branch string
+ Shared bool
+ NoCheckout bool
}
// Clone clones original repository to target path.
@@ -133,10 +135,17 @@ func Clone(from, to string, opts CloneRepoOptions) (err error) {
if opts.Quiet {
cmd.AddArguments("--quiet")
}
+ if opts.Shared {
+ cmd.AddArguments("-s")
+ }
+ if opts.NoCheckout {
+ cmd.AddArguments("--no-checkout")
+ }
+
if len(opts.Branch) > 0 {
cmd.AddArguments("-b", opts.Branch)
}
- cmd.AddArguments(from, to)
+ cmd.AddArguments("--", from, to)
if opts.Timeout <= 0 {
opts.Timeout = -1
@@ -181,6 +190,7 @@ type PushOptions struct {
Remote string
Branch string
Force bool
+ Env []string
}
// Push pushs local commits to given remote branch.
@@ -190,7 +200,7 @@ func Push(repoPath string, opts PushOptions) error {
cmd.AddArguments("-f")
}
cmd.AddArguments(opts.Remote, opts.Branch)
- _, err := cmd.RunInDir(repoPath)
+ _, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
return err
}
diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go
index 83689ee9d..116bdbee8 100644
--- a/modules/git/repo_branch.go
+++ b/modules/git/repo_branch.go
@@ -17,7 +17,7 @@ const BranchPrefix = "refs/heads/"
// IsReferenceExist returns true if given reference exists in the repository.
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
}
@@ -145,9 +145,9 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
}
// 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.AddArguments(branch, newBranch)
+ cmd.AddArguments("--", branch, oldbranchOrCommit)
_, err := cmd.RunInDir(repo.Path)
diff --git a/modules/git/repo_index.go b/modules/git/repo_index.go
new file mode 100644
index 000000000..4d26563a9
--- /dev/null
+++ b/modules/git/repo_index.go
@@ -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
+}
diff --git a/modules/git/repo_object.go b/modules/git/repo_object.go
index 3be8400d2..67060e30b 100644
--- a/modules/git/repo_object.go
+++ b/modules/git/repo_object.go
@@ -4,6 +4,12 @@
package git
+import (
+ "bytes"
+ "io"
+ "strings"
+)
+
// ObjectType git object type
type ObjectType string
@@ -17,3 +23,24 @@ const (
// ObjectTag tag object type
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
+}
diff --git a/modules/git/repo_tree.go b/modules/git/repo_tree.go
index 8bb729174..7d32d3685 100644
--- a/modules/git/repo_tree.go
+++ b/modules/git/repo_tree.go
@@ -6,6 +6,11 @@
package git
import (
+ "fmt"
+ "os"
+ "strings"
+ "time"
+
"gopkg.in/src-d/go-git.v4/plumbing"
)
@@ -47,3 +52,48 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
treeObject.ResolvedID = resolvedID
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))
+}
diff --git a/modules/repofiles/temp_repo.go b/modules/repofiles/temp_repo.go
index 46e03f565..ec3562867 100644
--- a/modules/repofiles/temp_repo.go
+++ b/modules/repofiles/temp_repo.go
@@ -11,17 +11,15 @@ import (
"io"
"os"
"os/exec"
- "path"
"regexp"
"strings"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
-
- "github.com/Unknwon/com"
)
// 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
func NewTemporaryUploadRepository(repo *models.Repository) (*TemporaryUploadRepository, error) {
- timeStr := com.ToStr(time.Now().Nanosecond()) // SHOULD USE SOMETHING UNIQUE
- basePath := path.Join(models.LocalCopyPath(), "upload-"+timeStr+".git")
- if err := os.MkdirAll(path.Dir(basePath), os.ModePerm); err != nil {
- 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")
+ basePath, err := models.CreateTemporaryPath("upload")
+ if err != nil {
+ return nil, err
}
t := &TemporaryUploadRepository{repo: repo, basePath: basePath}
return t, nil
@@ -47,8 +41,8 @@ func NewTemporaryUploadRepository(repo *models.Repository) (*TemporaryUploadRepo
// Close the repository cleaning up all files
func (t *TemporaryUploadRepository) Close() {
- if _, err := os.Stat(t.basePath); !os.IsNotExist(err) {
- os.RemoveAll(t.basePath)
+ if err := models.RemoveTemporaryPath(t.basePath); err != nil {
+ 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
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
- env := append(os.Environ(),
- "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),
- )
+ env := models.PushingEnvironment(doer, t.repo)
if _, stderr, err := process.GetManager().ExecDirEnv(5*time.Minute,
t.basePath,
diff --git a/modules/repofiles/update_test.go b/modules/repofiles/update_test.go
deleted file mode 100644
index a3a0b0a42..000000000
--- a/modules/repofiles/update_test.go
+++ /dev/null
@@ -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)
- })
-}
diff --git a/modules/setting/repository.go b/modules/setting/repository.go
index f47661efd..98e3d6e82 100644
--- a/modules/setting/repository.go
+++ b/modules/setting/repository.go
@@ -53,7 +53,6 @@ var (
// Repository local settings
Local struct {
LocalCopyPath string
- LocalWikiPath string
} `ini:"-"`
// Pull request settings
@@ -105,10 +104,8 @@ var (
// Repository local settings
Local: struct {
LocalCopyPath string
- LocalWikiPath string
}{
LocalCopyPath: "tmp/local-repo",
- LocalWikiPath: "tmp/local-wiki",
},
// Pull request settings
diff --git a/routers/repo/branch.go b/routers/repo/branch.go
index 8b987f0a6..ae87aa5b3 100644
--- a/routers/repo/branch.go
+++ b/routers/repo/branch.go
@@ -74,12 +74,6 @@ func DeleteBranchPost(ctx *context.Context) {
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))
}