diff --git a/datastore/bolt/build.go b/datastore/bolt/build.go index 5187b4a2c..b39dcad24 100644 --- a/datastore/bolt/build.go +++ b/datastore/bolt/build.go @@ -2,6 +2,7 @@ package bolt import ( "bytes" + "encoding/binary" "strconv" "time" @@ -67,10 +68,49 @@ func (db *DB) GetBuildStatusList(repo string, build int) ([]*common.Status, erro // InsertBuild inserts a new build for the named repository func (db *DB) InsertBuild(repo string, build *common.Build) error { - // TODO(bradrydzewski) use the `bucketBuildSeq` to increment the - // sequence for the build and set the build number. - key := []byte(repo + "/" + strconv.Itoa(build.Number)) - return update(db, bucketBuild, key, build) + var seqno int + + t, err := db.Begin(true) + if err != nil { + return err + } + key := []byte(repo) + raw := t.Bucket(bucketBuildSeq).Get(key) + if raw != nil { + // convert our raw to an integer value + seqno = int(binary.LittleEndian.Uint32(raw)) + } + + // increment the seqno, if no record was found, this starts us at 1 + seqno += 1 + + // convert our new seqno back to raw value + raw = make([]byte, 4) // TODO: replace magic number 4 (uint32) + binary.LittleEndian.PutUint32(raw, uint32(seqno)) + err = t.Bucket(bucketBuildSeq).Put(key, raw) + if err != nil { + t.Rollback() + return err + } + + // fill out build structure + build.Number = seqno + build.Created = time.Now().UTC().Unix() + + key = []byte(repo + "/" + strconv.Itoa(build.Number)) + raw, err = encode(build) + if err != nil { + t.Rollback() + return err + } + + err = t.Bucket(bucketBuild).Put(key, raw) + if err != nil { + t.Rollback() + return err + } + + return t.Commit() } // InsertBuildStatus inserts a new build status for the diff --git a/datastore/bolt/build_test.go b/datastore/bolt/build_test.go index a3ce8fd08..a0f3927b1 100644 --- a/datastore/bolt/build_test.go +++ b/datastore/bolt/build_test.go @@ -1 +1,46 @@ package bolt + +import ( + "os" + "testing" + + "github.com/drone/drone/common" + . "github.com/franela/goblin" +) + +func TestBuild(t *testing.T) { + g := Goblin(t) + g.Describe("Build", func() { + var db *DB // temporary database + repo := string("github.com/octopod/hq") + + // 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 sequence builds", func() { + err := db.InsertBuild(repo, &common.Build{State: "pending"}) + g.Assert(err).Equal(nil) + + // the first build should always be numero 1 + build, err := db.GetBuild(repo, 1) + g.Assert(err).Equal(nil) + g.Assert(build.State).Equal("pending") + + // add another build, just for fun + err = db.InsertBuild(repo, &common.Build{State: "success"}) + g.Assert(err).Equal(nil) + + // get the next build + build, err = db.GetBuild(repo, 2) + g.Assert(err).Equal(nil) + g.Assert(build.State).Equal("success") + }) + + }) +}