新增:获取文件下commit列表接口

This commit is contained in:
yystopf 2022-12-14 09:40:24 +08:00
parent e0bd2cd8d7
commit 753b7104af
4 changed files with 163 additions and 0 deletions

26
modules/git/repo.go Normal file
View File

@ -0,0 +1,26 @@
package git
import (
"bytes"
gitea_git "code.gitea.io/gitea/modules/git"
)
func parsePrettyFormatLogToList(repo *gitea_git.Repository, logs []byte) ([]*gitea_git.Commit, error) {
var commits []*gitea_git.Commit
if len(logs) == 0 {
return commits, nil
}
parts := bytes.Split(logs, []byte{'\n'})
for _, commitID := range parts {
commit, err := repo.GetCommit(string(commitID))
if err != nil {
return nil, err
}
commits = append(commits, commit)
}
return commits, nil
}

View File

@ -2,6 +2,9 @@ package git
import (
"bytes"
"io"
"strconv"
"strings"
gitea_git "code.gitea.io/gitea/modules/git"
)
@ -31,3 +34,48 @@ func GetFirstAndLastCommitByPath(repo *gitea_git.Repository, revision, relpath s
return commits[0], commits[len(commits)-1], nil
}
// CommitsByFileAndRange return the commits according revision file and the page
func CommitsByFileAndRange(repo *gitea_git.Repository, revision, file string, page, pageSize int) ([]*gitea_git.Commit, error) {
skip := (page - 1) * pageSize
stdoutReader, stdoutWriter := io.Pipe()
defer func() {
_ = stdoutReader.Close()
_ = stdoutWriter.Close()
}()
go func() {
stderr := strings.Builder{}
gitCmd := gitea_git.NewCommand(repo.Ctx, "log", prettyLogFormat, "--follow",
"--max-count="+strconv.Itoa(pageSize))
gitCmd.AddDynamicArguments(revision)
gitCmd.AddArguments("--", file)
err := gitCmd.Run(&gitea_git.RunOpts{
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = stdoutWriter.CloseWithError(gitea_git.ConcatenateError(err, (&stderr).String()))
} else {
_ = stdoutWriter.Close()
}
}()
if skip > 0 {
_, err := io.CopyN(io.Discard, stdoutReader, int64(skip*41))
if err != nil {
if err == io.EOF {
return []*gitea_git.Commit{}, nil
}
_ = stdoutReader.CloseWithError(err)
return nil, err
}
}
stdout, err := io.ReadAll(stdoutReader)
if err != nil {
return nil, err
}
return parsePrettyFormatLogToList(repo, stdout)
}

View File

@ -100,6 +100,9 @@ func Routers() *web.Route {
m.Group("/count", func() {
m.Get("", context.ReferencesGitRepo(), repo.GetCommitCount)
})
m.Group("/file_commits", func() {
m.Get("/*", context.ReferencesGitRepo(), repo.GetFileAllCommits)
})
}, repoAssignment())
})
m.Post("/orgs", reqToken(), bind(gitea_api.CreateOrgOption{}), org.Create)

View File

@ -8,12 +8,14 @@ import (
"code.gitea.io/gitea/models/repo"
user "code.gitea.io/gitea/models/user"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/utils"
hat_git "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git"
)
func GetAllCommitsSliceByTime(ctx *context.APIContext) {
@ -121,3 +123,87 @@ func toResponseCommit(repo *repo.Repository, gitRepo *git.Repository, commit *gi
CommitDate: apiCommit.Created.Format("2006-01-02"),
}, nil
}
func GetFileAllCommits(ctx *context.APIContext) {
if ctx.Repo.Repository.IsEmpty {
ctx.JSON(http.StatusConflict, api.APIError{
Message: "Git Repository is empty",
URL: setting.API.SwaggerURL,
})
return
}
listOptions := utils.GetListOptions(ctx)
if listOptions.Page <= 0 {
listOptions.Page = 1
}
if listOptions.PageSize > setting.Git.CommitsRangeSize {
listOptions.PageSize = setting.Git.CommitsRangeSize
}
ref := ctx.FormString("sha")
if ref == "" {
ref = ctx.FormString("ref")
}
treePath := ctx.Params("*")
var baseCommit *git.Commit
var commitsCountTotal int64
var err error
if len(ref) == 0 {
head, err := ctx.Repo.GitRepo.GetHEADBranch()
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetHeadBranch", err)
return
}
baseCommit, err = ctx.Repo.GitRepo.GetBranchCommit(head.Name)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetBranchCommit", err)
return
}
commitsCountTotal, err = git.CommitsCountFiles(ctx, ctx.Repo.Repository.RepoPath(), []string{head.Name}, []string{treePath})
if err != nil {
ctx.Error(http.StatusInternalServerError, "CommitsCountFiles", err)
return
}
} else {
baseCommit, err = ctx.Repo.GitRepo.GetCommit(ref)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
return
}
commitsCountTotal, err = git.CommitsCountFiles(ctx, ctx.Repo.GitRepo.Path, []string{ref}, []string{treePath})
if err != nil {
ctx.Error(http.StatusInternalServerError, "CommitsCountFiles", err)
return
}
}
pageCount := int(math.Ceil(float64(commitsCountTotal) / float64(listOptions.PageSize)))
commits, err := hat_git.CommitsByFileAndRange(ctx.Repo.GitRepo, baseCommit.ID.String(), treePath, listOptions.Page, listOptions.PageSize)
if err != nil {
ctx.Error(http.StatusInternalServerError, "CommitsByRange", err)
return
}
userCache := make(map[string]*user_model.User)
apiCommits := make([]*api.Commit, len(commits))
for i, commit := range commits {
apiCommits[i], err = convert.ToCommit(ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache)
if err != nil {
ctx.Error(http.StatusInternalServerError, "ToCommit", err)
return
}
}
ctx.Resp.Header().Set("X-Page", strconv.Itoa(listOptions.Page))
ctx.Resp.Header().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
ctx.Resp.Header().Set("X-Total", strconv.FormatInt(commitsCountTotal, 10))
ctx.Resp.Header().Set("X-PageCount", strconv.Itoa(pageCount))
ctx.Resp.Header().Set("X-HasMore", strconv.FormatBool(listOptions.Page < pageCount))
ctx.SetLinkHeader(int(commitsCountTotal), listOptions.PageSize)
ctx.Resp.Header().Set("X-Total-Count", fmt.Sprintf("%d", commitsCountTotal))
ctx.JSON(http.StatusOK, apiCommits)
}