Add support for listing commit related per file stats (#1116)

eb/code-1016-2
Darko Draskovic 2024-03-20 18:31:48 +00:00 committed by Harness
parent dae465a111
commit 564a0fef61
15 changed files with 325 additions and 252 deletions

View File

@ -43,15 +43,16 @@ func (c *Controller) ListCommits(ctx context.Context,
}
rpcOut, err := c.git.ListCommits(ctx, &git.ListCommitsParams{
ReadParams: git.CreateReadParams(repo),
GitREF: gitRef,
After: filter.After,
Page: int32(filter.Page),
Limit: int32(filter.Limit),
Path: filter.Path,
Since: filter.Since,
Until: filter.Until,
Committer: filter.Committer,
ReadParams: git.CreateReadParams(repo),
GitREF: gitRef,
After: filter.After,
Page: int32(filter.Page),
Limit: int32(filter.Limit),
Path: filter.Path,
Since: filter.Since,
Until: filter.Until,
Committer: filter.Committer,
IncludeStats: filter.IncludeStats,
})
if err != nil {
return types.ListCommitResponse{}, err

View File

@ -94,6 +94,13 @@ func MapCommit(c *git.Commit) (*types.Commit, error) {
return nil, fmt.Errorf("failed to map committer: %w", err)
}
var insertions int64
var deletions int64
for _, stat := range c.FileStats {
insertions += stat.Insertions
deletions += stat.Deletions
}
return &types.Commit{
SHA: c.SHA,
ParentSHAs: c.ParentSHAs,
@ -101,14 +108,36 @@ func MapCommit(c *git.Commit) (*types.Commit, error) {
Message: c.Message,
Author: *author,
Committer: *committer,
DiffStats: types.CommitDiffStats{
Additions: c.DiffStats.Additions,
Deletions: c.DiffStats.Deletions,
Total: c.DiffStats.Additions + c.DiffStats.Deletions,
Stats: types.CommitStats{
Total: types.ChangeStats{
Insertions: insertions,
Deletions: deletions,
Changes: insertions + deletions,
},
Files: mapFileStats(c),
},
}, nil
}
func mapFileStats(c *git.Commit) []types.CommitFileStats {
fileStats := make([]types.CommitFileStats, len(c.FileStats))
for i, fStat := range c.FileStats {
fileStats[i] = types.CommitFileStats{
Path: fStat.Path,
OldPath: fStat.OldPath,
Status: fStat.ChangeType,
ChangeStats: types.ChangeStats{
Insertions: fStat.Insertions,
Deletions: fStat.Deletions,
Changes: fStat.Insertions + fStat.Deletions,
},
}
}
return fileStats
}
func MapRenameDetails(c *git.RenameDetails) *types.RenameDetails {
if c == nil {
return nil

View File

@ -273,6 +273,21 @@ var queryParameterIncludeCommit = openapi3.ParameterOrRef{
},
}
var QueryParamIncludeStats = openapi3.ParameterOrRef{
Parameter: &openapi3.Parameter{
Name: request.QueryParamIncludeStats,
In: openapi3.ParameterInQuery,
Description: ptr.String("Indicates whether optional stats should be included in the response."),
Required: ptr.Bool(false),
Schema: &openapi3.SchemaOrRef{
Schema: &openapi3.Schema{
Type: ptrSchemaType(openapi3.SchemaTypeBoolean),
Default: ptrptr(false),
},
},
},
}
var queryParameterLineFrom = openapi3.ParameterOrRef{
Parameter: &openapi3.Parameter{
Name: request.QueryParamLineFrom,
@ -633,7 +648,8 @@ func repoOperations(reflector *openapi3.Reflector) {
opListCommits.WithTags("repository")
opListCommits.WithMapOfAnything(map[string]interface{}{"operationId": "listCommits"})
opListCommits.WithParameters(queryParameterGitRef, queryParameterAfterCommits, queryParameterPath,
queryParameterSince, queryParameterUntil, queryParameterCommitter, queryParameterPage, queryParameterLimit)
queryParameterSince, queryParameterUntil, queryParameterCommitter,
queryParameterPage, queryParameterLimit, QueryParamIncludeStats)
_ = reflector.SetRequest(&opListCommits, new(listCommitsRequest), http.MethodGet)
_ = reflector.SetJSONResponse(&opListCommits, []types.ListCommitResponse{}, http.StatusOK)
_ = reflector.SetJSONResponse(&opListCommits, new(usererror.Error), http.StatusInternalServerError)

View File

@ -36,6 +36,7 @@ const (
QueryParamSince = "since"
QueryParamUntil = "until"
QueryParamCommitter = "committer"
QueryParamIncludeStats = "include_stats"
QueryParamInternal = "internal"
QueryParamService = "service"
HeaderParamGitProtocol = "Git-Protocol"
@ -101,16 +102,22 @@ func ParseCommitFilter(r *http.Request) (*types.CommitFilter, error) {
if err != nil {
return nil, err
}
includeStats, err := QueryParamAsBoolOrDefault(r, QueryParamIncludeStats, false)
if err != nil {
return nil, err
}
return &types.CommitFilter{
After: QueryParamOrDefault(r, QueryParamAfter, ""),
PaginationFilter: types.PaginationFilter{
Page: ParsePage(r),
Limit: ParseLimit(r),
},
Path: QueryParamOrDefault(r, QueryParamPath, ""),
Since: since,
Until: until,
Committer: QueryParamOrDefault(r, QueryParamCommitter, ""),
Path: QueryParamOrDefault(r, QueryParamPath, ""),
Since: since,
Until: until,
Committer: QueryParamOrDefault(r, QueryParamCommitter, ""),
IncludeStats: includeStats,
}, nil
}

View File

@ -179,12 +179,12 @@ func (s *Service) fetchCommitsInfoForEvent(
newSHA string,
) ([]CommitInfo, int, error) {
listCommitsParams := git.ListCommitsParams{
ReadParams: git.ReadParams{RepoUID: repoUID},
GitREF: newSHA,
After: oldSHA,
Page: 0,
Limit: MaxWebhookCommitFileStats,
IncludeFileStats: true,
ReadParams: git.ReadParams{RepoUID: repoUID},
GitREF: newSHA,
After: oldSHA,
Page: 0,
Limit: MaxWebhookCommitFileStats,
IncludeStats: true,
}
listCommitsOutput, err := s.git.ListCommits(ctx, &listCommitsParams)

View File

@ -20,8 +20,11 @@ import (
"github.com/harness/gitness/app/url"
"github.com/harness/gitness/git"
gitenum "github.com/harness/gitness/git/enum"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
/*
@ -183,14 +186,35 @@ type CommitInfo struct {
// commitInfoFrom gets the CommitInfo from a git.Commit.
func commitInfoFrom(commit git.Commit) CommitInfo {
var added []string
var removed []string
var modified []string
for _, stat := range commit.FileStats {
switch {
case stat.ChangeType == gitenum.FileDiffStatusModified:
modified = append(modified, stat.Path)
case stat.ChangeType == gitenum.FileDiffStatusRenamed:
added = append(added, stat.Path)
removed = append(removed, stat.OldPath)
case stat.ChangeType == gitenum.FileDiffStatusDeleted:
removed = append(removed, stat.Path)
case stat.ChangeType == gitenum.FileDiffStatusAdded || stat.ChangeType == gitenum.FileDiffStatusCopied:
added = append(added, stat.Path)
case stat.ChangeType == gitenum.FileDiffStatusUndefined:
default:
log.Warn().Msgf("unknown change type %q for path %q", stat.ChangeType, stat.Path)
}
}
return CommitInfo{
SHA: commit.SHA,
Message: commit.Message,
Author: signatureInfoFrom(commit.Author),
Committer: signatureInfoFrom(commit.Committer),
Added: commit.FileStats.Added,
Removed: commit.FileStats.Removed,
Modified: commit.FileStats.Modified,
Added: added,
Removed: removed,
Modified: modified,
}
}

View File

@ -61,7 +61,7 @@ type Adapter interface {
ref string,
page int,
limit int,
includeFileStats bool,
includeStats bool,
filter types.CommitFilter) ([]types.Commit, []types.PathRenameDetails, error)
ListCommitSHAs(ctx context.Context, repoPath string,
ref string, page int, limit int, filter types.CommitFilter) ([]string, error)

View File

@ -18,6 +18,7 @@ import (
"bytes"
"context"
"fmt"
"regexp"
"strconv"
"strings"
"time"
@ -143,7 +144,7 @@ func (a Adapter) ListCommits(
ref string,
page int,
limit int,
includeFileStats bool,
includeStats bool,
filter types.CommitFilter,
) ([]types.Commit, []types.PathRenameDetails, error) {
if repoPath == "" {
@ -172,15 +173,16 @@ func (a Adapter) ListCommits(
if err != nil {
return nil, nil, err
}
commits[i] = *commit
if includeFileStats {
fileStat, err := getFileStats(ctx, giteaRepo, commit.SHA)
if includeStats {
fileStats, err := getCommitFileStats(ctx, giteaRepo, commit.SHA)
if err != nil {
return nil, nil, fmt.Errorf("encountered error getting file stat: %w", err)
return nil, nil, fmt.Errorf("encountered error getting commit file stats: %w", err)
}
commit.FileStats = fileStat
commit.FileStats = fileStats
}
commits[i] = *commit
}
if len(filter.Path) != 0 {
@ -195,34 +197,35 @@ func (a Adapter) ListCommits(
return commits, nil, nil
}
func getFileStats(
func getCommitFileStats(
ctx context.Context,
giteaRepo *gitea.Repository,
sha string,
) (types.CommitFileStats, error) {
changeInfos, err := getChangeInfos(ctx, giteaRepo, sha)
) ([]types.CommitFileStats, error) {
var changeInfoTypes map[string]changeInfoType
changeInfoTypes, err := getChangeInfoTypes(ctx, giteaRepo, sha)
if err != nil {
return types.CommitFileStats{}, fmt.Errorf("failed to get change infos: %w", err)
return nil, fmt.Errorf("failed to get change infos: %w", err)
}
fileStats := types.CommitFileStats{
Added: make([]string, 0),
Removed: make([]string, 0),
Modified: make([]string, 0),
changeInfoChanges, err := getChangeInfoChanges(giteaRepo, sha)
if err != nil {
return []types.CommitFileStats{}, fmt.Errorf("failed to get change infos: %w", err)
}
for _, c := range changeInfos {
switch {
case c.ChangeType == enum.FileDiffStatusModified || c.ChangeType == enum.FileDiffStatusRenamed:
fileStats.Modified = append(fileStats.Modified, c.Path)
case c.ChangeType == enum.FileDiffStatusDeleted:
fileStats.Removed = append(fileStats.Removed, c.Path)
case c.ChangeType == enum.FileDiffStatusAdded || c.ChangeType == enum.FileDiffStatusCopied:
fileStats.Added = append(fileStats.Added, c.Path)
case c.ChangeType == enum.FileDiffStatusUndefined:
default:
log.Ctx(ctx).Warn().Msgf("unknown change type %q for path %q",
c.ChangeType, c.Path)
fileStats := make([]types.CommitFileStats, len(changeInfoChanges))
i := 0
for path, info := range changeInfoChanges {
fileStats[i] = types.CommitFileStats{
Path: changeInfoTypes[path].Path,
OldPath: changeInfoTypes[path].OldPath,
Status: changeInfoTypes[path].ChangeType,
Insertions: info.Insertions,
Deletions: info.Deletions,
}
i++
}
return fileStats, nil
}
@ -261,7 +264,7 @@ func getRenameDetails(
if err != nil {
return nil, err
}
if renameDetails.NewPath != "" || renameDetails.OldPath != "" {
if renameDetails.Path != "" || renameDetails.OldPath != "" {
renameDetails.CommitSHABefore = commits[0].SHA
renameDetailsList = append(renameDetailsList, *renameDetails)
}
@ -275,7 +278,7 @@ func getRenameDetails(
return nil, err
}
if renameDetailsLast.NewPath != "" || renameDetailsLast.OldPath != "" {
if renameDetailsLast.Path != "" || renameDetailsLast.OldPath != "" {
renameDetailsLast.CommitSHAAfter = commits[len(commits)-1].SHA
renameDetailsList = append(renameDetailsList, *renameDetailsLast)
}
@ -288,16 +291,16 @@ func giteaGetRenameDetails(
ref string,
path string,
) (*types.PathRenameDetails, error) {
changeInfos, err := getChangeInfos(ctx, giteaRepo, ref)
changeInfos, err := getChangeInfoTypes(ctx, giteaRepo, ref)
if err != nil {
return &types.PathRenameDetails{}, fmt.Errorf("failed to get change infos %w", err)
}
for _, c := range changeInfos {
if c.ChangeType == enum.FileDiffStatusRenamed && (c.Path == path || c.NewPath == path) {
if c.ChangeType == enum.FileDiffStatusRenamed && (c.OldPath == path || c.Path == path) {
return &types.PathRenameDetails{
OldPath: c.Path,
NewPath: c.NewPath,
OldPath: c.OldPath,
Path: c.Path,
}, nil
}
}
@ -305,59 +308,132 @@ func giteaGetRenameDetails(
return &types.PathRenameDetails{}, nil
}
func getChangeInfos(
ctx context.Context,
giteaRepo *gitea.Repository,
ref string,
) ([]changeInfo, error) {
func gitLogNameStatus(giteaRepo *gitea.Repository, ref string) ([]string, error) {
cmd := command.New("log",
command.WithArg(ref),
command.WithFlag("--name-status"),
command.WithFlag("--pretty=format:", "-1"),
command.WithFlag("--format="),
command.WithArg(ref),
command.WithFlag("--max-count=1"),
)
output := &bytes.Buffer{}
err := cmd.Run(giteaRepo.Ctx, command.WithDir(giteaRepo.Path), command.WithStdout(output))
if err != nil {
return nil, fmt.Errorf("failed to trigger log command: %w", err)
}
lines := parseLinesToSlice(output.Bytes())
return parseLinesToSlice(output.Bytes()), nil
}
changeInfos, err := getFileChangeTypeFromLog(ctx, lines)
func gitShowNumstat(giteaRepo *gitea.Repository, ref string) ([]string, error) {
cmd := command.New("show",
command.WithFlag("--numstat"),
command.WithFlag("--format="),
command.WithArg(ref),
)
output := &bytes.Buffer{}
err := cmd.Run(giteaRepo.Ctx, command.WithDir(giteaRepo.Path), command.WithStdout(output))
if err != nil {
return nil, fmt.Errorf("failed to trigger show command: %w", err)
}
return parseLinesToSlice(output.Bytes()), nil
}
// Will match "R100\tREADME.md\tREADME_new.md".
// Will extract README.md and README_new.md.
var renameRegex = regexp.MustCompile(`\t(.+)\t(.+)`)
func getChangeInfoTypes(
ctx context.Context,
giteaRepo *gitea.Repository,
ref string,
) (map[string]changeInfoType, error) {
lines, err := gitLogNameStatus(giteaRepo, ref)
if err != nil {
return nil, err
}
return changeInfos, nil
}
type changeInfo struct {
ChangeType enum.FileDiffStatus
Path string
// populated only in case of renames
NewPath string
}
changeInfoTypes := make(map[string]changeInfoType, len(lines))
for _, line := range lines {
c := changeInfoType{}
func getFileChangeTypeFromLog(
ctx context.Context,
changeStrings []string,
) ([]changeInfo, error) {
changeInfos := make([]changeInfo, len(changeStrings))
for i, changeString := range changeStrings {
changeStringSplit := strings.Split(changeString, "\t")
if len(changeStringSplit) < 1 {
return changeInfos, fmt.Errorf("could not parse changeString %q", changeString)
matches := renameRegex.FindStringSubmatch(line) // renamed file
if len(matches) > 0 {
c.OldPath = matches[1]
c.Path = matches[2]
} else {
lineParts := strings.Split(line, "\t")
if len(lineParts) != 2 {
return changeInfoTypes, fmt.Errorf("could not parse file change status string %q", line)
}
c.Path = lineParts[1]
}
c := changeInfo{}
c.ChangeType = convertChangeType(ctx, changeStringSplit[0])
c.Path = changeStringSplit[1]
if len(changeStringSplit) == 3 {
c.NewPath = changeStringSplit[2]
}
changeInfos[i] = c
c.ChangeType = convertChangeType(ctx, line)
changeInfoTypes[c.Path] = c
}
return changeInfoTypes, nil
}
// Will match "31\t0\t.harness/apidiff.yaml".
// Will extract 31, 0 and .harness/apidiff.yaml.
var insertionsDeletionsRegex = regexp.MustCompile(`(\d+)\t(\d+)\t(.+)`)
// Will match "0\t0\tREADME.md => README_new.md".
// Will extract README_new.md.
var renameRegexWithArrow = regexp.MustCompile(`\d+\t\d+\t.+\s=>\s(.+)`)
func getChangeInfoChanges(
giteaRepo *gitea.Repository,
ref string,
) (map[string]changeInfoChange, error) {
lines, err := gitShowNumstat(giteaRepo, ref)
if err != nil {
return nil, err
}
changeInfos := make(map[string]changeInfoChange, len(lines))
for _, line := range lines {
matches := insertionsDeletionsRegex.FindStringSubmatch(line)
if len(matches) != 4 {
return map[string]changeInfoChange{},
fmt.Errorf("failed to regex match insertions and deletions for %q", line)
}
path := matches[3]
if renMatches := renameRegexWithArrow.FindStringSubmatch(line); len(renMatches) == 2 {
path = renMatches[1]
}
insertions, err := strconv.ParseInt(matches[1], 10, 64)
if err != nil {
return map[string]changeInfoChange{},
fmt.Errorf("failed to parse insertions for %q", line)
}
deletions, err := strconv.ParseInt(matches[2], 10, 64)
if err != nil {
return map[string]changeInfoChange{},
fmt.Errorf("failed to parse deletions for %q", line)
}
changeInfos[path] = changeInfoChange{
Insertions: insertions,
Deletions: deletions,
}
}
return changeInfos, nil
}
type changeInfoType struct {
ChangeType enum.FileDiffStatus
OldPath string // populated only in case of renames
Path string
}
type changeInfoChange struct {
Insertions int64
Deletions int64
}
func convertChangeType(ctx context.Context, c string) enum.FileDiffStatus {
switch {
case strings.HasPrefix(c, "A"):

View File

@ -20,9 +20,8 @@ import (
"time"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git/enum"
"github.com/harness/gitness/git/types"
"github.com/rs/zerolog/log"
)
type GetCommitParams struct {
@ -32,14 +31,13 @@ type GetCommitParams struct {
}
type Commit struct {
SHA string `json:"sha"`
ParentSHAs []string `json:"parent_shas,omitempty"`
Title string `json:"title"`
Message string `json:"message,omitempty"`
Author Signature `json:"author"`
Committer Signature `json:"committer"`
FileStats CommitFileStats `json:"file_stats,omitempty"`
DiffStats CommitDiffStats `json:"diff_stats,omitempty"`
SHA string `json:"sha"`
ParentSHAs []string `json:"parent_shas,omitempty"`
Title string `json:"title"`
Message string `json:"message,omitempty"`
Author Signature `json:"author"`
Committer Signature `json:"committer"`
FileStats []CommitFileStats `json:"file_stats,omitempty"`
}
type GetCommitOutput struct {
@ -111,8 +109,8 @@ type ListCommitsParams struct {
// Committer allows to filter for commits based on the committer - Optional, ignored if string is empty.
Committer string
// IncludeFileStats allows you to include information about files changed, added and modified.
IncludeFileStats bool
// IncludeStats allows to include information about inserted, deletions and status for changed files.
IncludeStats bool
}
type RenameDetails struct {
@ -129,9 +127,11 @@ type ListCommitsOutput struct {
}
type CommitFileStats struct {
Added []string
Modified []string
Removed []string
ChangeType enum.FileDiffStatus
Path string
OldPath string // populated only in case of renames
Insertions int64
Deletions int64
}
func (s *Service) ListCommits(ctx context.Context, params *ListCommitsParams) (*ListCommitsOutput, error) {
@ -147,7 +147,7 @@ func (s *Service) ListCommits(ctx context.Context, params *ListCommitsParams) (*
params.GitREF,
int(params.Page),
int(params.Limit),
params.IncludeFileStats,
params.IncludeStats,
types.CommitFilter{
AfterRef: params.After,
Path: params.Path,
@ -183,19 +183,6 @@ func (s *Service) ListCommits(ctx context.Context, params *ListCommitsParams) (*
return nil, fmt.Errorf("failed to map rpc commit: %w", err)
}
stat, err := s.CommitShortStat(ctx, &CommitShortStatParams{
Path: repoPath,
Ref: commit.SHA,
})
if err != nil {
log.Warn().Msgf("failed to get diff stats: %s", err)
}
commit.DiffStats = CommitDiffStats{
Additions: stat.Additions,
Deletions: stat.Deletions,
Total: stat.Additions + stat.Deletions,
}
commits[i] = *commit
}

View File

@ -16,16 +16,12 @@ package git
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"regexp"
"strconv"
"sync"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git/command"
"github.com/harness/gitness/git/diff"
"github.com/harness/gitness/git/enum"
"github.com/harness/gitness/git/types"
@ -33,26 +29,6 @@ import (
"golang.org/x/sync/errgroup"
)
// Parse "1 file changed, 3 insertions(+), 3 deletions(-)" for nums.
var shortStatsRegexp = regexp.MustCompile(
`files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?`)
type CommitShortStatParams struct {
Path string
Ref string
}
func (p CommitShortStatParams) Validate() error {
if p.Path == "" {
return errors.InvalidArgument("path cannot be empty")
}
if p.Ref == "" {
return errors.InvalidArgument("ref cannot be empty")
}
return nil
}
type DiffParams struct {
ReadParams
BaseRef string
@ -200,69 +176,6 @@ func (s *Service) DiffStats(ctx context.Context, params *DiffParams) (DiffStatsO
}, nil
}
func parseCommitShortStat(statBuffer *bytes.Buffer) (CommitShortStatOutput, error) {
matches := shortStatsRegexp.FindStringSubmatch(statBuffer.String())
if len(matches) != 3 {
return CommitShortStatOutput{}, errors.Internal(errors.New("failed to match stats line"), "")
}
var stat CommitShortStatOutput
// if there are insertions; no insertions case: "1 file changed, 3 deletions(-)"
if len(matches[1]) > 0 {
if value, err := strconv.Atoi(matches[1]); err == nil {
stat.Additions = value
} else {
return CommitShortStatOutput{}, fmt.Errorf("failed to parse additions stats: %w", err)
}
}
// if there are deletions; no deletions case: "1 file changed, 3 insertions(+)"
if len(matches[2]) > 0 {
if value, err := strconv.Atoi(matches[2]); err == nil {
stat.Deletions = value
} else {
return CommitShortStatOutput{}, fmt.Errorf("failed to parse deletions stats: %w", err)
}
}
return stat, nil
}
type CommitShortStatOutput struct {
Additions int
Deletions int
}
func (s *Service) CommitShortStat(
ctx context.Context,
params *CommitShortStatParams,
) (CommitShortStatOutput, error) {
if err := params.Validate(); err != nil {
return CommitShortStatOutput{}, err
}
// git log -1 --shortstat --pretty=format:""
cmd := command.New(
"log",
command.WithFlag("-1"),
command.WithFlag("--shortstat"),
command.WithFlag(`--pretty=format:""`),
command.WithArg(params.Ref),
)
stdout := bytes.NewBuffer(nil)
if err := cmd.Run(ctx, command.WithDir(params.Path), command.WithStdout(stdout)); err != nil {
return CommitShortStatOutput{}, errors.Internal(err, "failed to show stats")
}
stat, err := parseCommitShortStat(stdout)
if err != nil {
return CommitShortStatOutput{}, errors.Internal(err, "failed to parse stats line")
}
return stat, nil
}
type GetDiffHunkHeadersParams struct {
ReadParams
SourceCommitSHA string

View File

@ -74,7 +74,6 @@ type Interface interface {
CommitDiff(ctx context.Context, params *GetCommitParams, w io.Writer) error
DiffShortStat(ctx context.Context, params *DiffParams) (DiffShortStatOutput, error)
DiffStats(ctx context.Context, params *DiffParams) (DiffStatsOutput, error)
CommitShortStat(ctx context.Context, params *CommitShortStatParams) (CommitShortStatOutput, error)
GetDiffHunkHeaders(ctx context.Context, params GetDiffHunkHeadersParams) (GetDiffHunkHeadersOutput, error)
DiffCut(ctx context.Context, params *DiffCutParams) (DiffCutOutput, error)

View File

@ -55,6 +55,7 @@ func mapCommit(c *types.Commit) (*Commit, error) {
if err != nil {
return nil, fmt.Errorf("failed to map rpc committer: %w", err)
}
return &Commit{
SHA: c.SHA,
ParentSHAs: c.ParentSHAs,
@ -62,16 +63,24 @@ func mapCommit(c *types.Commit) (*Commit, error) {
Message: c.Message,
Author: *author,
Committer: *comitter,
FileStats: *mapFileStats(&c.FileStats),
FileStats: mapFileStats(c.FileStats),
}, nil
}
func mapFileStats(s *types.CommitFileStats) *CommitFileStats {
return &CommitFileStats{
Added: s.Added,
Modified: s.Modified,
Removed: s.Removed,
func mapFileStats(typeStats []types.CommitFileStats) []CommitFileStats {
var stats = make([]CommitFileStats, len(typeStats))
for i, tStat := range typeStats {
stats[i] = CommitFileStats{
ChangeType: tStat.Status,
Path: tStat.Path,
OldPath: tStat.OldPath,
Insertions: tStat.Insertions,
Deletions: tStat.Deletions,
}
}
return stats
}
func mapSignature(s *types.Signature) (*Signature, error) {
@ -201,7 +210,7 @@ func mapRenameDetails(c []types.PathRenameDetails) []*RenameDetails {
for i, detail := range c {
renameDetailsList[i] = &RenameDetails{
OldPath: detail.OldPath,
NewPath: detail.NewPath,
NewPath: detail.Path,
CommitShaBefore: detail.CommitSHABefore,
CommitShaAfter: detail.CommitSHAAfter,
}

View File

@ -84,12 +84,6 @@ func (p *CommitFilesParams) Validate() error {
return p.WriteParams.Validate()
}
type CommitDiffStats struct {
Total int
Additions int
Deletions int
}
type CommitFilesResponse struct {
CommitID string
}

View File

@ -20,6 +20,7 @@ import (
"time"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git/enum"
)
const NilSHA = "0000000000000000000000000000000000000000"
@ -140,20 +141,23 @@ type WalkReferencesOptions struct {
MaxWalkDistance int32
}
type Commit struct {
SHA string `json:"sha"`
ParentSHAs []string `json:"parent_shas,omitempty"`
Title string `json:"title"`
Message string `json:"message,omitempty"`
Author Signature `json:"author"`
Committer Signature `json:"committer"`
FileStats CommitFileStats `json:"file_stats,omitempty"`
type CommitFileStats struct {
Path string `json:"path"`
OldPath string `json:"old_path,omitempty"`
Status enum.FileDiffStatus `json:"status"`
Insertions int64 `json:"insertions"`
Deletions int64 `json:"deletions"`
Changes int64 `json:"changes"`
}
type CommitFileStats struct {
Added []string
Modified []string
Removed []string
type Commit struct {
SHA string `json:"sha"`
ParentSHAs []string `json:"parent_shas,omitempty"`
Title string `json:"title"`
Message string `json:"message,omitempty"`
Author Signature `json:"author"`
Committer Signature `json:"committer"`
FileStats []CommitFileStats `json:"file_stats,omitempty"`
}
type Branch struct {
@ -346,7 +350,7 @@ type BlamePart struct {
type PathRenameDetails struct {
OldPath string
NewPath string
Path string
CommitSHABefore string
CommitSHAAfter string
}

View File

@ -17,6 +17,7 @@ package types
import (
"time"
gitenum "github.com/harness/gitness/git/enum"
"github.com/harness/gitness/types/enum"
)
@ -31,11 +32,12 @@ type PaginationFilter struct {
// CommitFilter stores commit query parameters.
type CommitFilter struct {
PaginationFilter
After string `json:"after"`
Path string `json:"path"`
Since int64 `json:"since"`
Until int64 `json:"until"`
Committer string `json:"committer"`
After string `json:"after"`
Path string `json:"path"`
Since int64 `json:"since"`
Until int64 `json:"until"`
Committer string `json:"committer"`
IncludeStats bool `json:"include_stats"`
}
// BranchFilter stores branch query parameters.
@ -56,20 +58,32 @@ type TagFilter struct {
Size int `json:"size"`
}
type CommitDiffStats struct {
Total int `json:"total"`
Additions int `json:"additions"`
Deletions int `json:"deletions"`
type ChangeStats struct {
Insertions int64 `json:"insertions"`
Deletions int64 `json:"deletions"`
Changes int64 `json:"changes"`
}
type CommitFileStats struct {
Path string `json:"path"`
OldPath string `json:"old_path,omitempty"`
Status gitenum.FileDiffStatus `json:"status"`
ChangeStats
}
type CommitStats struct {
Total ChangeStats `json:"total,omitempty"`
Files []CommitFileStats `json:"files,omitempty"`
}
type Commit struct {
SHA string `json:"sha"`
ParentSHAs []string `json:"parent_shas,omitempty"`
Title string `json:"title"`
Message string `json:"message"`
Author Signature `json:"author"`
Committer Signature `json:"committer"`
DiffStats CommitDiffStats `json:"diff_stats"`
SHA string `json:"sha"`
ParentSHAs []string `json:"parent_shas,omitempty"`
Title string `json:"title"`
Message string `json:"message"`
Author Signature `json:"author"`
Committer Signature `json:"committer"`
Stats CommitStats `json:"stats,omitempty"`
}
type Signature struct {