mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-03 21:08:25 +00:00 
			
		
		
		
	Add latest commit's SHA to content response (#20398)
* Add latest commit's SHA to content response - When requesting the contents of a filepath, add the latest commit's SHA to the requested file. - Resolves #12840 * Add swagger * Fix NPE * Fix tests * Hook into LastCommitCache * Move AddLastCommitCache to a common nogogit and gogit file Signed-off-by: Andrew Thornton <art27@cantab.net> * Prevent NPE Co-authored-by: Andrew Thornton <art27@cantab.net> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		@@ -50,7 +50,7 @@ func getCreateFileOptions() api.CreateFileOptions {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getExpectedFileResponseForCreate(repoFullName, commitID, treePath string) *api.FileResponse {
 | 
					func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCommitSHA string) *api.FileResponse {
 | 
				
			||||||
	sha := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
 | 
						sha := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
 | 
				
			||||||
	encoding := "base64"
 | 
						encoding := "base64"
 | 
				
			||||||
	content := "VGhpcyBpcyBuZXcgdGV4dA=="
 | 
						content := "VGhpcyBpcyBuZXcgdGV4dA=="
 | 
				
			||||||
@@ -63,6 +63,7 @@ func getExpectedFileResponseForCreate(repoFullName, commitID, treePath string) *
 | 
				
			|||||||
			Name:          filepath.Base(treePath),
 | 
								Name:          filepath.Base(treePath),
 | 
				
			||||||
			Path:          treePath,
 | 
								Path:          treePath,
 | 
				
			||||||
			SHA:           sha,
 | 
								SHA:           sha,
 | 
				
			||||||
 | 
								LastCommitSHA: latestCommitSHA,
 | 
				
			||||||
			Size:          16,
 | 
								Size:          16,
 | 
				
			||||||
			Type:          "file",
 | 
								Type:          "file",
 | 
				
			||||||
			Encoding:      &encoding,
 | 
								Encoding:      &encoding,
 | 
				
			||||||
@@ -170,7 +171,8 @@ func TestAPICreateFile(t *testing.T) {
 | 
				
			|||||||
			resp := session.MakeRequest(t, req, http.StatusCreated)
 | 
								resp := session.MakeRequest(t, req, http.StatusCreated)
 | 
				
			||||||
			gitRepo, _ := git.OpenRepository(stdCtx.Background(), repo1.RepoPath())
 | 
								gitRepo, _ := git.OpenRepository(stdCtx.Background(), repo1.RepoPath())
 | 
				
			||||||
			commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
 | 
								commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
 | 
				
			||||||
			expectedFileResponse := getExpectedFileResponseForCreate("user2/repo1", commitID, treePath)
 | 
								latestCommit, _ := gitRepo.GetCommitByPath(treePath)
 | 
				
			||||||
 | 
								expectedFileResponse := getExpectedFileResponseForCreate("user2/repo1", commitID, treePath, latestCommit.ID.String())
 | 
				
			||||||
			var fileResponse api.FileResponse
 | 
								var fileResponse api.FileResponse
 | 
				
			||||||
			DecodeJSON(t, resp, &fileResponse)
 | 
								DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
			assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
								assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
@@ -289,7 +291,8 @@ func TestAPICreateFile(t *testing.T) {
 | 
				
			|||||||
		emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}).(*repo_model.Repository) // public repo
 | 
							emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}).(*repo_model.Repository) // public repo
 | 
				
			||||||
		gitRepo, _ := git.OpenRepository(stdCtx.Background(), emptyRepo.RepoPath())
 | 
							gitRepo, _ := git.OpenRepository(stdCtx.Background(), emptyRepo.RepoPath())
 | 
				
			||||||
		commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
 | 
							commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
 | 
				
			||||||
		expectedFileResponse := getExpectedFileResponseForCreate("user2/empty-repo", commitID, treePath)
 | 
							latestCommit, _ := gitRepo.GetCommitByPath(treePath)
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForCreate("user2/empty-repo", commitID, treePath, latestCommit.ID.String())
 | 
				
			||||||
		DecodeJSON(t, resp, &fileResponse)
 | 
							DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
							assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,7 @@ func getUpdateFileOptions() *api.UpdateFileOptions {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileResponse {
 | 
					func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string) *api.FileResponse {
 | 
				
			||||||
	sha := "08bd14b2e2852529157324de9c226b3364e76136"
 | 
						sha := "08bd14b2e2852529157324de9c226b3364e76136"
 | 
				
			||||||
	encoding := "base64"
 | 
						encoding := "base64"
 | 
				
			||||||
	content := "VGhpcyBpcyB1cGRhdGVkIHRleHQ="
 | 
						content := "VGhpcyBpcyB1cGRhdGVkIHRleHQ="
 | 
				
			||||||
@@ -61,6 +61,7 @@ func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileRespon
 | 
				
			|||||||
			Name:          filepath.Base(treePath),
 | 
								Name:          filepath.Base(treePath),
 | 
				
			||||||
			Path:          treePath,
 | 
								Path:          treePath,
 | 
				
			||||||
			SHA:           sha,
 | 
								SHA:           sha,
 | 
				
			||||||
 | 
								LastCommitSHA: lastCommitSHA,
 | 
				
			||||||
			Type:          "file",
 | 
								Type:          "file",
 | 
				
			||||||
			Size:          20,
 | 
								Size:          20,
 | 
				
			||||||
			Encoding:      &encoding,
 | 
								Encoding:      &encoding,
 | 
				
			||||||
@@ -137,7 +138,8 @@ func TestAPIUpdateFile(t *testing.T) {
 | 
				
			|||||||
			resp := session.MakeRequest(t, req, http.StatusOK)
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
			gitRepo, _ := git.OpenRepository(stdCtx.Background(), repo1.RepoPath())
 | 
								gitRepo, _ := git.OpenRepository(stdCtx.Background(), repo1.RepoPath())
 | 
				
			||||||
			commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName)
 | 
								commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName)
 | 
				
			||||||
			expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath)
 | 
								lasCommit, _ := gitRepo.GetCommitByPath(treePath)
 | 
				
			||||||
 | 
								expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath, lasCommit.ID.String())
 | 
				
			||||||
			var fileResponse api.FileResponse
 | 
								var fileResponse api.FileResponse
 | 
				
			||||||
			DecodeJSON(t, resp, &fileResponse)
 | 
								DecodeJSON(t, resp, &fileResponse)
 | 
				
			||||||
			assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
								assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ import (
 | 
				
			|||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getExpectedContentsListResponseForContents(ref, refType string) []*api.ContentsResponse {
 | 
					func getExpectedContentsListResponseForContents(ref, refType, lastCommitSHA string) []*api.ContentsResponse {
 | 
				
			||||||
	treePath := "README.md"
 | 
						treePath := "README.md"
 | 
				
			||||||
	sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
 | 
						sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
 | 
				
			||||||
	selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=" + ref
 | 
						selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=" + ref
 | 
				
			||||||
@@ -33,6 +33,7 @@ func getExpectedContentsListResponseForContents(ref, refType string) []*api.Cont
 | 
				
			|||||||
			Name:          filepath.Base(treePath),
 | 
								Name:          filepath.Base(treePath),
 | 
				
			||||||
			Path:          treePath,
 | 
								Path:          treePath,
 | 
				
			||||||
			SHA:           sha,
 | 
								SHA:           sha,
 | 
				
			||||||
 | 
								LastCommitSHA: lastCommitSHA,
 | 
				
			||||||
			Type:          "file",
 | 
								Type:          "file",
 | 
				
			||||||
			Size:          30,
 | 
								Size:          30,
 | 
				
			||||||
			URL:           &selfURL,
 | 
								URL:           &selfURL,
 | 
				
			||||||
@@ -94,7 +95,9 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	var contentsListResponse []*api.ContentsResponse
 | 
						var contentsListResponse []*api.ContentsResponse
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsListResponse)
 | 
						DecodeJSON(t, resp, &contentsListResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsListResponse)
 | 
						assert.NotNil(t, contentsListResponse)
 | 
				
			||||||
	expectedContentsListResponse := getExpectedContentsListResponseForContents(ref, refType)
 | 
						lastCommit, err := gitRepo.GetCommitByPath("README.md")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						expectedContentsListResponse := getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
 | 
				
			||||||
	assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
						assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// No ref
 | 
						// No ref
 | 
				
			||||||
@@ -103,7 +106,8 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsListResponse)
 | 
						DecodeJSON(t, resp, &contentsListResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsListResponse)
 | 
						assert.NotNil(t, contentsListResponse)
 | 
				
			||||||
	expectedContentsListResponse = getExpectedContentsListResponseForContents(repo1.DefaultBranch, refType)
 | 
					
 | 
				
			||||||
 | 
						expectedContentsListResponse = getExpectedContentsListResponseForContents(repo1.DefaultBranch, refType, lastCommit.ID.String())
 | 
				
			||||||
	assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
						assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ref is the branch we created above in setup
 | 
						// ref is the branch we created above in setup
 | 
				
			||||||
@@ -113,7 +117,11 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsListResponse)
 | 
						DecodeJSON(t, resp, &contentsListResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsListResponse)
 | 
						assert.NotNil(t, contentsListResponse)
 | 
				
			||||||
	expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType)
 | 
						branchCommit, err := gitRepo.GetBranchCommit(ref)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						lastCommit, err = branchCommit.GetCommitByPath("README.md")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
 | 
				
			||||||
	assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
						assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ref is the new tag we created above in setup
 | 
						// ref is the new tag we created above in setup
 | 
				
			||||||
