mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-08-29 22:06:06 +02:00
Add API to get file commit history (#17652)
Adds an API endpoint `api/v1/repos/{owner}/{repo}/git/history/{filepath}` to get the commits affecting the given file or directory. Closes https://github.com/go-gitea/gitea/issues/16206 and closes https://github.com/go-gitea/gitea/issues/16703
This commit is contained in:
parent
d155ffc610
commit
a9ed1c5c7c
3 changed files with 81 additions and 26 deletions
|
@ -132,3 +132,21 @@ func TestDownloadCommitDiffOrPatch(t *testing.T) {
|
||||||
resp.Body.String())
|
resp.Body.String())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetFileHistory(t *testing.T) {
|
||||||
|
defer prepareTestEnv(t)()
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||||
|
// Login as User2.
|
||||||
|
session := loginUser(t, user.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?path=readme.md&token="+token+"&sha=good-sign", user.Name)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
var apiData []api.Commit
|
||||||
|
DecodeJSON(t, resp, &apiData)
|
||||||
|
|
||||||
|
assert.Len(t, apiData, 1)
|
||||||
|
assert.Equal(t, "f27c2b2b03dcab38beaf89b0ab4ff61f6de63441", apiData[0].CommitMeta.SHA)
|
||||||
|
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
|
||||||
|
}
|
||||||
|
|
|
@ -108,13 +108,17 @@ func GetAllCommits(ctx *context.APIContext) {
|
||||||
// in: query
|
// in: query
|
||||||
// description: SHA or branch to start listing commits from (usually 'master')
|
// description: SHA or branch to start listing commits from (usually 'master')
|
||||||
// type: string
|
// type: string
|
||||||
|
// - name: path
|
||||||
|
// in: query
|
||||||
|
// description: filepath of a file/dir
|
||||||
|
// type: string
|
||||||
// - name: page
|
// - name: page
|
||||||
// in: query
|
// in: query
|
||||||
// description: page number of results to return (1-based)
|
// description: page number of results to return (1-based)
|
||||||
// type: integer
|
// type: integer
|
||||||
// - name: limit
|
// - name: limit
|
||||||
// in: query
|
// in: query
|
||||||
// description: page size of results
|
// description: page size of results (ignored if used with 'path')
|
||||||
// type: integer
|
// type: integer
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
|
@ -149,46 +153,73 @@ func GetAllCommits(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sha := ctx.FormString("sha")
|
sha := ctx.FormString("sha")
|
||||||
|
path := ctx.FormString("path")
|
||||||
|
|
||||||
var baseCommit *git.Commit
|
var (
|
||||||
if len(sha) == 0 {
|
commitsCountTotal int64
|
||||||
// no sha supplied - use default branch
|
commits []*git.Commit
|
||||||
head, err := gitRepo.GetHEADBranch()
|
)
|
||||||
|
|
||||||
|
if len(path) == 0 {
|
||||||
|
var baseCommit *git.Commit
|
||||||
|
if len(sha) == 0 {
|
||||||
|
// no sha supplied - use default branch
|
||||||
|
head, err := gitRepo.GetHEADBranch()
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetHEADBranch", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
baseCommit, err = gitRepo.GetBranchCommit(head.Name)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get commit specified by sha
|
||||||
|
baseCommit, err = gitRepo.GetCommit(sha)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total commit count
|
||||||
|
commitsCountTotal, err = baseCommit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetHEADBranch", err)
|
ctx.Error(http.StatusInternalServerError, "GetCommitsCount", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
baseCommit, err = gitRepo.GetBranchCommit(head.Name)
|
// Query commits
|
||||||
|
commits, err = baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
ctx.Error(http.StatusInternalServerError, "CommitsByRange", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// get commit specified by sha
|
if len(sha) == 0 {
|
||||||
baseCommit, err = gitRepo.GetCommit(sha)
|
sha = ctx.Repo.Repository.DefaultBranch
|
||||||
|
}
|
||||||
|
|
||||||
|
commitsCountTotal, err = gitRepo.FileCommitsCount(sha, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
ctx.Error(http.StatusInternalServerError, "FileCommitsCount", err)
|
||||||
|
return
|
||||||
|
} else if commitsCountTotal == 0 {
|
||||||
|
ctx.NotFound("FileCommitsCount", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commits, err = gitRepo.CommitsByFileAndRange(sha, path, listOptions.Page)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRange", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Total commit count
|
|
||||||
commitsCountTotal, err := baseCommit.CommitsCount()
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "GetCommitsCount", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pageCount := int(math.Ceil(float64(commitsCountTotal) / float64(listOptions.PageSize)))
|
pageCount := int(math.Ceil(float64(commitsCountTotal) / float64(listOptions.PageSize)))
|
||||||
|
|
||||||
// Query commits
|
|
||||||
commits, err := baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "CommitsByRange", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
userCache := make(map[string]*user_model.User)
|
userCache := make(map[string]*user_model.User)
|
||||||
|
|
||||||
apiCommits := make([]*api.Commit, len(commits))
|
apiCommits := make([]*api.Commit, len(commits))
|
||||||
|
|
|
@ -2950,6 +2950,12 @@
|
||||||
"name": "sha",
|
"name": "sha",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "filepath of a file/dir",
|
||||||
|
"name": "path",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number of results to return (1-based)",
|
"description": "page number of results to return (1-based)",
|
||||||
|
@ -2958,7 +2964,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page size of results",
|
"description": "page size of results (ignored if used with 'path')",
|
||||||
"name": "limit",
|
"name": "limit",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue