mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			15 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8733384e20 | ||
| 
						 | 
					84829fba82 | ||
| 
						 | 
					31a738b221 | ||
| 
						 | 
					812c225223 | ||
| 
						 | 
					33c3cbc968 | ||
| 
						 | 
					8f29f61a6b | ||
| 
						 | 
					93dcc6caef | ||
| 
						 | 
					4176e33148 | ||
| 
						 | 
					177b46fe77 | ||
| 
						 | 
					1e51307466 | ||
| 
						 | 
					c145cb745b | ||
| 
						 | 
					1a68b3962f | ||
| 
						 | 
					d918e63bc5 | ||
| 
						 | 
					1901f35980 | ||
| 
						 | 
					745c898561 | 
							
								
								
									
										20
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,6 +4,26 @@ This changelog goes through all the changes that have been made in each release
 | 
			
		||||
without substantial changes to our git log; to see the highlights of what has
 | 
			
		||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
 | 
			
		||||
## [1.5.3](https://github.com/go-gitea/gitea/releases/tag/v1.5.3) - 2018-10-31
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Fix remote command execution vulnerability in upstream library (#5177) (#5196)
 | 
			
		||||
 | 
			
		||||
## [1.5.2](https://github.com/go-gitea/gitea/releases/tag/v1.5.2) - 2018-10-09
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Enforce token on api routes (#4840) (#4905)
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Remove links from topics in edit mode (#5030)
 | 
			
		||||
  * Detect charset and convert non UTF-8 files for display (#4950) (#4994)
 | 
			
		||||
  * Fix layout of the topics editing form (#4971) (#4993)
 | 
			
		||||
  * Fix null pointer dereference in ParseCommitWithSignature (#4964)
 | 
			
		||||
  * Fix url in discord webhook (#4951)
 | 
			
		||||
  * Fix font-cropping UI bug in diff (#4726) (#4929)
 | 
			
		||||
  * Fix bug forget to remove Stopwatch when remove repository (#4933)
 | 
			
		||||
  * Fix bug when repo remained bare if multiple branches pushed (#4927)
 | 
			
		||||
  * Fix redirect with non-ascii branch names (#4764) (#4887)
 | 
			
		||||
  * Fix issues api allow pulls (#4852) (#4862)
 | 
			
		||||
  * Fix trimming of markup section names (#4864)
 | 
			
		||||
 | 
			
		||||
## [1.5.1](https://github.com/go-gitea/gitea/releases/tag/v1.5.1) - 2018-09-03
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Don't disclose emails of all users when sending out emails (#4784)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							@@ -279,12 +279,15 @@
 | 
			
		||||
  revision = "d8a0b8677191f4380287cfebd08e462217bac7ad"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:8fea5718d84af17762195beb6fe92a0d6c1048452a1dbc464d227f12e0cff0cc"
 | 
			
		||||
  name = "github.com/go-macaron/session"
 | 
			
		||||
  packages = [
 | 
			
		||||
    ".",
 | 
			
		||||
    "redis"
 | 
			
		||||
  ]
 | 
			
		||||
  revision = "66031fcb37a0fff002a1f028eb0b3a815c78306b"
 | 
			
		||||
  pruneopts = "NUT"
 | 
			
		||||
  revision = "330e4e4d8beb7b00111ac34539561f46f94c4458"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  name = "github.com/go-macaron/toolbox"
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,8 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
 | 
			
		||||
	session := loginUser(t, "user1")
 | 
			
		||||
	keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", keyOwner.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", keyOwner.Name, token)
 | 
			
		||||
	req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
			
		||||
		"key":   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
			
		||||
		"title": "test-key",
 | 
			
		||||
@@ -36,7 +37,7 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
 | 
			
		||||
		OwnerID:     keyOwner.ID,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d",
 | 
			
		||||
	req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
 | 
			
		||||
		keyOwner.Name, newPublicKey.ID)
 | 
			
		||||
	session.MakeRequest(t, req, http.StatusNoContent)
 | 
			
		||||
	models.AssertNotExistsBean(t, &models.PublicKey{ID: newPublicKey.ID})
 | 
			
		||||
@@ -46,8 +47,9 @@ func TestAPIAdminDeleteMissingSSHKey(t *testing.T) {
 | 
			
		||||
	prepareTestEnv(t)
 | 
			
		||||
	// user1 is an admin user
 | 
			
		||||
	session := loginUser(t, "user1")
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
 | 
			
		||||
	req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d", models.NonexistentID)
 | 
			
		||||
	req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d?token="+token, models.NonexistentID)
 | 
			
		||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -57,7 +59,8 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
 | 
			
		||||
	normalUsername := "user2"
 | 
			
		||||
	session := loginUser(t, adminUsername)
 | 
			
		||||
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", adminUsername)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", adminUsername, token)
 | 
			
		||||
	req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
			
		||||
		"key":   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
			
		||||
		"title": "test-key",
 | 
			
		||||
@@ -67,7 +70,8 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
 | 
			
		||||
	DecodeJSON(t, resp, &newPublicKey)
 | 
			
		||||
 | 
			
		||||
	session = loginUser(t, normalUsername)
 | 
			
		||||
	req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d",
 | 
			
		||||
	token = getTokenForLoggedInUser(t, session)
 | 
			
		||||
	req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
 | 
			
		||||
		adminUsername, newPublicKey.ID)
 | 
			
		||||
	session.MakeRequest(t, req, http.StatusForbidden)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,8 @@ func testAPIGetBranch(t *testing.T, branchName string, exists bool) {
 | 
			
		||||
	prepareTestEnv(t)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, "user2")
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s", branchName)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s?token=%s", branchName, token)
 | 
			
		||||
	resp := session.MakeRequest(t, req, NoExpectedStatus)
 | 
			
		||||
	if !exists {
 | 
			
		||||
		assert.EqualValues(t, http.StatusNotFound, resp.Code)
 | 
			
		||||
 
 | 
			
		||||
@@ -69,8 +69,9 @@ func TestAPICreateComment(t *testing.T) {
 | 
			
		||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, repoOwner.Name)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments",
 | 
			
		||||
		repoOwner.Name, repo.Name, issue.Index)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
 | 
			
		||||
		repoOwner.Name, repo.Name, issue.Index, token)
 | 
			
		||||
	req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
			
		||||
		"body": commentBody,
 | 
			
		||||
	})
 | 
			
		||||
@@ -93,8 +94,9 @@ func TestAPIEditComment(t *testing.T) {
 | 
			
		||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, repoOwner.Name)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d",
 | 
			
		||||
		repoOwner.Name, repo.Name, comment.ID)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
 | 
			
		||||
		repoOwner.Name, repo.Name, comment.ID, token)
 | 
			
		||||
	req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
 | 
			
		||||
		"body": newCommentBody,
 | 
			
		||||
	})
 | 
			
		||||
@@ -117,8 +119,9 @@ func TestAPIDeleteComment(t *testing.T) {
 | 
			
		||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, repoOwner.Name)
 | 
			
		||||
	req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d",
 | 
			
		||||
		repoOwner.Name, repo.Name, comment.ID)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
 | 
			
		||||
		repoOwner.Name, repo.Name, comment.ID, token)
 | 
			
		||||
	session.MakeRequest(t, req, http.StatusNoContent)
 | 
			
		||||
 | 
			
		||||
	models.AssertNotExistsBean(t, &models.Comment{ID: comment.ID})
 | 
			
		||||
 
 | 
			
		||||
@@ -20,16 +20,18 @@ type makeRequestFunc func(testing.TB, *http.Request, int) *httptest.ResponseReco
 | 
			
		||||
func TestGPGKeys(t *testing.T) {
 | 
			
		||||
	prepareTestEnv(t)
 | 
			
		||||
	session := loginUser(t, "user2")
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
 | 
			
		||||
	tt := []struct {
 | 
			
		||||
		name        string
 | 
			
		||||
		makeRequest makeRequestFunc
 | 
			
		||||
		token       string
 | 
			
		||||
		results     []int
 | 
			
		||||
	}{
 | 
			
		||||
		{name: "NoLogin", makeRequest: MakeRequest,
 | 
			
		||||
		{name: "NoLogin", makeRequest: MakeRequest, token: "",
 | 
			
		||||
			results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
 | 
			
		||||
		},
 | 
			
		||||
		{name: "LoggedAsUser2", makeRequest: session.MakeRequest,
 | 
			
		||||
		{name: "LoggedAsUser2", makeRequest: session.MakeRequest, token: token,
 | 
			
		||||
			results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusInternalServerError, http.StatusInternalServerError, http.StatusCreated, http.StatusCreated}},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -38,29 +40,29 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
		//Basic test on result code
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
			t.Run("ViewOwnGPGKeys", func(t *testing.T) {
 | 
			
		||||
				testViewOwnGPGKeys(t, tc.makeRequest, tc.results[0])
 | 
			
		||||
				testViewOwnGPGKeys(t, tc.makeRequest, tc.token, tc.results[0])
 | 
			
		||||
			})
 | 
			
		||||
			t.Run("ViewGPGKeys", func(t *testing.T) {
 | 
			
		||||
				testViewGPGKeys(t, tc.makeRequest, tc.results[1])
 | 
			
		||||
				testViewGPGKeys(t, tc.makeRequest, tc.token, tc.results[1])
 | 
			
		||||
			})
 | 
			
		||||
			t.Run("GetGPGKey", func(t *testing.T) {
 | 
			
		||||
				testGetGPGKey(t, tc.makeRequest, tc.results[2])
 | 
			
		||||
				testGetGPGKey(t, tc.makeRequest, tc.token, tc.results[2])
 | 
			
		||||
			})
 | 
			
		||||
			t.Run("DeleteGPGKey", func(t *testing.T) {
 | 
			
		||||
				testDeleteGPGKey(t, tc.makeRequest, tc.results[3])
 | 
			
		||||
				testDeleteGPGKey(t, tc.makeRequest, tc.token, tc.results[3])
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			t.Run("CreateInvalidGPGKey", func(t *testing.T) {
 | 
			
		||||
				testCreateInvalidGPGKey(t, tc.makeRequest, tc.results[4])
 | 
			
		||||
				testCreateInvalidGPGKey(t, tc.makeRequest, tc.token, tc.results[4])
 | 
			
		||||
			})
 | 
			
		||||
			t.Run("CreateNoneRegistredEmailGPGKey", func(t *testing.T) {
 | 
			
		||||
				testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.results[5])
 | 
			
		||||
				testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[5])
 | 
			
		||||
			})
 | 
			
		||||
			t.Run("CreateValidGPGKey", func(t *testing.T) {
 | 
			
		||||
				testCreateValidGPGKey(t, tc.makeRequest, tc.results[6])
 | 
			
		||||
				testCreateValidGPGKey(t, tc.makeRequest, tc.token, tc.results[6])
 | 
			
		||||
			})
 | 
			
		||||
			t.Run("CreateValidSecondaryEmailGPGKey", func(t *testing.T) {
 | 
			
		||||
				testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.results[7])
 | 
			
		||||
				testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[7])
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
@@ -70,7 +72,7 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
		var keys []*api.GPGKey
 | 
			
		||||
 | 
			
		||||
		req := NewRequest(t, "GET", "/api/v1/user/gpg_keys") //GET all keys
 | 
			
		||||
		req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token) //GET all keys
 | 
			
		||||
		resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
		DecodeJSON(t, resp, &keys)
 | 
			
		||||
 | 
			
		||||
@@ -91,7 +93,7 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
		assert.EqualValues(t, false, primaryKey2.Emails[0].Verified)
 | 
			
		||||
 | 
			
		||||
		var key api.GPGKey
 | 
			
		||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)) //Primary key 1
 | 
			
		||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)+"?token="+token) //Primary key 1
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
		DecodeJSON(t, resp, &key)
 | 
			
		||||
		assert.EqualValues(t, "38EA3BCED732982C", key.KeyID)
 | 
			
		||||
