Add last_committer_date and last_author_date for file contents API (#32921)

Fix #32886

Add `last_committer_date` and `last_author_date` in the content API
which is not implemented by Github API v3 at the moment.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Lunny Xiao 2025-04-02 21:47:31 -07:00 committed by GitHub
parent c27d87a9ac
commit 45c45934aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 264 additions and 176 deletions

View File

@ -4,6 +4,8 @@
package structs package structs
import "time"
// FileOptions options for all file APIs // FileOptions options for all file APIs
type FileOptions struct { type FileOptions struct {
// message (optional) for the commit of this file. if not supplied, a default message will be used // message (optional) for the commit of this file. if not supplied, a default message will be used
@ -121,6 +123,10 @@ type ContentsResponse struct {
Path string `json:"path"` Path string `json:"path"`
SHA string `json:"sha"` SHA string `json:"sha"`
LastCommitSHA string `json:"last_commit_sha"` LastCommitSHA string `json:"last_commit_sha"`
// swagger:strfmt date-time
LastCommitterDate time.Time `json:"last_committer_date"`
// swagger:strfmt date-time
LastAuthorDate time.Time `json:"last_author_date"`
// `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"`

View File

@ -188,6 +188,14 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref
}, },
} }
// GitHub doesn't have these fields in the response, but we could follow other similar APIs to name them
// https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#list-commits
if lastCommit.Committer != nil {
contentsResponse.LastCommitterDate = lastCommit.Committer.When
}
if lastCommit.Author != nil {
contentsResponse.LastAuthorDate = lastCommit.Author.When
}
// Now populate the rest of the ContentsResponse based on entry type // Now populate the rest of the ContentsResponse based on entry type
if entry.IsRegular() || entry.IsExecutable() { if entry.IsRegular() || entry.IsExecutable() {
contentsResponse.Type = string(ContentTypeRegular) contentsResponse.Type = string(ContentTypeRegular)

View File

@ -5,6 +5,7 @@ package files
import ( import (
"testing" "testing"
"time"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/gitrepo"
@ -34,6 +35,8 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse {
Path: treePath, Path: treePath,
SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d", LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
LastCommitterDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
LastAuthorDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
Type: "file", Type: "file",
Size: 30, Size: 30,
Encoding: &encoding, Encoding: &encoding,

View File

@ -5,6 +5,7 @@ package files
import ( import (
"testing" "testing"
"time"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/gitrepo"
@ -46,6 +47,8 @@ func getExpectedFileResponse() *api.FileResponse {
Path: treePath, Path: treePath,
SHA: sha, SHA: sha,
LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d", LastCommitSHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
LastCommitterDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
LastAuthorDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
Type: "file", Type: "file",
Size: 30, Size: 30,
Encoding: &encoding, Encoding: &encoding,

View File

@ -20411,10 +20411,20 @@
"type": "string", "type": "string",
"x-go-name": "HTMLURL" "x-go-name": "HTMLURL"
}, },
"last_author_date": {
"type": "string",
"format": "date-time",
"x-go-name": "LastAuthorDate"
},
"last_commit_sha": { "last_commit_sha": {
"type": "string", "type": "string",
"x-go-name": "LastCommitSHA" "x-go-name": "LastCommitSHA"
}, },
"last_committer_date": {
"type": "string",
"format": "date-time",
"x-go-name": "LastCommitterDate"
},
"name": { "name": {
"type": "string", "type": "string",
"x-go-name": "Name" "x-go-name": "Name"

View File

@ -8,7 +8,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"path/filepath" "path"
"testing" "testing"
"time" "time"
@ -49,20 +49,34 @@ func getCreateFileOptions() api.CreateFileOptions {
} }
} }
func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCommitSHA string) *api.FileResponse { func normalizeFileContentResponseCommitTime(c *api.ContentsResponse) {
// decoded JSON response may contain different timezone from the one parsed by git commit
// so we need to normalize the time to UTC to make "assert.Equal" pass
c.LastCommitterDate = c.LastCommitterDate.UTC()
c.LastAuthorDate = c.LastAuthorDate.UTC()
}
type apiFileResponseInfo struct {
repoFullName, commitID, treePath, lastCommitSHA string
lastCommitterWhen, lastAuthorWhen time.Time
}
func getExpectedFileResponseForCreate(info apiFileResponseInfo) *api.FileResponse {
sha := "a635aa942442ddfdba07468cf9661c08fbdf0ebf" sha := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
encoding := "base64" encoding := "base64"
content := "VGhpcyBpcyBuZXcgdGV4dA==" content := "VGhpcyBpcyBuZXcgdGV4dA=="
selfURL := setting.AppURL + "api/v1/repos/" + repoFullName + "/contents/" + treePath + "?ref=master" selfURL := setting.AppURL + "api/v1/repos/" + info.repoFullName + "/contents/" + info.treePath + "?ref=master"
htmlURL := setting.AppURL + repoFullName + "/src/branch/master/" + treePath htmlURL := setting.AppURL + info.repoFullName + "/src/branch/master/" + info.treePath
gitURL := setting.AppURL + "api/v1/repos/" + repoFullName + "/git/blobs/" + sha gitURL := setting.AppURL + "api/v1/repos/" + info.repoFullName + "/git/blobs/" + sha
downloadURL := setting.AppURL + repoFullName + "/raw/branch/master/" + treePath downloadURL := setting.AppURL + info.repoFullName + "/raw/branch/master/" + info.treePath
return &api.FileResponse{ ret := &api.FileResponse{
Content: &api.ContentsResponse{ Content: &api.ContentsResponse{
Name: filepath.Base(treePath), Name: path.Base(info.treePath),
Path: treePath, Path: info.treePath,
SHA: sha, SHA: sha,
LastCommitSHA: latestCommitSHA, LastCommitSHA: info.lastCommitSHA,
LastCommitterDate: info.lastCommitterWhen,
LastAuthorDate: info.lastAuthorWhen,
Size: 16, Size: 16,
Type: "file", Type: "file",
Encoding: &encoding, Encoding: &encoding,
@ -79,10 +93,10 @@ func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCo
}, },
Commit: &api.FileCommitResponse{ Commit: &api.FileCommitResponse{
CommitMeta: api.CommitMeta{ CommitMeta: api.CommitMeta{
URL: setting.AppURL + "api/v1/repos/" + repoFullName + "/git/commits/" + commitID, URL: setting.AppURL + "api/v1/repos/" + info.repoFullName + "/git/commits/" + info.commitID,
SHA: commitID, SHA: info.commitID,
}, },
HTMLURL: setting.AppURL + repoFullName + "/commit/" + commitID, HTMLURL: setting.AppURL + info.repoFullName + "/commit/" + info.commitID,
Author: &api.CommitUser{ Author: &api.CommitUser{
Identity: api.Identity{ Identity: api.Identity{
Name: "Anne Doe", Name: "Anne Doe",
@ -106,6 +120,8 @@ func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCo
Payload: "", Payload: "",
}, },
} }
normalizeFileContentResponseCommitTime(ret.Content)
return ret
} }
func BenchmarkAPICreateFileSmall(b *testing.B) { func BenchmarkAPICreateFileSmall(b *testing.B) {
@ -167,11 +183,20 @@ func TestAPICreateFile(t *testing.T) {
AddTokenAuth(token2) AddTokenAuth(token2)
resp := MakeRequest(t, req, http.StatusCreated) resp := MakeRequest(t, req, http.StatusCreated)
gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1) gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1)
defer gitRepo.Close()
commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName) commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
latestCommit, _ := gitRepo.GetCommitByPath(treePath) lastCommit, _ := gitRepo.GetCommitByPath(treePath)
expectedFileResponse := getExpectedFileResponseForCreate("user2/repo1", commitID, treePath, latestCommit.ID.String()) expectedFileResponse := getExpectedFileResponseForCreate(apiFileResponseInfo{
repoFullName: "user2/repo1",
commitID: commitID,
treePath: treePath,
lastCommitSHA: lastCommit.ID.String(),
lastCommitterWhen: lastCommit.Committer.When,
lastAuthorWhen: lastCommit.Author.When,
})
var fileResponse api.FileResponse var fileResponse api.FileResponse
DecodeJSON(t, resp, &fileResponse) DecodeJSON(t, resp, &fileResponse)
normalizeFileContentResponseCommitTime(fileResponse.Content)
assert.Equal(t, expectedFileResponse.Content, fileResponse.Content) assert.Equal(t, expectedFileResponse.Content, fileResponse.Content)
assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA) assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL) assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
@ -181,7 +206,6 @@ func TestAPICreateFile(t *testing.T) {
assert.Equal(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email) assert.Equal(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email)
assert.Equal(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name) assert.Equal(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name)
assert.Equal(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date) assert.Equal(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date)
gitRepo.Close()
} }
// Test creating a file in a new branch // Test creating a file in a new branch
@ -285,10 +309,19 @@ func TestAPICreateFile(t *testing.T) {
resp = MakeRequest(t, req, http.StatusCreated) resp = MakeRequest(t, req, http.StatusCreated)
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}) // public repo emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}) // public repo
gitRepo, _ := gitrepo.OpenRepository(t.Context(), emptyRepo) gitRepo, _ := gitrepo.OpenRepository(t.Context(), emptyRepo)
defer gitRepo.Close()
commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName) commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
latestCommit, _ := gitRepo.GetCommitByPath(treePath) latestCommit, _ := gitRepo.GetCommitByPath(treePath)
expectedFileResponse := getExpectedFileResponseForCreate("user2/empty-repo", commitID, treePath, latestCommit.ID.String()) expectedFileResponse := getExpectedFileResponseForCreate(apiFileResponseInfo{
repoFullName: "user2/empty-repo",
commitID: commitID,
treePath: treePath,
lastCommitSHA: latestCommit.ID.String(),
lastCommitterWhen: latestCommit.Committer.When,
lastAuthorWhen: latestCommit.Author.When,
})
DecodeJSON(t, resp, &fileResponse) DecodeJSON(t, resp, &fileResponse)
normalizeFileContentResponseCommitTime(fileResponse.Content)
assert.Equal(t, expectedFileResponse.Content, fileResponse.Content) assert.Equal(t, expectedFileResponse.Content, fileResponse.Content)
assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA) assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL) assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
@ -298,6 +331,5 @@ func TestAPICreateFile(t *testing.T) {
assert.Equal(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email) assert.Equal(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email)
assert.Equal(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name) assert.Equal(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name)
assert.Equal(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date) assert.Equal(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date)
gitRepo.Close()
}) })
} }

