forked from Gitlink/gitea_hat
新增:获取文件下commit列表接口
This commit is contained in:
parent
e0bd2cd8d7
commit
753b7104af
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,9 @@ package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
gitea_git "code.gitea.io/gitea/modules/git"
|
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
|
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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,9 @@ func Routers() *web.Route {
|
||||||
m.Group("/count", func() {
|
m.Group("/count", func() {
|
||||||
m.Get("", context.ReferencesGitRepo(), repo.GetCommitCount)
|
m.Get("", context.ReferencesGitRepo(), repo.GetCommitCount)
|
||||||
})
|
})
|
||||||
|
m.Group("/file_commits", func() {
|
||||||
|
m.Get("/*", context.ReferencesGitRepo(), repo.GetFileAllCommits)
|
||||||
|
})
|
||||||
}, repoAssignment())
|
}, repoAssignment())
|
||||||
})
|
})
|
||||||
m.Post("/orgs", reqToken(), bind(gitea_api.CreateOrgOption{}), org.Create)
|
m.Post("/orgs", reqToken(), bind(gitea_api.CreateOrgOption{}), org.Create)
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,14 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/repo"
|
"code.gitea.io/gitea/models/repo"
|
||||||
user "code.gitea.io/gitea/models/user"
|
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/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"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) {
|
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"),
|
CommitDate: apiCommit.Created.Format("2006-01-02"),
|
||||||
}, nil
|
}, 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)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue