aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/vcs
diff options
context:
space:
mode:
authorSpace Meyer <spm@google.com>2022-09-13 15:24:05 +0000
committerSpace Meyer <git@the-space.agency>2022-10-06 18:14:05 +0200
commit8a2121976b8020f2006c1a953766af912ba709dd (patch)
treec7d627e910657c8995fe4de4f991db3a8117c492 /pkg/vcs
parent80b58a4201a50d022574c185b387d54b3d442aae (diff)
pkg/bisect: try to reidentify commit rebased after crash
When bisecting a breaking commit, syzkaller starts the bisection from the commit recorded in the last crash for the given bug. Previously the bisection was aborted should the commit no longer exist in the repo. Now we try to reidentify the breaking commit. For git pretty much the best we can do is to search a commit reachable from HEAD with the same title. Other VCS systems might have something better. Syzkaller will still first validate that the start commit is indeed broken in the way it expects. This prevents syzkaller from getting confused should we accidentally pick a completely unrelated commit.
Diffstat (limited to 'pkg/vcs')
-rw-r--r--pkg/vcs/git_test.go79
-rw-r--r--pkg/vcs/vcs.go11
2 files changed, 85 insertions, 5 deletions
diff --git a/pkg/vcs/git_test.go b/pkg/vcs/git_test.go
index 25893d3fc..b216ddf75 100644
--- a/pkg/vcs/git_test.go
+++ b/pkg/vcs/git_test.go
@@ -157,3 +157,82 @@ v1.
t.Fatalf("got bad tags\ngot: %+v\nwant: %+v", gotRC, wantRC)
}
}
+
+func TestGetCommitsByTitles(t *testing.T) {
+ baseDir := t.TempDir()
+ repo := MakeTestRepo(t, baseDir)
+
+ validateSuccess := func(commit *Commit, results []*Commit, missing []string, err error) {
+ if err != nil {
+ t.Fatalf("expected success, got %v", err)
+ }
+ if len(missing) > 0 {
+ t.Fatalf("expected 0 missing, got %v", missing)
+ }
+ if len(results) != 1 {
+ t.Fatalf("expected 1 results, got %v", len(results))
+ }
+ if results[0].Hash != commit.Hash {
+ t.Fatalf("found unexpected commit %v", results[0].Hash)
+ }
+ }
+
+ // Put three commits in branch-a, two with the title we search for.
+ // We expect GetCommitsByTitles to only return the most recent match.
+ repo.Git("checkout", "-b", "branch-a")
+ repo.Git("commit", "--no-edit", "--allow-empty", "-m", "target")
+ repo.Git("commit", "--no-edit", "--allow-empty", "-m", "abc")
+ repo.Git("commit", "--no-edit", "--allow-empty", "-m", "target")
+ commitA, _ := repo.repo.HeadCommit()
+ results, missing, err := repo.repo.GetCommitsByTitles([]string{"target"})
+ validateSuccess(commitA, results, missing, err)
+
+ // Put another commit with the title we search for in another branch.
+ // We expect GetCommitsByTitles to only find commits in the current branch.
+ repo.Git("checkout", "-b", "branch-b")
+ repo.Git("commit", "--no-edit", "--allow-empty", "-m", "target")
+ repo.Git("checkout", "branch-a")
+ results, missing, err = repo.repo.GetCommitsByTitles([]string{"target"})
+ validateSuccess(commitA, results, missing, err)
+
+ // We expect GetCommitsByTitles to only find commits in the current branch.
+ repo.Git("checkout", "branch-b")
+ results, missing, err = repo.repo.GetCommitsByTitles([]string{"xyz"})
+ if err != nil {
+ t.Fatalf("expected success, got %v", err)
+ }
+ if len(results) > 0 {
+ t.Fatalf("expected 0 results, got %v", len(results))
+ }
+ if len(missing) != 1 {
+ t.Fatalf("expected 1 missing, got %v", missing)
+ }
+ if missing[0] != "xyz" {
+ t.Fatalf("found unexpected value in missing %v", missing[0])
+ }
+}
+
+func TestContains(t *testing.T) {
+ baseDir := t.TempDir()
+ repo := MakeTestRepo(t, baseDir)
+
+ // We expect Contains to return true, if commit is in current checkout.
+ repo.Git("checkout", "-b", "branch-a")
+ repo.Git("commit", "--no-edit", "--allow-empty", "-m", "target")
+ commitA, _ := repo.repo.HeadCommit()
+ if contained, _ := repo.repo.Contains(commitA.Hash); !contained {
+ t.Fatalf("contains claims commit that should be present is not")
+ }
+ if contained, _ := repo.repo.Contains("fake-hash"); contained {
+ t.Fatalf("contains claims commit that is not present is present")
+ }
+
+ // Commits must only be searched for from the checkedout HEAD.
+ repo.Git("checkout", "-b", "branch-b")
+ repo.Git("commit", "--no-edit", "--allow-empty", "-m", "target")
+ commitB, _ := repo.repo.HeadCommit()
+ repo.Git("checkout", "branch-a")
+ if contained, _ := repo.repo.Contains(commitB.Hash); contained {
+ t.Fatalf("contains found commit that is not in current branch")
+ }
+}
diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go
index 4e42b04a0..50e45252e 100644
--- a/pkg/vcs/vcs.go
+++ b/pkg/vcs/vcs.go
@@ -37,9 +37,9 @@ type Repo interface {
// HeadCommit returns info about the HEAD commit of the current branch of git repository.
HeadCommit() (*Commit, error)
- // GetCommitByTitle finds commit info by the title.
- // Remote is not fetched, the commit needs to be reachable from the current repo state
- // (e.g. do CheckoutBranch before). If the commit is not found, nil is returned.
+ // GetCommitByTitle finds commit info by the title. If the commit is not found, nil is returned.
+ // Remote is not fetched and only commits reachable from the checked out HEAD are searched
+ // (e.g. do CheckoutBranch before).
GetCommitByTitle(title string) (*Commit, error)
// GetCommitsByTitles is a batch version of GetCommitByTitle.
@@ -57,8 +57,9 @@ type Repo interface {
// ReleaseTag returns the latest release tag that is reachable from the given commit.
ReleaseTag(commit string) (string, error)
- // Returns true if the current tree contains the specified commit
- // (the commit is reachable from the current HEAD).
+ // Returns true if the current tree contains the specified commit.
+ // Remote is not fetched and only commits reachable from the checked out HEAD are searched
+ // (e.g. do CheckoutBranch before).
Contains(commit string) (bool, error)
}