From 627f8df98d0395bd67a47b90c2020d4c232e7cd2 Mon Sep 17 00:00:00 2001 From: Daniel Oliveira Date: Mon, 20 Apr 2015 15:01:48 -0600 Subject: [PATCH 1/3] Unit Tests for: repo_test.go, task_test.go --- datastore/bolt/repo_test.go | 140 ++++++++++++++++++++++++++++++++---- datastore/bolt/task_test.go | 88 +++++++++++++++++++++++ 2 files changed, 215 insertions(+), 13 deletions(-) diff --git a/datastore/bolt/repo_test.go b/datastore/bolt/repo_test.go index 6338e07e9..e38685dfd 100644 --- a/datastore/bolt/repo_test.go +++ b/datastore/bolt/repo_test.go @@ -1,24 +1,138 @@ package bolt import ( - "testing" - + "github.com/drone/drone/common" . "github.com/franela/goblin" + "os" + "testing" ) func TestRepo(t *testing.T) { g := Goblin(t) - g.Describe("Repos", func() { + g.Describe("Repo", func() { + testUser := "octocat" + testRepo := "github.com/octopod/hq" + testRepo2 := "github.com/octopod/avengers" + var db *DB // Temp database + + // create a new database before each unit + // test and destroy afterwards. + g.BeforeEach(func() { + db = Must("/tmp/drone.test.db") + }) + g.AfterEach(func() { + os.Remove(db.Path()) + }) + + g.It("Should set Repo", func() { + //err := db.SetRepoNotExists(&common.User{Name: testUser}, &common.Repo{Name: testRepo}) + err := db.SetRepo(&common.Repo{FullName: testRepo}) + g.Assert(err).Equal(nil) + + // setrepo only returns an error. Repo returns error and a structure + repo, err := db.Repo(testRepo) + g.Assert(err).Equal(nil) + g.Assert(repo.FullName).Equal(testRepo) + }) + + g.It("Should get Repo", func() { + //db.SetRepoNotExists(&common.User{Name: testUser}, &common.Repo{Name: testRepo}) + db.SetRepo(&common.Repo{FullName: testRepo}) + + // setrepo only returns an error. Repo returns error and a structure + repo, err := db.Repo(testRepo) + g.Assert(err).Equal(nil) + g.Assert(repo.FullName).Equal(testRepo) + }) + + g.It("Should del Repo", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + // setrepo only returns an error. Repo returns error and a structure + //repo, err := db.Repo(testRepo) + db.Repo(testRepo) + err_ := db.DelRepo((&common.Repo{FullName: testRepo})) + g.Assert(err_).Equal(nil) + }) + + g.It("Should get RepoList", func() { + db.SetRepoNotExists(&common.User{Login: testUser}, &common.Repo{FullName: testRepo}) + db.SetRepoNotExists(&common.User{Login: testUser}, &common.Repo{FullName: testRepo2}) + //db.SetRepo(&common.Repo{FullName: testRepo}) + //db.SetRepo(&common.Repo{FullName: testRepo2}) + repos, err := db.RepoList(testUser) + g.Assert(err).Equal(nil) + g.Assert(len(repos)).Equal(2) + }) + + g.It("Should set RepoParams", func() { + //db.SetRepoNotExists(&common.User{Name: testUser}, &common.Repo{Name: testRepo}) + db.SetRepo(&common.Repo{FullName: testRepo}) + err := db.SetRepoParams(testRepo, map[string]string{"A": "Alpha"}) + g.Assert(err).Equal(nil) + }) + + g.It("Should get RepoParams", func() { + //db.SetRepoNotExists(&common.User{Name: testUser}, &common.Repo{Name: testRepo}) + db.SetRepo(&common.Repo{FullName: testRepo}) + err := db.SetRepoParams(testRepo, map[string]string{"A": "Alpha", "B": "Beta"}) + params, err := db.RepoParams(testRepo) + g.Assert(err).Equal(nil) + g.Assert(len(params)).Equal(2) + g.Assert(params["A"]).Equal("Alpha") + g.Assert(params["B"]).Equal("Beta") + }) + + // we test again with same repo/user already existing + // to see if it will return "ErrConflict" + g.It("Should set SetRepoNotExists", func() { + err := db.SetRepoNotExists(&common.User{Login: testUser}, &common.Repo{FullName: testRepo}) + g.Assert(err).Equal(nil) + // We should get ErrConflict now, trying to add the same repo again. + err_ := db.SetRepoNotExists(&common.User{Login: testUser}, &common.Repo{FullName: testRepo}) + g.Assert(err_ == nil).IsFalse() // we should get (ErrConflict) + }) + + g.It("Should set RepoKeypair", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + //err := db.SetRepoKeypair(testRepo, &common.Keypair{Private: []byte("A"), Public: []byte("Alpha")}) + err := db.SetRepoKeypair(testRepo, &common.Keypair{Private: "A", Public: "Alpha"}) + g.Assert(err).Equal(nil) + }) + + g.It("Should get RepoKeypair", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + err := db.SetRepoKeypair(testRepo, &common.Keypair{Private: "A", Public: "Alpha"}) + //g.Assert(err).Equal(nil) + keypair, err := db.RepoKeypair(testRepo) + g.Assert(err).Equal(nil) + g.Assert(keypair.Public).Equal("Alpha") + g.Assert(keypair.Private).Equal("A") + }) + + g.It("Should set Subscriber", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + err := db.SetSubscriber(testUser, testRepo) + g.Assert(err).Equal(nil) + }) + + g.It("Should get Subscribed", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + err := db.SetSubscriber(testUser, testRepo) + subscribed, err := db.Subscribed(testUser, testRepo) + g.Assert(err).Equal(nil) + g.Assert(subscribed).Equal(true) + }) + + g.It("Should del Subscriber", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + db.SetSubscriber(testUser, testRepo) + err := db.DelSubscriber(testUser, testRepo) + g.Assert(err).Equal(nil) + // + subscribed, err := db.Subscribed(testUser, testRepo) + g.Assert(subscribed).Equal(false) + + }) - g.It("Should find by name") - g.It("Should find params") - g.It("Should find keys") - g.It("Should delete") - g.It("Should insert") - g.It("Should not insert if exists") - g.It("Should insert params") - g.It("Should update params") - g.It("Should insert keys") - g.It("Should update keys") }) } diff --git a/datastore/bolt/task_test.go b/datastore/bolt/task_test.go index a3ce8fd08..d2997819f 100644 --- a/datastore/bolt/task_test.go +++ b/datastore/bolt/task_test.go @@ -1 +1,89 @@ package bolt + +import ( + "github.com/drone/drone/common" + . "github.com/franela/goblin" + "io/ioutil" + "os" + "testing" +) + +func TestTask(t *testing.T) { + g := Goblin(t) + g.Describe("Tasks", func() { + //testUser := "octocat" + testRepo := "github.com/octopod/hq" + testBuild := 1 + testTask := 0 + testTask2 := 1 + testLogInfo := []byte("Log Info for SetLogs()") + var db *DB // Temp database + + // create a new database before each unit + // test and destroy afterwards. + g.BeforeEach(func() { + db = Must("/tmp/drone.test.db") + }) + g.AfterEach(func() { + os.Remove(db.Path()) + }) + + g.It("Should set Task", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + err := db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + g.Assert(err).Equal(nil) + }) + + g.It("Should get Task", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + // + task, err := db.Task(testRepo, testBuild, testTask) + g.Assert(err).Equal(nil) + g.Assert(task.Number).Equal(testTask) + }) + + /* + Brad Rydzewski1:00 PM + the `Task`, `TaskList` and `SetTask` are deprecated and can be probably be removed. + I just need to make sure we aren't still using those functions anywhere else in the code + */ + /* + g.It("Should get TaskList", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + //db.SetRepoNotExists(&common.User{Login: testUser}, &common.Repo{FullName: testRepo}) + err := db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + g.Assert(err).Equal(nil) + err_ := db.SetTask(testRepo, testBuild, &common.Task{Number: testTask2}) + g.Assert(err_).Equal(nil) + // + tasks, err := db.TaskList(testRepo, testBuild) + // We seem to have an issue here. TaskList doesn't seem to be returning + // All the tasks added to to repo/build. So commenting these for now. + //g.Assert(err).Equal(nil) + //g.Assert(len(tasks)).Equal(2) + }) + */ + + g.It("Should set Logs", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + db.SetTask(testRepo, testBuild, &common.Task{Number: testTask2}) + // + err := db.SetLogs(testRepo, testBuild, testTask, testLogInfo) + g.Assert(err).Equal(nil) + }) + + g.It("Should LogReader", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + db.SetTask(testRepo, testBuild, &common.Task{Number: testTask2}) + db.SetLogs(testRepo, testBuild, testTask, testLogInfo) + // + buf, err_ := db.LogReader(testRepo, testBuild, testTask) + g.Assert(err_).Equal(nil) + logInfo, err_ := ioutil.ReadAll(buf) + g.Assert(logInfo).Equal(testLogInfo) + }) + }) +} From 38b939982a029eec95056e95a94b1f92a3f6fb3f Mon Sep 17 00:00:00 2001 From: Ben Schumacher Date: Mon, 20 Apr 2015 16:48:44 -0600 Subject: [PATCH 2/3] Working on drone/drone#959 --- datastore/bolt/repo.go | 50 ++++++++++++++++++-------- datastore/bolt/repo_del_test.go | 63 +++++++++++++++++++++++++++++++++ datastore/bolt/util.go | 14 ++++++++ 3 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 datastore/bolt/repo_del_test.go diff --git a/datastore/bolt/repo.go b/datastore/bolt/repo.go index 6b32b9144..e1f70217f 100644 --- a/datastore/bolt/repo.go +++ b/datastore/bolt/repo.go @@ -132,23 +132,43 @@ func (db *DB) SetRepoKeypair(repo string, keypair *common.Keypair) error { // DelRepo deletes the repository. func (db *DB) DelRepo(repo *common.Repo) error { - //TODO(benschumacher) rework this to use BoltDB's txn wrapper - - t, err := db.Begin(true) - if err != nil { - return err - } key := []byte(repo.FullName) - err = t.Bucket(bucketRepo).Delete(key) - if err != nil { - t.Rollback() + + return db.Update(func(t *bolt.Tx) error { + err := t.Bucket(bucketRepo).Delete(key) + if err != nil { + return err + } + t.Bucket(bucketRepoKeys).Delete(key) + t.Bucket(bucketRepoParams).Delete(key) + + // should we just ignore these error conditions? or should + // we go ahead with the transaction and assume we can + // cleanup the leftovers through some other maintenance process? + err = db.deleteTracesOfRepo(t, key) + return err - } - t.Bucket(bucketRepoKeys).Delete(key) - t.Bucket(bucketRepoParams).Delete(key) - // TODO(bradrydzewski) delete all builds - // TODO(bradrydzewski) delete all tasks - return t.Commit() + }) +} + +// deleteTracesOfRepo cleans up build leftovers when a repo is removed +func (db *DB) deleteTracesOfRepo(t *bolt.Tx, repoKey []byte) error { + err := error(nil) + + // bucketBuildSeq uses the repoKey directly + t.Bucket(bucketBuildSeq).Delete(repoKey) + + // the other buckets use repoKey with '/buildNumber', at least. + // validating that an additiona '/' is there ensures that we don't + // match 'github.com/drone/droney' when we're cleaning up after + // 'github.com/drone/drone'. + prefix := append(repoKey, '/') + deleteWithPrefix(t, bucketBuildLogs, prefix, true) + deleteWithPrefix(t, bucketBuildStatus, prefix, true) + deleteWithPrefix(t, bucketBuildTasks, prefix, true) + deleteWithPrefix(t, bucketBuild, prefix, true) + + return err } // Subscribed returns true if the user is subscribed diff --git a/datastore/bolt/repo_del_test.go b/datastore/bolt/repo_del_test.go new file mode 100644 index 000000000..22e101087 --- /dev/null +++ b/datastore/bolt/repo_del_test.go @@ -0,0 +1,63 @@ +package bolt + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/drone/drone/common" + . "github.com/franela/goblin" +) + +func TestRepoDel(t *testing.T) { + g := Goblin(t) + g.Describe("Delete repo", func() { + + var db *DB // temporary database + + user := &common.User{Login: "freya"} + repoUri := string("github.com/octopod/hq") + + // create a new database before each unit + // test and destroy afterwards. + g.BeforeEach(func() { + file, err := ioutil.TempFile(os.TempDir(), "drone-bolt") + if err != nil { + panic(err) + } + + db = Must(file.Name()) + }) + g.AfterEach(func() { + os.Remove(db.Path()) + }) + + g.It("should cleanup", func() { + repo := &common.Repo{FullName: repoUri} + err := db.SetRepoNotExists(user, repo) + g.Assert(err).Equal(nil) + + db.SetBuild(repoUri, &common.Build{State: "success"}) + db.SetBuild(repoUri, &common.Build{State: "success"}) + db.SetBuild(repoUri, &common.Build{State: "pending"}) + + db.SetBuildStatus(repoUri, 1, &common.Status{Context: "success"}) + db.SetBuildStatus(repoUri, 2, &common.Status{Context: "success"}) + db.SetBuildStatus(repoUri, 3, &common.Status{Context: "pending"}) + + // first a little sanity to validate our test conditions + _, err = db.BuildLast(repoUri) + g.Assert(err).Equal(nil) + + // now run our specific test suite + // 1. ensure that we can delete the repo + err = db.DelRepo(repo) + g.Assert(err).Equal(nil) + + // 2. ensure that deleting the repo cleans up other references + _, err = db.Build(repoUri, 1) + g.Assert(err).Equal(ErrKeyNotFound) + }) + }) + +} diff --git a/datastore/bolt/util.go b/datastore/bolt/util.go index 744225d91..1d992f3f5 100644 --- a/datastore/bolt/util.go +++ b/datastore/bolt/util.go @@ -84,3 +84,17 @@ func splice(t *bolt.Tx, bucket, index, value []byte) error { return update(t, bucket, index, &keys) } + +func deleteWithPrefix(t *bolt.Tx, bucket, prefix []byte, ignoreErr bool) error { + var err error + + c := t.Bucket(bucket).Cursor() + for k, _ := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, _ = c.Next() { + err = c.Delete() + if !ignoreErr && err != nil { + break + } + } + + return err +} From 09d5c6f011b7717f182437f269eeda25afaa0eef Mon Sep 17 00:00:00 2001 From: Daniel Oliveira Date: Mon, 20 Apr 2015 18:39:32 -0600 Subject: [PATCH 3/3] Code changes related to PR #986 and Issue #984 --- datastore/bolt/repo_test.go | 20 ++++++------------- datastore/bolt/task.go | 12 ++++++++--- datastore/bolt/task_test.go | 40 ++++++++++++++++++------------------- datastore/datastore.go | 6 +++--- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/datastore/bolt/repo_test.go b/datastore/bolt/repo_test.go index e38685dfd..ab45babc7 100644 --- a/datastore/bolt/repo_test.go +++ b/datastore/bolt/repo_test.go @@ -25,21 +25,17 @@ func TestRepo(t *testing.T) { }) g.It("Should set Repo", func() { - //err := db.SetRepoNotExists(&common.User{Name: testUser}, &common.Repo{Name: testRepo}) err := db.SetRepo(&common.Repo{FullName: testRepo}) g.Assert(err).Equal(nil) - // setrepo only returns an error. Repo returns error and a structure repo, err := db.Repo(testRepo) g.Assert(err).Equal(nil) g.Assert(repo.FullName).Equal(testRepo) }) g.It("Should get Repo", func() { - //db.SetRepoNotExists(&common.User{Name: testUser}, &common.Repo{Name: testRepo}) db.SetRepo(&common.Repo{FullName: testRepo}) - // setrepo only returns an error. Repo returns error and a structure repo, err := db.Repo(testRepo) g.Assert(err).Equal(nil) g.Assert(repo.FullName).Equal(testRepo) @@ -47,8 +43,7 @@ func TestRepo(t *testing.T) { g.It("Should del Repo", func() { db.SetRepo(&common.Repo{FullName: testRepo}) - // setrepo only returns an error. Repo returns error and a structure - //repo, err := db.Repo(testRepo) + db.Repo(testRepo) err_ := db.DelRepo((&common.Repo{FullName: testRepo})) g.Assert(err_).Equal(nil) @@ -57,22 +52,19 @@ func TestRepo(t *testing.T) { g.It("Should get RepoList", func() { db.SetRepoNotExists(&common.User{Login: testUser}, &common.Repo{FullName: testRepo}) db.SetRepoNotExists(&common.User{Login: testUser}, &common.Repo{FullName: testRepo2}) - //db.SetRepo(&common.Repo{FullName: testRepo}) - //db.SetRepo(&common.Repo{FullName: testRepo2}) + repos, err := db.RepoList(testUser) g.Assert(err).Equal(nil) g.Assert(len(repos)).Equal(2) }) g.It("Should set RepoParams", func() { - //db.SetRepoNotExists(&common.User{Name: testUser}, &common.Repo{Name: testRepo}) db.SetRepo(&common.Repo{FullName: testRepo}) err := db.SetRepoParams(testRepo, map[string]string{"A": "Alpha"}) g.Assert(err).Equal(nil) }) g.It("Should get RepoParams", func() { - //db.SetRepoNotExists(&common.User{Name: testUser}, &common.Repo{Name: testRepo}) db.SetRepo(&common.Repo{FullName: testRepo}) err := db.SetRepoParams(testRepo, map[string]string{"A": "Alpha", "B": "Beta"}) params, err := db.RepoParams(testRepo) @@ -89,12 +81,12 @@ func TestRepo(t *testing.T) { g.Assert(err).Equal(nil) // We should get ErrConflict now, trying to add the same repo again. err_ := db.SetRepoNotExists(&common.User{Login: testUser}, &common.Repo{FullName: testRepo}) - g.Assert(err_ == nil).IsFalse() // we should get (ErrConflict) + g.Assert(err_).Equal(ErrKeyExists) }) g.It("Should set RepoKeypair", func() { db.SetRepo(&common.Repo{FullName: testRepo}) - //err := db.SetRepoKeypair(testRepo, &common.Keypair{Private: []byte("A"), Public: []byte("Alpha")}) + err := db.SetRepoKeypair(testRepo, &common.Keypair{Private: "A", Public: "Alpha"}) g.Assert(err).Equal(nil) }) @@ -102,7 +94,7 @@ func TestRepo(t *testing.T) { g.It("Should get RepoKeypair", func() { db.SetRepo(&common.Repo{FullName: testRepo}) err := db.SetRepoKeypair(testRepo, &common.Keypair{Private: "A", Public: "Alpha"}) - //g.Assert(err).Equal(nil) + keypair, err := db.RepoKeypair(testRepo) g.Assert(err).Equal(nil) g.Assert(keypair.Public).Equal("Alpha") @@ -128,7 +120,7 @@ func TestRepo(t *testing.T) { db.SetSubscriber(testUser, testRepo) err := db.DelSubscriber(testUser, testRepo) g.Assert(err).Equal(nil) - // + subscribed, err := db.Subscribed(testUser, testRepo) g.Assert(subscribed).Equal(false) diff --git a/datastore/bolt/task.go b/datastore/bolt/task.go index 637161dd4..ff09fcf13 100644 --- a/datastore/bolt/task.go +++ b/datastore/bolt/task.go @@ -2,13 +2,18 @@ package bolt import ( "bytes" + "github.com/boltdb/bolt" + //"github.com/drone/drone/common" "io" "strconv" - - "github.com/boltdb/bolt" - "github.com/drone/drone/common" ) +/* + Brad Rydzewski1:00 PM + the `Task`, `TaskList` and `SetTask` are deprecated and can be probably be removed. + I just need to make sure we aren't still using those functions anywhere else in the code +*/ +/* // GetTask gets the task at index N for the named // repository and build number. func (db *DB) Task(repo string, build int, task int) (*common.Task, error) { @@ -63,6 +68,7 @@ func (db *DB) SetTask(repo string, build int, task *common.Task) error { return update(t, bucketBuildTasks, key, task) }) } +*/ // SetLogs inserts or updates a task logs for the // named repository and build number. diff --git a/datastore/bolt/task_test.go b/datastore/bolt/task_test.go index d2997819f..573c75570 100644 --- a/datastore/bolt/task_test.go +++ b/datastore/bolt/task_test.go @@ -15,7 +15,7 @@ func TestTask(t *testing.T) { testRepo := "github.com/octopod/hq" testBuild := 1 testTask := 0 - testTask2 := 1 + //testTask2 := 1 testLogInfo := []byte("Log Info for SetLogs()") var db *DB // Temp database @@ -28,21 +28,6 @@ func TestTask(t *testing.T) { os.Remove(db.Path()) }) - g.It("Should set Task", func() { - db.SetRepo(&common.Repo{FullName: testRepo}) - err := db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) - g.Assert(err).Equal(nil) - }) - - g.It("Should get Task", func() { - db.SetRepo(&common.Repo{FullName: testRepo}) - db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) - // - task, err := db.Task(testRepo, testBuild, testTask) - g.Assert(err).Equal(nil) - g.Assert(task.Number).Equal(testTask) - }) - /* Brad Rydzewski1:00 PM the `Task`, `TaskList` and `SetTask` are deprecated and can be probably be removed. @@ -63,12 +48,27 @@ func TestTask(t *testing.T) { //g.Assert(err).Equal(nil) //g.Assert(len(tasks)).Equal(2) }) + + g.It("Should set Task", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + err := db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + g.Assert(err).Equal(nil) + }) + + g.It("Should get Task", func() { + db.SetRepo(&common.Repo{FullName: testRepo}) + db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + // + task, err := db.Task(testRepo, testBuild, testTask) + g.Assert(err).Equal(nil) + g.Assert(task.Number).Equal(testTask) + }) */ g.It("Should set Logs", func() { db.SetRepo(&common.Repo{FullName: testRepo}) - db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) - db.SetTask(testRepo, testBuild, &common.Task{Number: testTask2}) + //db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + //db.SetTask(testRepo, testBuild, &common.Task{Number: testTask2}) // err := db.SetLogs(testRepo, testBuild, testTask, testLogInfo) g.Assert(err).Equal(nil) @@ -76,8 +76,8 @@ func TestTask(t *testing.T) { g.It("Should LogReader", func() { db.SetRepo(&common.Repo{FullName: testRepo}) - db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) - db.SetTask(testRepo, testBuild, &common.Task{Number: testTask2}) + //db.SetTask(testRepo, testBuild, &common.Task{Number: testTask}) + //db.SetTask(testRepo, testBuild, &common.Task{Number: testTask2}) db.SetLogs(testRepo, testBuild, testTask, testLogInfo) // buf, err_ := db.LogReader(testRepo, testBuild, testTask) diff --git a/datastore/datastore.go b/datastore/datastore.go index 3bab2c5dc..19631da0f 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -121,15 +121,15 @@ type Datastore interface { // GetTask gets the task at index N for the named // repository and build number. - Task(string, int, int) (*common.Task, error) + //Task(string, int, int) (*common.Task, error) // TaskList gets all tasks for the named repository // and build number. - TaskList(string, int) ([]*common.Task, error) + //TaskList(string, int) ([]*common.Task, error) // SetTask inserts or updates a task for the named // repository and build number. - SetTask(string, int, *common.Task) error + //SetTask(string, int, *common.Task) error // LogReader gets the task logs at index N for // the named repository and build number.