diff --git a/status.go b/status.go new file mode 100644 index 0000000..76e4c70 --- /dev/null +++ b/status.go @@ -0,0 +1,54 @@ +package main + +import ( + git "github.com/libgit2/git2go/v30" + "github.com/pkg/errors" +) + +type RepoStatus int + +const ( + StatusOk RepoStatus = iota + StatusUntrackedFiles + StatusUncommittedChanges + StatusUnknown +) + +func GetStatus(path string) (RepoStatus, error) { + repo, err := git.OpenRepository(path) + if err != nil { + return StatusUnknown, errors.Wrap(err, "failed opening repository") + } + + _, err = statusEntries(repo) + return StatusOk, nil +} + +func statusEntries(repo *git.Repository) ([]git.StatusEntry, error) { + opts := &git.StatusOptions{ + Show: git.StatusShowIndexAndWorkdir, + Flags: git.StatusOptIncludeUntracked, + } + + status, err := repo.StatusList(opts) + if err != nil { + return nil, errors.Wrap(err, "failed getting repository status") + } + + entryCount, err := status.EntryCount() + if err != nil { + return nil, errors.Wrap(err, "failed getting repository status count") + } + + var entries []git.StatusEntry + for i := 0; i < entryCount; i++ { + entry, err := status.ByIndex(i) + if err != nil { + return nil, errors.Wrap(err, "failed getting repository status entry") + } + + entries = append(entries, entry) + } + + return entries, nil +} diff --git a/status_test.go b/status_test.go new file mode 100644 index 0000000..b2f513f --- /dev/null +++ b/status_test.go @@ -0,0 +1,109 @@ +package main + +import ( + "testing" + + git "github.com/libgit2/git2go/v30" +) + +func TestStatusEntriesWithEmptyRepo(t *testing.T) { + repo, err := newTestRepo() + checkFatal(t, err) + defer cleanupRepo(t, repo) + + entries, err := statusEntries(repo) + checkFatal(t, err) + + if len(entries) != 0 { + t.Errorf("Empty repo should have no status entries") + } +} + +func TestStatusEntriesWithSingleUnstagedFile(t *testing.T) { + repo, err := newTestRepo() + checkFatal(t, err) + defer cleanupRepo(t, repo) + + err = createFile(repo, "SomeFile") + checkFatal(t, err) + + entries, err := statusEntries(repo) + checkFatal(t, err) + + if len(entries) != 1 { + t.Errorf("Repo with single unstaged file should have only one status entry") + } + + if entries[0].Status != git.StatusWtNew { + t.Errorf("Invalid status, got %d; want %d", entries[0].Status, git.StatusWtNew) + } +} + +func TestStatusEntriesWithSingleStagedFile(t *testing.T) { + repo, err := newTestRepo() + checkFatal(t, err) + defer cleanupRepo(t, repo) + + err = createFile(repo, "SomeFile") + checkFatal(t, err) + err = stageFile(repo, "SomeFile") + checkFatal(t, err) + + entries, err := statusEntries(repo) + checkFatal(t, err) + + if len(entries) != 1 { + t.Errorf("Repo with single staged file should have only one status entry") + } + + if entries[0].Status != git.StatusIndexNew { + t.Errorf("Invalid status, got %d; want %d", entries[0].Status, git.StatusIndexNew) + } +} + +func TestStatusEntriesWithSingleCommit(t *testing.T) { + repo, err := newTestRepo() + checkFatal(t, err) + defer cleanupRepo(t, repo) + + err = createFile(repo, "SomeFile") + checkFatal(t, err) + err = stageFile(repo, "SomeFile") + checkFatal(t, err) + err = createCommit(repo, "Initial commit") + checkFatal(t, err) + + entries, err := statusEntries(repo) + checkFatal(t, err) + + if len(entries) != 0 { + t.Errorf("Repo with no uncommitted files should have no status entries") + } +} + +func TestStatusEntriesWithMultipleCommits(t *testing.T) { + repo, err := newTestRepo() + checkFatal(t, err) + defer cleanupRepo(t, repo) + + err = createFile(repo, "SomeFile") + checkFatal(t, err) + err = stageFile(repo, "SomeFile") + checkFatal(t, err) + err = createCommit(repo, "Initial commit") + checkFatal(t, err) + + err = createFile(repo, "AnotherFile") + checkFatal(t, err) + err = stageFile(repo, "AnotherFile") + checkFatal(t, err) + err = createCommit(repo, "Second commit") + checkFatal(t, err) + + entries, err := statusEntries(repo) + checkFatal(t, err) + + if len(entries) != 0 { + t.Errorf("Repo with no uncommitted files should have no status entries") + } +}