@@ -123,7 +131,11 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsListResponse)
 | 
						DecodeJSON(t, resp, &contentsListResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsListResponse)
 | 
						assert.NotNil(t, contentsListResponse)
 | 
				
			||||||
	expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType)
 | 
						tagCommit, err := gitRepo.GetTagCommit(ref)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						lastCommit, err = tagCommit.GetCommitByPath("README.md")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
 | 
				
			||||||
	assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
						assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ref is a commit
 | 
						// ref is a commit
 | 
				
			||||||
@@ -133,7 +145,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsListResponse)
 | 
						DecodeJSON(t, resp, &contentsListResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsListResponse)
 | 
						assert.NotNil(t, contentsListResponse)
 | 
				
			||||||
	expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType)
 | 
						expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, commitID)
 | 
				
			||||||
	assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
						assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test file contents a file with a bad ref
 | 
						// Test file contents a file with a bad ref
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ import (
 | 
				
			|||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getExpectedContentsResponseForContents(ref, refType string) *api.ContentsResponse {
 | 
					func getExpectedContentsResponseForContents(ref, refType, lastCommitSHA string) *api.ContentsResponse {
 | 
				
			||||||
	treePath := "README.md"
 | 
						treePath := "README.md"
 | 
				
			||||||
	sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
 | 
						sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
 | 
				
			||||||
	encoding := "base64"
 | 
						encoding := "base64"
 | 
				
			||||||
@@ -33,6 +33,7 @@ func getExpectedContentsResponseForContents(ref, refType string) *api.ContentsRe
 | 
				
			|||||||
		Name:          treePath,
 | 
							Name:          treePath,
 | 
				
			||||||
		Path:          treePath,
 | 
							Path:          treePath,
 | 
				
			||||||
		SHA:           sha,
 | 
							SHA:           sha,
 | 
				
			||||||
 | 
							LastCommitSHA: lastCommitSHA,
 | 
				
			||||||
		Type:          "file",
 | 
							Type:          "file",
 | 
				
			||||||
		Size:          30,
 | 
							Size:          30,
 | 
				
			||||||
		Encoding:      &encoding,
 | 
							Encoding:      &encoding,
 | 
				
			||||||
@@ -96,7 +97,8 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	var contentsResponse api.ContentsResponse
 | 
						var contentsResponse api.ContentsResponse
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsResponse)
 | 
						DecodeJSON(t, resp, &contentsResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsResponse)
 | 
						assert.NotNil(t, contentsResponse)
 | 
				
			||||||
	expectedContentsResponse := getExpectedContentsResponseForContents(ref, refType)
 | 
						lastCommit, _ := gitRepo.GetCommitByPath("README.md")
 | 
				
			||||||
 | 
						expectedContentsResponse := getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
 | 
				
			||||||
	assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
						assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// No ref
 | 
						// No ref
 | 
				
			||||||
@@ -105,7 +107,7 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsResponse)
 | 
						DecodeJSON(t, resp, &contentsResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsResponse)
 | 
						assert.NotNil(t, contentsResponse)
 | 
				
			||||||
	expectedContentsResponse = getExpectedContentsResponseForContents(repo1.DefaultBranch, refType)
 | 
						expectedContentsResponse = getExpectedContentsResponseForContents(repo1.DefaultBranch, refType, lastCommit.ID.String())
 | 
				
			||||||
	assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
						assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ref is the branch we created above  in setup
 | 
						// ref is the branch we created above  in setup
 | 
				
			||||||
@@ -115,7 +117,9 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsResponse)
 | 
						DecodeJSON(t, resp, &contentsResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsResponse)
 | 
						assert.NotNil(t, contentsResponse)
 | 
				
			||||||
	expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType)
 | 
						branchCommit, _ := gitRepo.GetBranchCommit(ref)
 | 
				
			||||||
 | 
						lastCommit, _ = branchCommit.GetCommitByPath("README.md")
 | 
				
			||||||
 | 
						expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
 | 
				
			||||||
	assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
						assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ref is the new tag we created above in setup
 | 
						// ref is the new tag we created above in setup
 | 
				
			||||||