View File

@ -8,7 +8,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"path/filepath" "path"
"testing" "testing"
auth_model "code.gitea.io/gitea/models/auth" auth_model "code.gitea.io/gitea/models/auth"
@ -47,20 +47,22 @@ func getUpdateFileOptions() *api.UpdateFileOptions {
} }
} }
func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string) *api.FileResponse { func getExpectedFileResponseForUpdate(info apiFileResponseInfo) *api.FileResponse {
sha := "08bd14b2e2852529157324de9c226b3364e76136" sha := "08bd14b2e2852529157324de9c226b3364e76136"
encoding := "base64" encoding := "base64"
content := "VGhpcyBpcyB1cGRhdGVkIHRleHQ=" content := "VGhpcyBpcyB1cGRhdGVkIHRleHQ="
selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master" selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + info.treePath + "?ref=master"
htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + treePath htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + info.treePath
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/branch/master/" + treePath downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + info.treePath
return &api.FileResponse{ ret := &api.FileResponse{
Content: &api.ContentsResponse{ Content: &api.ContentsResponse{
Name: filepath.Base(treePath), Name: path.Base(info.treePath),
Path: treePath, Path: info.treePath,
SHA: sha, SHA: sha,
LastCommitSHA: lastCommitSHA, LastCommitSHA: info.lastCommitSHA,
LastCommitterDate: info.lastCommitterWhen,
LastAuthorDate: info.lastAuthorWhen,
Type: "file", Type: "file",
Size: 20, Size: 20,
Encoding: &encoding, Encoding: &encoding,
@ -77,10 +79,10 @@ func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string)
}, },
Commit: &api.FileCommitResponse{ Commit: &api.FileCommitResponse{
CommitMeta: api.CommitMeta{ CommitMeta: api.CommitMeta{
URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/" + commitID, URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/" + info.commitID,
SHA: commitID, SHA: info.commitID,
}, },
HTMLURL: setting.AppURL + "user2/repo1/commit/" + commitID, HTMLURL: setting.AppURL + "user2/repo1/commit/" + info.commitID,
Author: &api.CommitUser{ Author: &api.CommitUser{
Identity: api.Identity{ Identity: api.Identity{
Name: "John Doe", Name: "John Doe",
@ -102,6 +104,8 @@ func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string)
Payload: "", Payload: "",
}, },
} }
normalizeFileContentResponseCommitTime(ret.Content)
return ret
} }
func TestAPIUpdateFile(t *testing.T) { func TestAPIUpdateFile(t *testing.T) {
@ -135,17 +139,24 @@ func TestAPIUpdateFile(t *testing.T) {
AddTokenAuth(token2) AddTokenAuth(token2)
resp := MakeRequest(t, req, http.StatusOK) resp := MakeRequest(t, req, http.StatusOK)
gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1) gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1)
defer gitRepo.Close()
commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName) commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName)
lasCommit, _ := gitRepo.GetCommitByPath(treePath) lasCommit, _ := gitRepo.GetCommitByPath(treePath)
expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath, lasCommit.ID.String()) expectedFileResponse := getExpectedFileResponseForUpdate(apiFileResponseInfo{
commitID: commitID,
treePath: treePath,
lastCommitSHA: lasCommit.ID.String(),
lastCommitterWhen: lasCommit.Committer.When,
lastAuthorWhen: lasCommit.Author.When,
})
var fileResponse api.FileResponse var fileResponse api.FileResponse
DecodeJSON(t, resp, &fileResponse) DecodeJSON(t, resp, &fileResponse)
normalizeFileContentResponseCommitTime(fileResponse.Content)
assert.Equal(t, expectedFileResponse.Content, fileResponse.Content) assert.Equal(t, expectedFileResponse.Content, fileResponse.Content)
assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA) assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL) assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
assert.Equal(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email) assert.Equal(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
assert.Equal(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name) assert.Equal(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
gitRepo.Close()
} }
// Test updating a file in a new branch // Test updating a file in a new branch

