Skip to content

Commit e267b1d

Browse files
authored
feat(internal/gitrepo): add git log functionality (#2510)
Updates #2378
1 parent 2dc6fc6 commit e267b1d

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

internal/gitrepo/gitrepo.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type Repository interface {
4545
HeadHash() (string, error)
4646
ChangedFilesInCommit(commitHash string) ([]string, error)
4747
GetCommit(commitHash string) (*Commit, error)
48+
GetLatestCommit(path string) (*Commit, error)
4849
GetCommitsForPathsSinceTag(paths []string, tagName string) ([]*Commit, error)
4950
GetCommitsForPathsSinceCommit(paths []string, sinceCommit string) ([]*Commit, error)
5051
CreateBranchAndCheckout(name string) error
@@ -274,6 +275,29 @@ func (r *LocalRepository) GetCommit(commitHash string) (*Commit, error) {
274275
}, nil
275276
}
276277

278+
// GetLatestCommit returns the latest commit of the given path in the repository.
279+
func (r *LocalRepository) GetLatestCommit(path string) (*Commit, error) {
280+
opt := &git.LogOptions{
281+
Order: git.LogOrderCommitterTime,
282+
FileName: &path,
283+
}
284+
log, err := r.repo.Log(opt)
285+
if err != nil {
286+
return nil, err
287+
}
288+
289+
commit, err := log.Next()
290+
if err != nil {
291+
return nil, err
292+
}
293+
294+
return &Commit{
295+
Hash: commit.Hash,
296+
Message: commit.Message,
297+
When: commit.Author.When,
298+
}, nil
299+
}
300+
277301
// GetCommitsForPathsSinceTag returns all commits since tagName that contains
278302
// files in paths.
279303
//

internal/gitrepo/gitrepo_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package gitrepo
1616

1717
import (
18+
"errors"
1819
"fmt"
1920
"os"
2021
"path/filepath"
@@ -1274,6 +1275,60 @@ func TestCleanUntracked(t *testing.T) {
12741275
}
12751276
}
12761277

1278+
func TestGetLatestCommit(t *testing.T) {
1279+
t.Parallel()
1280+
for _, test := range []struct {
1281+
name string
1282+
path string
1283+
setup func(t *testing.T, repo *git.Repository, path string)
1284+
want *Commit
1285+
wantErr error
1286+
}{
1287+
{
1288+
name: "get_latest_commit_of_a_path",
1289+
path: "a/path/example.txt",
1290+
setup: func(t *testing.T, repo *git.Repository, path string) {
1291+
createAndCommit(t, repo, path, []byte("1st content"), "first commit")
1292+
createAndCommit(t, repo, path, []byte("2nd content"), "second commit")
1293+
createAndCommit(t, repo, "another/path/example.txt", []byte("2nd content"), "second commit")
1294+
},
1295+
want: &Commit{
1296+
Message: "second commit",
1297+
},
1298+
},
1299+
{
1300+
name: "no_commit_of_a_path",
1301+
path: "a/path/example.txt",
1302+
setup: func(t *testing.T, repo *git.Repository, path string) {
1303+
// Do nothing.
1304+
},
1305+
wantErr: plumbing.ErrReferenceNotFound,
1306+
},
1307+
} {
1308+
t.Run(test.name, func(t *testing.T) {
1309+
t.Parallel()
1310+
repo, dir := initTestRepo(t)
1311+
test.setup(t, repo, test.path)
1312+
localRepo := &LocalRepository{Dir: dir, repo: repo}
1313+
got, err := localRepo.GetLatestCommit(test.path)
1314+
if test.wantErr != nil {
1315+
if !errors.Is(err, test.wantErr) {
1316+
t.Errorf("unexpected error type: got %v, want %v", err, test.wantErr)
1317+
}
1318+
1319+
return
1320+
}
1321+
if err != nil {
1322+
t.Error(err)
1323+
return
1324+
}
1325+
if diff := cmp.Diff(test.want, got, cmpopts.IgnoreFields(Commit{}, "When", "Hash")); diff != "" {
1326+
t.Errorf("GetLatestCommit() mismatch in %s (-want +got):\n%s", test.name, diff)
1327+
}
1328+
})
1329+
}
1330+
}
1331+
12771332
// initTestRepo creates a new git repository in a temporary directory.
12781333
func initTestRepo(t *testing.T) (*git.Repository, string) {
12791334
t.Helper()

0 commit comments

Comments
 (0)