@@ -125,7 +129,9 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsResponse)
 | 
						DecodeJSON(t, resp, &contentsResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsResponse)
 | 
						assert.NotNil(t, contentsResponse)
 | 
				
			||||||
	expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType)
 | 
						tagCommit, _ := gitRepo.GetTagCommit(ref)
 | 
				
			||||||
 | 
						lastCommit, _ = tagCommit.GetCommitByPath("README.md")
 | 
				
			||||||
 | 
						expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
 | 
				
			||||||
	assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
						assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ref is a commit
 | 
						// ref is a commit
 | 
				
			||||||
@@ -135,7 +141,7 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
 | 
				
			|||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	DecodeJSON(t, resp, &contentsResponse)
 | 
						DecodeJSON(t, resp, &contentsResponse)
 | 
				
			||||||
	assert.NotNil(t, contentsResponse)
 | 
						assert.NotNil(t, contentsResponse)
 | 
				
			||||||
	expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType)
 | 
						expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, commitID)
 | 
				
			||||||
	assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
						assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test file contents a file with a bad ref
 | 
						// Test file contents a file with a bad ref
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ func getUpdateRepoFileOptions(repo *repo_model.Repository) *files_service.Update
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileResponse {
 | 
					func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *api.FileResponse {
 | 
				
			||||||
	treePath := "new/file.txt"
 | 
						treePath := "new/file.txt"
 | 
				
			||||||
	encoding := "base64"
 | 
						encoding := "base64"
 | 
				
			||||||
	content := "VGhpcyBpcyBhIE5FVyBmaWxl"
 | 
						content := "VGhpcyBpcyBhIE5FVyBmaWxl"
 | 
				
			||||||
@@ -60,6 +60,7 @@ func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileRespons
 | 
				
			|||||||
			Name:          filepath.Base(treePath),
 | 
								Name:          filepath.Base(treePath),
 | 
				
			||||||
			Path:          treePath,
 | 
								Path:          treePath,
 | 
				
			||||||
			SHA:           "103ff9234cefeee5ec5361d22b49fbb04d385885",
 | 
								SHA:           "103ff9234cefeee5ec5361d22b49fbb04d385885",
 | 
				
			||||||
 | 
								LastCommitSHA: lastCommitSHA,
 | 
				
			||||||
			Type:          "file",
 | 
								Type:          "file",
 | 
				
			||||||
			Size:          18,
 | 
								Size:          18,
 | 
				
			||||||
			Encoding:      &encoding,
 | 
								Encoding:      &encoding,
 | 
				
			||||||
@@ -115,7 +116,7 @@ func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileRespons
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getExpectedFileResponseForRepofilesUpdate(commitID, filename string) *api.FileResponse {
 | 
					func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA string) *api.FileResponse {
 | 
				
			||||||
	encoding := "base64"
 | 
						encoding := "base64"
 | 
				
			||||||
	content := "VGhpcyBpcyBVUERBVEVEIGNvbnRlbnQgZm9yIHRoZSBSRUFETUUgZmlsZQ=="
 | 
						content := "VGhpcyBpcyBVUERBVEVEIGNvbnRlbnQgZm9yIHRoZSBSRUFETUUgZmlsZQ=="
 | 
				
			||||||
	selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + filename + "?ref=master"
 | 
						selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + filename + "?ref=master"
 | 
				
			||||||
@@ -127,6 +128,7 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename string) *api.F
 | 
				
			|||||||
			Name:          filename,
 | 
								Name:          filename,
 | 
				
			||||||
			Path:          filename,
 | 
								Path:          filename,
 | 
				
			||||||
			SHA:           "dbf8d00e022e05b7e5cf7e535de857de57925647",
 | 
								SHA:           "dbf8d00e022e05b7e5cf7e535de857de57925647",
 | 
				
			||||||
 | 
								LastCommitSHA: lastCommitSHA,
 | 
				
			||||||
			Type:          "file",
 | 
								Type:          "file",
 | 
				
			||||||
			Size:          43,
 | 
								Size:          43,
 | 
				
			||||||
			Encoding:      &encoding,
 | 
								Encoding:      &encoding,
 | 
				
			||||||
@@ -206,7 +208,8 @@ func TestCreateOrUpdateRepoFileForCreate(t *testing.T) {
 | 
				
			|||||||
		defer gitRepo.Close()
 | 
							defer gitRepo.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
 | 
							commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
 | 
				
			||||||
		expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID)
 | 
							lastCommit, _ := gitRepo.GetCommitByPath("new/file.txt")
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID, lastCommit.ID.String())
 | 
				
			||||||
		assert.NotNil(t, expectedFileResponse)
 | 
							assert.NotNil(t, expectedFileResponse)
 | 
				
			||||||
		if expectedFileResponse != nil {
 | 
							if expectedFileResponse != nil {
 | 
				
			||||||
			assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
								assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
@@ -241,8 +244,9 @@ func TestCreateOrUpdateRepoFileForUpdate(t *testing.T) {
 | 
				
			|||||||
		gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
 | 
							gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
 | 
				
			||||||
		defer gitRepo.Close()
 | 
							defer gitRepo.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
 | 
							commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
 | 
				
			||||||
		expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID, opts.TreePath)
 | 
							lastCommit, _ := commit.GetCommitByPath(opts.TreePath)
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath, lastCommit.ID.String())
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
							assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
							assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
 | 
				
			||||||
@@ -277,7 +281,8 @@ func TestCreateOrUpdateRepoFileForUpdateWithFileMove(t *testing.T) {
 | 
				
			|||||||
		defer gitRepo.Close()
 | 
							defer gitRepo.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
 | 
							commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
 | 
				
			||||||
		expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath)
 | 
							lastCommit, _ := commit.GetCommitByPath(opts.TreePath)
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath, lastCommit.ID.String())
 | 
				
			||||||
		// assert that the old file no longer exists in the last commit of the branch
 | 
							// assert that the old file no longer exists in the last commit of the branch
 | 
				
			||||||
		fromEntry, err := commit.GetTreeEntryByPath(opts.FromTreePath)
 | 
							fromEntry, err := commit.GetTreeEntryByPath(opts.FromTreePath)
 | 
				
			||||||
		switch err.(type) {
 | 
							switch err.(type) {
 | 
				
			||||||
@@ -326,8 +331,9 @@ func TestCreateOrUpdateRepoFileWithoutBranchNames(t *testing.T) {
 | 
				
			|||||||
		gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
 | 
							gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
 | 
				
			||||||
		defer gitRepo.Close()
 | 
							defer gitRepo.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		commitID, _ := gitRepo.GetBranchCommitID(repo.DefaultBranch)
 | 
							commit, _ := gitRepo.GetBranchCommit(repo.DefaultBranch)
 | 
				
			||||||
		expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commitID, opts.TreePath)
 | 
							lastCommit, _ := commit.GetCommitByPath(opts.TreePath)
 | 
				
			||||||
 | 
							expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.TreePath, lastCommit.ID.String())
 | 
				
			||||||
		assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
							assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ import (
 | 
				
			|||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/cache"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -434,3 +435,20 @@ func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err e
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return len(stdout) > 0, err
 | 
						return len(stdout) > 0, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (repo *Repository) AddLastCommitCache(cacheKey, fullName, sha string) error {
 | 
				
			||||||
 | 
						if repo.LastCommitCache == nil {
 | 
				
			||||||
 | 
							commitsCount, err := cache.GetInt64(cacheKey, func() (int64, error) {
 | 
				
			||||||
 | 
								commit, err := repo.GetCommit(sha)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return 0, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return commit.CommitsCount()
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							repo.LastCommitCache = NewLastCommitCache(commitsCount, fullName, repo, cache.GetCache())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,6 +90,7 @@ type ContentsResponse struct {
 | 
				
			|||||||
	Name          string `json:"name"`
 | 
						Name          string `json:"name"`
 | 
				
			||||||
	Path          string `json:"path"`
 | 
						Path          string `json:"path"`
 | 
				
			||||||
	SHA           string `json:"sha"`
 | 
						SHA           string `json:"sha"`
 | 
				
			||||||
 | 
						LastCommitSHA string `json:"last_commit_sha"`
 | 
				
			||||||
	// `type` will be `file`, `dir`, `symlink`, or `submodule`
 | 
						// `type` will be `file`, `dir`, `symlink`, or `submodule`
 | 
				
			||||||
	Type string `json:"type"`
 | 
						Type string `json:"type"`
 | 
				
			||||||
	Size int64  `json:"size"`
 | 
						Size int64  `json:"size"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,6 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/cache"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
@@ -35,19 +34,11 @@ func ResolveRefOrSha(ctx *context.APIContext, ref string) string {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ctx.Repo.GitRepo != nil && ctx.Repo.GitRepo.LastCommitCache == nil {
 | 
						if ctx.Repo.GitRepo != nil {
 | 
				
			||||||
		commitsCount, err := cache.GetInt64(ctx.Repo.Repository.GetCommitsCountCacheKey(ref, true), func() (int64, error) {
 | 
							err := ctx.Repo.GitRepo.AddLastCommitCache(ctx.Repo.Repository.GetCommitsCountCacheKey(ref, ref != sha), ctx.Repo.Repository.FullName(), sha)
 | 
				
			||||||
			commit, err := ctx.Repo.GitRepo.GetCommit(sha)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return 0, err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return commit.CommitsCount()
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Error("Unable to get commits count for %s in %s. Error: %v", sha, ctx.Repo.Repository.FullName(), err)
 | 
								log.Error("Unable to get commits count for %s in %s. Error: %v", sha, ctx.Repo.Repository.FullName(), err)
 | 
				
			||||||
			return sha
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ctx.Repo.GitRepo.LastCommitCache = git.NewLastCommitCache(commitsCount, ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, cache.GetCache())
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sha
 | 
						return sha
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -165,11 +165,22 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	selfURLString := selfURL.String()
 | 
						selfURLString := selfURL.String()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = gitRepo.AddLastCommitCache(repo.GetCommitsCountCacheKey(ref, refType != git.ObjectCommit), repo.FullName(), commitID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lastCommit, err := commit.GetCommitByPath(treePath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// All content types have these fields in populated
 | 
						// All content types have these fields in populated
 | 
				
			||||||
	contentsResponse := &api.ContentsResponse{
 | 
						contentsResponse := &api.ContentsResponse{
 | 
				
			||||||
		Name:          entry.Name(),
 | 
							Name:          entry.Name(),
 | 
				
			||||||
		Path:          treePath,
 | 
							Path:          treePath,
 | 
				
			||||||
		SHA:           entry.ID.String(),
 | 
							SHA:           entry.ID.String(),
 | 
				
			||||||
 | 
							LastCommitSHA: lastCommit.ID.String(),
 | 
				
			||||||
		Size:          entry.Size(),
 | 
							Size:          entry.Size(),
 | 
				
			||||||
		URL:           &selfURLString,
 | 
							URL:           &selfURLString,
 | 
				
			||||||
		Links: &api.FileLinksResponse{
 | 
							Links: &api.FileLinksResponse{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse {
 | 
				
			|||||||
		Name:          treePath,
 | 
							Name:          treePath,
 | 
				
			||||||
		Path:          treePath,
 | 
							Path:          treePath,
 | 
				
			||||||
		SHA:           "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
 | 
							SHA:           "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
 | 
				
			||||||
 | 
							LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
		Type:          "file",
 | 
							Type:          "file",
 | 
				
			||||||
		Size:          30,
 | 
							Size:          30,
 | 
				
			||||||
		Encoding:      &encoding,
 | 
							Encoding:      &encoding,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,7 @@ func getExpectedFileResponse() *api.FileResponse {
 | 
				
			|||||||
			Name:          treePath,
 | 
								Name:          treePath,
 | 
				
			||||||
			Path:          treePath,
 | 
								Path:          treePath,
 | 
				
			||||||
			SHA:           sha,
 | 
								SHA:           sha,
 | 
				
			||||||
 | 
								LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
 | 
				
			||||||
			Type:          "file",
 | 
								Type:          "file",
 | 
				
			||||||
			Size:          30,
 | 
								Size:          30,
 | 
				
			||||||
			Encoding:      &encoding,
 | 
								Encoding:      &encoding,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13779,6 +13779,10 @@
 | 
				
			|||||||
          "type": "string",
 | 
					          "type": "string",
 | 
				
			||||||
          "x-go-name": "HTMLURL"
 | 
					          "x-go-name": "HTMLURL"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        "last_commit_sha": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "x-go-name": "LastCommitSHA"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "name": {
 | 
					        "name": {
 | 
				
			||||||
          "type": "string",
 | 
					          "type": "string",
 | 
				
			||||||
          "x-go-name": "Name"
 | 
					          "x-go-name": "Name"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user