View File

@ -77,16 +77,14 @@ func TestAPIChangeFiles(t *testing.T) {
token4 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) token4 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
// Test changing files in repo1 which user2 owns, try both with branch and empty branch // Test changing files in repo1 which user2 owns, try both with branch and empty branch
for _, branch := range [...]string{ for _, branch := range []string{"master", ""} {
"master", // Branch t.Run("Branch-"+branch, func(t *testing.T) {
"", // Empty branch
} {
fileID++ fileID++
createTreePath := fmt.Sprintf("new/file%d.txt", fileID) createTreePath := fmt.Sprintf("new/file%d.txt", fileID)
updateTreePath := fmt.Sprintf("update/file%d.txt", fileID) updateTreePath := fmt.Sprintf("update/file%d.txt", fileID)
deleteTreePath := fmt.Sprintf("delete/file%d.txt", fileID) deleteTreePath := fmt.Sprintf("delete/file%d.txt", fileID)
createFile(user2, repo1, updateTreePath) _, _ = createFile(user2, repo1, updateTreePath)
createFile(user2, repo1, deleteTreePath) _, _ = createFile(user2, repo1, deleteTreePath)
changeFilesOptions := getChangeFilesOptions() changeFilesOptions := getChangeFilesOptions()
changeFilesOptions.BranchName = branch changeFilesOptions.BranchName = branch
changeFilesOptions.Files[0].Path = createTreePath changeFilesOptions.Files[0].Path = createTreePath
@ -96,32 +94,39 @@ func TestAPIChangeFiles(t *testing.T) {
AddTokenAuth(token2) AddTokenAuth(token2)
resp := MakeRequest(t, req, http.StatusCreated) resp := MakeRequest(t, req, http.StatusCreated)
gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1) gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1)
defer gitRepo.Close()
commitID, _ := gitRepo.GetBranchCommitID(changeFilesOptions.NewBranchName) commitID, _ := gitRepo.GetBranchCommitID(changeFilesOptions.NewBranchName)
createLasCommit, _ := gitRepo.GetCommitByPath(createTreePath) createLasCommit, _ := gitRepo.GetCommitByPath(createTreePath)
updateLastCommit, _ := gitRepo.GetCommitByPath(updateTreePath) updateLastCommit, _ := gitRepo.GetCommitByPath(updateTreePath)
expectedCreateFileResponse := getExpectedFileResponseForCreate(fmt.Sprintf("%v/%v", user2.Name, repo1.Name), commitID, createTreePath, createLasCommit.ID.String()) expectedCreateFileResponse := getExpectedFileResponseForCreate(apiFileResponseInfo{
expectedUpdateFileResponse := getExpectedFileResponseForUpdate(commitID, updateTreePath, updateLastCommit.ID.String()) repoFullName: fmt.Sprintf("%s/%s", user2.Name, repo1.Name),
commitID: commitID,
treePath: createTreePath,
lastCommitSHA: createLasCommit.ID.String(),
lastCommitterWhen: createLasCommit.Committer.When,
lastAuthorWhen: createLasCommit.Author.When,
})
expectedUpdateFileResponse := getExpectedFileResponseForUpdate(apiFileResponseInfo{
commitID: commitID,
treePath: updateTreePath,
lastCommitSHA: updateLastCommit.ID.String(),
lastCommitterWhen: updateLastCommit.Committer.When,
lastAuthorWhen: updateLastCommit.Author.When,
})
var filesResponse api.FilesResponse var filesResponse api.FilesResponse
DecodeJSON(t, resp, &filesResponse) DecodeJSON(t, resp, &filesResponse)
normalizeFileContentResponseCommitTime(filesResponse.Files[0])
// check create file normalizeFileContentResponseCommitTime(filesResponse.Files[1])
assert.Equal(t, expectedCreateFileResponse.Content, filesResponse.Files[0]) assert.Equal(t, expectedCreateFileResponse.Content, filesResponse.Files[0]) // check create file
assert.Equal(t, expectedUpdateFileResponse.Content, filesResponse.Files[1]) // check update file
// check update file
assert.Equal(t, expectedUpdateFileResponse.Content, filesResponse.Files[1])
// test commit info
assert.Equal(t, expectedCreateFileResponse.Commit.SHA, filesResponse.Commit.SHA) assert.Equal(t, expectedCreateFileResponse.Commit.SHA, filesResponse.Commit.SHA)
assert.Equal(t, expectedCreateFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL) assert.Equal(t, expectedCreateFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
assert.Equal(t, expectedCreateFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email) assert.Equal(t, expectedCreateFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email)
assert.Equal(t, expectedCreateFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name) assert.Equal(t, expectedCreateFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name)
assert.Equal(t, expectedCreateFileResponse.Commit.Committer.Email, filesResponse.Commit.Committer.Email) assert.Equal(t, expectedCreateFileResponse.Commit.Committer.Email, filesResponse.Commit.Committer.Email)
assert.Equal(t, expectedCreateFileResponse.Commit.Committer.Name, filesResponse.Commit.Committer.Name) assert.Equal(t, expectedCreateFileResponse.Commit.Committer.Name, filesResponse.Commit.Committer.Name)
assert.Nil(t, filesResponse.Files[2]) // test delete file
// test delete file })
assert.Nil(t, filesResponse.Files[2])
gitRepo.Close()
} }
// Test changing files in a new branch // Test changing files in a new branch

