diff --git a/cmd/drone-agent/main.go b/cmd/drone-agent/main.go index 1caccb435..cccbb8e0f 100644 --- a/cmd/drone-agent/main.go +++ b/cmd/drone-agent/main.go @@ -54,7 +54,7 @@ func main() { } log.Infof("Pulled and running build %s / %d", - w.Repo.FullName, w.Commit.Sequence) + w.Repo.FullName, w.Build.Number) updater := &updater{} runner_ := runner.Runner{Updater: updater} diff --git a/cmd/drone-agent/updater.go b/cmd/drone-agent/updater.go index a2da642a7..79e391171 100644 --- a/cmd/drone-agent/updater.go +++ b/cmd/drone-agent/updater.go @@ -17,18 +17,18 @@ import ( type updater struct{} -func (u *updater) SetCommit(user *common.User, r *common.Repo, c *common.Commit) error { +func (u *updater) SetBuild(user *common.User, r *common.Repo, b *common.Build) error { path := fmt.Sprintf("/api/queue/push/%s", r.FullName) - return sendBackoff("POST", path, c, nil) + return sendBackoff("POST", path, b, nil) } -func (u *updater) SetJob(r *common.Repo, c *common.Commit, j *common.Job) error { - path := fmt.Sprintf("/api/queue/push/%s/%v", r.FullName, c.Sequence) +func (u *updater) SetJob(r *common.Repo, b *common.Build, j *common.Job) error { + path := fmt.Sprintf("/api/queue/push/%s/%v", r.FullName, b.Number) return sendBackoff("POST", path, j, nil) } -func (u *updater) SetLogs(r *common.Repo, c *common.Commit, j *common.Job, rc io.ReadCloser) error { - path := fmt.Sprintf("/api/queue/push/%s/%v/%v", r.FullName, c.Sequence, j.Number) +func (u *updater) SetLogs(r *common.Repo, b *common.Build, j *common.Job, rc io.ReadCloser) error { + path := fmt.Sprintf("/api/queue/push/%s/%v/%v", r.FullName, b.Number, j.Number) return sendBackoff("POST", path, rc, nil) } diff --git a/pkg/ccmenu/ccmenu.go b/pkg/ccmenu/ccmenu.go index aa830b84a..8c4bf3f27 100644 --- a/pkg/ccmenu/ccmenu.go +++ b/pkg/ccmenu/ccmenu.go @@ -23,7 +23,7 @@ type CCProject struct { WebURL string `xml:"webUrl,attr"` } -func NewCC(r *types.Repo, c *types.Commit) *CCProjects { +func NewCC(r *types.Repo, b *types.Build) *CCProjects { proj := &CCProject{ Name: r.Owner + "/" + r.Name, WebURL: r.Self, @@ -34,16 +34,16 @@ func NewCC(r *types.Repo, c *types.Commit) *CCProjects { // if the build is not currently running then // we can return the latest build status. - if c.State != types.StatePending && - c.State != types.StateRunning { + if b.Status != types.StatePending && + b.Status != types.StateRunning { proj.Activity = "Sleeping" - proj.LastBuildTime = time.Unix(c.Started, 0).Format(time.RFC3339) - proj.LastBuildLabel = strconv.Itoa(c.Sequence) + proj.LastBuildTime = time.Unix(b.Started, 0).Format(time.RFC3339) + proj.LastBuildLabel = strconv.Itoa(b.Number) } // ensure the last build state accepts a valid // ccmenu enumeration - switch c.State { + switch b.Status { case types.StateError, types.StateKilled: proj.LastBuildStatus = "Exception" case types.StateSuccess: diff --git a/pkg/queue/worker.go b/pkg/queue/worker.go index 611e77fa9..901b31572 100644 --- a/pkg/queue/worker.go +++ b/pkg/queue/worker.go @@ -11,7 +11,7 @@ import ( type Work struct { User *common.User `json:"user"` Repo *common.Repo `json:"repo"` - Commit *common.Commit `json:"commit"` + Build *common.Build `json:"build"` Keys *common.Keypair `json:"keypair"` Netrc *common.Netrc `json:"netrc"` Yaml []byte `json:"yaml"` diff --git a/pkg/remote/builtin/github/github.go b/pkg/remote/builtin/github/github.go index 479d627f0..b7fb1f82a 100644 --- a/pkg/remote/builtin/github/github.go +++ b/pkg/remote/builtin/github/github.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" "net/url" - "strconv" "strings" "time" @@ -143,15 +142,9 @@ func (g *GitHub) Perm(u *common.User, owner, name string) (*common.Perm, error) // Script fetches the build script (.drone.yml) from the remote // repository and returns in string format. -func (g *GitHub) Script(u *common.User, r *common.Repo, c *common.Commit) ([]byte, error) { +func (g *GitHub) Script(u *common.User, r *common.Repo, b *common.Build) ([]byte, error) { client := NewClient(g.API, u.Token, g.SkipVerify) - var sha string - if len(c.SourceSha) == 0 { - sha = c.Sha - } else { - sha = c.SourceSha - } - return GetFile(client, r.Owner, r.Name, ".drone.yml", sha) + return GetFile(client, r.Owner, r.Name, ".drone.yml", b.Commit.Sha) } // Netrc returns a .netrc file that can be used to clone @@ -209,19 +202,19 @@ func (g *GitHub) Deactivate(u *common.User, r *common.Repo, link string) error { return DeleteHook(client, r.Owner, r.Name, link) } -func (g *GitHub) Status(u *common.User, r *common.Repo, c *common.Commit) error { +func (g *GitHub) Status(u *common.User, r *common.Repo, b *common.Build) error { client := NewClient(g.API, u.Token, g.SkipVerify) - link := fmt.Sprintf("%s/%v", r.Self, c.Sequence) - status := getStatus(c.State) - desc := getDesc(c.State) + link := fmt.Sprintf("%s/%v", r.Self, b.Number) + status := getStatus(b.Status) + desc := getDesc(b.Status) data := github.RepoStatus{ Context: github.String("Drone"), State: github.String(status), Description: github.String(desc), TargetURL: github.String(link), } - _, _, err := client.Repositories.CreateStatus(r.Owner, r.Name, c.SourceSha, &data) + _, _, err := client.Repositories.CreateStatus(r.Owner, r.Name, b.Commit.Sha, &data) return err } @@ -270,10 +263,10 @@ func (g *GitHub) push(r *http.Request) (*common.Hook, error) { commit.Branch = strings.Replace(commit.Ref, "refs/heads/", "", -1) commit.Message = hook.Head.Message commit.Timestamp = hook.Head.Timestamp - commit.Author = hook.Head.Author.Username - // commit.Author.Name = hook.Head.Author.Name - // commit.Author.Email = hook.Head.Author.Email - // commit.Author.Login = hook.Head.Author.Username + commit.Author = &common.Author{} + commit.Author.Email = hook.Head.Author.Email + commit.Author.Login = hook.Head.Author.Username + commit.Remote = hook.Repo.CloneURL // we should ignore github pages if commit.Ref == "refs/heads/gh-pages" { @@ -318,19 +311,31 @@ func (g *GitHub) pullRequest(r *http.Request) (*common.Hook, error) { } c := &common.Commit{} - c.PullRequest = strconv.Itoa(*hook.PullRequest.Number) - c.Message = *hook.PullRequest.Title - c.Sha = *hook.PullRequest.Base.SHA - c.Ref = *hook.PullRequest.Base.Ref - c.Ref = fmt.Sprintf("refs/pull/%s/merge", c.PullRequest) - c.Branch = *hook.PullRequest.Base.Ref + c.Sha = *hook.PullRequest.Head.SHA + c.Ref = *hook.PullRequest.Head.Ref + c.Ref = fmt.Sprintf("refs/pull/%s/merge", *hook.PullRequest.Number) + c.Branch = *hook.PullRequest.Head.Ref c.Timestamp = time.Now().UTC().Format("2006-01-02 15:04:05.000000000 +0000 MST") - c.Author = *hook.PullRequest.Base.User.Login - c.SourceRemote = *hook.PullRequest.Head.Repo.CloneURL - c.SourceBranch = *hook.PullRequest.Head.Ref - c.SourceSha = *hook.PullRequest.Head.SHA + c.Remote = *hook.PullRequest.Head.Repo.CloneURL + c.Author = &common.Author{} + c.Author.Login = *hook.PullRequest.Head.User.Login + // Author.Email + // Message - return &common.Hook{Repo: repo, Commit: c}, nil + pr := &common.PullRequest{} + pr.Number = *hook.PullRequest.Number + pr.Title = *hook.PullRequest.Title + pr.Base = &common.Commit{} + pr.Base.Sha = *hook.PullRequest.Base.SHA + pr.Base.Ref = *hook.PullRequest.Base.Ref + pr.Base.Remote = *hook.PullRequest.Base.Repo.CloneURL + // Branch + // Message + // Timestamp + // Author.Login + // Author.Email + + return &common.Hook{Repo: repo, Commit: c, PullRequest: pr}, nil } type pushHook struct { diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index 7d3bdf698..a195f416d 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -23,11 +23,11 @@ type Remote interface { // Script fetches the build script (.drone.yml) from the remote // repository and returns in string format. - Script(u *common.User, r *common.Repo, c *common.Commit) ([]byte, error) + Script(u *common.User, r *common.Repo, b *common.Build) ([]byte, error) // Status sends the commit status to the remote system. // An example would be the GitHub pull request status. - Status(u *common.User, r *common.Repo, c *common.Commit) error + Status(u *common.User, r *common.Repo, b *common.Build) error // Netrc returns a .netrc file that can be used to clone // private repositories from a remote system. diff --git a/pkg/runner/builtin/runner.go b/pkg/runner/builtin/runner.go index c71cea384..3b7240d7a 100644 --- a/pkg/runner/builtin/runner.go +++ b/pkg/runner/builtin/runner.go @@ -53,10 +53,10 @@ func (r *Runner) Run(w *queue.Work) error { // if any part of the commit fails and leaves // behind orphan sub-builds we need to cleanup // after ourselves. - if w.Commit.State == types.StateRunning { + if w.Build.Status == types.StateRunning { // if any tasks are running or pending // we should mark them as complete. - for _, b := range w.Commit.Builds { + for _, b := range w.Build.Jobs { if b.Status == types.StateRunning { b.Status = types.StateError b.Finished = time.Now().UTC().Unix() @@ -68,23 +68,23 @@ func (r *Runner) Run(w *queue.Work) error { b.Finished = time.Now().UTC().Unix() b.ExitCode = 255 } - r.SetJob(w.Repo, w.Commit, b) + r.SetJob(w.Repo, w.Build, b) } // must populate build start - if w.Commit.Started == 0 { - w.Commit.Started = time.Now().UTC().Unix() + if w.Build.Started == 0 { + w.Build.Started = time.Now().UTC().Unix() } // mark the build as complete (with error) - w.Commit.State = types.StateError - w.Commit.Finished = time.Now().UTC().Unix() - r.SetCommit(w.User, w.Repo, w.Commit) + w.Build.Status = types.StateError + w.Build.Finished = time.Now().UTC().Unix() + r.SetBuild(w.User, w.Repo, w.Build) } }() // marks the build as running - w.Commit.Started = time.Now().UTC().Unix() - w.Commit.State = types.StateRunning - err := r.SetCommit(w.User, w.Repo, w.Commit) + w.Build.Started = time.Now().UTC().Unix() + w.Build.Status = types.StateRunning + err := r.SetBuild(w.User, w.Repo, w.Build) if err != nil { return err } @@ -99,19 +99,19 @@ func (r *Runner) Run(w *queue.Work) error { // loop through and execute the build and // clone steps for each build job. - for _, job := range w.Commit.Builds { + for _, job := range w.Build.Jobs { // marks the task as running job.Status = types.StateRunning job.Started = time.Now().UTC().Unix() - err = r.SetJob(w.Repo, w.Commit, job) + err = r.SetJob(w.Repo, w.Build, job) if err != nil { return err } work := &work{ Repo: w.Repo, - Commit: w.Commit, + Build: w.Build, Keys: w.Keys, Netrc: w.Netrc, Yaml: w.Yaml, @@ -127,7 +127,7 @@ func (r *Runner) Run(w *queue.Work) error { worker := newWorkerTimeout(client, w.Repo.Timeout) workers = append(workers, worker) cname := cname(job) - pullrequest := (w.Commit.PullRequest != "") + pullrequest := (w.Build.PullRequest != nil) state, builderr := worker.Build(cname, in, pullrequest) switch { @@ -156,14 +156,14 @@ func (r *Runner) Run(w *queue.Work) error { defer rc.Close() docker.StdCopy(&buf, &buf, rc) } - err = r.SetLogs(w.Repo, w.Commit, job, ioutil.NopCloser(&buf)) + err = r.SetLogs(w.Repo, w.Build, job, ioutil.NopCloser(&buf)) if err != nil { return err } // update the task in the datastore job.Finished = time.Now().UTC().Unix() - err = r.SetJob(w.Repo, w.Commit, job) + err = r.SetJob(w.Repo, w.Build, job) if err != nil { return err } @@ -171,24 +171,24 @@ func (r *Runner) Run(w *queue.Work) error { // update the build state if any of the sub-tasks // had a non-success status - w.Commit.State = types.StateSuccess - for _, job := range w.Commit.Builds { + w.Build.Status = types.StateSuccess + for _, job := range w.Build.Jobs { if job.Status != types.StateSuccess { - w.Commit.State = job.Status + w.Build.Status = job.Status break } } - err = r.SetCommit(w.User, w.Repo, w.Commit) + err = r.SetBuild(w.User, w.Repo, w.Build) if err != nil { return err } // loop through and execute the notifications and // the destroy all containers afterward. - for i, job := range w.Commit.Builds { + for i, job := range w.Build.Jobs { work := &work{ Repo: w.Repo, - Commit: w.Commit, + Build: w.Build, Keys: w.Keys, Netrc: w.Netrc, Yaml: w.Yaml, diff --git a/pkg/runner/builtin/updater.go b/pkg/runner/builtin/updater.go index a969c1824..634743c57 100644 --- a/pkg/runner/builtin/updater.go +++ b/pkg/runner/builtin/updater.go @@ -12,9 +12,9 @@ import ( ) type Updater interface { - SetCommit(*types.User, *types.Repo, *types.Commit) error - SetJob(*types.Repo, *types.Commit, *types.Job) error - SetLogs(*types.Repo, *types.Commit, *types.Job, io.ReadCloser) error + SetBuild(*types.User, *types.Repo, *types.Build) error + SetJob(*types.Repo, *types.Build, *types.Job) error + SetLogs(*types.Repo, *types.Build, *types.Job, io.ReadCloser) error } // NewUpdater returns an implementation of the Updater interface @@ -29,8 +29,8 @@ type updater struct { remote remote.Remote } -func (u *updater) SetCommit(user *types.User, r *types.Repo, c *types.Commit) error { - err := u.store.SetCommit(c) +func (u *updater) SetBuild(user *types.User, r *types.Repo, c *types.Build) error { + err := u.store.SetBuild(c) if err != nil { return err } @@ -44,8 +44,8 @@ func (u *updater) SetCommit(user *types.User, r *types.Repo, c *types.Commit) er // a remote agent won't have the embedded // build list. we should probably just rethink // the messaging instead of this hack. - if c.Builds == nil || len(c.Builds) == 0 { - c.Builds, _ = u.store.JobList(c) + if c.Jobs == nil || len(c.Jobs) == 0 { + c.Jobs, _ = u.store.JobList(c) } msg, err := json.Marshal(c) @@ -61,7 +61,7 @@ func (u *updater) SetCommit(user *types.User, r *types.Repo, c *types.Commit) er return nil } -func (u *updater) SetJob(r *types.Repo, c *types.Commit, j *types.Job) error { +func (u *updater) SetJob(r *types.Repo, c *types.Build, j *types.Job) error { err := u.store.SetJob(j) if err != nil { return err @@ -71,8 +71,8 @@ func (u *updater) SetJob(r *types.Repo, c *types.Commit, j *types.Job) error { // a remote agent won't have the embedded // build list. we should probably just rethink // the messaging instead of this hack. - if c.Builds == nil || len(c.Builds) == 0 { - c.Builds, _ = u.store.JobList(c) + if c.Jobs == nil || len(c.Jobs) == 0 { + c.Jobs, _ = u.store.JobList(c) } msg, err := json.Marshal(c) @@ -88,7 +88,7 @@ func (u *updater) SetJob(r *types.Repo, c *types.Commit, j *types.Job) error { return nil } -func (u *updater) SetLogs(r *types.Repo, c *types.Commit, j *types.Job, rc io.ReadCloser) error { - path := fmt.Sprintf("/logs/%s/%v/%v", r.FullName, c.Sequence, j.Number) +func (u *updater) SetLogs(r *types.Repo, c *types.Build, j *types.Job, rc io.ReadCloser) error { + path := fmt.Sprintf("/logs/%s/%v/%v", r.FullName, c.Number, j.Number) return u.store.SetBlobReader(path, rc) } diff --git a/pkg/runner/builtin/worker.go b/pkg/runner/builtin/worker.go index fe2ffb347..c42e0a986 100644 --- a/pkg/runner/builtin/worker.go +++ b/pkg/runner/builtin/worker.go @@ -53,7 +53,7 @@ var ( type work struct { Repo *types.Repo `json:"repo"` - Commit *types.Commit `json:"commit"` + Build *types.Build `json:"build"` Job *types.Job `json:"job"` Keys *types.Keypair `json:"keys"` Netrc *types.Netrc `json:"netrc"` diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index dbfe5b4cd..99683848c 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -16,7 +16,7 @@ type Runner interface { // Updater defines a set of functions that are required for // the runner to sent Drone updates during a build. type Updater interface { - SetCommit(*types.User, *types.Repo, *types.Commit) error - SetJob(*types.Repo, *types.Commit, *types.Job) error - SetLogs(*types.Repo, *types.Commit, *types.Job, io.ReadCloser) error + SetBuild(*types.User, *types.Repo, *types.Build) error + SetJob(*types.Repo, *types.Build, *types.Job) error + SetLogs(*types.Repo, *types.Build, *types.Job, io.ReadCloser) error } diff --git a/pkg/server/badge.go b/pkg/server/badge.go index a4b4c4575..dea1e769e 100644 --- a/pkg/server/badge.go +++ b/pkg/server/badge.go @@ -36,13 +36,13 @@ func GetBadge(c *gin.Context) { // if no commit was found then display // the 'none' badge, instead of throwing // an error response - commit, err := store.CommitLast(repo, branch) + build, err := store.BuildLast(repo, branch) if err != nil { c.Writer.Write(badgeNone) return } - switch commit.State { + switch build.Status { case common.StateSuccess: c.Writer.Write(badgeSuccess) case common.StateFailure: @@ -66,7 +66,7 @@ func GetBadge(c *gin.Context) { func GetCC(c *gin.Context) { store := ToDatastore(c) repo := ToRepo(c) - list, err := store.CommitList(repo, 1, 0) + list, err := store.BuildList(repo, 1, 0) if err != nil || len(list) == 0 { c.AbortWithStatus(404) return diff --git a/pkg/server/commits.go b/pkg/server/commits.go index 17fc94a5d..ee86b1979 100644 --- a/pkg/server/commits.go +++ b/pkg/server/commits.go @@ -27,15 +27,15 @@ func GetCommit(c *gin.Context) { c.Fail(400, err) return } - commit, err := store.CommitSeq(repo, num) + build, err := store.BuildNumber(repo, num) if err != nil { c.Fail(404, err) } - commit.Builds, err = store.JobList(commit) + build.Jobs, err = store.JobList(build) if err != nil { c.Fail(404, err) } else { - c.JSON(200, commit) + c.JSON(200, build) } } @@ -47,11 +47,11 @@ func GetCommit(c *gin.Context) { func GetCommits(c *gin.Context) { store := ToDatastore(c) repo := ToRepo(c) - commits, err := store.CommitList(repo, 20, 0) + builds, err := store.BuildList(repo, 20, 0) if err != nil { c.Fail(404, err) } else { - c.JSON(200, commits) + c.JSON(200, builds) } } @@ -65,10 +65,10 @@ func GetLogs(c *gin.Context) { store := ToDatastore(c) repo := ToRepo(c) full, _ := strconv.ParseBool(c.Params.ByName("full")) - commit, _ := strconv.Atoi(c.Params.ByName("number")) - build, _ := strconv.Atoi(c.Params.ByName("task")) + build, _ := strconv.Atoi(c.Params.ByName("number")) + job, _ := strconv.Atoi(c.Params.ByName("task")) - path := fmt.Sprintf("/logs/%s/%v/%v", repo.FullName, commit, build) + path := fmt.Sprintf("/logs/%s/%v/%v", repo.FullName, build, job) r, err := store.GetBlobReader(path) if err != nil { c.Fail(404, err) @@ -121,12 +121,12 @@ func RunBuild(c *gin.Context) { c.Fail(400, err) return } - commit, err := store.CommitSeq(repo, num) + build, err := store.BuildNumber(repo, num) if err != nil { c.Fail(404, err) return } - commit.Builds, err = store.JobList(commit) + build.Jobs, err = store.JobList(build) if err != nil { c.Fail(404, err) return @@ -139,22 +139,22 @@ func RunBuild(c *gin.Context) { } // must not restart a running build - if commit.State == common.StatePending || commit.State == common.StateRunning { + if build.Status == common.StatePending || build.Status == common.StateRunning { c.AbortWithStatus(409) return } - commit.State = common.StatePending - commit.Started = 0 - commit.Finished = 0 - for _, job := range commit.Builds { + build.Status = common.StatePending + build.Started = 0 + build.Finished = 0 + for _, job := range build.Jobs { job.Status = common.StatePending job.Started = 0 job.Finished = 0 job.ExitCode = 0 } - err = store.SetCommit(commit) + err = store.SetBuild(build) if err != nil { c.Fail(500, err) return @@ -167,7 +167,7 @@ func RunBuild(c *gin.Context) { } // featch the .drone.yml file from the database - raw, err := remote.Script(user, repo, commit) + raw, err := remote.Script(user, repo, build) if err != nil { c.Fail(404, err) return @@ -178,12 +178,12 @@ func RunBuild(c *gin.Context) { raw = []byte(inject.InjectSafe(string(raw), repo.Params)) } - c.JSON(202, commit) + c.JSON(202, build) queue_.Publish(&queue.Work{ User: user, Repo: repo, - Commit: commit, + Build: build, Keys: repo.Keys, Netrc: netrc, Yaml: raw, @@ -206,19 +206,19 @@ func KillBuild(c *gin.Context) { c.Fail(400, err) return } - commit, err := store.CommitSeq(repo, num) + build, err := store.BuildNumber(repo, num) if err != nil { c.Fail(404, err) return } - commit.Builds, err = store.JobList(commit) + build.Jobs, err = store.JobList(build) if err != nil { c.Fail(404, err) return } // must not restart a running build - if commit.State != common.StatePending && commit.State != common.StateRunning { + if build.Status != common.StatePending && build.Status != common.StateRunning { c.Fail(409, err) return } @@ -228,32 +228,32 @@ func KillBuild(c *gin.Context) { // TODO(bradrydzewski) this could yield a race condition // because other threads may also be accessing these items. for _, item := range queue.Items() { - if item.Repo.FullName == repo.FullName && item.Commit.Sequence == commit.Sequence { + if item.Repo.FullName == repo.FullName && item.Build.Number == build.Number { queue.Remove(item) break } } - commit.State = common.StateKilled - commit.Finished = time.Now().Unix() - if commit.Started == 0 { - commit.Started = commit.Finished + build.Status = common.StateKilled + build.Finished = time.Now().Unix() + if build.Started == 0 { + build.Started = build.Finished } - for _, job := range commit.Builds { + for _, job := range build.Jobs { if job.Status != common.StatePending && job.Status != common.StateRunning { continue } job.Status = common.StateKilled - job.Started = commit.Started - job.Finished = commit.Finished + job.Started = build.Started + job.Finished = build.Finished } - err = store.SetCommit(commit) + err = store.SetBuild(build) if err != nil { c.Fail(500, err) return } - for _, job := range commit.Builds { + for _, job := range build.Jobs { runner.Cancel(job) } // // get the agent from the repository so we can @@ -272,5 +272,5 @@ func KillBuild(c *gin.Context) { // } // defer resp.Body.Close() - c.JSON(200, commit) + c.JSON(200, build) } diff --git a/pkg/server/hooks.go b/pkg/server/hooks.go index 59b033353..aeca92c8b 100644 --- a/pkg/server/hooks.go +++ b/pkg/server/hooks.go @@ -68,11 +68,11 @@ func PostHook(c *gin.Context) { log.Warnf("ignoring hook. repo %s has no owner.", repo.FullName) c.Writer.WriteHeader(204) return - case !repo.Hooks.Push && hook.Commit.PullRequest != "": + case !repo.Hooks.Push && hook.PullRequest != nil: log.Infof("ignoring hook. repo %s is disabled.", repo.FullName) c.Writer.WriteHeader(204) return - case !repo.Hooks.PullRequest && hook.Commit.PullRequest == "": + case !repo.Hooks.PullRequest && hook.PullRequest == nil: log.Warnf("ignoring hook. repo %s is disabled for pull requests.", repo.FullName) c.Writer.WriteHeader(204) return @@ -85,12 +85,14 @@ func PostHook(c *gin.Context) { return } - commit := hook.Commit - commit.State = common.StatePending - commit.RepoID = repo.ID + build := &common.Build{} + build.Commit = hook.Commit + build.PullRequest = hook.PullRequest + build.Status = common.StatePending + build.RepoID = repo.ID // featch the .drone.yml file from the database - raw, err := remote.Script(user, repo, commit) + raw, err := remote.Script(user, repo, build) if err != nil { log.Errorf("failure to get .drone.yml for %s. %s", repo.FullName, err) c.Fail(404, err) @@ -110,8 +112,8 @@ func PostHook(c *gin.Context) { axes = append(axes, matrix.Axis{}) } for num, axis := range axes { - commit.Builds = append(commit.Builds, &common.Job{ - BuildID: commit.ID, + build.Jobs = append(build.Jobs, &common.Job{ + BuildID: build.ID, Number: num + 1, Status: common.StatePending, Environment: axis, @@ -127,30 +129,30 @@ func PostHook(c *gin.Context) { // verify the branches can be built vs skipped when, _ := parser.ParseCondition(string(raw)) - if commit.PullRequest != "" && when != nil && !when.MatchBranch(commit.Branch) { - log.Infof("ignoring hook. yaml file excludes repo and branch %s %s", repo.FullName, commit.Branch) + if build.PullRequest != nil && when != nil && !when.MatchBranch(build.Commit.Branch) { + log.Infof("ignoring hook. yaml file excludes repo and branch %s %s", repo.FullName, build.Commit.Branch) c.AbortWithStatus(200) return } - err = store.AddCommit(commit) + err = store.AddBuild(build) if err != nil { log.Errorf("failure to save commit for %s. %s", repo.FullName, err) c.Fail(500, err) return } - c.JSON(200, commit) + c.JSON(200, build) - err = remote.Status(user, repo, commit) + err = remote.Status(user, repo, build) if err != nil { - log.Errorf("error setting commit status for %s/%d", repo.FullName, commit.Sequence) + log.Errorf("error setting commit status for %s/%d", repo.FullName, build.Number) } queue_.Publish(&queue.Work{ User: user, Repo: repo, - Commit: commit, + Build: build, Keys: repo.Keys, Netrc: netrc, Yaml: raw, diff --git a/pkg/server/queue.go b/pkg/server/queue.go index 3ec96e345..ea68285e3 100644 --- a/pkg/server/queue.go +++ b/pkg/server/queue.go @@ -35,13 +35,13 @@ func PollBuild(c *gin.Context) { } // persist the relationship between agent and commit. - err = store.SetAgent(work.Commit, addr) + err = store.SetAgent(work.Build, addr) if err != nil { // note the we are ignoring and just logging the error here. // we consider this an acceptible failure because it doesn't // impact anything other than live-streaming output. log.Errorf("unable to store the agent address %s for build %s %v", - addr, work.Repo.FullName, work.Commit.Sequence) + addr, work.Repo.FullName, work.Build.Number) } c.JSON(200, work) @@ -55,7 +55,7 @@ func PushCommit(c *gin.Context) { store := ToDatastore(c) repo := ToRepo(c) - in := &common.Commit{} + in := &common.Build{} if !c.BindWith(in, binding.JSON) { return } @@ -64,18 +64,18 @@ func PushCommit(c *gin.Context) { c.Fail(404, err) return } - commit, err := store.CommitSeq(repo, in.Sequence) + build, err := store.BuildNumber(repo, in.Number) if err != nil { c.Fail(404, err) return } - commit.Started = in.Started - commit.Finished = in.Finished - commit.State = in.State + build.Started = in.Started + build.Finished = in.Finished + build.Status = in.Status updater := ToUpdater(c) - err = updater.SetCommit(user, repo, commit) + err = updater.SetBuild(user, repo, build) if err != nil { c.Fail(500, err) return @@ -94,12 +94,12 @@ func PushBuild(c *gin.Context) { return } - commit, err := store.CommitSeq(repo, cnum) + build, err := store.BuildNumber(repo, cnum) if err != nil { c.Fail(404, err) return } - job, err := store.JobNumber(commit, in.Number) + job, err := store.JobNumber(build, in.Number) if err != nil { c.Fail(404, err) return @@ -111,7 +111,7 @@ func PushBuild(c *gin.Context) { job.Status = in.Status updater := ToUpdater(c) - err = updater.SetJob(repo, commit, job) + err = updater.SetJob(repo, build, job) if err != nil { c.Fail(500, err) return @@ -126,18 +126,18 @@ func PushLogs(c *gin.Context) { cnum, _ := strconv.Atoi(c.Params.ByName("commit")) bnum, _ := strconv.Atoi(c.Params.ByName("build")) - commit, err := store.CommitSeq(repo, cnum) + build, err := store.BuildNumber(repo, cnum) if err != nil { c.Fail(404, err) return } - job, err := store.JobNumber(commit, bnum) + job, err := store.JobNumber(build, bnum) if err != nil { c.Fail(404, err) return } updater := ToUpdater(c) - err = updater.SetLogs(repo, commit, job, c.Request.Body) + err = updater.SetLogs(repo, build, job, c.Request.Body) if err != nil { c.Fail(500, err) return diff --git a/pkg/server/ws.go b/pkg/server/ws.go index 7abc6f9f5..d5aaf9597 100644 --- a/pkg/server/ws.go +++ b/pkg/server/ws.go @@ -60,12 +60,12 @@ func GetStream(c *gin.Context) { c.Writer.Header().Set("Content-Type", "text/event-stream") - commit, err := store.CommitSeq(repo, commitseq) + build, err := store.BuildNumber(repo, commitseq) if err != nil { c.Fail(404, err) return } - job, err := store.JobNumber(commit, jobnum) + job, err := store.JobNumber(build, jobnum) if err != nil { c.Fail(404, err) return @@ -77,7 +77,7 @@ func GetStream(c *gin.Context) { // we'll proxy the build output directly to the // remote Docker client, through the agent. if conf.Agents.Secret != "" { - addr, err := store.Agent(commit) + addr, err := store.Agent(build) if err != nil { c.Fail(500, err) return diff --git a/pkg/store/builtin/agent.go b/pkg/store/builtin/agent.go index 615e3eb2a..323e6d49e 100644 --- a/pkg/store/builtin/agent.go +++ b/pkg/store/builtin/agent.go @@ -15,8 +15,8 @@ func NewAgentstore(db *sql.DB) *Agentstore { } // Agent returns an agent by ID. -func (db *Agentstore) Agent(commit *types.Commit) (string, error) { - agent, err := getAgent(db, rebind(stmtAgentSelectAgentCommit), commit.ID) +func (db *Agentstore) Agent(build *types.Build) (string, error) { + agent, err := getAgent(db, rebind(stmtAgentSelectAgentCommit), build.ID) if err != nil { return "", err } @@ -24,13 +24,13 @@ func (db *Agentstore) Agent(commit *types.Commit) (string, error) { } // SetAgent updates an agent in the datastore. -func (db *Agentstore) SetAgent(commit *types.Commit, addr string) error { - agent := Agent{Addr: addr, CommitID: commit.ID} +func (db *Agentstore) SetAgent(build *types.Build, addr string) error { + agent := Agent{Addr: addr, BuildID: build.ID} return createAgent(db, rebind(stmtAgentInsert), &agent) } type Agent struct { - ID int64 - Addr string - CommitID int64 `sql:"unique:ux_agent_commit"` + ID int64 + Addr string + BuildID int64 `sql:"unique:ux_agent_build"` } diff --git a/pkg/store/builtin/agent_sql.go b/pkg/store/builtin/agent_sql.go index c1977d1ba..3280d0843 100644 --- a/pkg/store/builtin/agent_sql.go +++ b/pkg/store/builtin/agent_sql.go @@ -35,7 +35,7 @@ func createAgent(db agentDB, query string, v *Agent) error { var v0 string var v1 int64 v0 = v.Addr - v1 = v.CommitID + v1 = v.BuildID res, err := db.Exec(query, &v0, @@ -55,7 +55,7 @@ func updateAgent(db agentDB, query string, v *Agent) error { var v2 int64 v0 = v.ID v1 = v.Addr - v2 = v.CommitID + v2 = v.BuildID _, err := db.Exec(query, &v1, @@ -82,7 +82,7 @@ func scanAgent(row *sql.Row) (*Agent, error) { v := &Agent{} v.ID = v0 v.Addr = v1 - v.CommitID = v2 + v.BuildID = v2 return v, nil } @@ -106,7 +106,7 @@ func scanAgents(rows *sql.Rows) ([]*Agent, error) { v := &Agent{} v.ID = v0 v.Addr = v1 - v.CommitID = v2 + v.BuildID = v2 vv = append(vv, v) } return vv, rows.Err() @@ -116,7 +116,7 @@ const stmtAgentSelectList = ` SELECT agent_id ,agent_addr -,agent_commit_id +,agent_build_id FROM agents ` diff --git a/pkg/store/builtin/build.go b/pkg/store/builtin/build.go index e4442b494..ead54a120 100644 --- a/pkg/store/builtin/build.go +++ b/pkg/store/builtin/build.go @@ -6,35 +6,136 @@ import ( "github.com/drone/drone/pkg/types" ) -type Jobstore struct { +type Buildstore struct { *sql.DB } -func NewJobstore(db *sql.DB) *Jobstore { - return &Jobstore{db} +func NewBuildstore(db *sql.DB) *Buildstore { + return &Buildstore{db} } -// Job returns a Job by ID. -func (db *Jobstore) Job(id int64) (*types.Job, error) { - return getJob(db, rebind(stmtJobSelect), id) +// Build gets a build by ID +func (db *Buildstore) Build(id int64) (*types.Build, error) { + return getBuild(db, rebind(stmtBuildSelect), id) } -// JobNumber returns a job by sequence number. -func (db *Jobstore) JobNumber(commit *types.Commit, seq int) (*types.Job, error) { - return getJob(db, rebind(stmtJobSelectBuildNumber), commit.ID, seq) +// BuildNumber gets the specified build number for the +// named repository and build number +func (db *Buildstore) BuildNumber(repo *types.Repo, seq int) (*types.Build, error) { + return getBuild(db, rebind(stmtBuildSelectBuildNumber), repo.ID, seq) } -// JobList returns a list of all build jobs -func (db *Jobstore) JobList(commit *types.Commit) ([]*types.Job, error) { - return getJobs(db, rebind(stmtJobSelectJobBuildId), commit.ID) +// BuildLast gets the last executed build for the +// named repository. +func (db *Buildstore) BuildLast(repo *types.Repo, branch string) (*types.Build, error) { + return getBuild(db, rebind(buildLastQuery), repo.ID, branch) } -// SetJob updates an existing build job. -func (db *Jobstore) SetJob(job *types.Job) error { - return updateJob(db, rebind(stmtJobUpdate), job) +// BuildList gets a list of recent builds for the +// named repository. +func (db *Buildstore) BuildList(repo *types.Repo, limit, offset int) ([]*types.Build, error) { + return getBuilds(db, rebind(buildListQuery), repo.ID, limit, offset) } -// AddJob inserts a build job. -func (db *Jobstore) AddJob(job *types.Job) error { - return createJob(db, rebind(stmtJobInsert), job) +// AddBuild inserts a new build in the datastore. +func (db *Buildstore) AddBuild(build *types.Build) error { + tx, err := db.Begin() + if err != nil { + return err + } + defer tx.Rollback() + + // extract the next build number from the database + row := tx.QueryRow(rebind(buildNumberLast), build.RepoID) + if row != nil { + row.Scan(&build.Number) + } + + build.Number = build.Number + 1 // increment + err = createBuild(tx, rebind(stmtBuildInsert), build) + if err != nil { + return err + } + + for _, job := range build.Jobs { + job.BuildID = build.ID + err := createJob(tx, rebind(stmtJobInsert), job) + if err != nil { + return err + } + } + return tx.Commit() } + +// SetBuild updates an existing build and build jobs. +func (db *Buildstore) SetBuild(build *types.Build) error { + tx, err := db.Begin() + if err != nil { + return err + } + defer tx.Rollback() + + err = updateBuild(tx, rebind(stmtBuildUpdate), build) + if err != nil { + return err + } + + for _, job := range build.Jobs { + err = updateJob(tx, rebind(stmtJobUpdate), job) + if err != nil { + return err + } + } + return tx.Commit() +} + +// KillBuilds updates all pending or started builds +// in the datastore settings the status to killed. +func (db *Buildstore) KillBuilds() error { + var _, err1 = db.Exec(rebind(buildKillStmt)) + if err1 != nil { + return err1 + } + var _, err2 = db.Exec(rebind(jobKillStmt)) + return err2 +} + +// SQL query to retrieve the latest builds across all branches. +const buildListQuery = ` +SELECT * +FROM builds +WHERE build_repo_id = ? +ORDER BY build_number DESC +LIMIT ? OFFSET ? +` + +// SQL query to retrieve the most recent build. +// TODO exclude pull requests +const buildLastQuery = ` +SELECT * +FROM builds +WHERE build_repo_id = ? + AND build_commit_branch = ? +ORDER BY build_number DESC +LIMIT 1 +` + +// SQL statement to cancel all running builds. +const buildKillStmt = ` +UPDATE builds SET build_status = 'killed' +WHERE build_status IN ('pending', 'running'); +` + +// SQL statement to cancel all running build jobs. +const jobKillStmt = ` +UPDATE jobs SET job_status = 'killed' +WHERE job_status IN ('pending', 'running'); +` + +// SQL statement to retrieve the latest sequential +// build number for a build +const buildNumberLast = ` +SELECT MAX(build_number) +FROM builds +WHERE build_repo_id = ? +` diff --git a/pkg/store/builtin/build_sql.go b/pkg/store/builtin/build_sql.go index 317a73ac1..169d1ec25 100644 --- a/pkg/store/builtin/build_sql.go +++ b/pkg/store/builtin/build_sql.go @@ -13,41 +13,83 @@ import ( var _ = json.Marshal // generic database interface, matching both *sql.Db and *sql.Tx -type jobDB interface { +type buildDB interface { Exec(query string, args ...interface{}) (sql.Result, error) Query(query string, args ...interface{}) (*sql.Rows, error) QueryRow(query string, args ...interface{}) *sql.Row } -func getJob(db jobDB, query string, args ...interface{}) (*Job, error) { +func getBuild(db buildDB, query string, args ...interface{}) (*Build, error) { row := db.QueryRow(query, args...) - return scanJob(row) + return scanBuild(row) } -func getJobs(db jobDB, query string, args ...interface{}) ([]*Job, error) { +func getBuilds(db buildDB, query string, args ...interface{}) ([]*Build, error) { rows, err := db.Query(query, args...) if err != nil { return nil, err } defer rows.Close() - return scanJobs(rows) + return scanBuilds(rows) } -func createJob(db jobDB, query string, v *Job) error { +func createBuild(db buildDB, query string, v *Build) error { var v0 int64 var v1 int var v2 string - var v3 int + var v3 int64 var v4 int64 - var v5 int64 - var v6 []byte - v0 = v.BuildID + var v5 string + var v6 string + var v7 string + var v8 string + var v9 string + var v10 string + var v11 string + var v12 string + var v13 int + var v14 string + var v15 string + var v16 string + var v17 string + var v18 string + var v19 string + var v20 string + var v21 string + var v22 string + v0 = v.RepoID v1 = v.Number v2 = v.Status - v3 = v.ExitCode - v4 = v.Started - v5 = v.Finished - v6, _ = json.Marshal(v.Environment) + v3 = v.Started + v4 = v.Finished + if v.Commit != nil { + v5 = v.Commit.Sha + v6 = v.Commit.Ref + v7 = v.Commit.Branch + v8 = v.Commit.Message + v9 = v.Commit.Timestamp + v10 = v.Commit.Remote + if v.Commit.Author != nil { + v11 = v.Commit.Author.Login + v12 = v.Commit.Author.Email + } + } + if v.PullRequest != nil { + v13 = v.PullRequest.Number + v14 = v.PullRequest.Title + if v.PullRequest.Base != nil { + v15 = v.PullRequest.Base.Sha + v16 = v.PullRequest.Base.Ref + v17 = v.PullRequest.Base.Branch + v18 = v.PullRequest.Base.Message + v19 = v.PullRequest.Base.Timestamp + v20 = v.PullRequest.Base.Remote + if v.PullRequest.Base.Author != nil { + v21 = v.PullRequest.Base.Author.Login + v22 = v.PullRequest.Base.Author.Email + } + } + } res, err := db.Exec(query, &v0, @@ -57,6 +99,22 @@ func createJob(db jobDB, query string, v *Job) error { &v4, &v5, &v6, + &v7, + &v8, + &v9, + &v10, + &v11, + &v12, + &v13, + &v14, + &v15, + &v16, + &v17, + &v18, + &v19, + &v20, + &v21, + &v22, ) if err != nil { return err @@ -66,23 +124,65 @@ func createJob(db jobDB, query string, v *Job) error { return err } -func updateJob(db jobDB, query string, v *Job) error { +func updateBuild(db buildDB, query string, v *Build) error { var v0 int64 var v1 int64 var v2 int var v3 string - var v4 int + var v4 int64 var v5 int64 - var v6 int64 - var v7 []byte + var v6 string + var v7 string + var v8 string + var v9 string + var v10 string + var v11 string + var v12 string + var v13 string + var v14 int + var v15 string + var v16 string + var v17 string + var v18 string + var v19 string + var v20 string + var v21 string + var v22 string + var v23 string v0 = v.ID - v1 = v.BuildID + v1 = v.RepoID v2 = v.Number v3 = v.Status - v4 = v.ExitCode - v5 = v.Started - v6 = v.Finished - v7, _ = json.Marshal(v.Environment) + v4 = v.Started + v5 = v.Finished + if v.Commit != nil { + v6 = v.Commit.Sha + v7 = v.Commit.Ref + v8 = v.Commit.Branch + v9 = v.Commit.Message + v10 = v.Commit.Timestamp + v11 = v.Commit.Remote + if v.Commit.Author != nil { + v12 = v.Commit.Author.Login + v13 = v.Commit.Author.Email + } + } + if v.PullRequest != nil { + v14 = v.PullRequest.Number + v15 = v.PullRequest.Title + if v.PullRequest.Base != nil { + v16 = v.PullRequest.Base.Sha + v17 = v.PullRequest.Base.Ref + v18 = v.PullRequest.Base.Branch + v19 = v.PullRequest.Base.Message + v20 = v.PullRequest.Base.Timestamp + v21 = v.PullRequest.Base.Remote + if v.PullRequest.Base.Author != nil { + v22 = v.PullRequest.Base.Author.Login + v23 = v.PullRequest.Base.Author.Email + } + } + } _, err := db.Exec(query, &v1, @@ -92,20 +192,52 @@ func updateJob(db jobDB, query string, v *Job) error { &v5, &v6, &v7, + &v8, + &v9, + &v10, + &v11, + &v12, + &v13, + &v14, + &v15, + &v16, + &v17, + &v18, + &v19, + &v20, + &v21, + &v22, + &v23, &v0, ) return err } -func scanJob(row *sql.Row) (*Job, error) { +func scanBuild(row *sql.Row) (*Build, error) { var v0 int64 var v1 int64 var v2 int var v3 string - var v4 int + var v4 int64 var v5 int64 - var v6 int64 - var v7 []byte + var v6 string + var v7 string + var v8 string + var v9 string + var v10 string + var v11 string + var v12 string + var v13 string + var v14 int + var v15 string + var v16 string + var v17 string + var v18 string + var v19 string + var v20 string + var v21 string + var v22 string + var v23 string err := row.Scan( &v0, @@ -116,36 +248,89 @@ func scanJob(row *sql.Row) (*Job, error) { &v5, &v6, &v7, + &v8, + &v9, + &v10, + &v11, + &v12, + &v13, + &v14, + &v15, + &v16, + &v17, + &v18, + &v19, + &v20, + &v21, + &v22, + &v23, ) if err != nil { return nil, err } - v := &Job{} + v := &Build{} v.ID = v0 - v.BuildID = v1 + v.RepoID = v1 v.Number = v2 v.Status = v3 - v.ExitCode = v4 - v.Started = v5 - v.Finished = v6 - json.Unmarshal(v7, &v.Environment) + v.Started = v4 + v.Finished = v5 + v.Commit = &Commit{} + v.Commit.Sha = v6 + v.Commit.Ref = v7 + v.Commit.Branch = v8 + v.Commit.Message = v9 + v.Commit.Timestamp = v10 + v.Commit.Remote = v11 + v.Commit.Author = &Author{} + v.Commit.Author.Login = v12 + v.Commit.Author.Email = v13 + v.PullRequest = &PullRequest{} + v.PullRequest.Number = v14 + v.PullRequest.Title = v15 + v.PullRequest.Base = &Commit{} + v.PullRequest.Base.Sha = v16 + v.PullRequest.Base.Ref = v17 + v.PullRequest.Base.Branch = v18 + v.PullRequest.Base.Message = v19 + v.PullRequest.Base.Timestamp = v20 + v.PullRequest.Base.Remote = v21 + v.PullRequest.Base.Author = &Author{} + v.PullRequest.Base.Author.Login = v22 + v.PullRequest.Base.Author.Email = v23 return v, nil } -func scanJobs(rows *sql.Rows) ([]*Job, error) { +func scanBuilds(rows *sql.Rows) ([]*Build, error) { var err error - var vv []*Job + var vv []*Build for rows.Next() { var v0 int64 var v1 int64 var v2 int var v3 string - var v4 int + var v4 int64 var v5 int64 - var v6 int64 - var v7 []byte + var v6 string + var v7 string + var v8 string + var v9 string + var v10 string + var v11 string + var v12 string + var v13 string + var v14 int + var v15 string + var v16 string + var v17 string + var v18 string + var v19 string + var v20 string + var v21 string + var v22 string + var v23 string err = rows.Scan( &v0, &v1, @@ -155,146 +340,346 @@ func scanJobs(rows *sql.Rows) ([]*Job, error) { &v5, &v6, &v7, + &v8, + &v9, + &v10, + &v11, + &v12, + &v13, + &v14, + &v15, + &v16, + &v17, + &v18, + &v19, + &v20, + &v21, + &v22, + &v23, ) if err != nil { return vv, err } - v := &Job{} + v := &Build{} v.ID = v0 - v.BuildID = v1 + v.RepoID = v1 v.Number = v2 v.Status = v3 - v.ExitCode = v4 - v.Started = v5 - v.Finished = v6 - json.Unmarshal(v7, &v.Environment) + v.Started = v4 + v.Finished = v5 + v.Commit = &Commit{} + v.Commit.Sha = v6 + v.Commit.Ref = v7 + v.Commit.Branch = v8 + v.Commit.Message = v9 + v.Commit.Timestamp = v10 + v.Commit.Remote = v11 + v.Commit.Author = &Author{} + v.Commit.Author.Login = v12 + v.Commit.Author.Email = v13 + v.PullRequest = &PullRequest{} + v.PullRequest.Number = v14 + v.PullRequest.Title = v15 + v.PullRequest.Base = &Commit{} + v.PullRequest.Base.Sha = v16 + v.PullRequest.Base.Ref = v17 + v.PullRequest.Base.Branch = v18 + v.PullRequest.Base.Message = v19 + v.PullRequest.Base.Timestamp = v20 + v.PullRequest.Base.Remote = v21 + v.PullRequest.Base.Author = &Author{} + v.PullRequest.Base.Author.Login = v22 + v.PullRequest.Base.Author.Email = v23 vv = append(vv, v) } return vv, rows.Err() } -const stmtJobSelectList = ` +const stmtBuildSelectList = ` SELECT - job_id -,job_build_id -,job_number -,job_status -,job_exit_code -,job_started -,job_finished -,job_environment -FROM jobs + build_id +,build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +FROM builds ` -const stmtJobSelectRange = ` +const stmtBuildSelectRange = ` SELECT - job_id -,job_build_id -,job_number -,job_status -,job_exit_code -,job_started -,job_finished -,job_environment -FROM jobs + build_id +,build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +FROM builds LIMIT ? OFFSET ? ` -const stmtJobSelect = ` +const stmtBuildSelect = ` SELECT - job_id -,job_build_id -,job_number -,job_status -,job_exit_code -,job_started -,job_finished -,job_environment -FROM jobs -WHERE job_id = ? + build_id +,build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +FROM builds +WHERE build_id = ? ` -const stmtJobSelectJobBuildId = ` +const stmtBuildSelectBuildRepoId = ` SELECT - job_id -,job_build_id -,job_number -,job_status -,job_exit_code -,job_started -,job_finished -,job_environment -FROM jobs -WHERE job_build_id = ? + build_id +,build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +FROM builds +WHERE build_repo_id = ? ` -const stmtJobSelectBuildNumber = ` +const stmtBuildSelectBuildNumber = ` SELECT - job_id -,job_build_id -,job_number -,job_status -,job_exit_code -,job_started -,job_finished -,job_environment -FROM jobs -WHERE job_build_id = ? -AND job_number = ? + build_id +,build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +FROM builds +WHERE build_repo_id = ? +AND build_number = ? ` -const stmtJobSelectCount = ` +const stmtBuildSelectCommitBranch = ` +SELECT + build_id +,build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +FROM builds +WHERE build_branch = ? +AND build_branch = ? +` + +const stmtBuildSelectCount = ` SELECT count(1) -FROM jobs +FROM builds ` -const stmtJobInsert = ` -INSERT INTO jobs ( - job_build_id -,job_number -,job_status -,job_exit_code -,job_started -,job_finished -,job_environment -) VALUES (?,?,?,?,?,?,?); +const stmtBuildInsert = ` +INSERT INTO builds ( + build_repo_id +,build_number +,build_status +,build_started +,build_finished +,build_commit_sha +,build_commit_ref +,build_commit_branch +,build_commit_message +,build_commit_timestamp +,build_commit_remote +,build_commit_author_login +,build_commit_author_email +,build_pull_request_number +,build_pull_request_title +,build_pull_request_base_sha +,build_pull_request_base_ref +,build_pull_request_base_branch +,build_pull_request_base_message +,build_pull_request_base_timestamp +,build_pull_request_base_remote +,build_pull_request_base_author_login +,build_pull_request_base_author_email +) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); ` -const stmtJobUpdate = ` -UPDATE jobs SET - job_build_id = ? -,job_number = ? -,job_status = ? -,job_exit_code = ? -,job_started = ? -,job_finished = ? -,job_environment = ? -WHERE job_id = ? +const stmtBuildUpdate = ` +UPDATE builds SET + build_repo_id = ? +,build_number = ? +,build_status = ? +,build_started = ? +,build_finished = ? +,build_commit_sha = ? +,build_commit_ref = ? +,build_commit_branch = ? +,build_commit_message = ? +,build_commit_timestamp = ? +,build_commit_remote = ? +,build_commit_author_login = ? +,build_commit_author_email = ? +,build_pull_request_number = ? +,build_pull_request_title = ? +,build_pull_request_base_sha = ? +,build_pull_request_base_ref = ? +,build_pull_request_base_branch = ? +,build_pull_request_base_message = ? +,build_pull_request_base_timestamp = ? +,build_pull_request_base_remote = ? +,build_pull_request_base_author_login = ? +,build_pull_request_base_author_email = ? +WHERE build_id = ? ` -const stmtJobDelete = ` -DELETE FROM jobs -WHERE job_id = ? +const stmtBuildDelete = ` +DELETE FROM builds +WHERE build_id = ? ` -const stmtJobTable = ` -CREATE TABLE IF NOT EXISTS jobs ( - job_id INTEGER PRIMARY KEY AUTOINCREMENT -,job_build_id INTEGER -,job_number INTEGER -,job_status VARCHAR -,job_exit_code INTEGER -,job_started INTEGER -,job_finished INTEGER -,job_environmentVARCHAR(2048) +const stmtBuildTable = ` +CREATE TABLE IF NOT EXISTS builds ( + build_id INTEGER PRIMARY KEY AUTOINCREMENT +,build_repo_id INTEGER +,build_number INTEGER +,build_status VARCHAR(512) +,build_started INTEGER +,build_finished INTEGER +,build_commit_sha VARCHAR(512) +,build_commit_ref VARCHAR(512) +,build_commit_branch VARCHAR(512) +,build_commit_message VARCHAR(512) +,build_commit_timestamp VARCHAR(512) +,build_commit_remote VARCHAR(512) +,build_commit_author_login VARCHAR(512) +,build_commit_author_email VARCHAR(512) +,build_pull_request_number INTEGER +,build_pull_request_title VARCHAR(512) +,build_pull_request_base_sha VARCHAR(512) +,build_pull_request_base_ref VARCHAR(512) +,build_pull_request_base_branch VARCHAR(512) +,build_pull_request_base_message VARCHAR(512) +,build_pull_request_base_timestamp VARCHAR(512) +,build_pull_request_base_remote VARCHAR(512) +,build_pull_request_base_author_login VARCHAR(512) +,build_pull_request_base_author_email VARCHAR(512) ); ` -const stmtJobJobBuildIdIndex = ` -CREATE INDEX IF NOT EXISTS ix_job_build_id ON jobs (job_build_id); +const stmtBuildBuildRepoIdIndex = ` +CREATE INDEX IF NOT EXISTS ix_build_repo_id ON builds (build_repo_id); ` -const stmtJobBuildNumberIndex = ` -CREATE UNIQUE INDEX IF NOT EXISTS ux_build_number ON jobs (job_build_id,job_number); +const stmtBuildBuildNumberIndex = ` +CREATE UNIQUE INDEX IF NOT EXISTS ux_build_number ON builds (build_repo_id,build_number); +` + +const stmtBuildCommitBranchIndex = ` +CREATE INDEX IF NOT EXISTS ix_commit_branch ON builds (build_branch,build_branch); ` diff --git a/pkg/store/builtin/build_test.go b/pkg/store/builtin/build_test.go index e3b458428..80aa02f0c 100644 --- a/pkg/store/builtin/build_test.go +++ b/pkg/store/builtin/build_test.go @@ -7,119 +7,166 @@ import ( "github.com/drone/drone/pkg/types" ) -func TestBuildstore(t *testing.T) { +func TestCommitstore(t *testing.T) { db := mustConnectTest() - bs := NewJobstore(db) - cs := NewCommitstore(db) + bs := NewBuildstore(db) defer db.Close() g := goblin.Goblin(t) - g.Describe("Jobstore", func() { + g.Describe("Buildstore", func() { - // before each test we purge the package table data from the database. + // before each test be sure to purge the package + // table data from the database. g.BeforeEach(func() { + db.Exec("DELETE FROM builds") db.Exec("DELETE FROM jobs") - db.Exec("DELETE FROM commits") }) - g.It("Should Set a job", func() { - job := &types.Job{ - BuildID: 1, - Status: "pending", - ExitCode: 0, - Number: 1, - } - err1 := bs.AddJob(job) - g.Assert(err1 == nil).IsTrue() - g.Assert(job.ID != 0).IsTrue() - - job.Status = "started" - err2 := bs.SetJob(job) - g.Assert(err2 == nil).IsTrue() - - getjob, err3 := bs.Job(job.ID) - g.Assert(err3 == nil).IsTrue() - g.Assert(getjob.Status).Equal(job.Status) - }) - - g.It("Should Get a Job by ID", func() { - job := &types.Job{ - BuildID: 1, - Status: "pending", - ExitCode: 1, - Number: 1, - Environment: map[string]string{"foo": "bar"}, - } - err1 := bs.AddJob(job) - g.Assert(err1 == nil).IsTrue() - g.Assert(job.ID != 0).IsTrue() - - getjob, err2 := bs.Job(job.ID) - g.Assert(err2 == nil).IsTrue() - g.Assert(getjob.ID).Equal(job.ID) - g.Assert(getjob.Status).Equal(job.Status) - g.Assert(getjob.ExitCode).Equal(job.ExitCode) - g.Assert(getjob.Environment).Equal(job.Environment) - g.Assert(getjob.Environment["foo"]).Equal("bar") - }) - - g.It("Should Get a Job by Number", func() { - job := &types.Job{ - BuildID: 1, - Status: "pending", - ExitCode: 1, - Number: 1, - } - err1 := bs.AddJob(job) - g.Assert(err1 == nil).IsTrue() - g.Assert(job.ID != 0).IsTrue() - - getjob, err2 := bs.JobNumber(&types.Commit{ID: 1}, 1) - g.Assert(err2 == nil).IsTrue() - g.Assert(getjob.ID).Equal(job.ID) - g.Assert(getjob.Status).Equal(job.Status) - }) - - g.It("Should Get a List of Jobs by Commit", func() { - - //In order for buid to be populated, - //The AddCommit command will insert builds - //if the Commit.Builds array is populated - //Add Commit. - commit := types.Commit{ + g.It("Should Post a Build", func() { + build := types.Build{ RepoID: 1, - State: types.StateSuccess, - Ref: "refs/heads/master", - Sha: "14710626f22791619d3b7e9ccf58b10374e5b76d", - Builds: []*types.Job{ - &types.Job{ - BuildID: 1, - Status: "success", - ExitCode: 0, - Number: 1, - }, - &types.Job{ - BuildID: 3, - Status: "error", - ExitCode: 1, - Number: 2, - }, - &types.Job{ - BuildID: 5, - Status: "pending", - ExitCode: 0, - Number: 3, - }, + Status: types.StateSuccess, + Commit: &types.Commit{ + Ref: "refs/heads/master", + Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", }, } - // - err1 := cs.AddCommit(&commit) - g.Assert(err1 == nil).IsTrue() - getjobs, err2 := bs.JobList(&commit) - g.Assert(err2 == nil).IsTrue() - g.Assert(len(getjobs)).Equal(3) - g.Assert(getjobs[0].Number).Equal(1) - g.Assert(getjobs[0].Status).Equal(types.StateSuccess) + err := bs.AddBuild(&build) + g.Assert(err == nil).IsTrue() + g.Assert(build.ID != 0).IsTrue() + g.Assert(build.Number).Equal(1) + g.Assert(build.Commit.Ref).Equal("refs/heads/master") + g.Assert(build.Commit.Sha).Equal("85f8c029b902ed9400bc600bac301a0aadb144ac") }) + + g.It("Should Put a Build", func() { + build := types.Build{ + RepoID: 1, + Number: 5, + Status: types.StatePending, + Commit: &types.Commit{ + Ref: "refs/heads/master", + Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", + }, + } + bs.AddBuild(&build) + build.Status = types.StateRunning + err1 := bs.SetBuild(&build) + getbuild, err2 := bs.Build(build.ID) + g.Assert(err1 == nil).IsTrue() + g.Assert(err2 == nil).IsTrue() + g.Assert(build.ID).Equal(getbuild.ID) + g.Assert(build.RepoID).Equal(getbuild.RepoID) + g.Assert(build.Status).Equal(getbuild.Status) + g.Assert(build.Number).Equal(getbuild.Number) + }) + + g.It("Should Get a Build", func() { + build := types.Build{ + RepoID: 1, + Status: types.StateSuccess, + } + bs.AddBuild(&build) + getbuild, err := bs.Build(build.ID) + g.Assert(err == nil).IsTrue() + g.Assert(build.ID).Equal(getbuild.ID) + g.Assert(build.RepoID).Equal(getbuild.RepoID) + g.Assert(build.Status).Equal(getbuild.Status) + }) + + g.It("Should Get a Build by Number", func() { + build1 := &types.Build{ + RepoID: 1, + Status: types.StatePending, + } + build2 := &types.Build{ + RepoID: 1, + Status: types.StatePending, + } + err1 := bs.AddBuild(build1) + err2 := bs.AddBuild(build2) + getbuild, err3 := bs.BuildNumber(&types.Repo{ID: 1}, build2.Number) + g.Assert(err1 == nil).IsTrue() + g.Assert(err2 == nil).IsTrue() + g.Assert(err3 == nil).IsTrue() + g.Assert(build2.ID).Equal(getbuild.ID) + g.Assert(build2.RepoID).Equal(getbuild.RepoID) + g.Assert(build2.Number).Equal(getbuild.Number) + }) + + g.It("Should Kill Pending or Started Builds", func() { + build1 := &types.Build{ + RepoID: 1, + Status: types.StateRunning, + } + build2 := &types.Build{ + RepoID: 1, + Status: types.StatePending, + } + bs.AddBuild(build1) + bs.AddBuild(build2) + err1 := bs.KillBuilds() + getbuild1, err2 := bs.Build(build1.ID) + getbuild2, err3 := bs.Build(build2.ID) + g.Assert(err1 == nil).IsTrue() + g.Assert(err2 == nil).IsTrue() + g.Assert(err3 == nil).IsTrue() + g.Assert(getbuild1.Status).Equal(types.StateKilled) + g.Assert(getbuild2.Status).Equal(types.StateKilled) + }) + + g.It("Should get recent Builds", func() { + build1 := &types.Build{ + RepoID: 1, + Status: types.StateFailure, + } + build2 := &types.Build{ + RepoID: 1, + Status: types.StateSuccess, + } + bs.AddBuild(build1) + bs.AddBuild(build2) + builds, err := bs.BuildList(&types.Repo{ID: 1}, 20, 0) + g.Assert(err == nil).IsTrue() + g.Assert(len(builds)).Equal(2) + g.Assert(builds[0].ID).Equal(build2.ID) + g.Assert(builds[0].RepoID).Equal(build2.RepoID) + g.Assert(builds[0].Status).Equal(build2.Status) + }) + // + // g.It("Should get the last Commit", func() { + // commit1 := &types.Commit{ + // RepoID: 1, + // State: types.StateFailure, + // Branch: "master", + // Ref: "refs/heads/master", + // Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", + // } + // commit2 := &types.Commit{ + // RepoID: 1, + // State: types.StateFailure, + // Branch: "master", + // Ref: "refs/heads/master", + // Sha: "8d6a233744a5dcacbf2605d4592a4bfe8b37320d", + // } + // commit3 := &types.Commit{ + // RepoID: 1, + // State: types.StateSuccess, + // Branch: "dev", + // Ref: "refs/heads/dev", + // Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", + // } + // err1 := bs.AddCommit(commit1) + // err2 := bs.AddCommit(commit2) + // err3 := bs.AddCommit(commit3) + // last, err4 := bs.CommitLast(&types.Repo{ID: 1}, "master") + // g.Assert(err1 == nil).IsTrue() + // g.Assert(err2 == nil).IsTrue() + // g.Assert(err3 == nil).IsTrue() + // g.Assert(err4 == nil).IsTrue() + // g.Assert(last.ID).Equal(commit2.ID) + // g.Assert(last.RepoID).Equal(commit2.RepoID) + // g.Assert(last.Sequence).Equal(commit2.Sequence) + // }) }) } diff --git a/pkg/store/builtin/commit.go b/pkg/store/builtin/commit.go deleted file mode 100644 index 9079866f9..000000000 --- a/pkg/store/builtin/commit.go +++ /dev/null @@ -1,148 +0,0 @@ -package builtin - -import ( - "database/sql" - "time" - - "github.com/drone/drone/pkg/types" -) - -type Commitstore struct { - *sql.DB -} - -func NewCommitstore(db *sql.DB) *Commitstore { - return &Commitstore{db} -} - -// Commit gets a commit by ID -func (db *Commitstore) Commit(id int64) (*types.Commit, error) { - return getCommit(db, rebind(stmtCommitSelect), id) -} - -// CommitSeq gets the specified commit sequence for the -// named repository and commit number -func (db *Commitstore) CommitSeq(repo *types.Repo, seq int) (*types.Commit, error) { - return getCommit(db, rebind(stmtCommitSelectCommitSeq), repo.ID, seq) -} - -// CommitLast gets the last executed commit for the -// named repository. -func (db *Commitstore) CommitLast(repo *types.Repo, branch string) (*types.Commit, error) { - return getCommit(db, rebind(commitLastQuery), repo.ID, branch) -} - -// CommitList gets a list of recent commits for the -// named repository. -func (db *Commitstore) CommitList(repo *types.Repo, limit, offset int) ([]*types.Commit, error) { - return getCommits(db, rebind(commitListQuery), repo.ID, limit, offset) -} - -// AddCommit inserts a new commit in the datastore. -func (db *Commitstore) AddCommit(commit *types.Commit) error { - tx, err := db.Begin() - if err != nil { - return err - } - defer tx.Rollback() - - // extract the next commit number from the database - row := tx.QueryRow(rebind(commitNumberLast), commit.RepoID) - if row != nil { - row.Scan(&commit.Sequence) - } - - commit.Sequence = commit.Sequence + 1 // increment - commit.Created = time.Now().UTC().Unix() - commit.Updated = time.Now().UTC().Unix() - err = createCommit(tx, rebind(stmtCommitInsert), commit) - if err != nil { - return err - } - - for _, job := range commit.Builds { - job.BuildID = commit.ID - err := createJob(tx, rebind(stmtJobInsert), job) - if err != nil { - return err - } - } - return tx.Commit() -} - -// SetCommit updates an existing commit and commit tasks. -func (db *Commitstore) SetCommit(commit *types.Commit) error { - tx, err := db.Begin() - if err != nil { - return err - } - defer tx.Rollback() - - commit.Updated = time.Now().UTC().Unix() - err = updateCommit(tx, rebind(stmtCommitUpdate), commit) - if err != nil { - return err - } - - for _, job := range commit.Builds { - err = updateJob(tx, rebind(stmtJobUpdate), job) - if err != nil { - return err - } - } - return tx.Commit() -} - -// KillCommits updates all pending or started commits -// in the datastore settings the status to killed. -func (db *Commitstore) KillCommits() error { - var _, err1 = db.Exec(rebind(buildKillStmt)) - if err1 != nil { - return err1 - } - var _, err2 = db.Exec(rebind(commitKillStmt)) - return err2 -} - -// Commit table name in database. -const commitTable = "commits" - -// SQL query to retrieve the latest commits across all branches. -const commitListQuery = ` -SELECT * -FROM commits -WHERE commit_repo_id = ? -ORDER BY commit_sequence DESC -LIMIT ? OFFSET ? -` - -// SQL query to retrieve the most recent commit. -// TODO exclude pull requests -const commitLastQuery = ` -SELECT * -FROM commits -WHERE commit_repo_id = ? - AND commit_branch = ? -ORDER BY commit_sequence DESC -LIMIT 1 -` - -// SQL statement to cancel all running commits. -const commitKillStmt = ` -UPDATE commits SET commit_state = 'killed' -WHERE commit_state IN ('pending', 'running'); -` - -// SQL statement to cancel all running commits. -const buildKillStmt = ` -UPDATE jobs SET job_status = 'killed' -WHERE job_status IN ('pending', 'running'); -` - -// SQL statement to retrieve the commit number for -// a commit -const commitNumberLast = ` -SELECT MAX(commit_sequence) -FROM commits -WHERE commit_repo_id = ? -` diff --git a/pkg/store/builtin/commit_sql.go b/pkg/store/builtin/commit_sql.go deleted file mode 100644 index 9357d4169..000000000 --- a/pkg/store/builtin/commit_sql.go +++ /dev/null @@ -1,520 +0,0 @@ -package builtin - -// DO NOT EDIT -// code generated by go:generate - -import ( - "database/sql" - "encoding/json" - - . "github.com/drone/drone/pkg/types" -) - -var _ = json.Marshal - -// generic database interface, matching both *sql.Db and *sql.Tx -type commitDB interface { - Exec(query string, args ...interface{}) (sql.Result, error) - Query(query string, args ...interface{}) (*sql.Rows, error) - QueryRow(query string, args ...interface{}) *sql.Row -} - -func getCommit(db commitDB, query string, args ...interface{}) (*Commit, error) { - row := db.QueryRow(query, args...) - return scanCommit(row) -} - -func getCommits(db commitDB, query string, args ...interface{}) ([]*Commit, error) { - rows, err := db.Query(query, args...) - if err != nil { - return nil, err - } - defer rows.Close() - return scanCommits(rows) -} - -func createCommit(db commitDB, query string, v *Commit) error { - var v0 int64 - var v1 int - var v2 string - var v3 int64 - var v4 int64 - var v5 string - var v6 string - var v7 string - var v8 string - var v9 string - var v10 string - var v11 string - var v12 string - var v13 string - var v14 string - var v15 string - var v16 int64 - var v17 int64 - v0 = v.RepoID - v1 = v.Sequence - v2 = v.State - v3 = v.Started - v4 = v.Finished - v5 = v.Sha - v6 = v.Ref - v7 = v.PullRequest - v8 = v.Branch - v9 = v.Author - v10 = v.Gravatar - v11 = v.Timestamp - v12 = v.Message - v13 = v.SourceRemote - v14 = v.SourceBranch - v15 = v.SourceSha - v16 = v.Created - v17 = v.Updated - - res, err := db.Exec(query, - &v0, - &v1, - &v2, - &v3, - &v4, - &v5, - &v6, - &v7, - &v8, - &v9, - &v10, - &v11, - &v12, - &v13, - &v14, - &v15, - &v16, - &v17, - ) - if err != nil { - return err - } - - v.ID, err = res.LastInsertId() - return err -} - -func updateCommit(db commitDB, query string, v *Commit) error { - var v0 int64 - var v1 int64 - var v2 int - var v3 string - var v4 int64 - var v5 int64 - var v6 string - var v7 string - var v8 string - var v9 string - var v10 string - var v11 string - var v12 string - var v13 string - var v14 string - var v15 string - var v16 string - var v17 int64 - var v18 int64 - v0 = v.ID - v1 = v.RepoID - v2 = v.Sequence - v3 = v.State - v4 = v.Started - v5 = v.Finished - v6 = v.Sha - v7 = v.Ref - v8 = v.PullRequest - v9 = v.Branch - v10 = v.Author - v11 = v.Gravatar - v12 = v.Timestamp - v13 = v.Message - v14 = v.SourceRemote - v15 = v.SourceBranch - v16 = v.SourceSha - v17 = v.Created - v18 = v.Updated - - _, err := db.Exec(query, - &v1, - &v2, - &v3, - &v4, - &v5, - &v6, - &v7, - &v8, - &v9, - &v10, - &v11, - &v12, - &v13, - &v14, - &v15, - &v16, - &v17, - &v18, - &v0, - ) - return err -} - -func scanCommit(row *sql.Row) (*Commit, error) { - var v0 int64 - var v1 int64 - var v2 int - var v3 string - var v4 int64 - var v5 int64 - var v6 string - var v7 string - var v8 string - var v9 string - var v10 string - var v11 string - var v12 string - var v13 string - var v14 string - var v15 string - var v16 string - var v17 int64 - var v18 int64 - - err := row.Scan( - &v0, - &v1, - &v2, - &v3, - &v4, - &v5, - &v6, - &v7, - &v8, - &v9, - &v10, - &v11, - &v12, - &v13, - &v14, - &v15, - &v16, - &v17, - &v18, - ) - if err != nil { - return nil, err - } - - v := &Commit{} - v.ID = v0 - v.RepoID = v1 - v.Sequence = v2 - v.State = v3 - v.Started = v4 - v.Finished = v5 - v.Sha = v6 - v.Ref = v7 - v.PullRequest = v8 - v.Branch = v9 - v.Author = v10 - v.Gravatar = v11 - v.Timestamp = v12 - v.Message = v13 - v.SourceRemote = v14 - v.SourceBranch = v15 - v.SourceSha = v16 - v.Created = v17 - v.Updated = v18 - - return v, nil -} - -func scanCommits(rows *sql.Rows) ([]*Commit, error) { - var err error - var vv []*Commit - for rows.Next() { - var v0 int64 - var v1 int64 - var v2 int - var v3 string - var v4 int64 - var v5 int64 - var v6 string - var v7 string - var v8 string - var v9 string - var v10 string - var v11 string - var v12 string - var v13 string - var v14 string - var v15 string - var v16 string - var v17 int64 - var v18 int64 - err = rows.Scan( - &v0, - &v1, - &v2, - &v3, - &v4, - &v5, - &v6, - &v7, - &v8, - &v9, - &v10, - &v11, - &v12, - &v13, - &v14, - &v15, - &v16, - &v17, - &v18, - ) - if err != nil { - return vv, err - } - - v := &Commit{} - v.ID = v0 - v.RepoID = v1 - v.Sequence = v2 - v.State = v3 - v.Started = v4 - v.Finished = v5 - v.Sha = v6 - v.Ref = v7 - v.PullRequest = v8 - v.Branch = v9 - v.Author = v10 - v.Gravatar = v11 - v.Timestamp = v12 - v.Message = v13 - v.SourceRemote = v14 - v.SourceBranch = v15 - v.SourceSha = v16 - v.Created = v17 - v.Updated = v18 - vv = append(vv, v) - } - return vv, rows.Err() -} - -const stmtCommitSelectList = ` -SELECT - commit_id -,commit_repo_id -,commit_sequence -,commit_state -,commit_started -,commit_finished -,commit_sha -,commit_ref -,commit_pull_request -,commit_branch -,commit_author -,commit_gravatar -,commit_timestamp -,commit_message -,commit_source_remote -,commit_source_branch -,commit_source_sha -,commit_created -,commit_updated -FROM commits -` - -const stmtCommitSelectRange = ` -SELECT - commit_id -,commit_repo_id -,commit_sequence -,commit_state -,commit_started -,commit_finished -,commit_sha -,commit_ref -,commit_pull_request -,commit_branch -,commit_author -,commit_gravatar -,commit_timestamp -,commit_message -,commit_source_remote -,commit_source_branch -,commit_source_sha -,commit_created -,commit_updated -FROM commits -LIMIT ? OFFSET ? -` - -const stmtCommitSelect = ` -SELECT - commit_id -,commit_repo_id -,commit_sequence -,commit_state -,commit_started -,commit_finished -,commit_sha -,commit_ref -,commit_pull_request -,commit_branch -,commit_author -,commit_gravatar -,commit_timestamp -,commit_message -,commit_source_remote -,commit_source_branch -,commit_source_sha -,commit_created -,commit_updated -FROM commits -WHERE commit_id = ? -` - -const stmtCommitSelectCommitSeq = ` -SELECT - commit_id -,commit_repo_id -,commit_sequence -,commit_state -,commit_started -,commit_finished -,commit_sha -,commit_ref -,commit_pull_request -,commit_branch -,commit_author -,commit_gravatar -,commit_timestamp -,commit_message -,commit_source_remote -,commit_source_branch -,commit_source_sha -,commit_created -,commit_updated -FROM commits -WHERE commit_repo_id = ? -AND commit_sequence = ? -` - -const stmtCommitSelectCommitRepoId = ` -SELECT - commit_id -,commit_repo_id -,commit_sequence -,commit_state -,commit_started -,commit_finished -,commit_sha -,commit_ref -,commit_pull_request -,commit_branch -,commit_author -,commit_gravatar -,commit_timestamp -,commit_message -,commit_source_remote -,commit_source_branch -,commit_source_sha -,commit_created -,commit_updated -FROM commits -WHERE commit_repo_id = ? -` - -const stmtCommitSelectCount = ` -SELECT count(1) -FROM commits -` - -const stmtCommitInsert = ` -INSERT INTO commits ( - commit_repo_id -,commit_sequence -,commit_state -,commit_started -,commit_finished -,commit_sha -,commit_ref -,commit_pull_request -,commit_branch -,commit_author -,commit_gravatar -,commit_timestamp -,commit_message -,commit_source_remote -,commit_source_branch -,commit_source_sha -,commit_created -,commit_updated -) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); -` - -const stmtCommitUpdate = ` -UPDATE commits SET - commit_repo_id = ? -,commit_sequence = ? -,commit_state = ? -,commit_started = ? -,commit_finished = ? -,commit_sha = ? -,commit_ref = ? -,commit_pull_request = ? -,commit_branch = ? -,commit_author = ? -,commit_gravatar = ? -,commit_timestamp = ? -,commit_message = ? -,commit_source_remote = ? -,commit_source_branch = ? -,commit_source_sha = ? -,commit_created = ? -,commit_updated = ? -WHERE commit_id = ? -` - -const stmtCommitDelete = ` -DELETE FROM commits -WHERE commit_id = ? -` - -const stmtCommitTable = ` -CREATE TABLE IF NOT EXISTS commits ( - commit_id INTEGER PRIMARY KEY AUTOINCREMENT -,commit_repo_id INTEGER -,commit_sequence INTEGER -,commit_state VARCHAR -,commit_started INTEGER -,commit_finished INTEGER -,commit_sha VARCHAR -,commit_ref VARCHAR -,commit_pull_request VARCHAR -,commit_branch VARCHAR -,commit_author VARCHAR -,commit_gravatar VARCHAR -,commit_timestamp VARCHAR -,commit_message VARCHAR -,commit_source_remote VARCHAR -,commit_source_branch VARCHAR -,commit_source_sha VARCHAR -,commit_created INTEGER -,commit_updated INTEGER -); -` - -const stmtCommitCommitSeqIndex = ` -CREATE UNIQUE INDEX IF NOT EXISTS ux_commit_seq ON commits (commit_repo_id,commit_sequence); -` - -const stmtCommitCommitRepoIdIndex = ` -CREATE INDEX IF NOT EXISTS ix_commit_repo_id ON commits (commit_repo_id); -` diff --git a/pkg/store/builtin/commit_test.go b/pkg/store/builtin/commit_test.go deleted file mode 100644 index b5b3b3619..000000000 --- a/pkg/store/builtin/commit_test.go +++ /dev/null @@ -1,178 +0,0 @@ -package builtin - -import ( - "testing" - - "github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" - "github.com/drone/drone/pkg/types" -) - -func TestCommitstore(t *testing.T) { - db := mustConnectTest() - bs := NewCommitstore(db) - defer db.Close() - - g := goblin.Goblin(t) - g.Describe("Commitstore", func() { - - // before each test be sure to purge the package - // table data from the database. - g.BeforeEach(func() { - db.Exec("DELETE FROM commits") - db.Exec("DELETE FROM tasks") - }) - - g.It("Should Post a Commit", func() { - commit := types.Commit{ - RepoID: 1, - State: types.StateSuccess, - Ref: "refs/heads/master", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - err := bs.AddCommit(&commit) - g.Assert(err == nil).IsTrue() - g.Assert(commit.ID != 0).IsTrue() - g.Assert(commit.Sequence).Equal(1) - }) - - g.It("Should Put a Commit", func() { - commit := types.Commit{ - RepoID: 1, - Sequence: 5, - State: types.StatePending, - Ref: "refs/heads/master", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - bs.AddCommit(&commit) - commit.State = types.StateRunning - err1 := bs.SetCommit(&commit) - getcommit, err2 := bs.Commit(commit.ID) - g.Assert(err1 == nil).IsTrue() - g.Assert(err2 == nil).IsTrue() - g.Assert(commit.ID).Equal(getcommit.ID) - g.Assert(commit.RepoID).Equal(getcommit.RepoID) - g.Assert(commit.State).Equal(getcommit.State) - g.Assert(commit.Sequence).Equal(getcommit.Sequence) - }) - - g.It("Should Get a Commit", func() { - commit := types.Commit{ - RepoID: 1, - State: types.StateSuccess, - } - bs.AddCommit(&commit) - getcommit, err := bs.Commit(commit.ID) - g.Assert(err == nil).IsTrue() - g.Assert(commit.ID).Equal(getcommit.ID) - g.Assert(commit.RepoID).Equal(getcommit.RepoID) - g.Assert(commit.State).Equal(getcommit.State) - }) - - g.It("Should Get a Commit by Sequence", func() { - commit1 := &types.Commit{ - RepoID: 1, - State: types.StatePending, - Ref: "refs/heads/master", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - commit2 := &types.Commit{ - RepoID: 1, - State: types.StatePending, - Ref: "refs/heads/dev", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - err1 := bs.AddCommit(commit1) - err2 := bs.AddCommit(commit2) - getcommit, err3 := bs.CommitSeq(&types.Repo{ID: 1}, commit2.Sequence) - g.Assert(err1 == nil).IsTrue() - g.Assert(err2 == nil).IsTrue() - g.Assert(err3 == nil).IsTrue() - g.Assert(commit2.ID).Equal(getcommit.ID) - g.Assert(commit2.RepoID).Equal(getcommit.RepoID) - g.Assert(commit2.Sequence).Equal(getcommit.Sequence) - }) - - g.It("Should Kill Pending or Started Commits", func() { - commit1 := &types.Commit{ - RepoID: 1, - State: types.StateRunning, - Ref: "refs/heads/master", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - commit2 := &types.Commit{ - RepoID: 1, - State: types.StatePending, - Ref: "refs/heads/dev", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - bs.AddCommit(commit1) - bs.AddCommit(commit2) - err1 := bs.KillCommits() - getcommit1, err2 := bs.Commit(commit1.ID) - getcommit2, err3 := bs.Commit(commit2.ID) - g.Assert(err1 == nil).IsTrue() - g.Assert(err2 == nil).IsTrue() - g.Assert(err3 == nil).IsTrue() - g.Assert(getcommit1.State).Equal(types.StateKilled) - g.Assert(getcommit2.State).Equal(types.StateKilled) - }) - - g.It("Should get recent Commits", func() { - commit1 := &types.Commit{ - RepoID: 1, - State: types.StateFailure, - Ref: "refs/heads/master", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - commit2 := &types.Commit{ - RepoID: 1, - State: types.StateSuccess, - Ref: "refs/heads/dev", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - bs.AddCommit(commit1) - bs.AddCommit(commit2) - commits, err := bs.CommitList(&types.Repo{ID: 1}, 20, 0) - g.Assert(err == nil).IsTrue() - g.Assert(len(commits)).Equal(2) - g.Assert(commits[0].ID).Equal(commit2.ID) - g.Assert(commits[0].RepoID).Equal(commit2.RepoID) - g.Assert(commits[0].State).Equal(commit2.State) - }) - - g.It("Should get the last Commit", func() { - commit1 := &types.Commit{ - RepoID: 1, - State: types.StateFailure, - Branch: "master", - Ref: "refs/heads/master", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - commit2 := &types.Commit{ - RepoID: 1, - State: types.StateFailure, - Branch: "master", - Ref: "refs/heads/master", - Sha: "8d6a233744a5dcacbf2605d4592a4bfe8b37320d", - } - commit3 := &types.Commit{ - RepoID: 1, - State: types.StateSuccess, - Branch: "dev", - Ref: "refs/heads/dev", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - err1 := bs.AddCommit(commit1) - err2 := bs.AddCommit(commit2) - err3 := bs.AddCommit(commit3) - last, err4 := bs.CommitLast(&types.Repo{ID: 1}, "master") - g.Assert(err1 == nil).IsTrue() - g.Assert(err2 == nil).IsTrue() - g.Assert(err3 == nil).IsTrue() - g.Assert(err4 == nil).IsTrue() - g.Assert(last.ID).Equal(commit2.ID) - g.Assert(last.RepoID).Equal(commit2.RepoID) - g.Assert(last.Sequence).Equal(commit2.Sequence) - }) - }) -} diff --git a/pkg/store/builtin/job.go b/pkg/store/builtin/job.go new file mode 100644 index 000000000..1db0655c4 --- /dev/null +++ b/pkg/store/builtin/job.go @@ -0,0 +1,40 @@ +package builtin + +import ( + "database/sql" + + "github.com/drone/drone/pkg/types" +) + +type Jobstore struct { + *sql.DB +} + +func NewJobstore(db *sql.DB) *Jobstore { + return &Jobstore{db} +} + +// Job returns a Job by ID. +func (db *Jobstore) Job(id int64) (*types.Job, error) { + return getJob(db, rebind(stmtJobSelect), id) +} + +// JobNumber returns a job by sequence number. +func (db *Jobstore) JobNumber(build *types.Build, seq int) (*types.Job, error) { + return getJob(db, rebind(stmtJobSelectBuildNumber), build.ID, seq) +} + +// JobList returns a list of all build jobs +func (db *Jobstore) JobList(build *types.Build) ([]*types.Job, error) { + return getJobs(db, rebind(stmtJobSelectJobBuildId), build.ID) +} + +// SetJob updates an existing build job. +func (db *Jobstore) SetJob(job *types.Job) error { + return updateJob(db, rebind(stmtJobUpdate), job) +} + +// AddJob inserts a build job. +func (db *Jobstore) AddJob(job *types.Job) error { + return createJob(db, rebind(stmtJobInsert), job) +} diff --git a/pkg/store/builtin/job_sql.go b/pkg/store/builtin/job_sql.go new file mode 100644 index 000000000..1fb8e6e28 --- /dev/null +++ b/pkg/store/builtin/job_sql.go @@ -0,0 +1,300 @@ +package builtin + +// DO NOT EDIT +// code generated by go:generate + +import ( + "database/sql" + "encoding/json" + + . "github.com/drone/drone/pkg/types" +) + +var _ = json.Marshal + +// generic database interface, matching both *sql.Db and *sql.Tx +type jobDB interface { + Exec(query string, args ...interface{}) (sql.Result, error) + Query(query string, args ...interface{}) (*sql.Rows, error) + QueryRow(query string, args ...interface{}) *sql.Row +} + +func getJob(db jobDB, query string, args ...interface{}) (*Job, error) { + row := db.QueryRow(query, args...) + return scanJob(row) +} + +func getJobs(db jobDB, query string, args ...interface{}) ([]*Job, error) { + rows, err := db.Query(query, args...) + if err != nil { + return nil, err + } + defer rows.Close() + return scanJobs(rows) +} + +func createJob(db jobDB, query string, v *Job) error { + var v0 int64 + var v1 int + var v2 string + var v3 int + var v4 int64 + var v5 int64 + var v6 []byte + v0 = v.BuildID + v1 = v.Number + v2 = v.Status + v3 = v.ExitCode + v4 = v.Started + v5 = v.Finished + v6, _ = json.Marshal(v.Environment) + + res, err := db.Exec(query, + &v0, + &v1, + &v2, + &v3, + &v4, + &v5, + &v6, + ) + if err != nil { + return err + } + + v.ID, err = res.LastInsertId() + return err +} + +func updateJob(db jobDB, query string, v *Job) error { + var v0 int64 + var v1 int64 + var v2 int + var v3 string + var v4 int + var v5 int64 + var v6 int64 + var v7 []byte + v0 = v.ID + v1 = v.BuildID + v2 = v.Number + v3 = v.Status + v4 = v.ExitCode + v5 = v.Started + v6 = v.Finished + v7, _ = json.Marshal(v.Environment) + + _, err := db.Exec(query, + &v1, + &v2, + &v3, + &v4, + &v5, + &v6, + &v7, + &v0, + ) + return err +} + +func scanJob(row *sql.Row) (*Job, error) { + var v0 int64 + var v1 int64 + var v2 int + var v3 string + var v4 int + var v5 int64 + var v6 int64 + var v7 []byte + + err := row.Scan( + &v0, + &v1, + &v2, + &v3, + &v4, + &v5, + &v6, + &v7, + ) + if err != nil { + return nil, err + } + + v := &Job{} + v.ID = v0 + v.BuildID = v1 + v.Number = v2 + v.Status = v3 + v.ExitCode = v4 + v.Started = v5 + v.Finished = v6 + json.Unmarshal(v7, &v.Environment) + + return v, nil +} + +func scanJobs(rows *sql.Rows) ([]*Job, error) { + var err error + var vv []*Job + for rows.Next() { + var v0 int64 + var v1 int64 + var v2 int + var v3 string + var v4 int + var v5 int64 + var v6 int64 + var v7 []byte + err = rows.Scan( + &v0, + &v1, + &v2, + &v3, + &v4, + &v5, + &v6, + &v7, + ) + if err != nil { + return vv, err + } + + v := &Job{} + v.ID = v0 + v.BuildID = v1 + v.Number = v2 + v.Status = v3 + v.ExitCode = v4 + v.Started = v5 + v.Finished = v6 + json.Unmarshal(v7, &v.Environment) + vv = append(vv, v) + } + return vv, rows.Err() +} + +const stmtJobSelectList = ` +SELECT + job_id +,job_build_id +,job_number +,job_status +,job_exit_code +,job_started +,job_finished +,job_environment +FROM jobs +` + +const stmtJobSelectRange = ` +SELECT + job_id +,job_build_id +,job_number +,job_status +,job_exit_code +,job_started +,job_finished +,job_environment +FROM jobs +LIMIT ? OFFSET ? +` + +const stmtJobSelect = ` +SELECT + job_id +,job_build_id +,job_number +,job_status +,job_exit_code +,job_started +,job_finished +,job_environment +FROM jobs +WHERE job_id = ? +` + +const stmtJobSelectJobBuildId = ` +SELECT + job_id +,job_build_id +,job_number +,job_status +,job_exit_code +,job_started +,job_finished +,job_environment +FROM jobs +WHERE job_build_id = ? +` + +const stmtJobSelectBuildNumber = ` +SELECT + job_id +,job_build_id +,job_number +,job_status +,job_exit_code +,job_started +,job_finished +,job_environment +FROM jobs +WHERE job_build_id = ? +AND job_number = ? +` + +const stmtJobSelectCount = ` +SELECT count(1) +FROM jobs +` + +const stmtJobInsert = ` +INSERT INTO jobs ( + job_build_id +,job_number +,job_status +,job_exit_code +,job_started +,job_finished +,job_environment +) VALUES (?,?,?,?,?,?,?); +` + +const stmtJobUpdate = ` +UPDATE jobs SET + job_build_id = ? +,job_number = ? +,job_status = ? +,job_exit_code = ? +,job_started = ? +,job_finished = ? +,job_environment = ? +WHERE job_id = ? +` + +const stmtJobDelete = ` +DELETE FROM jobs +WHERE job_id = ? +` + +const stmtJobTable = ` +CREATE TABLE IF NOT EXISTS jobs ( + job_id INTEGER PRIMARY KEY AUTOINCREMENT +,job_build_id INTEGER +,job_number INTEGER +,job_status VARCHAR(512) +,job_exit_code INTEGER +,job_started INTEGER +,job_finished INTEGER +,job_environmentVARCHAR(2048) +); +` + +const stmtJobJobBuildIdIndex = ` +CREATE INDEX IF NOT EXISTS ix_job_build_id ON jobs (job_build_id); +` + +const stmtJobBuildNumberIndex = ` +CREATE UNIQUE INDEX IF NOT EXISTS ux_build_number ON jobs (job_build_id,job_number); +` diff --git a/pkg/store/builtin/job_test.go b/pkg/store/builtin/job_test.go new file mode 100644 index 000000000..6d06fb8db --- /dev/null +++ b/pkg/store/builtin/job_test.go @@ -0,0 +1,119 @@ +package builtin + +import ( + "testing" + + "github.com/drone/drone/Godeps/_workspace/src/github.com/franela/goblin" + "github.com/drone/drone/pkg/types" +) + +func TestBuildstore(t *testing.T) { + db := mustConnectTest() + bs := NewJobstore(db) + cs := NewBuildstore(db) + defer db.Close() + + g := goblin.Goblin(t) + g.Describe("Jobstore", func() { + + // before each test we purge the package table data from the database. + g.BeforeEach(func() { + db.Exec("DELETE FROM jobs") + db.Exec("DELETE FROM builds") + }) + + g.It("Should Set a job", func() { + job := &types.Job{ + BuildID: 1, + Status: "pending", + ExitCode: 0, + Number: 1, + } + err1 := bs.AddJob(job) + g.Assert(err1 == nil).IsTrue() + g.Assert(job.ID != 0).IsTrue() + + job.Status = "started" + err2 := bs.SetJob(job) + g.Assert(err2 == nil).IsTrue() + + getjob, err3 := bs.Job(job.ID) + g.Assert(err3 == nil).IsTrue() + g.Assert(getjob.Status).Equal(job.Status) + }) + + g.It("Should Get a Job by ID", func() { + job := &types.Job{ + BuildID: 1, + Status: "pending", + ExitCode: 1, + Number: 1, + Environment: map[string]string{"foo": "bar"}, + } + err1 := bs.AddJob(job) + g.Assert(err1 == nil).IsTrue() + g.Assert(job.ID != 0).IsTrue() + + getjob, err2 := bs.Job(job.ID) + g.Assert(err2 == nil).IsTrue() + g.Assert(getjob.ID).Equal(job.ID) + g.Assert(getjob.Status).Equal(job.Status) + g.Assert(getjob.ExitCode).Equal(job.ExitCode) + g.Assert(getjob.Environment).Equal(job.Environment) + g.Assert(getjob.Environment["foo"]).Equal("bar") + }) + + g.It("Should Get a Job by Number", func() { + job := &types.Job{ + BuildID: 1, + Status: "pending", + ExitCode: 1, + Number: 1, + } + err1 := bs.AddJob(job) + g.Assert(err1 == nil).IsTrue() + g.Assert(job.ID != 0).IsTrue() + + getjob, err2 := bs.JobNumber(&types.Build{ID: 1}, 1) + g.Assert(err2 == nil).IsTrue() + g.Assert(getjob.ID).Equal(job.ID) + g.Assert(getjob.Status).Equal(job.Status) + }) + + g.It("Should Get a List of Jobs by Commit", func() { + + build := types.Build{ + RepoID: 1, + Status: types.StateSuccess, + Jobs: []*types.Job{ + &types.Job{ + BuildID: 1, + Status: "success", + ExitCode: 0, + Number: 1, + }, + &types.Job{ + BuildID: 3, + Status: "error", + ExitCode: 1, + Number: 2, + }, + &types.Job{ + BuildID: 5, + Status: "pending", + ExitCode: 0, + Number: 3, + }, + }, + } + // + err1 := cs.AddBuild(&build) + g.Assert(err1 == nil).IsTrue() + getjobs, err2 := bs.JobList(&build) + g.Assert(err2 == nil).IsTrue() + g.Assert(len(getjobs)).Equal(3) + g.Assert(getjobs[0].Number).Equal(1) + g.Assert(getjobs[0].Status).Equal(types.StateSuccess) + }) + }) +} diff --git a/pkg/store/builtin/migrate/migrate.go b/pkg/store/builtin/migrate/migrate.go index c31a457e2..6ea29b5a6 100644 --- a/pkg/store/builtin/migrate/migrate.go +++ b/pkg/store/builtin/migrate/migrate.go @@ -12,11 +12,12 @@ func Setup(tx migration.LimitedTx) error { starTable, repoTable, repoUserIndex, - commitTable, - commitRepoIndex, - tokenTable, buildTable, - buildCommitIndex, + buildRepoIndex, + buildBranchIndex, + tokenTable, + jobTable, + jobBuildIndex, statusTable, statusCommitIndex, blobTable, @@ -84,33 +85,42 @@ CREATE TABLE IF NOT EXISTS stars ( ); ` -var commitTable = ` -CREATE TABLE IF NOT EXISTS commits ( - commit_id INTEGER PRIMARY KEY AUTOINCREMENT - ,commit_repo_id INTEGER - ,commit_sequence INTEGER - ,commit_state VARCHAR(255) - ,commit_started INTEGER - ,commit_finished INTEGER - ,commit_sha VARCHAR(255) - ,commit_ref VARCHAR(255) - ,commit_branch VARCHAR(255) - ,commit_pull_request VARCHAR(255) - ,commit_author VARCHAR(255) - ,commit_gravatar VARCHAR(255) - ,commit_timestamp VARCHAR(255) - ,commit_message VARCHAR(1000) - ,commit_source_remote VARCHAR(255) - ,commit_source_branch VARCHAR(255) - ,commit_source_sha VARCHAR(255) - ,commit_created INTEGER - ,commit_updated INTEGER - ,UNIQUE(commit_repo_id, commit_sequence) +var buildTable = ` +CREATE TABLE IF NOT EXISTS builds ( + build_id INTEGER PRIMARY KEY AUTOINCREMENT + ,build_repo_id INTEGER + ,build_number INTEGER + ,build_status VARCHAR(512) + ,build_started INTEGER + ,build_finished INTEGER + ,build_commit_sha VARCHAR(512) + ,build_commit_ref VARCHAR(512) + ,build_commit_branch VARCHAR(512) + ,build_commit_message VARCHAR(512) + ,build_commit_timestamp VARCHAR(512) + ,build_commit_remote VARCHAR(512) + ,build_commit_author_login VARCHAR(512) + ,build_commit_author_email VARCHAR(512) + ,build_pull_request_number INTEGER + ,build_pull_request_title VARCHAR(512) + ,build_pull_request_base_sha VARCHAR(512) + ,build_pull_request_base_ref VARCHAR(512) + ,build_pull_request_base_branch VARCHAR(512) + ,build_pull_request_base_message VARCHAR(512) + ,build_pull_request_base_timestamp VARCHAR(512) + ,build_pull_request_base_remote VARCHAR(512) + ,build_pull_request_base_author_login VARCHAR(512) + ,build_pull_request_base_author_email VARCHAR(512) + ,UNIQUE(build_repo_id, build_number) ); ` -var commitRepoIndex = ` -CREATE INDEX commits_repo_idx ON commits (commit_repo_id); +var buildRepoIndex = ` +CREATE INDEX build_repo_idx ON builds (build_repo_id); +` + +var buildBranchIndex = ` +CREATE INDEX build_branch_idx ON builds (build_commit_branch); ` var tokenTable = ` @@ -129,7 +139,7 @@ var tokenUserIndex = ` CREATE INDEX tokens_user_idx ON tokens (token_user_id); ` -var buildTable = ` +var jobTable = ` CREATE TABLE IF NOT EXISTS jobs ( job_id INTEGER PRIMARY KEY AUTOINCREMENT ,job_build_id INTEGER @@ -143,7 +153,7 @@ CREATE TABLE IF NOT EXISTS jobs ( ); ` -var buildCommitIndex = ` +var jobBuildIndex = ` CREATE INDEX ix_job_build_id ON jobs (job_build_id); ` @@ -176,8 +186,8 @@ CREATE TABLE IF NOT EXISTS blobs ( var agentTable = ` CREATE TABLE IF NOT EXISTS agents ( agent_id INTEGER PRIMARY KEY AUTOINCREMENT - ,agent_commit_id INTEGER + ,agent_build_id INTEGER ,agent_addr VARCHAR(2000) - ,UNIQUE(agent_commit_id) + ,UNIQUE(agent_build_id) ); ` diff --git a/pkg/store/builtin/store.go b/pkg/store/builtin/store.go index 975576e6c..33800f2db 100644 --- a/pkg/store/builtin/store.go +++ b/pkg/store/builtin/store.go @@ -98,7 +98,7 @@ func New(db *sql.DB) store.Store { return struct { *Userstore *Repostore - *Commitstore + *Buildstore *Jobstore *Blobstore *Starstore @@ -107,7 +107,7 @@ func New(db *sql.DB) store.Store { }{ NewUserstore(db), NewRepostore(db), - NewCommitstore(db), + NewBuildstore(db), NewJobstore(db), NewBlobstore(db), NewStarstore(db), diff --git a/pkg/store/builtin/user.go b/pkg/store/builtin/user.go index 210304792..cc7728df6 100644 --- a/pkg/store/builtin/user.go +++ b/pkg/store/builtin/user.go @@ -72,18 +72,18 @@ SELECT ,r.repo_owner ,r.repo_name ,r.repo_full_name -,c.commit_sequence -,c.commit_state -,c.commit_started -,c.commit_finished +,b.build_number +,b.build_status +,b.build_started +,b.build_finished FROM - commits c + builds b ,repos r ,stars s -WHERE c.commit_repo_id = r.repo_id +WHERE b.build_repo_id = r.repo_id AND r.repo_id = s.star_repo_id AND s.star_user_id = ? -ORDER BY c.commit_sequence DESC +ORDER BY b.build_number DESC LIMIT ? OFFSET ? ` diff --git a/pkg/store/builtin/users_test.go b/pkg/store/builtin/users_test.go index 52ae7975f..c77ebd080 100644 --- a/pkg/store/builtin/users_test.go +++ b/pkg/store/builtin/users_test.go @@ -10,7 +10,7 @@ import ( func TestUserstore(t *testing.T) { db := mustConnectTest() us := NewUserstore(db) - cs := NewCommitstore(db) + cs := NewBuildstore(db) rs := NewRepostore(db) ss := NewStarstore(db) defer db.Close() @@ -25,7 +25,7 @@ func TestUserstore(t *testing.T) { db.Exec("DELETE FROM stars") db.Exec("DELETE FROM repos") db.Exec("DELETE FROM builds") - db.Exec("DELETE FROM tasks") + db.Exec("DELETE FROM jobs") }) g.It("Should Update a User", func() { @@ -181,33 +181,27 @@ func TestUserstore(t *testing.T) { rs.AddRepo(repo1) rs.AddRepo(repo2) ss.AddStar(&types.User{ID: 1}, repo1) - commit1 := &types.Commit{ + build1 := &types.Build{ RepoID: 1, - State: types.StateFailure, - Ref: "refs/heads/master", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", + Status: types.StateFailure, } - commit2 := &types.Commit{ + build2 := &types.Build{ RepoID: 1, - State: types.StateSuccess, - Ref: "refs/heads/dev", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", + Status: types.StateSuccess, } - commit3 := &types.Commit{ + build3 := &types.Build{ RepoID: 2, - State: types.StateSuccess, - Ref: "refs/heads/dev", - Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac", + Status: types.StateSuccess, } - cs.AddCommit(commit1) - cs.AddCommit(commit2) - cs.AddCommit(commit3) - commits, err := us.UserFeed(&types.User{ID: 1}, 20, 0) + cs.AddBuild(build1) + cs.AddBuild(build2) + cs.AddBuild(build3) + builds, err := us.UserFeed(&types.User{ID: 1}, 20, 0) g.Assert(err == nil).IsTrue() - g.Assert(len(commits)).Equal(2) - g.Assert(commits[0].State).Equal(commit2.State) - g.Assert(commits[0].Owner).Equal("bradrydzewski") - g.Assert(commits[0].Name).Equal("drone") + g.Assert(len(builds)).Equal(2) + //g.Assert(builds[0].Status).Equal(commit2.Status) + g.Assert(builds[0].Owner).Equal("bradrydzewski") + g.Assert(builds[0].Name).Equal("drone") }) }) } diff --git a/pkg/store/store.go b/pkg/store/store.go index cc4c6ce21..d71f0ced1 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -127,30 +127,30 @@ type Store interface { // - // Commit gets a commit by ID - Commit(int64) (*types.Commit, error) + // Build gets a build by ID + Build(int64) (*types.Build, error) - // CommitSeq gets the specified commit sequence for the - // named repository and commit number - CommitSeq(*types.Repo, int) (*types.Commit, error) + // BuildNumber gets the specified build number for the + // named repository and build number + BuildNumber(*types.Repo, int) (*types.Build, error) - // CommitLast gets the last executed commit for the + // BuildLast gets the last executed build for the // named repository and branch - CommitLast(*types.Repo, string) (*types.Commit, error) + BuildLast(*types.Repo, string) (*types.Build, error) - // CommitList gets a list of recent commits for the + // BuildList gets a list of recent builds for the // named repository. - CommitList(*types.Repo, int, int) ([]*types.Commit, error) + BuildList(*types.Repo, int, int) ([]*types.Build, error) - // AddCommit inserts a new commit in the datastore. - AddCommit(*types.Commit) error + // AddBuild inserts a new build in the datastore. + AddBuild(*types.Build) error - // SetCommit updates an existing commit and commit tasks. - SetCommit(*types.Commit) error + // SetBuild updates an existing build and build jobs. + SetBuild(*types.Build) error - // KillCommits updates all pending or started commits + // KillBuilds updates all pending or started builds // in the datastore settings the status to killed. - KillCommits() error + KillBuilds() error // @@ -158,10 +158,10 @@ type Store interface { Job(int64) (*types.Job, error) // JobNumber returns a jobs by sequence number. - JobNumber(*types.Commit, int) (*types.Job, error) + JobNumber(*types.Build, int) (*types.Job, error) - // JobList returns a list of all commit jobs - JobList(*types.Commit) ([]*types.Job, error) + // JobList returns a list of all build jobs + JobList(*types.Build) ([]*types.Job, error) // SetJob updates an existing job. SetJob(*types.Job) error @@ -189,8 +189,8 @@ type Store interface { // // Agent returns an agent by ID. - Agent(*types.Commit) (string, error) + Agent(*types.Build) (string, error) // SetAgent updates an agent in the datastore. - SetAgent(*types.Commit, string) error + SetAgent(*types.Build, string) error } diff --git a/pkg/types/build.go b/pkg/types/build.go index 2cc242b32..e831a7013 100644 --- a/pkg/types/build.go +++ b/pkg/types/build.go @@ -1,13 +1,45 @@ package types -type Job struct { - ID int64 `json:"id"` - BuildID int64 `json:"-" sql:"unique:ux_build_number,index:ix_job_build_id"` - Number int `json:"number" sql:"unique:ux_build_number"` +const ( + StatePending = "pending" + StateRunning = "running" + StateSuccess = "success" + StateFailure = "failure" + StateKilled = "killed" + StateError = "error" +) + +type Build struct { + ID int64 + RepoID int64 `json:"-" sql:"unique:ux_build_number,index:ix_build_repo_id"` + Number int `json:"number" sql:"unique:ux_build_number"` Status string `json:"status"` - ExitCode int `json:"exit_code"` Started int64 `json:"started_at"` Finished int64 `json:"finished_at"` - Environment map[string]string `json:"environment" sql:"type:varchar,size:2048"` + Commit *Commit `json:"head_commit"` + PullRequest *PullRequest `json:"pull_request"` + + Jobs []*Job `json:"jobs,omitempty" sql:"-"` +} + +type PullRequest struct { + Number int `json:"number"` + Title string `json:"title"` + Base *Commit `json:"base_commit"` +} + +type Commit struct { + Sha string `json:"sha"` + Ref string `json:"ref"` + Branch string `json:"branch" sql:"index:ix_commit_branch"` + Message string `json:"message"` + Timestamp string `json:"timestamp"` + Remote string `json:"remote"` + Author *Author `json:"author"` +} + +type Author struct { + Login string `json:"login"` + Email string `json:"email"` } diff --git a/pkg/types/commit.go b/pkg/types/commit.go deleted file mode 100644 index 26c6fbc39..000000000 --- a/pkg/types/commit.go +++ /dev/null @@ -1,34 +0,0 @@ -package types - -const ( - StatePending = "pending" - StateRunning = "running" - StateSuccess = "success" - StateFailure = "failure" - StateKilled = "killed" - StateError = "error" -) - -type Commit struct { - ID int64 `meddler:"commit_id,pk" json:"id"` - RepoID int64 `meddler:"commit_repo_id" json:"-" sql:"unique:ux_commit_seq,index:ix_commit_repo_id"` - Sequence int `meddler:"commit_sequence" json:"sequence" sql:"unique:ux_commit_seq"` - State string `meddler:"commit_state" json:"state"` - Started int64 `meddler:"commit_started" json:"started_at"` - Finished int64 `meddler:"commit_finished" json:"finished_at"` - Sha string `meddler:"commit_sha" json:"sha"` - Ref string `meddler:"commit_ref" json:"ref"` - PullRequest string `meddler:"commit_pull_request" json:"pull_request,omitempty"` - Branch string `meddler:"commit_branch" json:"branch"` - Author string `meddler:"commit_author" json:"author"` - Gravatar string `meddler:"commit_gravatar" json:"gravatar"` - Timestamp string `meddler:"commit_timestamp" json:"timestamp"` - Message string `meddler:"commit_message" json:"message"` - SourceRemote string `meddler:"commit_source_remote" json:"source_remote,omitempty"` - SourceBranch string `meddler:"commit_source_branch" json:"source_branch,omitempty"` - SourceSha string `meddler:"commit_source_sha" json:"source_sha,omitempty"` - Created int64 `meddler:"commit_created" json:"created_at"` - Updated int64 `meddler:"commit_updated" json:"updated_at"` - - Builds []*Job `meddler:"-" json:"builds,omitempty" sql:"-"` -} diff --git a/pkg/types/hook.go b/pkg/types/hook.go index 38a522d3d..042cc1a80 100644 --- a/pkg/types/hook.go +++ b/pkg/types/hook.go @@ -1,6 +1,7 @@ package types type Hook struct { - Repo *Repo - Commit *Commit + Repo *Repo + Commit *Commit + PullRequest *PullRequest } diff --git a/pkg/types/job.go b/pkg/types/job.go new file mode 100644 index 000000000..2cc242b32 --- /dev/null +++ b/pkg/types/job.go @@ -0,0 +1,13 @@ +package types + +type Job struct { + ID int64 `json:"id"` + BuildID int64 `json:"-" sql:"unique:ux_build_number,index:ix_job_build_id"` + Number int `json:"number" sql:"unique:ux_build_number"` + Status string `json:"status"` + ExitCode int `json:"exit_code"` + Started int64 `json:"started_at"` + Finished int64 `json:"finished_at"` + + Environment map[string]string `json:"environment" sql:"type:varchar,size:2048"` +}