@@ -99,13 +101,13 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
		assert.EqualValues(t, "user2@example.com", key.Emails[0].Email)
 | 
			
		||||
		assert.EqualValues(t, true, key.Emails[0].Verified)
 | 
			
		||||
 | 
			
		||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)) //Subkey of 38EA3BCED732982C
 | 
			
		||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)+"?token="+token) //Subkey of 38EA3BCED732982C
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
		DecodeJSON(t, resp, &key)
 | 
			
		||||
		assert.EqualValues(t, "70D7C694D17D03AD", key.KeyID)
 | 
			
		||||
		assert.EqualValues(t, 0, len(key.Emails))
 | 
			
		||||
 | 
			
		||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)) //Primary key 2
 | 
			
		||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)+"?token="+token) //Primary key 2
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
		DecodeJSON(t, resp, &key)
 | 
			
		||||
		assert.EqualValues(t, "FABF39739FE1E927", key.KeyID)
 | 
			
		||||
@@ -119,7 +121,7 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
	t.Run("CheckCommits", func(t *testing.T) {
 | 
			
		||||
		t.Run("NotSigned", func(t *testing.T) {
 | 
			
		||||
			var branch api.Branch
 | 
			
		||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed")
 | 
			
		||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed?token="+token)
 | 
			
		||||
			resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
			DecodeJSON(t, resp, &branch)
 | 
			
		||||
			assert.EqualValues(t, false, branch.Commit.Verification.Verified)
 | 
			
		||||
@@ -127,7 +129,7 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
		t.Run("SignedWithNotValidatedEmail", func(t *testing.T) {
 | 
			
		||||
			var branch api.Branch
 | 
			
		||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated")
 | 
			
		||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated?token="+token)
 | 
			
		||||
			resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
			DecodeJSON(t, resp, &branch)
 | 
			
		||||
			assert.EqualValues(t, false, branch.Commit.Verification.Verified)
 | 
			
		||||
@@ -135,7 +137,7 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
		t.Run("SignedWithValidEmail", func(t *testing.T) {
 | 
			
		||||
			var branch api.Branch
 | 
			
		||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign")
 | 
			
		||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign?token="+token)
 | 
			
		||||
			resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
			DecodeJSON(t, resp, &branch)
 | 
			
		||||
			assert.EqualValues(t, true, branch.Commit.Verification.Verified)
 | 
			
		||||
@@ -143,39 +145,39 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
			
		||||
	req := NewRequest(t, "GET", "/api/v1/user/gpg_keys")
 | 
			
		||||
func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
			
		||||
	req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token)
 | 
			
		||||
	makeRequest(t, req, expected)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
			
		||||
	req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys")
 | 
			
		||||
func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
			
		||||
	req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys?token="+token)
 | 
			
		||||
	makeRequest(t, req, expected)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
			
		||||
	req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1")
 | 
			
		||||
func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
			
		||||
	req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1?token="+token)
 | 
			
		||||
	makeRequest(t, req, expected)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
			
		||||
	req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1")
 | 
			
		||||
func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
			
		||||
	req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1?token="+token)
 | 
			
		||||
	makeRequest(t, req, expected)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int, publicKey string) {
 | 
			
		||||
	req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys", api.CreateGPGKeyOption{
 | 
			
		||||
func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int, publicKey string) {
 | 
			
		||||
	req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys?token="+token, api.CreateGPGKeyOption{
 | 
			
		||||
		ArmoredKey: publicKey,
 | 
			
		||||
	})
 | 
			
		||||
	makeRequest(t, req, expected)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
			
		||||
	testCreateGPGKey(t, makeRequest, expected, "invalid_key")
 | 
			
		||||
func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
			
		||||
	testCreateGPGKey(t, makeRequest, token, expected, "invalid_key")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
			
		||||
	testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
			
		||||
func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
			
		||||
	testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
			
		||||
 | 
			
		||||
mQENBFmGUygBCACjCNbKvMGgp0fd5vyFW9olE1CLCSyyF9gQN2hSuzmZLuAZF2Kh
 | 
			
		||||
dCMCG2T1UwzUB/yWUFWJ2BtCwSjuaRv+cGohqEy6bhEBV90peGA33lHfjx7wP25O
 | 
			
		||||
@@ -194,9 +196,9 @@ INx/MmBfmtCq05FqNclvU+sj2R3N1JJOtBOjZrJHQbJhzoILou8AkxeX1A+q9OAz
 | 
			
		||||
-----END PGP PUBLIC KEY BLOCK-----`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
			
		||||
func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
			
		||||
	//User2 <user2@example.com> //primary & activated
 | 
			
		||||
	testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
			
		||||
	testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
			
		||||
 | 
			
		||||
mQENBFmGVsMBCACuxgZ7W7rI9xN08Y4M7B8yx/6/I4Slm94+wXf8YNRvAyqj30dW
 | 
			
		||||
VJhyBcnfNRDLKSQp5o/hhfDkCgdqBjLa1PnHlGS3PXJc0hP/FyYPD2BFvNMPpCYS
 | 
			
		||||
@@ -228,9 +230,9 @@ uy6MA3VSB99SK9ducGmE1Jv8mcziREroz2TEGr0zPs6h
 | 
			
		||||
-----END PGP PUBLIC KEY BLOCK-----`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
			
		||||
func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
			
		||||
	//User2 <user21@example.com> //secondary and not activated
 | 
			
		||||
	testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
			
		||||
	testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
			
		||||
 | 
			
		||||
mQENBFmGWN4BCAC18V4tVGO65VLCV7p14FuXJlUtZ5CuYMvgEkcOqrvRaBSW9ao4
 | 
			
		||||
PGESOhJpfWpnW3QgJniYndLzPpsmdHEclEER6aZjiNgReWPOjHD5tykWocZAJqXD
 | 
			
		||||
 
 | 
			
		||||
@@ -23,12 +23,13 @@ func TestAPIAddIssueLabels(t *testing.T) {
 | 
			
		||||
	label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
 | 
			
		||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
 | 
			
		||||
		owner.Name, repo.Name, issue.Index)
 | 
			
		||||
	session := loginUser(t, owner.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
 | 
			
		||||
		owner.Name, repo.Name, issue.Index, token)
 | 
			
		||||
	req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{
 | 
			
		||||
		Labels: []int64{label.ID},
 | 
			
		||||
	})
 | 
			
		||||
	session := loginUser(t, owner.Name)
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
	var apiLabels []*api.Label
 | 
			
		||||
	DecodeJSON(t, resp, &apiLabels)
 | 
			
		||||
@@ -45,12 +46,13 @@ func TestAPIReplaceIssueLabels(t *testing.T) {
 | 
			
		||||
	label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
 | 
			
		||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
 | 
			
		||||
		owner.Name, repo.Name, issue.Index)
 | 
			
		||||
	session := loginUser(t, owner.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
 | 
			
		||||
		owner.Name, repo.Name, issue.Index, token)
 | 
			
		||||
	req := NewRequestWithJSON(t, "PUT", urlStr, &api.IssueLabelsOption{
 | 
			
		||||
		Labels: []int64{label.ID},
 | 
			
		||||
	})
 | 
			
		||||
	session := loginUser(t, owner.Name)
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
	var apiLabels []*api.Label
 | 
			
		||||
	DecodeJSON(t, resp, &apiLabels)
 | 
			
		||||
 
 | 
			
		||||
@@ -22,8 +22,9 @@ func TestAPIListIssues(t *testing.T) {
 | 
			
		||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, owner.Name)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all",
 | 
			
		||||
		owner.Name, repo.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all&token=%s",
 | 
			
		||||
		owner.Name, repo.Name, token)
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
	var apiIssues []*api.Issue
 | 
			
		||||
	DecodeJSON(t, resp, &apiIssues)
 | 
			
		||||
@@ -41,8 +42,8 @@ func TestAPICreateIssue(t *testing.T) {
 | 
			
		||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, owner.Name)
 | 
			
		||||
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all", owner.Name, repo.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all&token=%s", owner.Name, repo.Name, token)
 | 
			
		||||
	req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
 | 
			
		||||
		Body:     body,
 | 
			
		||||
		Title:    title,
 | 
			
		||||
 
 | 
			
		||||
@@ -46,8 +46,8 @@ func TestCreateReadOnlyDeployKey(t *testing.T) {
 | 
			
		||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, repoOwner.Name)
 | 
			
		||||
 | 
			
		||||
	keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys", repoOwner.Name, repo.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
 | 
			
		||||
	rawKeyBody := api.CreateKeyOption{
 | 
			
		||||
		Title:    "read-only",
 | 
			
		||||
		Key:      "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
			
		||||
@@ -72,8 +72,8 @@ func TestCreateReadWriteDeployKey(t *testing.T) {
 | 
			
		||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, repoOwner.Name)
 | 
			
		||||
 | 
			
		||||
	keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys", repoOwner.Name, repo.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
 | 
			
		||||
	rawKeyBody := api.CreateKeyOption{
 | 
			
		||||
		Title: "read-write",
 | 
			
		||||
		Key:   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsufOCrDDlT8DLkodnnJtbq7uGflcPae7euTfM+Laq4So+v4WeSV362Rg0O/+Sje1UthrhN6lQkfRkdWIlCRQEXg+LMqr6RhvDfZquE2Xwqv/itlz7LjbdAUdYoO1iH7rMSmYvQh4WEnC/DAacKGbhdGIM/ZBz0z6tHm7bPgbI9ykEKekTmPwQFP1Qebvf5NYOFMWqQ2sCEAI9dBMVLoojsIpV+KADf+BotiIi8yNfTG2rzmzpxBpW9fYjd1Sy1yd4NSUpoPbEJJYJ1TrjiSWlYOVq9Ar8xW1O87i6gBjL/3zN7ANeoYhaAXupdOS6YL22YOK/yC0tJtXwwdh/eSrh",
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,8 @@ func TestAPIViewPulls(t *testing.T) {
 | 
			
		||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, "user2")
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all", owner.Name, repo.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all&token="+token, owner.Name, repo.Name)
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
 | 
			
		||||
	var pulls []*api.PullRequest
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ func TestAPICreateRelease(t *testing.T) {
 | 
			
		||||
	repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
 | 
			
		||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
			
		||||
	session := loginUser(t, owner.LowerName)
 | 
			
		||||
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	gitRepo, err := git.OpenRepository(repo.RepoPath())
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
@@ -32,8 +32,8 @@ func TestAPICreateRelease(t *testing.T) {
 | 
			
		||||
	commitID, err := gitRepo.GetTagCommitID("v0.0.1")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases",
 | 
			
		||||
		owner.Name, repo.Name)
 | 
			
		||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
 | 
			
		||||
		owner.Name, repo.Name, token)
 | 
			
		||||
	req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
 | 
			
		||||
		TagName:      "v0.0.1",
 | 
			
		||||
		Title:        "v0.0.1",
 | 
			
		||||
@@ -53,8 +53,8 @@ func TestAPICreateRelease(t *testing.T) {
 | 
			
		||||
		Note:    newRelease.Note,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d",
 | 
			
		||||
		owner.Name, repo.Name, newRelease.ID)
 | 
			
		||||
	urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d?token=%s",
 | 
			
		||||
		owner.Name, repo.Name, newRelease.ID, token)
 | 
			
		||||
	req = NewRequest(t, "GET", urlStr)
 | 
			
		||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,16 +16,17 @@ func TestAPIReposRaw(t *testing.T) {
 | 
			
		||||
	user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
 | 
			
		||||
	// Login as User2.
 | 
			
		||||
	session := loginUser(t, user.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
 | 
			
		||||
	for _, ref := range [...]string{
 | 
			
		||||
		"master", // Branch
 | 
			
		||||
		"v1.1",   // Tag
 | 
			
		||||
		"65f1bf27bc3bf70f64657658635e66094edbcb4d", // Commit
 | 
			
		||||
	} {
 | 
			
		||||
		req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md", user.Name, ref)
 | 
			
		||||
		req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md?token="+token, user.Name, ref)
 | 
			
		||||
		session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
	}
 | 
			
		||||
	// Test default branch
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md", user.Name)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md?token="+token, user.Name)
 | 
			
		||||
	session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -67,16 +67,16 @@ func TestAPISearchRepo(t *testing.T) {
 | 
			
		||||
		expectedResults
 | 
			
		||||
	}{
 | 
			
		||||
		{name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50", expectedResults: expectedResults{
 | 
			
		||||
			nil:   {count: 16},
 | 
			
		||||
			user:  {count: 16},
 | 
			
		||||
			user2: {count: 16}},
 | 
			
		||||
			nil:   {count: 17},
 | 
			
		||||
			user:  {count: 17},
 | 
			
		||||
			user2: {count: 17}},
 | 
			
		||||
		},
 | 
			
		||||
		{name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10", expectedResults: expectedResults{
 | 
			
		||||
			nil:   {count: 10},
 | 
			
		||||
			user:  {count: 10},
 | 
			
		||||
			user2: {count: 10}},
 | 
			
		||||
		},
 | 
			
		||||
		{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search", expectedResults: expectedResults{
 | 
			
		||||
		{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default", expectedResults: expectedResults{
 | 
			
		||||
			nil:   {count: 10},
 | 
			
		||||
			user:  {count: 10},
 | 
			
		||||
			user2: {count: 10}},
 | 
			
		||||
@@ -143,17 +143,19 @@ func TestAPISearchRepo(t *testing.T) {
 | 
			
		||||
				var session *TestSession
 | 
			
		||||
				var testName string
 | 
			
		||||
				var userID int64
 | 
			
		||||
				var token string
 | 
			
		||||
				if userToLogin != nil && userToLogin.ID > 0 {
 | 
			
		||||
					testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
 | 
			
		||||
					session = loginUser(t, userToLogin.Name)
 | 
			
		||||
					userID = userToLogin.ID
 | 
			
		||||
					token = getTokenForLoggedInUser(t, session)
 | 
			
		||||
				} else {
 | 
			
		||||
					testName = "AnonymousUser"
 | 
			
		||||
					session = emptyTestSession(t)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				t.Run(testName, func(t *testing.T) {
 | 
			
		||||
					request := NewRequest(t, "GET", testCase.requestURL)
 | 
			
		||||
					request := NewRequest(t, "GET", testCase.requestURL+"&token="+token)
 | 
			
		||||
					response := session.MakeRequest(t, request, http.StatusOK)
 | 
			
		||||
 | 
			
		||||
					var body api.SearchResults
 | 
			
		||||
@@ -215,7 +217,8 @@ func TestAPIOrgRepos(t *testing.T) {
 | 
			
		||||
	// Login as User2.
 | 
			
		||||
	session := loginUser(t, user.Name)
 | 
			
		||||
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", sourceOrg.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token="+token, sourceOrg.Name)
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
 | 
			
		||||
	var apiRepos []*api.Repository
 | 
			
		||||
@@ -231,9 +234,10 @@ func TestAPIOrgRepos(t *testing.T) {
 | 
			
		||||
func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
 | 
			
		||||
	prepareTestEnv(t)
 | 
			
		||||
	user := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)
 | 
			
		||||
	sess := loginUser(t, user.Name)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repositories/2")
 | 
			
		||||
	sess.MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
	session := loginUser(t, user.Name)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/repositories/2?token="+token)
 | 
			
		||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAPIRepoMigrate(t *testing.T) {
 | 
			
		||||
@@ -253,8 +257,8 @@ func TestAPIRepoMigrate(t *testing.T) {
 | 
			
		||||
	for _, testCase := range testCases {
 | 
			
		||||
		user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
 | 
			
		||||
		session := loginUser(t, user.Name)
 | 
			
		||||
 | 
			
		||||
		req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate", &api.MigrateRepoOption{
 | 
			
		||||
		token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
		req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOption{
 | 
			
		||||
			CloneAddr: testCase.cloneURL,
 | 
			
		||||
			UID:       int(testCase.userID),
 | 
			
		||||
			RepoName:  testCase.repoName,
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,8 @@ func TestAPITeam(t *testing.T) {
 | 
			
		||||
	user := models.AssertExistsAndLoadBean(t, &models.User{ID: teamUser.UID}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, user.Name)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID)
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
	req := NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamUser.TeamID)
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
 | 
			
		||||
	var apiTeam api.Team
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,8 @@ func TestGit(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
				t.Run("CreateRepo", func(t *testing.T) {
 | 
			
		||||
					session := loginUser(t, "user2")
 | 
			
		||||
					req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
 | 
			
		||||
					token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
					req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
 | 
			
		||||
						AutoInit:    true,
 | 
			
		||||
						Description: "Temporary repo",
 | 
			
		||||
						Name:        "repo-tmp-17",
 | 
			
		||||
@@ -166,7 +167,8 @@ func TestGit(t *testing.T) {
 | 
			
		||||
			t.Run("Standard", func(t *testing.T) {
 | 
			
		||||
				t.Run("CreateRepo", func(t *testing.T) {
 | 
			
		||||
					session := loginUser(t, "user2")
 | 
			
		||||
					req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
 | 
			
		||||
					token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
					req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
 | 
			
		||||
						AutoInit:    true,
 | 
			
		||||
						Description: "Temporary repo",
 | 
			
		||||
						Name:        "repo-tmp-18",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/HEAD
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/HEAD
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
ref: refs/heads/master
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
[core]
 | 
			
		||||
	repositoryformatversion = 0
 | 
			
		||||
	filemode = true
 | 
			
		||||
	bare = true
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
Unnamed repository; edit this file 'description' to name the repository.
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# An example hook script to check the commit log message taken by
 | 
			
		||||
# applypatch from an e-mail message.
 | 
			
		||||
#
 | 
			
		||||
# The hook should exit with non-zero status after issuing an
 | 
			
		||||
# appropriate message if it wants to stop the commit.  The hook is
 | 
			
		||||
# allowed to edit the commit message file.
 | 
			
		||||
#
 | 
			
		||||
# To enable this hook, rename this file to "applypatch-msg".
 | 
			
		||||
 | 
			
		||||
. git-sh-setup
 | 
			
		||||
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
 | 
			
		||||
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
 | 
			
		||||
:
 | 
			
		||||
							
								
								
									
										24
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/commit-msg.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										24
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/commit-msg.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# An example hook script to check the commit log message.
 | 
			
		||||
# Called by "git commit" with one argument, the name of the file
 | 
			
		||||
# that has the commit message.  The hook should exit with non-zero
 | 
			
		||||
# status after issuing an appropriate message if it wants to stop the
 | 
			
		||||
# commit.  The hook is allowed to edit the commit message file.
 | 
			
		||||
#
 | 
			
		||||
# To enable this hook, rename this file to "commit-msg".
 | 
			
		||||
 | 
			
		||||
# Uncomment the below to add a Signed-off-by line to the message.
 | 
			
		||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
 | 
			
		||||
# hook is more suited to it.
 | 
			
		||||
#
 | 
			
		||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
 | 
			
		||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
 | 
			
		||||
 | 
			
		||||
# This example catches duplicate Signed-off-by lines.
 | 
			
		||||
 | 
			
		||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
 | 
			
		||||
	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
 | 
			
		||||
	echo >&2 Duplicate Signed-off-by lines.
 | 
			
		||||
	exit 1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/post-receive
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/post-receive
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
ORI_DIR=`pwd`
 | 
			
		||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
 | 
			
		||||
cd "$ORI_DIR"
 | 
			
		||||
for i in `ls "$SHELL_FOLDER/post-receive.d"`; do
 | 
			
		||||
    sh "$SHELL_FOLDER/post-receive.d/$i"
 | 
			
		||||
done
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# An example hook script to prepare a packed repository for use over
 | 
			
		||||
# dumb transports.
 | 
			
		||||
#
 | 
			
		||||
# To enable this hook, rename this file to "post-update".
 | 
			
		||||
 | 
			
		||||
exec git update-server-info
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# An example hook script to verify what is about to be committed
 | 
			
		||||
# by applypatch from an e-mail message.
 | 
			
		||||
#
 | 
			
		||||
# The hook should exit with non-zero status after issuing an
 | 
			
		||||
# appropriate message if it wants to stop the commit.
 | 
			
		||||
#
 | 
			
		||||
# To enable this hook, rename this file to "pre-applypatch".
 | 
			
		||||
 | 
			
		||||
. git-sh-setup
 | 
			
		||||
precommit="$(git rev-parse --git-path hooks/pre-commit)"
 | 
			
		||||
test -x "$precommit" && exec "$precommit" ${1+"$@"}
 | 
			
		||||
:
 | 
			
		||||
							
								
								
									
										49
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-commit.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										49
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-commit.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# An example hook script to verify what is about to be committed.
 | 
			
		||||
# Called by "git commit" with no arguments.  The hook should
 | 
			
		||||
# exit with non-zero status after issuing an appropriate message if
 | 
			
		||||
# it wants to stop the commit.
 | 
			
		||||
#
 | 
			
		||||
# To enable this hook, rename this file to "pre-commit".
 | 
			
		||||
 | 
			
		||||
if git rev-parse --verify HEAD >/dev/null 2>&1
 | 
			
		||||
then
 | 
			
		||||
	against=HEAD
 | 
			
		||||
else
 | 
			
		||||
	# Initial commit: diff against an empty tree object
 | 
			
		||||
	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# If you want to allow non-ASCII filenames set this variable to true.
 | 
			
		||||
allownonascii=$(git config --bool hooks.allownonascii)
 | 
			
		||||
 | 
			
		||||
# Redirect output to stderr.
 | 
			
		||||
exec 1>&2
 | 
			
		||||
 | 
			
		||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
 | 
			
		||||
# them from being added to the repository. We exploit the fact that the
 | 
			
		||||
# printable range starts at the space character and ends with tilde.
 | 
			
		||||
if [ "$allownonascii" != "true" ] &&
 | 
			
		||||
	# Note that the use of brackets around a tr range is ok here, (it's
 | 
			
		||||
	# even required, for portability to Solaris 10's /usr/bin/tr), since
 | 
			
		||||
	# the square bracket bytes happen to fall in the designated range.
 | 
			
		||||
	test $(git diff --cached --name-only --diff-filter=A -z $against |
 | 
			
		||||
	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
 | 
			
		||||
then
 | 
			
		||||
	cat <<\EOF
 | 
			
		||||
Error: Attempt to add a non-ASCII file name.
 | 
			
		||||
 | 
			
		||||
This can cause problems if you want to work with people on other platforms.
 | 
			
		||||
 | 
			
		||||
To be portable it is advisable to rename the file.
 | 
			
		||||
 | 
			
		||||
If you know what you are doing you can disable this check using:
 | 
			
		||||
 | 
			
		||||
  git config hooks.allownonascii true
 | 
			
		||||
EOF
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# If there are whitespace errors, print the offending file names and fail.
 | 
			
		||||
exec git diff-index --check --cached $against --
 | 
			
		||||
							
								
								
									
										53
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-push.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										53
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-push.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
# An example hook script to verify what is about to be pushed.  Called by "git
 | 
			
		||||
# push" after it has checked the remote status, but before anything has been
 | 
			
		||||
# pushed.  If this script exits with a non-zero status nothing will be pushed.
 | 
			
		||||
#
 | 
			
		||||
# This hook is called with the following parameters:
 | 
			
		||||
#
 | 
			
		||||
# $1 -- Name of the remote to which the push is being done
 | 
			
		||||
# $2 -- URL to which the push is being done
 | 
			
		||||
#
 | 
			
		||||
# If pushing without using a named remote those arguments will be equal.
 | 
			
		||||
#
 | 
			
		||||
# Information about the commits which are being pushed is supplied as lines to
 | 
			
		||||
# the standard input in the form:
 | 
			
		||||
#
 | 
			
		||||
#   <local ref> <local sha1> <remote ref> <remote sha1>
 | 
			
		||||
#
 | 
			
		||||
# This sample shows how to prevent push of commits where the log message starts
 | 
			
		||||
# with "WIP" (work in progress).
 | 
			
		||||
 | 
			
		||||
remote="$1"
 | 
			
		||||
url="$2"
 | 
			
		||||
 | 
			
		||||
z40=0000000000000000000000000000000000000000
 | 
			
		||||
 | 
			
		||||
while read local_ref local_sha remote_ref remote_sha
 | 
			
		||||
do
 | 
			
		||||
	if [ "$local_sha" = $z40 ]
 | 
			
		||||
	then
 | 
			
		||||
		# Handle delete
 | 
			
		||||
		:
 | 
			
		||||
	else
 | 
			
		||||
		if [ "$remote_sha" = $z40 ]
 | 
			
		||||
		then
 | 
			
		||||
			# New branch, examine all commits
 | 
			
		||||
			range="$local_sha"
 | 
			
		||||
		else
 | 
			
		||||
			# Update to existing branch, examine new commits
 | 
			
		||||
			range="$remote_sha..$local_sha"
 | 
			
		||||
		fi
 | 
			
		||||
 | 
			
		||||
		# Check for WIP commit
 | 
			
		||||
		commit=`git rev-list -n 1 --grep '^WIP' "$range"`
 | 
			
		||||
		if [ -n "$commit" ]
 | 
			
		||||
		then
 | 
			
		||||
			echo >&2 "Found WIP commit in $local_ref, not pushing"
 | 
			
		||||
			exit 1
 | 
			
		||||
		fi
 | 
			
		||||
	fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
exit 0
 | 
			
		||||
							
								
								
									
										169
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-rebase.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										169
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-rebase.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2006, 2008 Junio C Hamano
 | 
			
		||||
#
 | 
			
		||||
# The "pre-rebase" hook is run just before "git rebase" starts doing
 | 
			
		||||
# its job, and can prevent the command from running by exiting with
 | 
			
		||||
# non-zero status.
 | 
			
		||||
#
 | 
			
		||||
# The hook is called with the following parameters:
 | 
			
		||||
#
 | 
			
		||||
# $1 -- the upstream the series was forked from.
 | 
			
		||||
# $2 -- the branch being rebased (or empty when rebasing the current branch).
 | 
			
		||||
#
 | 
			
		||||
# This sample shows how to prevent topic branches that are already
 | 
			
		||||
# merged to 'next' branch from getting rebased, because allowing it
 | 
			
		||||
# would result in rebasing already published history.
 | 
			
		||||
 | 
			
		||||
publish=next
 | 
			
		||||
basebranch="$1"
 | 
			
		||||
if test "$#" = 2
 | 
			
		||||
then
 | 
			
		||||
	topic="refs/heads/$2"
 | 
			
		||||
else
 | 
			
		||||
	topic=`git symbolic-ref HEAD` ||
 | 
			
		||||
	exit 0 ;# we do not interrupt rebasing detached HEAD
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
case "$topic" in
 | 
			
		||||
refs/heads/??/*)
 | 
			
		||||
	;;
 | 
			
		||||
*)
 | 
			
		||||
	exit 0 ;# we do not interrupt others.
 | 
			
		||||
	;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
# Now we are dealing with a topic branch being rebased
 | 
			
		||||
# on top of master.  Is it OK to rebase it?
 | 
			
		||||
 | 
			
		||||
# Does the topic really exist?
 | 
			
		||||
git show-ref -q "$topic" || {
 | 
			
		||||
	echo >&2 "No such branch $topic"
 | 
			
		||||
	exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Is topic fully merged to master?
 | 
			
		||||
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
 | 
			
		||||
if test -z "$not_in_master"
 | 
			
		||||
then
 | 
			
		||||
	echo >&2 "$topic is fully merged to master; better remove it."
 | 
			
		||||
	exit 1 ;# we could allow it, but there is no point.
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Is topic ever merged to next?  If so you should not be rebasing it.
 | 
			
		||||
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
 | 
			
		||||
only_next_2=`git rev-list ^master           ${publish} | sort`
 | 
			
		||||
if test "$only_next_1" = "$only_next_2"
 | 
			
		||||
then
 | 
			
		||||
	not_in_topic=`git rev-list "^$topic" master`
 | 
			
		||||
	if test -z "$not_in_topic"
 | 
			
		||||
	then
 | 
			
		||||
		echo >&2 "$topic is already up-to-date with master"
 | 
			
		||||
		exit 1 ;# we could allow it, but there is no point.
 | 
			
		||||
	else
 | 
			
		||||
		exit 0
 | 
			
		||||
	fi
 | 
			
		||||
else
 | 
			
		||||
	not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
 | 
			
		||||
	/usr/bin/perl -e '
 | 
			
		||||
		my $topic = $ARGV[0];
 | 
			
		||||
		my $msg = "* $topic has commits already merged to public branch:\n";
 | 
			
		||||
		my (%not_in_next) = map {
 | 
			
		||||
			/^([0-9a-f]+) /;
 | 
			
		||||
			($1 => 1);
 | 
			
		||||
		} split(/\n/, $ARGV[1]);
 | 
			
		||||
		for my $elem (map {
 | 
			
		||||
				/^([0-9a-f]+) (.*)$/;
 | 
			
		||||
				[$1 => $2];
 | 
			
		||||
			} split(/\n/, $ARGV[2])) {
 | 
			
		||||
			if (!exists $not_in_next{$elem->[0]}) {
 | 
			
		||||
				if ($msg) {
 | 
			
		||||
					print STDERR $msg;
 | 
			
		||||
					undef $msg;
 | 
			
		||||
				}
 | 
			
		||||
				print STDERR " $elem->[1]\n";
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	' "$topic" "$not_in_next" "$not_in_master"
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
<<\DOC_END
 | 
			
		||||
 | 
			
		||||
This sample hook safeguards topic branches that have been
 | 
			
		||||
published from being rewound.
 | 
			
		||||
 | 
			
		||||
The workflow assumed here is:
 | 
			
		||||
 | 
			
		||||
 * Once a topic branch forks from "master", "master" is never
 | 
			
		||||
   merged into it again (either directly or indirectly).
 | 
			
		||||
 | 
			
		||||
 * Once a topic branch is fully cooked and merged into "master",
 | 
			
		||||
   it is deleted.  If you need to build on top of it to correct
 | 
			
		||||
   earlier mistakes, a new topic branch is created by forking at
 | 
			
		||||
   the tip of the "master".  This is not strictly necessary, but
 | 
			
		||||
   it makes it easier to keep your history simple.
 | 
			
		||||
 | 
			
		||||
 * Whenever you need to test or publish your changes to topic
 | 
			
		||||
   branches, merge them into "next" branch.
 | 
			
		||||
 | 
			
		||||
The script, being an example, hardcodes the publish branch name
 | 
			
		||||
to be "next", but it is trivial to make it configurable via
 | 
			
		||||
$GIT_DIR/config mechanism.
 | 
			
		||||
 | 
			
		||||
With this workflow, you would want to know:
 | 
			
		||||
 | 
			
		||||
(1) ... if a topic branch has ever been merged to "next".  Young
 | 
			
		||||
    topic branches can have stupid mistakes you would rather
 | 
			
		||||
    clean up before publishing, and things that have not been
 | 
			
		||||
    merged into other branches can be easily rebased without
 | 
			
		||||
    affecting other people.  But once it is published, you would
 | 
			
		||||
    not want to rewind it.
 | 
			
		||||
 | 
			
		||||
(2) ... if a topic branch has been fully merged to "master".
 | 
			
		||||
    Then you can delete it.  More importantly, you should not
 | 
			
		||||
    build on top of it -- other people may already want to
 | 
			
		||||
    change things related to the topic as patches against your
 | 
			
		||||
    "master", so if you need further changes, it is better to
 | 
			
		||||
    fork the topic (perhaps with the same name) afresh from the
 | 
			
		||||
    tip of "master".
 | 
			
		||||
 | 
			
		||||
Let's look at this example:
 | 
			
		||||
 | 
			
		||||
		   o---o---o---o---o---o---o---o---o---o "next"
 | 
			
		||||
		  /       /           /           /
 | 
			
		||||
		 /   a---a---b A     /           /
 | 
			
		||||
		/   /               /           /
 | 
			
		||||
	       /   /   c---c---c---c B         /
 | 
			
		||||
	      /   /   /             \         /
 | 
			
		||||
	     /   /   /   b---b C     \       /
 | 
			
		||||
	    /   /   /   /             \     /
 | 
			
		||||
    ---o---o---o---o---o---o---o---o---o---o---o "master"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
A, B and C are topic branches.
 | 
			
		||||
 | 
			
		||||
 * A has one fix since it was merged up to "next".
 | 
			
		||||
 | 
			
		||||
 * B has finished.  It has been fully merged up to "master" and "next",
 | 
			
		||||
   and is ready to be deleted.
 | 
			
		||||
 | 
			
		||||
 * C has not merged to "next" at all.
 | 
			
		||||
 | 
			
		||||
We would want to allow C to be rebased, refuse A, and encourage
 | 
			
		||||
B to be deleted.
 | 
			
		||||
 | 
			
		||||
To compute (1):
 | 
			
		||||
 | 
			
		||||
	git rev-list ^master ^topic next
 | 
			
		||||
	git rev-list ^master        next
 | 
			
		||||
 | 
			
		||||
	if these match, topic has not merged in next at all.
 | 
			
		||||
 | 
			
		||||
To compute (2):
 | 
			
		||||
 | 
			
		||||
	git rev-list master..topic
 | 
			
		||||
 | 
			
		||||
	if this is empty, it is fully merged to "master".
 | 
			
		||||
 | 
			
		||||
DOC_END
 | 
			
		||||
							
								
								
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-receive
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-receive
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
ORI_DIR=`pwd`
 | 
			
		||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
 | 
			
		||||
cd "$ORI_DIR"
 | 
			
		||||
for i in `ls "$SHELL_FOLDER/pre-receive.d"`; do
 | 
			
		||||
    sh "$SHELL_FOLDER/pre-receive.d/$i"
 | 
			
		||||
done
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# An example hook script to prepare the commit log message.
 | 
			
		||||
# Called by "git commit" with the name of the file that has the
 | 
			
		||||
# commit message, followed by the description of the commit
 | 
			
		||||
# message's source.  The hook's purpose is to edit the commit
 | 
			
		||||
# message file.  If the hook fails with a non-zero status,
 | 
			
		||||
# the commit is aborted.
 | 
			
		||||
#
 | 
			
		||||
# To enable this hook, rename this file to "prepare-commit-msg".
 | 
			
		||||
 | 
			
		||||
# This hook includes three examples.  The first comments out the
 | 
			
		||||
# "Conflicts:" part of a merge commit.
 | 
			
		||||
#
 | 
			
		||||
# The second includes the output of "git diff --name-status -r"
 | 
			
		||||
# into the message, just before the "git status" output.  It is
 | 
			
		||||
# commented because it doesn't cope with --amend or with squashed
 | 
			
		||||
# commits.
 | 
			
		||||
#
 | 
			
		||||
# The third example adds a Signed-off-by line to the message, that can
 | 
			
		||||
# still be edited.  This is rarely a good idea.
 | 
			
		||||
 | 
			
		||||
case "$2,$3" in
 | 
			
		||||
  merge,)
 | 
			
		||||
    /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
 | 
			
		||||
 | 
			
		||||
# ,|template,)
 | 
			
		||||
#   /usr/bin/perl -i.bak -pe '
 | 
			
		||||
#      print "\n" . `git diff --cached --name-status -r`
 | 
			
		||||
#	 if /^#/ && $first++ == 0' "$1" ;;
 | 
			
		||||
 | 
			
		||||
  *) ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
 | 
			
		||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
 | 
			
		||||
							
								
								
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
ORI_DIR=`pwd`
 | 
			
		||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
 | 
			
		||||
cd "$ORI_DIR"
 | 
			
		||||
for i in `ls "$SHELL_FOLDER/update.d"`; do
 | 
			
		||||
    sh "$SHELL_FOLDER/update.d/$i" $1 $2 $3
 | 
			
		||||
done
 | 
			
		||||
							
								
								
									
										2
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update.d/gitea
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update.d/gitea
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
 | 
			
		||||
							
								
								
									
										128
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										128
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# An example hook script to block unannotated tags from entering.
 | 
			
		||||
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
 | 
			
		||||
#
 | 
			
		||||
# To enable this hook, rename this file to "update".
 | 
			
		||||
#
 | 
			
		||||
# Config
 | 
			
		||||
# ------
 | 
			
		||||
# hooks.allowunannotated
 | 
			
		||||
#   This boolean sets whether unannotated tags will be allowed into the
 | 
			
		||||
#   repository.  By default they won't be.
 | 
			
		||||
# hooks.allowdeletetag
 | 
			
		||||
#   This boolean sets whether deleting tags will be allowed in the
 | 
			
		||||
#   repository.  By default they won't be.
 | 
			
		||||
# hooks.allowmodifytag
 | 
			
		||||
#   This boolean sets whether a tag may be modified after creation. By default
 | 
			
		||||
#   it won't be.
 | 
			
		||||
# hooks.allowdeletebranch
 | 
			
		||||
#   This boolean sets whether deleting branches will be allowed in the
 | 
			
		||||
#   repository.  By default they won't be.
 | 
			
		||||
# hooks.denycreatebranch
 | 
			
		||||
#   This boolean sets whether remotely creating branches will be denied
 | 
			
		||||
#   in the repository.  By default this is allowed.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# --- Command line
 | 
			
		||||
refname="$1"
 | 
			
		||||
oldrev="$2"
 | 
			
		||||
newrev="$3"
 | 
			
		||||
 | 
			
		||||
# --- Safety check
 | 
			
		||||
if [ -z "$GIT_DIR" ]; then
 | 
			
		||||
	echo "Don't run this script from the command line." >&2
 | 
			
		||||
	echo " (if you want, you could supply GIT_DIR then run" >&2
 | 
			
		||||
	echo "  $0 <ref> <oldrev> <newrev>)" >&2
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
 | 
			
		||||
	echo "usage: $0 <ref> <oldrev> <newrev>" >&2
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# --- Config
 | 
			
		||||
allowunannotated=$(git config --bool hooks.allowunannotated)
 | 
			
		||||
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
 | 
			
		||||
denycreatebranch=$(git config --bool hooks.denycreatebranch)
 | 
			
		||||
allowdeletetag=$(git config --bool hooks.allowdeletetag)
 | 
			
		||||
allowmodifytag=$(git config --bool hooks.allowmodifytag)
 | 
			
		||||
 | 
			
		||||
# check for no description
 | 
			
		||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
 | 
			
		||||
case "$projectdesc" in
 | 
			
		||||
"Unnamed repository"* | "")
 | 
			
		||||
	echo "*** Project description file hasn't been set" >&2
 | 
			
		||||
	exit 1
 | 
			
		||||
	;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
# --- Check types
 | 
			
		||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
 | 
			
		||||
zero="0000000000000000000000000000000000000000"
 | 
			
		||||
if [ "$newrev" = "$zero" ]; then
 | 
			
		||||
	newrev_type=delete
 | 
			
		||||
else
 | 
			
		||||
	newrev_type=$(git cat-file -t $newrev)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
case "$refname","$newrev_type" in
 | 
			
		||||
	refs/tags/*,commit)
 | 
			
		||||
		# un-annotated tag
 | 
			
		||||
		short_refname=${refname##refs/tags/}
 | 
			
		||||
		if [ "$allowunannotated" != "true" ]; then
 | 
			
		||||
			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
 | 
			
		||||
			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
 | 
			
		||||
			exit 1
 | 
			
		||||
		fi
 | 
			
		||||
		;;
 | 
			
		||||
	refs/tags/*,delete)
 | 
			
		||||
		# delete tag
 | 
			
		||||
		if [ "$allowdeletetag" != "true" ]; then
 | 
			
		||||
			echo "*** Deleting a tag is not allowed in this repository" >&2
 | 
			
		||||
			exit 1
 | 
			
		||||
		fi
 | 
			
		||||
		;;
 | 
			
		||||
	refs/tags/*,tag)
 | 
			
		||||
		# annotated tag
 | 
			
		||||
		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
 | 
			
		||||
		then
 | 
			
		||||
			echo "*** Tag '$refname' already exists." >&2
 | 
			
		||||
			echo "*** Modifying a tag is not allowed in this repository." >&2
 | 
			
		||||
			exit 1
 | 
			
		||||
		fi
 | 
			
		||||
		;;
 | 
			
		||||
	refs/heads/*,commit)
 | 
			
		||||
		# branch
 | 
			
		||||
		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
 | 
			
		||||
			echo "*** Creating a branch is not allowed in this repository" >&2
 | 
			
		||||
			exit 1
 | 
			
		||||
		fi
 | 
			
		||||
		;;
 | 
			
		||||
	refs/heads/*,delete)
 | 
			
		||||
		# delete branch
 | 
			
		||||
		if [ "$allowdeletebranch" != "true" ]; then
 | 
			
		||||
			echo "*** Deleting a branch is not allowed in this repository" >&2
 | 
			
		||||
			exit 1
 | 
			
		||||
		fi
 | 
			
		||||
		;;
 | 
			
		||||
	refs/remotes/*,commit)
 | 
			
		||||
		# tracking branch
 | 
			
		||||
		;;
 | 
			
		||||
	refs/remotes/*,delete)
 | 
			
		||||
		# delete tracking branch
 | 
			
		||||
		if [ "$allowdeletebranch" != "true" ]; then
 | 
			
		||||
			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
 | 
			
		||||
			exit 1
 | 
			
		||||
		fi
 | 
			
		||||
		;;
 | 
			
		||||
	*)
 | 
			
		||||
		# Anything else (is there anything else?)
 | 
			
		||||
		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
 | 
			
		||||
		exit 1
 | 
			
		||||
		;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
# --- Finished
 | 
			
		||||
exit 0
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
# git ls-files --others --exclude-from=.git/info/exclude
 | 
			
		||||
# Lines that start with '#' are comments.
 | 
			
		||||
# For a project mostly in C, the following would be a good set of
 | 
			
		||||
# exclude patterns (uncomment them if you want to use them):
 | 
			
		||||
# *.[oa]
 | 
			
		||||
# *~
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/heads/Grüßen
 | 
			
		||||
3a810dbf6b96afaa8c5f69a8b6ec1dabfca7368b	refs/heads/Plus+Is+Not+Space
 | 
			
		||||
3aa73c3499bff049a352b4e265575373e964b89a	refs/heads/master
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/heads/ГлавнаяВетка
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/heads/а/б/в
 | 
			
		||||
28d579e4920fbf4f66e71dab3e779d9fbf41422a	refs/heads/ブランチ
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/tags/Ё/人
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/tags/Тэг
 | 
			
		||||
28d579e4920fbf4f66e71dab3e779d9fbf41422a	refs/tags/タグ
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
x<01><>Aj<41>0E<><45>)<29><>R(<28>ci<PJ{Ŗ<>)ILo_<6F>M<EFBFBD>]}x<>/<2F>u<EFBFBD>uDO<44><4F><EFBFBD>/<2F><>6!<21>9K<>KT<4B>H<EFBFBD>
 | 
			
		||||
<EFBFBD><EFBFBD>(E<><45>vi<76>u<EFBFBD><75>|dK8Y<38>s<EFBFBD><73><EFBFBD><EFBFBD>Зd<D097><64>><0C>셜<EFBFBD><EC859C><EFBFBD>6<EFBFBD><1F><02><>·>d<>}<7D>u}O<13><>)x<><78><EFBFBD>i]<5D>%<25><>R<EFBFBD>Kv<4B><76>P<EFBFBD>ۢ<EFBFBD><DBA2><1F><>l<EFBFBD>
 | 
			
		||||
u[<5B><>d<EFBFBD><64><EFBFBD><EFBFBD>ǣ><3E><1F><>Q<EFBFBD>
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
x<01><>]jC!<10><><EFBFBD>*<2A><>PtF<74>+<2B><>.e4#<11><><EFBFBD><18>쾶;<3B>Ӂ<EFBFBD><D381><EFBFBD><EFBFBD><EFBFBD>{<7B><><EFBFBD>_<EFBFBD>P<05><><1B><18>OX<4F><58><EFBFBD>r<EFBFBD><72>b<EFBFBD>2<EFBFBD>+<1C>yg<79>2<EFBFBD>2<EFBFBD>D"<15>)<29><><EFBFBD>I(`<60><>Bi<><69><EFBFBD>%1r<31><72>c<EFBFBD><63><EFBFBD><03><>O><3E>!<21><><EFBFBD>[9<><07>@<40><>-!<21>Z<EFBFBD><5A>,w<>M<EFBFBD>W<EFBFBD>|<7C>NPۮ<50><DBAE><EFBFBD><19>s<EFBFBD>}o.<2E><15><><EFBFBD>r<><72>UQ<7F><03>M<EFBFBD>
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
3a810dbf6b96afaa8c5f69a8b6ec1dabfca7368b
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
3aa73c3499bff049a352b4e265575373e964b89a
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
28d579e4920fbf4f66e71dab3e779d9fbf41422a
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
28d579e4920fbf4f66e71dab3e779d9fbf41422a
 | 
			
		||||
@@ -223,6 +223,22 @@ func loginUserWithPassword(t testing.TB, userName, password string) *TestSession
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTokenForLoggedInUser(t testing.TB, session *TestSession) string {
 | 
			
		||||
	req := NewRequest(t, "GET", "/user/settings/applications")
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
	doc := NewHTMLParser(t, resp.Body)
 | 
			
		||||
	req = NewRequestWithValues(t, "POST", "/user/settings/applications", map[string]string{
 | 
			
		||||
		"_csrf": doc.GetCSRF(),
 | 
			
		||||
		"name":  "api-testing-token",
 | 
			
		||||
	})
 | 
			
		||||
	resp = session.MakeRequest(t, req, http.StatusFound)
 | 
			
		||||
	req = NewRequest(t, "GET", "/user/settings/applications")
 | 
			
		||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
	htmlDoc := NewHTMLParser(t, resp.Body)
 | 
			
		||||
	token := htmlDoc.doc.Find(".ui.info p").Text()
 | 
			
		||||
	return token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewRequest(t testing.TB, method, urlStr string) *http.Request {
 | 
			
		||||
	return NewRequestWithBody(t, method, urlStr, nil)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										178
									
								
								integrations/nonascii_branches_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								integrations/nonascii_branches_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
// Copyright 2018 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/http"
 | 
			
		||||
	"path"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func testSrcRouteRedirect(t *testing.T, session *TestSession, user, repo, route, expectedLocation string, expectedStatus int) {
 | 
			
		||||
	prefix := path.Join("/", user, repo, "src")
 | 
			
		||||
 | 
			
		||||
	// Make request
 | 
			
		||||
	req := NewRequest(t, "GET", path.Join(prefix, route))
 | 
			
		||||
	resp := session.MakeRequest(t, req, http.StatusFound)
 | 
			
		||||
 | 
			
		||||
	// Check Location header
 | 
			
		||||
	location := resp.HeaderMap.Get("Location")
 | 
			
		||||
	assert.Equal(t, path.Join(prefix, expectedLocation), location)
 | 
			
		||||
 | 
			
		||||
	// Perform redirect
 | 
			
		||||
	req = NewRequest(t, "GET", location)
 | 
			
		||||
	resp = session.MakeRequest(t, req, expectedStatus)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setDefaultBranch(t *testing.T, session *TestSession, user, repo, branch string) {
 | 
			
		||||
	location := path.Join("/", user, repo, "settings/branches")
 | 
			
		||||
	csrf := GetCSRF(t, session, location)
 | 
			
		||||
	req := NewRequestWithValues(t, "POST", location, map[string]string{
 | 
			
		||||
		"_csrf":  csrf,
 | 
			
		||||
		"action": "default_branch",
 | 
			
		||||
		"branch": branch,
 | 
			
		||||
	})
 | 
			
		||||
	session.MakeRequest(t, req, http.StatusFound)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNonasciiBranches(t *testing.T) {
 | 
			
		||||
	testRedirects := []struct {
 | 
			
		||||
		from   string
 | 
			
		||||
		to     string
 | 
			
		||||
		status int
 | 
			
		||||
	}{
 | 
			
		||||
		// Branches
 | 
			
		||||
		{
 | 
			
		||||
			from:   "master",
 | 
			
		||||
			to:     "branch/master",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "master/README.md",
 | 
			
		||||
			to:     "branch/master/README.md",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "master/badfile",
 | 
			
		||||
			to:     "branch/master/badfile",
 | 
			
		||||
			status: http.StatusNotFound, // it does not exists
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "ГлавнаяВетка",
 | 
			
		||||
			to:     "branch/%d0%93%d0%bb%d0%b0%d0%b2%d0%bd%d0%b0%d1%8f%d0%92%d0%b5%d1%82%d0%ba%d0%b0",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "а/б/в",
 | 
			
		||||
			to:     "branch/%d0%b0/%d0%b1/%d0%b2",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "Grüßen/README.md",
 | 
			
		||||
			to:     "branch/Gr%c3%bc%c3%9fen/README.md",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "Plus+Is+Not+Space",
 | 
			
		||||
			to:     "branch/Plus+Is+Not+Space",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "Plus+Is+Not+Space/Файл.md",
 | 
			
		||||
			to:     "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "Plus+Is+Not+Space/and+it+is+valid.md",
 | 
			
		||||
			to:     "branch/Plus+Is+Not+Space/and+it+is+valid.md",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "ブランチ",
 | 
			
		||||
			to:     "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		// Tags
 | 
			
		||||
		{
 | 
			
		||||
			from:   "Тэг",
 | 
			
		||||
			to:     "tag/%d0%a2%d1%8d%d0%b3",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "Ё/人",
 | 
			
		||||
			to:     "tag/%d0%81/%e4%ba%ba",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "タグ",
 | 
			
		||||
			to:     "tag/%e3%82%bf%e3%82%b0",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "タグ/ファイル.md",
 | 
			
		||||
			to:     "tag/%e3%82%bf%e3%82%b0/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		// Files
 | 
			
		||||
		{
 | 
			
		||||
			from:   "README.md",
 | 
			
		||||
			to:     "branch/Plus+Is+Not+Space/README.md",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "Файл.md",
 | 
			
		||||
			to:     "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "ファイル.md",
 | 
			
		||||
			to:     "branch/Plus+Is+Not+Space/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
 | 
			
		||||
			status: http.StatusNotFound, // it's not on default branch
 | 
			
		||||
		},
 | 
			
		||||
		// Same but url-encoded (few tests)
 | 
			
		||||
		{
 | 
			
		||||
			from:   "%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81",
 | 
			
		||||
			to:     "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "%E3%82%BF%E3%82%b0",
 | 
			
		||||
			to:     "tag/%e3%82%bf%e3%82%b0",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "%D0%A4%D0%B0%D0%B9%D0%BB.md",
 | 
			
		||||
			to:     "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "%D0%81%2F%E4%BA%BA",
 | 
			
		||||
			to:     "tag/%d0%81/%e4%ba%ba",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			from:   "Ё%2F%E4%BA%BA",
 | 
			
		||||
			to:     "tag/%d0%81/%e4%ba%ba",
 | 
			
		||||
			status: http.StatusOK,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	prepareTestEnv(t)
 | 
			
		||||
 | 
			
		||||
	user := "user2"
 | 
			
		||||
	repo := "utf8"
 | 
			
		||||
	session := loginUser(t, user)
 | 
			
		||||
 | 
			
		||||
	setDefaultBranch(t, session, user, repo, "Plus+Is+Not+Space")
 | 
			
		||||
 | 
			
		||||
	for _, test := range testRedirects {
 | 
			
		||||
		testSrcRouteRedirect(t, session, user, repo, test.from, test.to, test.status)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setDefaultBranch(t, session, user, repo, "master")
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -33,6 +33,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
 | 
			
		||||
	prepareTestEnv(t)
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, "user2")
 | 
			
		||||
	token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
 | 
			
		||||
	// Request repository commits page
 | 
			
		||||
	req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
 | 
			
		||||
@@ -45,7 +46,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
 | 
			
		||||
	assert.NotEmpty(t, commitURL)
 | 
			
		||||
 | 
			
		||||
	// Call API to add status for commit
 | 
			
		||||
	req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL),
 | 
			
		||||
	req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL)+"?token="+token,
 | 
			
		||||
		api.CreateStatusOption{
 | 
			
		||||
			State:       api.StatusState(state),
 | 
			
		||||
			TargetURL:   "http://test.ci/",
 | 
			
		||||
 
 | 
			
		||||
@@ -524,12 +524,14 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	refName := git.RefEndName(opts.RefFullName)
 | 
			
		||||
	if repo.IsBare && refName != repo.DefaultBranch {
 | 
			
		||||
 | 
			
		||||
	// Change default branch and bare status only if pushed ref is non-empty branch.
 | 
			
		||||
	if repo.IsBare && opts.NewCommitID != git.EmptySHA && strings.HasPrefix(opts.RefFullName, git.BranchPrefix) {
 | 
			
		||||
		repo.DefaultBranch = refName
 | 
			
		||||
		repo.IsBare = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Change repository bare status and update last updated time.
 | 
			
		||||
	repo.IsBare = repo.IsBare && opts.Commits.Len <= 0
 | 
			
		||||
	if err = UpdateRepository(repo, false); err != nil {
 | 
			
		||||
		return fmt.Errorf("UpdateRepository: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -74,3 +74,38 @@
 | 
			
		||||
  type: 1
 | 
			
		||||
  config: "{}"
 | 
			
		||||
  created_unix: 1524304355
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 12
 | 
			
		||||
  repo_id: 33
 | 
			
		||||
  type: 1
 | 
			
		||||
  config: "{}"
 | 
			
		||||
  created_unix: 1535593231
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 13
 | 
			
		||||
  repo_id: 33
 | 
			
		||||
  type: 2
 | 
			
		||||
  config: "{\"EnableTimetracker\":true,\"AllowOnlyContributorsToTrackTime\":true}"
 | 
			
		||||
  created_unix: 1535593231
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 14
 | 
			
		||||
  repo_id: 33
 | 
			
		||||
  type: 3
 | 
			
		||||
  config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowSquash\":true}"
 | 
			
		||||
  created_unix: 1535593231
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 15
 | 
			
		||||
  repo_id: 33
 | 
			
		||||
  type: 4
 | 
			
		||||
  config: "{}"
 | 
			
		||||
  created_unix: 1535593231
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 16
 | 
			
		||||
  repo_id: 33
 | 
			
		||||
  type: 5
 | 
			
		||||
  config: "{}"
 | 
			
		||||
  created_unix: 1535593231
 | 
			
		||||
@@ -400,3 +400,10 @@
 | 
			
		||||
  num_forks: 0
 | 
			
		||||
  num_issues: 0
 | 
			
		||||
  is_mirror: false
 | 
			
		||||
 | 
			
		||||
-
 | 
			
		||||
  id: 33
 | 
			
		||||
  owner_id: 2
 | 
			
		||||
  lower_name: utf8
 | 
			
		||||
  name: utf8
 | 
			
		||||
  is_private: false
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
  is_admin: false
 | 
			
		||||
  avatar: avatar2
 | 
			
		||||
  avatar_email: user2@example.com
 | 
			
		||||
  num_repos: 5
 | 
			
		||||
  num_repos: 6
 | 
			
		||||
  num_stars: 2
 | 
			
		||||
  num_followers: 2
 | 
			
		||||
  num_following: 1
 | 
			
		||||
 
 | 
			
		||||
@@ -360,7 +360,7 @@ func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error {
 | 
			
		||||
 | 
			
		||||
// ParseCommitWithSignature check if signature is good against keystore.
 | 
			
		||||
func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
 | 
			
		||||
	if c.Signature != nil {
 | 
			
		||||
	if c.Signature != nil && c.Committer != nil {
 | 
			
		||||
		//Parsing signature
 | 
			
		||||
		sig, err := extractSignature(c.Signature.Signature)
 | 
			
		||||
		if err != nil { //Skipping failed to extract sign
 | 
			
		||||
 
 | 
			
		||||
@@ -1852,6 +1852,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
 | 
			
		||||
		if _, err = sess.In("issue_id", issueIDs).Delete(&IssueWatch{}); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if _, err = sess.In("issue_id", issueIDs).Delete(&Stopwatch{}); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		attachments := make([]*Attachment, 0, 5)
 | 
			
		||||
		if err = sess.
 | 
			
		||||
 
 | 
			
		||||
@@ -147,10 +147,10 @@ func TestSearchRepositoryByName(t *testing.T) {
 | 
			
		||||
			count: 14},
 | 
			
		||||
		{name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
 | 
			
		||||
			opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, AllPublic: true},
 | 
			
		||||
			count: 16},
 | 
			
		||||
			count: 17},
 | 
			
		||||
		{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
 | 
			
		||||
			opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
 | 
			
		||||
			count: 20},
 | 
			
		||||
			count: 21},
 | 
			
		||||
		{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
 | 
			
		||||
			opts:  &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
 | 
			
		||||
			count: 13},
 | 
			
		||||
@@ -159,7 +159,7 @@ func TestSearchRepositoryByName(t *testing.T) {
 | 
			
		||||
			count: 11},
 | 
			
		||||
		{name: "AllPublic/PublicRepositoriesOfOrganization",
 | 
			
		||||
			opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse},
 | 
			
		||||
			count: 16},
 | 
			
		||||
			count: 17},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, testCase := range testCases {
 | 
			
		||||
 
 | 
			
		||||
@@ -213,6 +213,7 @@ func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPaylo
 | 
			
		||||
func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPayload, error) {
 | 
			
		||||
	var text, title string
 | 
			
		||||
	var color int
 | 
			
		||||
	url := fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index)
 | 
			
		||||
	switch p.Action {
 | 
			
		||||
	case api.HookIssueOpened:
 | 
			
		||||
		title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
 | 
			
		||||
@@ -268,7 +269,7 @@ func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPa
 | 
			
		||||
			{
 | 
			
		||||
				Title:       title,
 | 
			
		||||
				Description: text,
 | 
			
		||||
				URL:         p.Issue.URL,
 | 
			
		||||
				URL:         url,
 | 
			
		||||
				Color:       color,
 | 
			
		||||
				Author: DiscordEmbedAuthor{
 | 
			
		||||
					Name:    p.Sender.UserName,
 | 
			
		||||
 
 | 
			
		||||
@@ -63,6 +63,7 @@ func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
 | 
			
		||||
			if err = models.UpdateAccessToken(t); err != nil {
 | 
			
		||||
				log.Error(4, "UpdateAccessToken: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			ctx.Data["IsApiToken"] = true
 | 
			
		||||
			return t.UID
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -136,7 +137,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
 | 
			
		||||
				}
 | 
			
		||||
				return nil, false
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ctx.Data["IsApiToken"] = true
 | 
			
		||||
			return u, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,22 @@ func DetectEncoding(content []byte) (string, error) {
 | 
			
		||||
		return "UTF-8", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := chardet.NewTextDetector().DetectBest(content)
 | 
			
		||||
	textDetector := chardet.NewTextDetector()
 | 
			
		||||
	var detectContent []byte
 | 
			
		||||
	if len(content) < 1024 {
 | 
			
		||||
		// Check if original content is valid
 | 
			
		||||
		if _, err := textDetector.DetectBest(content); err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		times := 1024 / len(content)
 | 
			
		||||
		detectContent = make([]byte, 0, times*len(content))
 | 
			
		||||
		for i := 0; i < times; i++ {
 | 
			
		||||
			detectContent = append(detectContent, content...)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		detectContent = content
 | 
			
		||||
	}
 | 
			
		||||
	result, err := textDetector.DetectBest(detectContent)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -620,7 +620,7 @@ func RepoRefByType(refType RepoRefType) macaron.Handler {
 | 
			
		||||
				// redirect from old URL scheme to new URL scheme
 | 
			
		||||
				ctx.Redirect(path.Join(
 | 
			
		||||
					setting.AppSubURL,
 | 
			
		||||
					strings.TrimSuffix(ctx.Req.URL.String(), ctx.Params("*")),
 | 
			
		||||
					strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*")),
 | 
			
		||||
					ctx.Repo.BranchNameSubURL(),
 | 
			
		||||
					ctx.Repo.TreePath))
 | 
			
		||||
				return
 | 
			
		||||
 
 | 
			
		||||
@@ -1112,7 +1112,7 @@ func NewContext() {
 | 
			
		||||
 | 
			
		||||
	extensionReg := regexp.MustCompile(`\.\w`)
 | 
			
		||||
	for _, sec := range Cfg.Section("markup").ChildSections() {
 | 
			
		||||
		name := strings.TrimLeft(sec.Name(), "markup.")
 | 
			
		||||
		name := strings.TrimPrefix(sec.Name(), "markup.")
 | 
			
		||||
		if name == "" {
 | 
			
		||||
			log.Warn("name is empty, markup " + sec.Name() + "ignored")
 | 
			
		||||
			continue
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
// Copyright 2018 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
@@ -243,7 +244,7 @@ func ToUTF8WithErr(content []byte) (string, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If there is an error, we concatenate the nicely decoded part and the
 | 
			
		||||
	// original left over. This way we won't loose data.
 | 
			
		||||
	// original left over. This way we won't lose data.
 | 
			
		||||
	result, n, err := transform.String(encoding.NewDecoder(), string(content))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		result = result + string(content[n:])
 | 
			
		||||
@@ -252,6 +253,28 @@ func ToUTF8WithErr(content []byte) (string, error) {
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToUTF8WithFallback detects the encoding of content and coverts to UTF-8 if possible
 | 
			
		||||
func ToUTF8WithFallback(content []byte) []byte {
 | 
			
		||||
	charsetLabel, err := base.DetectEncoding(content)
 | 
			
		||||
	if err != nil || charsetLabel == "UTF-8" {
 | 
			
		||||
		return content
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	encoding, _ := charset.Lookup(charsetLabel)
 | 
			
		||||
	if encoding == nil {
 | 
			
		||||
		return content
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If there is an error, we concatenate the nicely decoded part and the
 | 
			
		||||
	// original left over. This way we won't lose data.
 | 
			
		||||
	result, n, err := transform.Bytes(encoding.NewDecoder(), content)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return append(result, content[n:]...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToUTF8 converts content to UTF8 encoding and ignore error
 | 
			
		||||
func ToUTF8(content string) string {
 | 
			
		||||
	res, _ := ToUTF8WithErr([]byte(content))
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -2309,7 +2309,7 @@ function initTopicbar() {
 | 
			
		||||
 | 
			
		||||
    mgrBtn.click(function() {
 | 
			
		||||
        viewDiv.hide();
 | 
			
		||||
        editDiv.show();
 | 
			
		||||
        editDiv.css('display', ''); // show Semantic UI Grid
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    saveBtn.click(function() {
 | 
			
		||||
@@ -2334,7 +2334,7 @@ function initTopicbar() {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }).done(function() {
 | 
			
		||||
            editDiv.hide();
 | 
			
		||||
            editDiv.css('display', 'none'); // hide Semantic UI Grid
 | 
			
		||||
            viewDiv.show();
 | 
			
		||||
        }).fail(function(xhr) {
 | 
			
		||||
            alert(xhr.responseJSON.message)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,9 @@ body {
 | 
			
		||||
img {
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
}
 | 
			
		||||
table {
 | 
			
		||||
    border-collapse: collapse;
 | 
			
		||||
}
 | 
			
		||||
.rounded {
 | 
			
		||||
    border-radius: .28571429rem !important;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1743,7 +1743,6 @@ tbody.commit-list {
 | 
			
		||||
 | 
			
		||||
#topic_edit {
 | 
			
		||||
    margin-top:5px;
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#repo-topic {
 | 
			
		||||
 
 | 
			
		||||
@@ -132,7 +132,7 @@ func repoAssignment() macaron.Handler {
 | 
			
		||||
// Contexter middleware already checks token for user sign in process.
 | 
			
		||||
func reqToken() macaron.Handler {
 | 
			
		||||
	return func(ctx *context.Context) {
 | 
			
		||||
		if !ctx.IsSigned {
 | 
			
		||||
		if true != ctx.Data["IsApiToken"] {
 | 
			
		||||
			ctx.Error(401)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
@@ -273,6 +273,14 @@ func mustAllowPulls(ctx *context.Context) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mustEnableIssuesOrPulls(ctx *context.Context) {
 | 
			
		||||
	if !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) &&
 | 
			
		||||
		!ctx.Repo.Repository.AllowsPulls() {
 | 
			
		||||
		ctx.Status(404)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RegisterRoutes registers all v1 APIs routes to web application.
 | 
			
		||||
// FIXME: custom form error response
 | 
			
		||||
func RegisterRoutes(m *macaron.Macaron) {
 | 
			
		||||
@@ -447,7 +455,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
			
		||||
								Post(reqToken(), bind(api.AddTimeOption{}), repo.AddTime)
 | 
			
		||||
						})
 | 
			
		||||
					})
 | 
			
		||||
				}, mustEnableIssues)
 | 
			
		||||
				}, mustEnableIssuesOrPulls)
 | 
			
		||||
				m.Group("/labels", func() {
 | 
			
		||||
					m.Combo("").Get(repo.ListLabels).
 | 
			
		||||
						Post(reqToken(), bind(api.CreateLabelOption{}), repo.CreateLabel)
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/markup"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/templates"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/paginater"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -99,7 +100,8 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 | 
			
		||||
				ctx.Data["FileSize"] = readmeFile.Size()
 | 
			
		||||
			} else {
 | 
			
		||||
				d, _ := ioutil.ReadAll(dataRc)
 | 
			
		||||
				buf = append(buf, d...)
 | 
			
		||||
				buf = templates.ToUTF8WithFallback(append(buf, d...))
 | 
			
		||||
 | 
			
		||||
				if markup.Type(readmeFile.Name()) != "" {
 | 
			
		||||
					ctx.Data["IsMarkup"] = true
 | 
			
		||||
					ctx.Data["FileContent"] = string(markup.Render(readmeFile.Name(), buf, treeLink, ctx.Repo.Repository.ComposeMetas()))
 | 
			
		||||
@@ -201,7 +203,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		d, _ := ioutil.ReadAll(dataRc)
 | 
			
		||||
		buf = append(buf, d...)
 | 
			
		||||
		buf = templates.ToUTF8WithFallback(append(buf, d...))
 | 
			
		||||
 | 
			
		||||
		readmeExist := markup.IsReadmeFile(blob.Name())
 | 
			
		||||
		ctx.Data["ReadmeExist"] = readmeExist
 | 
			
		||||
 
 | 
			
		||||
@@ -28,17 +28,17 @@
 | 
			
		||||
		{{if .IsRepositoryAdmin}}<a id="manage_topic" style="cursor:pointer;margin-left:10px;">{{.i18n.Tr "repo.topic.manage_topics"}}</a>{{end}}
 | 
			
		||||
		</div>
 | 
			
		||||
		{{if .IsRepositoryAdmin}}
 | 
			
		||||
		<div class="ui repo-topic-edit grid" id="topic_edit" >
 | 
			
		||||
		<div class="ui repo-topic-edit grid" id="topic_edit" style="display:none">
 | 
			
		||||
			<div class="fourteen wide column">
 | 
			
		||||
				<div class="ui fluid multiple search selection dropdown">
 | 
			
		||||
					<input type="hidden" name="topics" value="{{range $i, $v := .Topics}}{{.Name}}{{if lt (Add $i 1) (len $.Topics)}},{{end}}{{end}}">
 | 
			
		||||
					{{range .Topics}}
 | 
			
		||||
					<a class="ui green basic label topic transition visible" data-value="{{.Name}}" style="display: inline-block !important;">{{.Name}}<i class="delete icon"></i></a>
 | 
			
		||||
					<div class="ui green basic label topic transition visible" data-value="{{.Name}}" style="display: inline-block !important; cursor: default;">{{.Name}}<i class="delete icon"></i></div>
 | 
			
		||||
					{{end}}
 | 
			
		||||
					<div class="text"></div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="one wide column">
 | 
			
		||||
			<div class="two wide column">
 | 
			
		||||
				<a class="ui compact button primary" href="javascript:;" id="save_topic"
 | 
			
		||||
				data-link="{{.RepoLink}}/topics">{{.i18n.Tr "repo.topic.done"}}</a>
 | 
			
		||||
			</div>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								vendor/github.com/go-macaron/session/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/go-macaron/session/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -86,7 +86,7 @@ func (s *FileStore) Release() error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ioutil.WriteFile(s.p.filepath(s.sid), data, os.ModePerm)
 | 
			
		||||
	return ioutil.WriteFile(s.p.filepath(s.sid), data, 0600)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Flush deletes all session data.
 | 
			
		||||
@@ -121,7 +121,7 @@ func (p *FileProvider) filepath(sid string) string {
 | 
			
		||||
// Read returns raw session store by session ID.
 | 
			
		||||
func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
 | 
			
		||||
	filename := p.filepath(sid)
 | 
			
		||||
	if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
 | 
			
		||||
	if err = os.MkdirAll(path.Dir(filename), 0700); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	p.lock.RLock()
 | 
			
		||||
@@ -129,7 +129,7 @@ func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
 | 
			
		||||
 | 
			
		||||
	var f *os.File
 | 
			
		||||
	if com.IsFile(filename) {
 | 
			
		||||
		f, err = os.OpenFile(filename, os.O_RDWR, os.ModePerm)
 | 
			
		||||
		f, err = os.OpenFile(filename, os.O_RDONLY, 0600)
 | 
			
		||||
	} else {
 | 
			
		||||
		f, err = os.Create(filename)
 | 
			
		||||
	}
 | 
			
		||||
@@ -187,15 +187,15 @@ func (p *FileProvider) regenerate(oldsid, sid string) (err error) {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if err = os.MkdirAll(path.Dir(oldname), os.ModePerm); err != nil {
 | 
			
		||||
		if err = os.MkdirAll(path.Dir(oldname), 0700); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if err = ioutil.WriteFile(oldname, data, os.ModePerm); err != nil {
 | 
			
		||||
		if err = ioutil.WriteFile(oldname, data, 0600); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
 | 
			
		||||
	if err = os.MkdirAll(path.Dir(filename), 0700); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err = os.Rename(oldname, filename); err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/go-macaron/session/session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/go-macaron/session/session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -18,15 +18,17 @@ package session
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gopkg.in/macaron.v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const _VERSION = "0.3.0"
 | 
			
		||||
const _VERSION = "0.4.0"
 | 
			
		||||
 | 
			
		||||
func Version() string {
 | 
			
		||||
	return _VERSION
 | 
			
		||||
@@ -245,8 +247,8 @@ func NewManager(name string, opt Options) (*Manager, error) {
 | 
			
		||||
	return &Manager{p, opt}, p.Init(opt.Maxlifetime, opt.ProviderConfig)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sessionId generates a new session ID with rand string, unix nano time, remote addr by hash function.
 | 
			
		||||
func (m *Manager) sessionId() string {
 | 
			
		||||
// sessionID generates a new session ID with rand string, unix nano time, remote addr by hash function.
 | 
			
		||||
func (m *Manager) sessionID() string {
 | 
			
		||||
	return hex.EncodeToString(generateRandomKey(m.opt.IDLength / 2))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -255,10 +257,10 @@ func (m *Manager) sessionId() string {
 | 
			
		||||
func (m *Manager) Start(ctx *macaron.Context) (RawStore, error) {
 | 
			
		||||
	sid := ctx.GetCookie(m.opt.CookieName)
 | 
			
		||||
	if len(sid) > 0 && m.provider.Exist(sid) {
 | 
			
		||||
		return m.provider.Read(sid)
 | 
			
		||||
		return m.Read(sid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sid = m.sessionId()
 | 
			
		||||
	sid = m.sessionID()
 | 
			
		||||
	sess, err := m.provider.Read(sid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
@@ -282,6 +284,12 @@ func (m *Manager) Start(ctx *macaron.Context) (RawStore, error) {
 | 
			
		||||
 | 
			
		||||
// Read returns raw session store by session ID.
 | 
			
		||||
func (m *Manager) Read(sid string) (RawStore, error) {
 | 
			
		||||
	// No slashes or dots "./" should ever occur in the sid and to prevent session file forgery bug.
 | 
			
		||||
	// See https://github.com/gogs/gogs/issues/5469
 | 
			
		||||
	if strings.ContainsAny(sid, "./") {
 | 
			
		||||
		return nil, errors.New("invalid 'sid': " + sid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return m.provider.Read(sid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -308,7 +316,7 @@ func (m *Manager) Destory(ctx *macaron.Context) error {
 | 
			
		||||
 | 
			
		||||
// RegenerateId regenerates a session store from old session ID to new one.
 | 
			
		||||
func (m *Manager) RegenerateId(ctx *macaron.Context) (sess RawStore, err error) {
 | 
			
		||||
	sid := m.sessionId()
 | 
			
		||||
	sid := m.sessionID()
 | 
			
		||||
	oldsid := ctx.GetCookie(m.opt.CookieName)
 | 
			
		||||
	sess, err = m.provider.Regenerate(oldsid, sid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user