View File

@ -6,8 +6,9 @@ package integration
import ( import (
"net/http" "net/http"
"net/url" "net/url"
"path/filepath" "path"
"testing" "testing"
"time"
auth_model "code.gitea.io/gitea/models/auth" auth_model "code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -31,10 +32,12 @@ func getExpectedContentsListResponseForContents(ref, refType, lastCommitSHA stri
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: path.Base(treePath),
Path: treePath, Path: treePath,
SHA: sha, SHA: sha,
LastCommitSHA: lastCommitSHA, LastCommitSHA: lastCommitSHA,
LastCommitterDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
LastAuthorDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
Type: "file", Type: "file",
Size: 30, Size: 30,
URL: &selfURL, URL: &selfURL,

View File

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"testing" "testing"
"time"
auth_model "code.gitea.io/gitea/models/auth" auth_model "code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -37,6 +38,8 @@ func getExpectedContentsResponseForContents(ref, refType, lastCommitSHA string)
Path: treePath, Path: treePath,
SHA: sha, SHA: sha,
LastCommitSHA: lastCommitSHA, LastCommitSHA: lastCommitSHA,
LastCommitterDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
LastAuthorDate: time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400)),
Type: "file", Type: "file",
Size: 30, Size: 30,
Encoding: &encoding, Encoding: &encoding,

