diff --git a/git/adapter/branch.go b/git/adapter/branch.go index cfd93fd38..3f348b2c3 100644 --- a/git/adapter/branch.go +++ b/git/adapter/branch.go @@ -16,9 +16,9 @@ package adapter import ( "context" + "fmt" "strings" - "github.com/harness/gitness/errors" "github.com/harness/gitness/git/types" gitea "code.gitea.io/gitea/modules/git" @@ -37,30 +37,15 @@ func (a Adapter) GetBranch( return nil, ErrBranchNameEmpty } - giteaRepo, err := gitea.OpenRepository(ctx, repoPath) + ref := GetReferenceFromBranchName(branchName) + commit, err := getCommit(ctx, repoPath, ref, "") if err != nil { - return nil, processGiteaErrorf(err, "failed to open repository") - } - 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 nil, fmt.Errorf("failed to find the commit for the branch: %w", err) } return &types.Branch{ - Name: giteaBranch.Name, - SHA: giteaCommit.ID.String(), + Name: branchName, + SHA: commit.SHA, Commit: commit, }, nil } diff --git a/git/adapter/commit.go b/git/adapter/commit.go index b9315d1e7..173198571 100644 --- a/git/adapter/commit.go +++ b/git/adapter/commit.go @@ -20,6 +20,7 @@ import ( "fmt" "strconv" "strings" + "time" "github.com/harness/gitness/errors" "github.com/harness/gitness/git/types" @@ -27,16 +28,11 @@ import ( gitea "code.gitea.io/gitea/modules/git" ) -const ( - giteaPrettyLogFormat = `--pretty=format:` + fmtCommitHash -) - -// GetLatestCommit gets the latest commit of a path relative from the provided reference. -// Note: ref can be Branch / Tag / CommitSHA. +// GetLatestCommit gets the latest commit of a path relative from the provided revision. func (a Adapter) GetLatestCommit( ctx context.Context, repoPath string, - ref string, + rev string, treePath string, ) (*types.Commit, error) { if repoPath == "" { @@ -44,45 +40,7 @@ func (a Adapter) GetLatestCommit( } treePath = cleanTreePath(treePath) - giteaRepo, err := gitea.OpenRepository(ctx, repoPath) - 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 + return getCommit(ctx, repoPath, rev, treePath) } func getGiteaCommits( @@ -324,28 +282,17 @@ func getFileChangeTypeFromLog( return nil, nil, nil, fmt.Errorf("could not parse change for the file '%s'", filePath) } -// GetCommit returns the (latest) commit for a specific ref. -// Note: ref can be Branch / Tag / CommitSHA. +// GetCommit returns the (latest) commit for a specific revision. func (a Adapter) GetCommit( ctx context.Context, repoPath string, - ref string, + rev string, ) (*types.Commit, error) { if repoPath == "" { 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) - if err != nil { - return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref) - } - - return mapGiteaCommit(commit) + return getCommit(ctx, repoPath, rev, "") } func (a Adapter) GetFullCommitID( @@ -497,3 +444,79 @@ func parseLinesToSlice(output []byte) []string { 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 +} diff --git a/git/adapter/last_commit_cache.go b/git/adapter/last_commit_cache.go index 83343af67..5c37d13b6 100644 --- a/git/adapter/last_commit_cache.go +++ b/git/adapter/last_commit_cache.go @@ -20,7 +20,6 @@ import ( "encoding/gob" "encoding/hex" "fmt" - "strconv" "strings" "time" @@ -28,7 +27,6 @@ import ( "github.com/harness/gitness/errors" "github.com/harness/gitness/git/types" - gitea "code.gitea.io/gitea/modules/git" "github.com/go-redis/redis/v8" ) @@ -123,57 +121,5 @@ func (c commitEntryGetter) Find( path = "." } - const format = "" + - 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 + return getCommit(ctx, repoPath, commitSHA, path) }