optimized get branch (#912)

This commit is contained in:
Marko Gacesa 2023-12-18 10:03:22 +00:00 committed by Harness
parent cb817bf2ad
commit ee7b2775c1
3 changed files with 90 additions and 136 deletions

View File

@ -16,9 +16,9 @@ package adapter
import ( import (
"context" "context"
"fmt"
"strings" "strings"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git/types" "github.com/harness/gitness/git/types"
gitea "code.gitea.io/gitea/modules/git" gitea "code.gitea.io/gitea/modules/git"
@ -37,30 +37,15 @@ func (a Adapter) GetBranch(
return nil, ErrBranchNameEmpty return nil, ErrBranchNameEmpty
} }
giteaRepo, err := gitea.OpenRepository(ctx, repoPath) ref := GetReferenceFromBranchName(branchName)
commit, err := getCommit(ctx, repoPath, ref, "")
if err != nil { if err != nil {
return nil, processGiteaErrorf(err, "failed to open repository") return nil, fmt.Errorf("failed to find the commit for the branch: %w", err)
}
defer giteaRepo.Close()
giteaBranch, err := giteaRepo.GetBranch(branchName)
if err != nil {
return nil, processGiteaErrorf(err, "failed to get branch '%s'", branchName)
}
giteaCommit, err := giteaBranch.GetCommit()
if err != nil {
return nil, processGiteaErrorf(err, "failed to get commit '%s'", branchName)
}
commit, err := mapGiteaCommit(giteaCommit)
if err != nil {
return nil, errors.Internal("failed to map gitea commit", err)
} }
return &types.Branch{ return &types.Branch{
Name: giteaBranch.Name, Name: branchName,
SHA: giteaCommit.ID.String(), SHA: commit.SHA,
Commit: commit, Commit: commit,
}, nil }, nil
} }

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/harness/gitness/errors" "github.com/harness/gitness/errors"
"github.com/harness/gitness/git/types" "github.com/harness/gitness/git/types"
@ -27,16 +28,11 @@ import (
gitea "code.gitea.io/gitea/modules/git" gitea "code.gitea.io/gitea/modules/git"
) )
const ( // GetLatestCommit gets the latest commit of a path relative from the provided revision.
giteaPrettyLogFormat = `--pretty=format:` + fmtCommitHash
)
// GetLatestCommit gets the latest commit of a path relative from the provided reference.
// Note: ref can be Branch / Tag / CommitSHA.
func (a Adapter) GetLatestCommit( func (a Adapter) GetLatestCommit(
ctx context.Context, ctx context.Context,
repoPath string, repoPath string,
ref string, rev string,
treePath string, treePath string,
) (*types.Commit, error) { ) (*types.Commit, error) {
if repoPath == "" { if repoPath == "" {
@ -44,45 +40,7 @@ func (a Adapter) GetLatestCommit(
} }
treePath = cleanTreePath(treePath) treePath = cleanTreePath(treePath)
giteaRepo, err := gitea.OpenRepository(ctx, repoPath) return getCommit(ctx, repoPath, rev, treePath)
if err != nil {
return nil, processGiteaErrorf(err, "failed to open repository")
}
defer giteaRepo.Close()
giteaCommit, err := giteaGetCommitByPath(giteaRepo, ref, treePath)
if err != nil {
return nil, processGiteaErrorf(err, "error getting latest commit for '%s'", treePath)
}
return mapGiteaCommit(giteaCommit)
}
// giteaGetCommitByPath returns the latest commit per specific branch.
func giteaGetCommitByPath(
giteaRepo *gitea.Repository,
ref string,
treePath string,
) (*gitea.Commit, error) {
if treePath == "" {
treePath = "."
}
// NOTE: the difference to gitea implementation is passing `ref`.
stdout, _, runErr := gitea.NewCommand(giteaRepo.Ctx, "log", ref, "-1", giteaPrettyLogFormat, "--", treePath).
RunStdBytes(&gitea.RunOpts{Dir: giteaRepo.Path})
if runErr != nil {
return nil, fmt.Errorf("in giteaGetCommitByPath: failed to trigger log command: %w", runErr)
}
lines := parseLinesToSlice(stdout)
giteaCommits, err := getGiteaCommits(giteaRepo, lines)
if err != nil {
return nil, fmt.Errorf("in giteaGetCommitByPath: failed to get commits: %w", err)
}
return giteaCommits[0], nil
} }
func getGiteaCommits( func getGiteaCommits(
@ -324,28 +282,17 @@ func getFileChangeTypeFromLog(
return nil, nil, nil, fmt.Errorf("could not parse change for the file '%s'", filePath) return nil, nil, nil, fmt.Errorf("could not parse change for the file '%s'", filePath)
} }
// GetCommit returns the (latest) commit for a specific ref. // GetCommit returns the (latest) commit for a specific revision.
// Note: ref can be Branch / Tag / CommitSHA.
func (a Adapter) GetCommit( func (a Adapter) GetCommit(
ctx context.Context, ctx context.Context,
repoPath string, repoPath string,
ref string, rev string,
) (*types.Commit, error) { ) (*types.Commit, error) {
if repoPath == "" { if repoPath == "" {
return nil, ErrRepositoryPathEmpty return nil, ErrRepositoryPathEmpty
} }
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
if err != nil {
return nil, processGiteaErrorf(err, "failed to open repository")
}
defer giteaRepo.Close()
commit, err := giteaRepo.GetCommit(ref) return getCommit(ctx, repoPath, rev, "")
if err != nil {
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
}
return mapGiteaCommit(commit)
} }
func (a Adapter) GetFullCommitID( func (a Adapter) GetFullCommitID(
@ -497,3 +444,79 @@ func parseLinesToSlice(output []byte) []string {
return slice return slice
} }
func getCommit(
ctx context.Context,
repoPath string,
rev string,
path string,
) (*types.Commit, error) {
const format = "" +
fmtCommitHash + fmtZero + // 0
fmtAuthorName + fmtZero + // 1
fmtAuthorEmail + fmtZero + // 2
fmtAuthorTime + fmtZero + // 3
fmtCommitterName + fmtZero + // 4
fmtCommitterEmail + fmtZero + // 5
fmtCommitterTime + fmtZero + // 6
fmtSubject + fmtZero + // 7
fmtBody // 8
args := []string{"log", "--max-count=1", "--format=" + format, rev}
if path != "" {
args = append(args, "--", path)
}
commitLine, stderr, err := gitea.NewCommand(ctx, args...).RunStdString(&gitea.RunOpts{Dir: repoPath})
if strings.Contains(stderr, "ambiguous argument") {
return nil, errors.NotFound("revision %q not found", rev)
}
if err != nil {
return nil, fmt.Errorf("failed to run git to get commit data: %w", err)
}
if commitLine == "" {
return nil, errors.InvalidArgument("path %q not found in %s", path, rev)
}
const columnCount = 9
commitData := strings.Split(strings.TrimSpace(commitLine), separatorZero)
if len(commitData) != columnCount {
return nil, fmt.Errorf(
"unexpected git log formatted output, expected %d, but got %d columns", columnCount, len(commitData))
}
sha := commitData[0]
authorName := commitData[1]
authorEmail := commitData[2]
authorTimestamp := commitData[3]
committerName := commitData[4]
committerEmail := commitData[5]
committerTimestamp := commitData[6]
subject := commitData[7]
body := commitData[8]
authorTime, _ := time.Parse(time.RFC3339Nano, authorTimestamp)
committerTime, _ := time.Parse(time.RFC3339Nano, committerTimestamp)
return &types.Commit{
SHA: sha,
Title: subject,
Message: body,
Author: types.Signature{
Identity: types.Identity{
Name: authorName,
Email: authorEmail,
},
When: authorTime,
},
Committer: types.Signature{
Identity: types.Identity{
Name: committerName,
Email: committerEmail,
},
When: committerTime,
},
}, nil
}

View File

@ -20,7 +20,6 @@ import (
"encoding/gob" "encoding/gob"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"strconv"
"strings" "strings"
"time" "time"
@ -28,7 +27,6 @@ import (
"github.com/harness/gitness/errors" "github.com/harness/gitness/errors"
"github.com/harness/gitness/git/types" "github.com/harness/gitness/git/types"
gitea "code.gitea.io/gitea/modules/git"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
) )
@ -123,57 +121,5 @@ func (c commitEntryGetter) Find(
path = "." path = "."
} }
const format = "" + return getCommit(ctx, repoPath, commitSHA, path)
fmtCommitHash + fmtZero + // 0
fmtAuthorName + fmtZero + // 1
fmtAuthorEmail + fmtZero + // 2
fmtAuthorUnix + fmtZero + // 3
fmtCommitterName + fmtZero + // 4
fmtCommitterEmail + fmtZero + // 5
fmtCommitterUnix + fmtZero + // 6
fmtSubject + fmtZero + // 7
fmtBody // 8
args := []string{"log", "--max-count=1", "--format=" + format, commitSHA, "--", path}
commitLine, _, err := gitea.NewCommand(ctx, args...).RunStdString(&gitea.RunOpts{Dir: repoPath})
if err != nil {
return nil, fmt.Errorf("failed to run git to get the last commit for path: %w", err)
}
const columnCount = 9
commitData := strings.Split(strings.TrimSpace(commitLine), separatorZero)
if len(commitData) != columnCount {
return nil, errors.InvalidArgument("path %q not found in commit %s", path, commitSHA)
}
sha := commitData[0]
authorName := commitData[1]
authorEmail := commitData[2]
authorTime, _ := strconv.ParseInt(commitData[3], 10, 64) // parse failure produces 01-01-1970
committerName := commitData[4]
committerEmail := commitData[5]
committerTime, _ := strconv.ParseInt(commitData[6], 10, 64) // parse failure produces 01-01-1970
subject := commitData[7]
body := commitData[8]
return &types.Commit{
SHA: sha,
Title: subject,
Message: body,
Author: types.Signature{
Identity: types.Identity{
Name: authorName,
Email: authorEmail,
},
When: time.Unix(authorTime, 0),
},
Committer: types.Signature{
Identity: types.Identity{
Name: committerName,
Email: committerEmail,
},
When: time.Unix(committerTime, 0),
},
}, nil
} }