mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09: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==" | ||||||
| @@ -60,17 +60,18 @@ func getExpectedFileResponseForCreate(repoFullName, commitID, treePath string) * | |||||||
| 	downloadURL := setting.AppURL + repoFullName + "/raw/branch/master/" + treePath | 	downloadURL := setting.AppURL + repoFullName + "/raw/branch/master/" + treePath | ||||||
| 	return &api.FileResponse{ | 	return &api.FileResponse{ | ||||||
| 		Content: &api.ContentsResponse{ | 		Content: &api.ContentsResponse{ | ||||||
| 			Name:        filepath.Base(treePath), | 			Name:          filepath.Base(treePath), | ||||||
| 			Path:        treePath, | 			Path:          treePath, | ||||||
| 			SHA:         sha, | 			SHA:           sha, | ||||||
| 			Size:        16, | 			LastCommitSHA: latestCommitSHA, | ||||||
| 			Type:        "file", | 			Size:          16, | ||||||
| 			Encoding:    &encoding, | 			Type:          "file", | ||||||
| 			Content:     &content, | 			Encoding:      &encoding, | ||||||
| 			URL:         &selfURL, | 			Content:       &content, | ||||||
| 			HTMLURL:     &htmlURL, | 			URL:           &selfURL, | ||||||
| 			GitURL:      &gitURL, | 			HTMLURL:       &htmlURL, | ||||||
| 			DownloadURL: &downloadURL, | 			GitURL:        &gitURL, | ||||||
|  | 			DownloadURL:   &downloadURL, | ||||||
| 			Links: &api.FileLinksResponse{ | 			Links: &api.FileLinksResponse{ | ||||||
| 				Self:    &selfURL, | 				Self:    &selfURL, | ||||||
| 				GitURL:  &gitURL, | 				GitURL:  &gitURL, | ||||||
| @@ -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=" | ||||||
| @@ -58,17 +58,18 @@ func getExpectedFileResponseForUpdate(commitID, treePath string) *api.FileRespon | |||||||
| 	downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath | 	downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath | ||||||
| 	return &api.FileResponse{ | 	return &api.FileResponse{ | ||||||
| 		Content: &api.ContentsResponse{ | 		Content: &api.ContentsResponse{ | ||||||
| 			Name:        filepath.Base(treePath), | 			Name:          filepath.Base(treePath), | ||||||
| 			Path:        treePath, | 			Path:          treePath, | ||||||
| 			SHA:         sha, | 			SHA:           sha, | ||||||
| 			Type:        "file", | 			LastCommitSHA: lastCommitSHA, | ||||||
| 			Size:        20, | 			Type:          "file", | ||||||
| 			Encoding:    &encoding, | 			Size:          20, | ||||||
| 			Content:     &content, | 			Encoding:      &encoding, | ||||||
| 			URL:         &selfURL, | 			Content:       &content, | ||||||
| 			HTMLURL:     &htmlURL, | 			URL:           &selfURL, | ||||||
| 			GitURL:      &gitURL, | 			HTMLURL:       &htmlURL, | ||||||
| 			DownloadURL: &downloadURL, | 			GitURL:        &gitURL, | ||||||
|  | 			DownloadURL:   &downloadURL, | ||||||
| 			Links: &api.FileLinksResponse{ | 			Links: &api.FileLinksResponse{ | ||||||
| 				Self:    &selfURL, | 				Self:    &selfURL, | ||||||
| 				GitURL:  &gitURL, | 				GitURL:  &gitURL, | ||||||
| @@ -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 | ||||||
| @@ -30,15 +30,16 @@ func getExpectedContentsListResponseForContents(ref, refType string) []*api.Cont | |||||||
| 	downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath | 	downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath | ||||||
| 	return []*api.ContentsResponse{ | 	return []*api.ContentsResponse{ | ||||||
| 		{ | 		{ | ||||||
| 			Name:        filepath.Base(treePath), | 			Name:          filepath.Base(treePath), | ||||||
| 			Path:        treePath, | 			Path:          treePath, | ||||||
| 			SHA:         sha, | 			SHA:           sha, | ||||||
| 			Type:        "file", | 			LastCommitSHA: lastCommitSHA, | ||||||
| 			Size:        30, | 			Type:          "file", | ||||||
| 			URL:         &selfURL, | 			Size:          30, | ||||||
| 			HTMLURL:     &htmlURL, | 			URL:           &selfURL, | ||||||
| 			GitURL:      &gitURL, | 			HTMLURL:       &htmlURL, | ||||||
| 			DownloadURL: &downloadURL, | 			GitURL:        &gitURL, | ||||||
|  | 			DownloadURL:   &downloadURL, | ||||||
| 			Links: &api.FileLinksResponse{ | 			Links: &api.FileLinksResponse{ | ||||||
| 				Self:    &selfURL, | 				Self:    &selfURL, | ||||||
| 				GitURL:  &gitURL, | 				GitURL:  &gitURL, | ||||||
| @@ -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,17 +106,22 @@ 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 | ||||||
| 	ref = newBranch | 	ref = newBranch | ||||||
| 	refType = "branch" | 	refType = "branch" | ||||||
| 	req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) | 	req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) | ||||||
| 	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" | ||||||
| @@ -30,17 +30,18 @@ func getExpectedContentsResponseForContents(ref, refType string) *api.ContentsRe | |||||||
| 	gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha | 	gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha | ||||||
| 	downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath | 	downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath | ||||||
| 	return &api.ContentsResponse{ | 	return &api.ContentsResponse{ | ||||||
| 		Name:        treePath, | 		Name:          treePath, | ||||||
| 		Path:        treePath, | 		Path:          treePath, | ||||||
| 		SHA:         sha, | 		SHA:           sha, | ||||||
| 		Type:        "file", | 		LastCommitSHA: lastCommitSHA, | ||||||
| 		Size:        30, | 		Type:          "file", | ||||||
| 		Encoding:    &encoding, | 		Size:          30, | ||||||
| 		Content:     &content, | 		Encoding:      &encoding, | ||||||
| 		URL:         &selfURL, | 		Content:       &content, | ||||||
| 		HTMLURL:     &htmlURL, | 		URL:           &selfURL, | ||||||
| 		GitURL:      &gitURL, | 		HTMLURL:       &htmlURL, | ||||||
| 		DownloadURL: &downloadURL, | 		GitURL:        &gitURL, | ||||||
|  | 		DownloadURL:   &downloadURL, | ||||||
| 		Links: &api.FileLinksResponse{ | 		Links: &api.FileLinksResponse{ | ||||||
| 			Self:    &selfURL, | 			Self:    &selfURL, | ||||||
| 			GitURL:  &gitURL, | 			GitURL:  &gitURL, | ||||||
| @@ -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" | ||||||
| @@ -57,17 +57,18 @@ func getExpectedFileResponseForRepofilesCreate(commitID string) *api.FileRespons | |||||||
| 	downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath | 	downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath | ||||||
| 	return &api.FileResponse{ | 	return &api.FileResponse{ | ||||||
| 		Content: &api.ContentsResponse{ | 		Content: &api.ContentsResponse{ | ||||||
| 			Name:        filepath.Base(treePath), | 			Name:          filepath.Base(treePath), | ||||||
| 			Path:        treePath, | 			Path:          treePath, | ||||||
| 			SHA:         "103ff9234cefeee5ec5361d22b49fbb04d385885", | 			SHA:           "103ff9234cefeee5ec5361d22b49fbb04d385885", | ||||||
| 			Type:        "file", | 			LastCommitSHA: lastCommitSHA, | ||||||
| 			Size:        18, | 			Type:          "file", | ||||||
| 			Encoding:    &encoding, | 			Size:          18, | ||||||
| 			Content:     &content, | 			Encoding:      &encoding, | ||||||
| 			URL:         &selfURL, | 			Content:       &content, | ||||||
| 			HTMLURL:     &htmlURL, | 			URL:           &selfURL, | ||||||
| 			GitURL:      &gitURL, | 			HTMLURL:       &htmlURL, | ||||||
| 			DownloadURL: &downloadURL, | 			GitURL:        &gitURL, | ||||||
|  | 			DownloadURL:   &downloadURL, | ||||||
| 			Links: &api.FileLinksResponse{ | 			Links: &api.FileLinksResponse{ | ||||||
| 				Self:    &selfURL, | 				Self:    &selfURL, | ||||||
| 				GitURL:  &gitURL, | 				GitURL:  &gitURL, | ||||||
| @@ -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" | ||||||
| @@ -124,17 +125,18 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename string) *api.F | |||||||
| 	downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + filename | 	downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + filename | ||||||
| 	return &api.FileResponse{ | 	return &api.FileResponse{ | ||||||
| 		Content: &api.ContentsResponse{ | 		Content: &api.ContentsResponse{ | ||||||
| 			Name:        filename, | 			Name:          filename, | ||||||
| 			Path:        filename, | 			Path:          filename, | ||||||
| 			SHA:         "dbf8d00e022e05b7e5cf7e535de857de57925647", | 			SHA:           "dbf8d00e022e05b7e5cf7e535de857de57925647", | ||||||
| 			Type:        "file", | 			LastCommitSHA: lastCommitSHA, | ||||||
| 			Size:        43, | 			Type:          "file", | ||||||
| 			Encoding:    &encoding, | 			Size:          43, | ||||||
| 			Content:     &content, | 			Encoding:      &encoding, | ||||||
| 			URL:         &selfURL, | 			Content:       &content, | ||||||
| 			HTMLURL:     &htmlURL, | 			URL:           &selfURL, | ||||||
| 			GitURL:      &gitURL, | 			HTMLURL:       &htmlURL, | ||||||
| 			DownloadURL: &downloadURL, | 			GitURL:        &gitURL, | ||||||
|  | 			DownloadURL:   &downloadURL, | ||||||
| 			Links: &api.FileLinksResponse{ | 			Links: &api.FileLinksResponse{ | ||||||
| 				Self:    &selfURL, | 				Self:    &selfURL, | ||||||
| 				GitURL:  &gitURL, | 				GitURL:  &gitURL, | ||||||
| @@ -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 | ||||||
|  | } | ||||||
|   | |||||||
| @@ -87,9 +87,10 @@ type FileLinksResponse struct { | |||||||
|  |  | ||||||
| // ContentsResponse contains information about a repo's entry's (dir, file, symlink, submodule) metadata and content | // ContentsResponse contains information about a repo's entry's (dir, file, symlink, submodule) metadata and content | ||||||
| type ContentsResponse struct { | 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,13 +165,24 @@ 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(), | ||||||
| 		Size: entry.Size(), | 		LastCommitSHA: lastCommit.ID.String(), | ||||||
| 		URL:  &selfURLString, | 		Size:          entry.Size(), | ||||||
|  | 		URL:           &selfURLString, | ||||||
| 		Links: &api.FileLinksResponse{ | 		Links: &api.FileLinksResponse{ | ||||||
| 			Self: &selfURLString, | 			Self: &selfURLString, | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -33,17 +33,18 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse { | |||||||
| 	gitURL := "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/" + sha | 	gitURL := "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/" + sha | ||||||
| 	downloadURL := "https://try.gitea.io/user2/repo1/raw/branch/master/" + treePath | 	downloadURL := "https://try.gitea.io/user2/repo1/raw/branch/master/" + treePath | ||||||
| 	return &api.ContentsResponse{ | 	return &api.ContentsResponse{ | ||||||
| 		Name:        treePath, | 		Name:          treePath, | ||||||
| 		Path:        treePath, | 		Path:          treePath, | ||||||
| 		SHA:         "4b4851ad51df6a7d9f25c979345979eaeb5b349f", | 		SHA:           "4b4851ad51df6a7d9f25c979345979eaeb5b349f", | ||||||
| 		Type:        "file", | 		LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d", | ||||||
| 		Size:        30, | 		Type:          "file", | ||||||
| 		Encoding:    &encoding, | 		Size:          30, | ||||||
| 		Content:     &content, | 		Encoding:      &encoding, | ||||||
| 		URL:         &selfURL, | 		Content:       &content, | ||||||
| 		HTMLURL:     &htmlURL, | 		URL:           &selfURL, | ||||||
| 		GitURL:      &gitURL, | 		HTMLURL:       &htmlURL, | ||||||
| 		DownloadURL: &downloadURL, | 		GitURL:        &gitURL, | ||||||
|  | 		DownloadURL:   &downloadURL, | ||||||
| 		Links: &api.FileLinksResponse{ | 		Links: &api.FileLinksResponse{ | ||||||
| 			Self:    &selfURL, | 			Self:    &selfURL, | ||||||
| 			GitURL:  &gitURL, | 			GitURL:  &gitURL, | ||||||
|   | |||||||
| @@ -43,17 +43,18 @@ func getExpectedFileResponse() *api.FileResponse { | |||||||
| 	downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath | 	downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath | ||||||
| 	return &api.FileResponse{ | 	return &api.FileResponse{ | ||||||
| 		Content: &api.ContentsResponse{ | 		Content: &api.ContentsResponse{ | ||||||
| 			Name:        treePath, | 			Name:          treePath, | ||||||
| 			Path:        treePath, | 			Path:          treePath, | ||||||
| 			SHA:         sha, | 			SHA:           sha, | ||||||
| 			Type:        "file", | 			LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d", | ||||||
| 			Size:        30, | 			Type:          "file", | ||||||
| 			Encoding:    &encoding, | 			Size:          30, | ||||||
| 			Content:     &content, | 			Encoding:      &encoding, | ||||||
| 			URL:         &selfURL, | 			Content:       &content, | ||||||
| 			HTMLURL:     &htmlURL, | 			URL:           &selfURL, | ||||||
| 			GitURL:      &gitURL, | 			HTMLURL:       &htmlURL, | ||||||
| 			DownloadURL: &downloadURL, | 			GitURL:        &gitURL, | ||||||
|  | 			DownloadURL:   &downloadURL, | ||||||
| 			Links: &api.FileLinksResponse{ | 			Links: &api.FileLinksResponse{ | ||||||
| 				Self:    &selfURL, | 				Self:    &selfURL, | ||||||
| 				GitURL:  &gitURL, | 				GitURL:  &gitURL, | ||||||
|   | |||||||
| @@ -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