Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API to get file commit history #17652

Merged
merged 26 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9634f56
Add API to get file comment history
qwerty287 Nov 15, 2021
dc1c3a5
Update swagger description
qwerty287 Nov 15, 2021
f7b15df
Update swagger
qwerty287 Nov 16, 2021
be658d7
Use user cache
qwerty287 Nov 16, 2021
ddc2f7f
Merge branch 'main' into api-file-hist
qwerty287 Nov 16, 2021
b19d8f0
Fix test
qwerty287 Nov 16, 2021
963a718
Merge branch 'main' into api-file-hist
qwerty287 Nov 18, 2021
0f74927
Merge branch 'main' into api-file-hist
qwerty287 Nov 21, 2021
c690801
Update desc
qwerty287 Nov 22, 2021
803bb05
Merge branch 'main' into api-file-hist
qwerty287 Nov 22, 2021
4376f26
Merge branch 'main' into api-file-hist
lunny Nov 23, 2021
0132166
Merge branch 'main' into api-file-hist
qwerty287 Nov 23, 2021
3d2f168
Merge branch 'main' into api-file-hist
qwerty287 Nov 25, 2021
0c1d718
Merge branch 'main' into api-file-hist
qwerty287 Nov 26, 2021
388db13
Merge branch 'main' into api-file-hist
qwerty287 Nov 29, 2021
a27b524
Merge branch 'main' into api-file-hist
qwerty287 Dec 5, 2021
2ee9ac8
Merge branch 'main' into api-file-hist
qwerty287 Dec 12, 2021
f91aba5
Move func to commits.go
qwerty287 Dec 13, 2021
4ebd8c0
Use GitHub-compatible endpoint
qwerty287 Dec 13, 2021
92e3de5
Update swagger
qwerty287 Dec 13, 2021
887addb
fmt
qwerty287 Dec 13, 2021
e1d9fd6
Merge branch 'main' into api-file-hist
qwerty287 Dec 16, 2021
1831fb5
Merge branch 'main' into api-file-hist
qwerty287 Dec 21, 2021
01c8883
Fix empty list
qwerty287 Dec 21, 2021
07f853e
Fix test
qwerty287 Dec 21, 2021
905e814
Merge branch 'main' into api-file-hist
lunny Dec 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions integrations/api_repo_git_commits_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,20 @@ func TestDownloadCommitDiffOrPatch(t *testing.T) {
resp.Body.String())

}

func TestGetFileHistory(t *testing.T) {
user := db.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
// Login as User2.
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session)
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved

req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/git/history/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, 3)
assert.Equal(t, "69554a64c1e6030f051e5c3f94bfbd773cd6a324", apiData[0].CommitMeta.SHA)
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
}
1 change: 1 addition & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
m.Get("/blobs/{sha}", context.RepoRefForAPI, repo.GetBlob)
m.Get("/tags/{sha}", context.RepoRefForAPI, repo.GetAnnotatedTag)
m.Get("/notes/{sha}", repo.GetNote)
m.Get("/history/*", context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetFileHistory)
}, reqRepoReader(unit.TypeCode))
m.Group("/contents", func() {
m.Get("", repo.GetContentsList)
Expand Down
85 changes: 85 additions & 0 deletions routers/api/v1/repo/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/repofiles"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/common"
Expand Down Expand Up @@ -597,3 +599,86 @@ func GetContentsList(ctx *context.APIContext) {
// same as GetContents(), this function is here because swagger fails if path is empty in GetContents() interface
GetContents(ctx)
}

// GetFileHistory get a file's commit history
func GetFileHistory(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/git/history/{filepath} repository repoGetFileHistory
// ---
// summary: Get the commit history of a file or directory
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: filepath
// in: path
// description: filepath of the file/directory
// type: string
// required: true
// - name: ref
// in: query
// description: "The name of the branch. Default the repository’s default branch (usually master)"
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved
// type: string
// required: false
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// responses:
// "200":
// "$ref": "#/responses/CommitList"
// "404":
// "$ref": "#/responses/notFound"

if ctx.Repo.Repository.IsEmpty {
ctx.NotFound()
return
}

ref := ctx.FormTrim("ref")
if len(ref) < 1 {
ref = ctx.Repo.Repository.DefaultBranch
}

page := ctx.FormInt("page")
if page <= 1 {
page = 1
}

commitsCount, err := ctx.Repo.GitRepo.FileCommitsCount(ref, ctx.Repo.TreePath)
if err != nil {
ctx.Error(http.StatusInternalServerError, "FileCommitsCount", err)
return
} else if commitsCount == 0 {
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved
ctx.NotFound("FileCommitsCount", nil)
return
}

commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(ref, ctx.Repo.TreePath, page)
if err != nil {
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved
ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRange", err)
return
}
apiCommits := make([]*api.Commit, len(commits))
for i, commit := range commits {
// Create json struct
apiCommits[i], err = convert.ToCommit(ctx.Repo.Repository, commit, make(map[string]*models.User))
if err != nil {
ctx.Error(http.StatusInternalServerError, "toCommit", err)
return
}
}

ctx.SetLinkHeader(int(commitsCount), setting.Git.CommitsRangeSize)
ctx.SetTotalCountHeader(commitsCount)

ctx.JSON(http.StatusOK, &apiCommits)
}
55 changes: 55 additions & 0 deletions templates/swagger/v1_json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3652,6 +3652,61 @@
}
}
},
"/repos/{owner}/{repo}/git/history/{filepath}": {
"get": {
"produces": [
"application/json"
],
"tags": [
"repository"
],
"summary": "Get the commit history of a file or directory",
"operationId": "repoGetFileHistory",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "string",
"description": "filepath of the file/directory",
"name": "filepath",
"in": "path",
"required": true
},
{
"type": "string",
"description": "The name of the branch. Default the repository’s default branch (usually master)",
"name": "ref",
"in": "query"
},
{
"type": "integer",
"description": "page number of results to return (1-based)",
"name": "page",
"in": "query"
}
],
"responses": {
"200": {
"$ref": "#/responses/CommitList"
},
"404": {
"$ref": "#/responses/notFound"
}
}
}
},
"/repos/{owner}/{repo}/git/notes/{sha}": {
"get": {
"produces": [
Expand Down