View File

@ -6,7 +6,7 @@ package integration
import ( import (
"fmt" "fmt"
"net/url" "net/url"
"path/filepath" "path"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -79,7 +79,7 @@ func getDeleteRepoFilesOptions(repo *repo_model.Repository) *files_service.Chang
} }
} }
func getExpectedFileResponseForRepofilesDelete() *api.FileResponse { func getExpectedFileResponseForRepoFilesDelete() *api.FileResponse {
// Just returns fields that don't change, i.e. fields with commit SHAs and dates can't be determined // Just returns fields that don't change, i.e. fields with commit SHAs and dates can't be determined
return &api.FileResponse{ return &api.FileResponse{
Content: nil, Content: nil,
@ -107,7 +107,7 @@ func getExpectedFileResponseForRepofilesDelete() *api.FileResponse {
} }
} }
func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *api.FileResponse { func getExpectedFileResponseForRepoFilesCreate(commitID string, lastCommit *git.Commit) *api.FileResponse {
treePath := "new/file.txt" treePath := "new/file.txt"
encoding := "base64" encoding := "base64"
content := "VGhpcyBpcyBhIE5FVyBmaWxl" content := "VGhpcyBpcyBhIE5FVyBmaWxl"
@ -117,10 +117,12 @@ func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *
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: path.Base(treePath),
Path: treePath, Path: treePath,
SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885", SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
LastCommitSHA: lastCommitSHA, LastCommitSHA: lastCommit.ID.String(),
LastCommitterDate: lastCommit.Committer.When,
LastAuthorDate: lastCommit.Author.When,
Type: "file", Type: "file",
Size: 18, Size: 18,
Encoding: &encoding, Encoding: &encoding,
@ -176,7 +178,7 @@ func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *
} }
} }
func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA string) *api.FileResponse { func getExpectedFileResponseForRepoFilesUpdate(commitID, filename, lastCommitSHA string, lastCommitterWhen, lastAuthorWhen time.Time) *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"
@ -189,6 +191,8 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA
Path: filename, Path: filename,
SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647", SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647",
LastCommitSHA: lastCommitSHA, LastCommitSHA: lastCommitSHA,
LastCommitterDate: lastCommitterWhen,
LastAuthorDate: lastAuthorWhen,
Type: "file", Type: "file",
Size: 43, Size: 43,
Encoding: &encoding, Encoding: &encoding,
@ -269,7 +273,7 @@ func TestChangeRepoFilesForCreate(t *testing.T) {
commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch) commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
lastCommit, _ := gitRepo.GetCommitByPath("new/file.txt") lastCommit, _ := gitRepo.GetCommitByPath("new/file.txt")
expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID, lastCommit.ID.String()) expectedFileResponse := getExpectedFileResponseForRepoFilesCreate(commitID, lastCommit)
assert.NotNil(t, expectedFileResponse) assert.NotNil(t, expectedFileResponse)
if expectedFileResponse != nil { if expectedFileResponse != nil {
assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0]) assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0])
@ -306,7 +310,7 @@ func TestChangeRepoFilesForUpdate(t *testing.T) {
commit, _ := gitRepo.GetBranchCommit(opts.NewBranch) commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath) lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath)
expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) expectedFileResponse := getExpectedFileResponseForRepoFilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String(), lastCommit.Committer.When, lastCommit.Author.When)
assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0]) assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0])
assert.Equal(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA) assert.Equal(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA)
assert.Equal(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL) assert.Equal(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
@ -342,7 +346,7 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) {
commit, _ := gitRepo.GetBranchCommit(opts.NewBranch) commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath) lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath)
expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) expectedFileResponse := getExpectedFileResponseForRepoFilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String(), lastCommit.Committer.When, lastCommit.Author.When)
// 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.Files[0].FromTreePath) fromEntry, err := commit.GetTreeEntryByPath(opts.Files[0].FromTreePath)
switch err.(type) { switch err.(type) {
@ -393,7 +397,7 @@ func TestChangeRepoFilesWithoutBranchNames(t *testing.T) {
commit, _ := gitRepo.GetBranchCommit(repo.DefaultBranch) commit, _ := gitRepo.GetBranchCommit(repo.DefaultBranch)
lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath) lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath)
expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) expectedFileResponse := getExpectedFileResponseForRepoFilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String(), lastCommit.Committer.When, lastCommit.Author.When)
assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0]) assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0])
}) })
} }
@ -419,7 +423,7 @@ func testDeleteRepoFiles(t *testing.T, u *url.URL) {
t.Run("Delete README.md file", func(t *testing.T) { t.Run("Delete README.md file", func(t *testing.T) {
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
assert.NoError(t, err) assert.NoError(t, err)
expectedFileResponse := getExpectedFileResponseForRepofilesDelete() expectedFileResponse := getExpectedFileResponseForRepoFilesDelete()
assert.NotNil(t, filesResponse) assert.NotNil(t, filesResponse)
assert.Nil(t, filesResponse.Files[0]) assert.Nil(t, filesResponse.Files[0])
assert.Equal(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) assert.Equal(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
@ -461,7 +465,7 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) {
t.Run("Delete README.md without Branch Name", func(t *testing.T) { t.Run("Delete README.md without Branch Name", func(t *testing.T) {
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
assert.NoError(t, err) assert.NoError(t, err)
expectedFileResponse := getExpectedFileResponseForRepofilesDelete() expectedFileResponse := getExpectedFileResponseForRepoFilesDelete()
assert.NotNil(t, filesResponse) assert.NotNil(t, filesResponse)
assert.Nil(t, filesResponse.Files[0]) assert.Nil(t, filesResponse.Files[0])
assert.Equal(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) assert.Equal(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)