didn't realize gin supports net.Context. Change to support Context pattern!

This commit is contained in:
Brad Rydzewski 2015-10-21 16:14:02 -07:00
parent af2ef2347a
commit cfdfbcfd3b
56 changed files with 1495 additions and 1051 deletions

View file

@ -4,7 +4,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/store"
)
var (
@ -16,8 +16,7 @@ var (
)
func GetBadge(c *gin.Context) {
db := context.Database(c)
repo, err := model.GetRepoName(db,
repo, err := store.GetRepoOwnerName(c,
c.Param("owner"),
c.Param("name"),
)
@ -38,7 +37,7 @@ func GetBadge(c *gin.Context) {
branch = repo.Branch
}
build, err := model.GetBuildLast(db, repo, branch)
build, err := store.GetBuildLast(c, repo, branch)
if err != nil {
c.String(404, badgeNone)
return
@ -59,8 +58,7 @@ func GetBadge(c *gin.Context) {
}
func GetCC(c *gin.Context) {
db := context.Database(c)
repo, err := model.GetRepoName(db,
repo, err := store.GetRepoOwnerName(c,
c.Param("owner"),
c.Param("name"),
)
@ -69,7 +67,7 @@ func GetCC(c *gin.Context) {
return
}
builds, err := model.GetBuildList(db, repo)
builds, err := store.GetBuildList(c, repo)
if err != nil || len(builds) == 0 {
c.AbortWithStatus(404)
return

View file

@ -12,6 +12,7 @@ import (
"github.com/drone/drone/engine"
"github.com/drone/drone/remote"
"github.com/drone/drone/shared/httputil"
"github.com/drone/drone/store"
"github.com/gin-gonic/gin"
"github.com/drone/drone/model"
@ -21,8 +22,7 @@ import (
func GetBuilds(c *gin.Context) {
repo := session.Repo(c)
db := context.Database(c)
builds, err := model.GetBuildList(db, repo)
builds, err := store.GetBuildList(c, repo)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
@ -32,7 +32,6 @@ func GetBuilds(c *gin.Context) {
func GetBuild(c *gin.Context) {
repo := session.Repo(c)
db := context.Database(c)
num, err := strconv.Atoi(c.Param("number"))
if err != nil {
@ -40,12 +39,12 @@ func GetBuild(c *gin.Context) {
return
}
build, err := model.GetBuildNumber(db, repo, num)
build, err := store.GetBuildNumber(c, repo, num)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
jobs, _ := model.GetJobList(db, build)
jobs, _ := store.GetJobList(c, build)
out := struct {
*model.Build
@ -57,7 +56,6 @@ func GetBuild(c *gin.Context) {
func GetBuildLogs(c *gin.Context) {
repo := session.Repo(c)
db := context.Database(c)
// the user may specify to stream the full logs,
// or partial logs, capped at 2MB.
@ -68,19 +66,19 @@ func GetBuildLogs(c *gin.Context) {
num, _ := strconv.Atoi(c.Params.ByName("number"))
seq, _ := strconv.Atoi(c.Params.ByName("job"))
build, err := model.GetBuildNumber(db, repo, num)
build, err := store.GetBuildNumber(c, repo, num)
if err != nil {
c.AbortWithError(404, err)
return
}
job, err := model.GetJobNumber(db, build, seq)
job, err := store.GetJobNumber(c, build, seq)
if err != nil {
c.AbortWithError(404, err)
return
}
r, err := model.GetLog(db, job)
r, err := store.ReadLog(c, job)
if err != nil {
c.AbortWithError(404, err)
return
@ -97,25 +95,24 @@ func GetBuildLogs(c *gin.Context) {
func DeleteBuild(c *gin.Context) {
engine_ := context.Engine(c)
repo := session.Repo(c)
db := context.Database(c)
// parse the build number and job sequence number from
// the repquest parameter.
num, _ := strconv.Atoi(c.Params.ByName("number"))
seq, _ := strconv.Atoi(c.Params.ByName("job"))
build, err := model.GetBuildNumber(db, repo, num)
build, err := store.GetBuildNumber(c, repo, num)
if err != nil {
c.AbortWithError(404, err)
return
}
job, err := model.GetJobNumber(db, build, seq)
job, err := store.GetJobNumber(c, build, seq)
if err != nil {
c.AbortWithError(404, err)
return
}
node, err := model.GetNode(db, job.NodeID)
node, err := store.GetNode(c, job.NodeID)
if err != nil {
c.AbortWithError(404, err)
return
@ -125,9 +122,8 @@ func DeleteBuild(c *gin.Context) {
func PostBuild(c *gin.Context) {
remote_ := context.Remote(c)
remote_ := remote.FromContext(c)
repo := session.Repo(c)
db := context.Database(c)
num, err := strconv.Atoi(c.Param("number"))
if err != nil {
@ -135,14 +131,14 @@ func PostBuild(c *gin.Context) {
return
}
user, err := model.GetUser(db, repo.UserID)
user, err := store.GetUser(c, repo.UserID)
if err != nil {
log.Errorf("failure to find repo owner %s. %s", repo.FullName, err)
c.AbortWithError(500, err)
return
}
build, err := model.GetBuildNumber(db, repo, num)
build, err := store.GetBuildNumber(c, repo, num)
if err != nil {
log.Errorf("failure to get build %d. %s", num, err)
c.AbortWithError(404, err)
@ -155,7 +151,7 @@ func PostBuild(c *gin.Context) {
if refresher, ok := remote_.(remote.Refresher); ok {
ok, _ := refresher.Refresh(user)
if ok {
model.UpdateUser(db, user)
store.UpdateUser(c, user)
}
}
@ -167,7 +163,7 @@ func PostBuild(c *gin.Context) {
return
}
key, _ := model.GetKey(db, repo)
key, _ := store.GetKey(c, repo)
netrc, err := remote_.Netrc(user, repo)
if err != nil {
log.Errorf("failure to generate netrc for %s. %s", repo.FullName, err)
@ -175,7 +171,7 @@ func PostBuild(c *gin.Context) {
return
}
jobs, err := model.GetJobList(db, build)
jobs, err := store.GetJobList(c, build)
if err != nil {
log.Errorf("failure to get build %d jobs. %s", build.Number, err)
c.AbortWithError(404, err)
@ -188,13 +184,8 @@ func PostBuild(c *gin.Context) {
return
}
tx, err := db.Begin()
if err != nil {
c.AbortWithStatus(500)
return
}
defer tx.Rollback()
// todo move this to database tier
// and wrap inside a transaction
build.Status = model.StatusPending
build.Started = 0
build.Finished = 0
@ -205,25 +196,23 @@ func PostBuild(c *gin.Context) {
job.Finished = 0
job.ExitCode = 0
job.Enqueued = build.Enqueued
model.UpdateJob(db, job)
store.UpdateJob(c, job)
}
err = model.UpdateBuild(db, build)
err = store.UpdateBuild(c, build)
if err != nil {
c.AbortWithStatus(500)
return
}
tx.Commit()
c.JSON(202, build)
// get the previous build so taht we can send
// on status change notifications
last, _ := model.GetBuildLastBefore(db, repo, build.Branch, build.ID)
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
engine_ := context.Engine(c)
go engine_.Schedule(&engine.Task{
go engine_.Schedule(c.Copy(), &engine.Task{
User: user,
Repo: repo,
Build: build,

View file

@ -6,14 +6,12 @@ import (
"github.com/gin-gonic/gin"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
)
func GetCommit(c *gin.Context) {
db := context.Database(c)
repo := session.Repo(c)
parsed, err := token.ParseRequest(c.Request, func(t *token.Token) (string, error) {
@ -34,7 +32,7 @@ func GetCommit(c *gin.Context) {
branch = repo.Branch
}
build, err := model.GetBuildCommit(db, repo, commit, branch)
build, err := store.GetBuildCommit(c, repo, commit, branch)
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
return
@ -44,7 +42,6 @@ func GetCommit(c *gin.Context) {
}
func GetPullRequest(c *gin.Context) {
db := context.Database(c)
repo := session.Repo(c)
refs := fmt.Sprintf("refs/pull/%s/head", c.Param("number"))
@ -60,7 +57,7 @@ func GetPullRequest(c *gin.Context) {
return
}
build, err := model.GetBuildRef(db, repo, refs)
build, err := store.GetBuildRef(c, repo, refs)
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
return
@ -70,7 +67,6 @@ func GetPullRequest(c *gin.Context) {
}
func RedirectSha(c *gin.Context) {
db := context.Database(c)
repo := session.Repo(c)
commit := c.Param("sha")
@ -79,7 +75,7 @@ func RedirectSha(c *gin.Context) {
branch = repo.Branch
}
build, err := model.GetBuildCommit(db, repo, commit, branch)
build, err := store.GetBuildCommit(c, repo, commit, branch)
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
return
@ -90,11 +86,10 @@ func RedirectSha(c *gin.Context) {
}
func RedirectPullRequest(c *gin.Context) {
db := context.Database(c)
repo := session.Repo(c)
refs := fmt.Sprintf("refs/pull/%s/head", c.Param("number"))
build, err := model.GetBuildRef(db, repo, refs)
build, err := store.GetBuildRef(c, repo, refs)
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
return

View file

@ -14,13 +14,13 @@ import (
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/shared/httputil"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
"github.com/drone/drone/yaml"
"github.com/drone/drone/yaml/matrix"
)
func PostHook(c *gin.Context) {
remote_ := context.Remote(c)
db := context.Database(c)
remote_ := remote.FromContext(c)
tmprepo, build, err := remote_.Hook(c.Request)
if err != nil {
@ -46,7 +46,7 @@ func PostHook(c *gin.Context) {
return
}
repo, err := model.GetRepoName(db, tmprepo.Owner, tmprepo.Name)
repo, err := store.GetRepoOwnerName(c, tmprepo.Owner, tmprepo.Name)
if err != nil {
log.Errorf("failure to find repo %s/%s from hook. %s", tmprepo.Owner, tmprepo.Name, err)
c.AbortWithError(404, err)
@ -87,7 +87,7 @@ func PostHook(c *gin.Context) {
return
}
user, err := model.GetUser(db, repo.UserID)
user, err := store.GetUser(c, repo.UserID)
if err != nil {
log.Errorf("failure to find repo owner %s. %s", repo.FullName, err)
c.AbortWithError(500, err)
@ -103,7 +103,7 @@ func PostHook(c *gin.Context) {
// a small number of people will probably be upset by this, I'm not sure
// it is actually that big of a deal.
if len(build.Email) == 0 {
author, err := model.GetUserLogin(db, build.Author)
author, err := store.GetUserLogin(c, build.Author)
if err == nil {
build.Email = author.Email
}
@ -115,7 +115,7 @@ func PostHook(c *gin.Context) {
if refresher, ok := remote_.(remote.Refresher); ok {
ok, _ := refresher.Refresh(user)
if ok {
model.UpdateUser(db, user)
store.UpdateUser(c, user)
}
}
@ -144,7 +144,7 @@ func PostHook(c *gin.Context) {
return
}
key, _ := model.GetKey(db, repo)
key, _ := store.GetKey(c, repo)
// verify the branches can be built vs skipped
yconfig, _ := yaml.Parse(string(raw))
@ -164,18 +164,12 @@ func PostHook(c *gin.Context) {
c.AbortWithStatus(200)
return
}
tx, err := db.Begin()
if err != nil {
log.Errorf("failure to begin database transaction", err)
c.AbortWithError(500, err)
return
}
defer tx.Rollback()
// update some build fields
build.Status = model.StatusPending
build.RepoID = repo.ID
// and use a transaction
var jobs []*model.Job
for num, axis := range axes {
jobs = append(jobs, &model.Job{
@ -185,13 +179,12 @@ func PostHook(c *gin.Context) {
Environment: axis,
})
}
err = model.CreateBuild(tx, build, jobs...)
err = store.CreateBuild(c, build, jobs...)
if err != nil {
log.Errorf("failure to save commit for %s. %s", repo.FullName, err)
c.AbortWithError(500, err)
return
}
tx.Commit()
c.JSON(200, build)
@ -203,10 +196,10 @@ func PostHook(c *gin.Context) {
// get the previous build so taht we can send
// on status change notifications
last, _ := model.GetBuildLastBefore(db, repo, build.Branch, build.ID)
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
engine_ := context.Engine(c)
go engine_.Schedule(&engine.Task{
go engine_.Schedule(c.Copy(), &engine.Task{
User: user,
Repo: repo,
Build: build,

View file

@ -8,15 +8,15 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/remote"
"github.com/drone/drone/shared/crypto"
"github.com/drone/drone/shared/httputil"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
)
func GetLogin(c *gin.Context) {
db := context.Database(c)
remote := context.Remote(c)
remote := remote.FromContext(c)
// when dealing with redirects we may need
// to adjust the content type. I cannot, however,
@ -36,9 +36,9 @@ func GetLogin(c *gin.Context) {
}
// get the user from the database
u, err := model.GetUserLogin(db, tmpuser.Login)
u, err := store.GetUserLogin(c, tmpuser.Login)
if err != nil {
count, err := model.GetUserCount(db)
count, err := store.CountUsers(c)
if err != nil {
log.Errorf("cannot register %s. %s", tmpuser.Login, err)
c.Redirect(303, "/login?error=internal_error")
@ -64,7 +64,7 @@ func GetLogin(c *gin.Context) {
u.Hash = crypto.Rand()
// insert the user into the database
if err := model.CreateUser(db, u); err != nil {
if err := store.CreateUser(c, u); err != nil {
log.Errorf("cannot insert %s. %s", u.Login, err)
c.Redirect(303, "/login?error=internal_error")
return
@ -84,7 +84,7 @@ func GetLogin(c *gin.Context) {
u.Email = tmpuser.Email
u.Avatar = tmpuser.Avatar
if err := model.UpdateUser(db, u); err != nil {
if err := store.UpdateUser(c, u); err != nil {
log.Errorf("cannot update %s. %s", u.Login, err)
c.Redirect(303, "/login?error=internal_error")
return
@ -116,8 +116,7 @@ func GetLogout(c *gin.Context) {
}
func GetLoginToken(c *gin.Context) {
db := context.Database(c)
remote := context.Remote(c)
remote := remote.FromContext(c)
in := &tokenPayload{}
err := c.Bind(in)
@ -132,7 +131,7 @@ func GetLoginToken(c *gin.Context) {
return
}
user, err := model.GetUserLogin(db, login)
user, err := store.GetUserLogin(c, login)
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
return

View file

@ -10,22 +10,21 @@ import (
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
)
func GetNodes(c *gin.Context) {
db := context.Database(c)
nodes, err := model.GetNodeList(db)
nodes, err := store.GetNodeList(c)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
c.String(400, err.Error())
} else {
c.IndentedJSON(http.StatusOK, nodes)
c.JSON(200, nodes)
}
}
func ShowNodes(c *gin.Context) {
db := context.Database(c)
user := session.User(c)
nodes, _ := model.GetNodeList(db)
nodes, _ := store.GetNodeList(c)
token, _ := token.New(token.CsrfToken, user.Login).Sign(user.Hash)
c.HTML(http.StatusOK, "nodes.html", gin.H{"User": user, "Nodes": nodes, "Csrf": token})
}
@ -35,7 +34,6 @@ func GetNode(c *gin.Context) {
}
func PostNode(c *gin.Context) {
db := context.Database(c)
engine := context.Engine(c)
in := struct {
@ -64,7 +62,7 @@ func PostNode(c *gin.Context) {
return
}
err = model.InsertNode(db, node)
err = store.CreateNode(c, node)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
@ -74,16 +72,15 @@ func PostNode(c *gin.Context) {
}
func DeleteNode(c *gin.Context) {
db := context.Database(c)
engine := context.Engine(c)
id, _ := strconv.Atoi(c.Param("node"))
node, err := model.GetNode(db, int64(id))
node, err := store.GetNode(c, int64(id))
if err != nil {
c.AbortWithStatus(http.StatusNotFound)
return
}
err = model.DeleteNode(db, node)
err = store.DeleteNode(c, node)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return

View file

@ -9,15 +9,15 @@ import (
"github.com/gin-gonic/gin"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/remote"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/shared/httputil"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
)
func ShowIndex(c *gin.Context) {
db := context.Database(c)
remote := context.Remote(c)
remote := remote.FromContext(c)
user := session.User(c)
if user == nil {
c.Redirect(http.StatusSeeOther, "/login")
@ -43,7 +43,7 @@ func ShowIndex(c *gin.Context) {
// for each repository in the remote system we get
// the intersection of those repostiories in Drone
repos_, err := model.GetRepoListOf(db, repos)
repos_, err := store.GetRepoListOf(c, repos)
if err != nil {
log.Errorf("Failure to get repository list for %s. %s.",
user.Login, err)
@ -73,13 +73,12 @@ func ShowUser(c *gin.Context) {
}
func ShowUsers(c *gin.Context) {
db := context.Database(c)
user := session.User(c)
if !user.Admin {
c.AbortWithStatus(http.StatusForbidden)
return
}
users, _ := model.GetUserList(db)
users, _ := store.GetUserList(c)
token, _ := token.New(
token.CsrfToken,
@ -94,11 +93,10 @@ func ShowUsers(c *gin.Context) {
}
func ShowRepo(c *gin.Context) {
db := context.Database(c)
user := session.User(c)
repo := session.Repo(c)
builds, _ := model.GetBuildList(db, repo)
builds, _ := store.GetBuildList(c, repo)
groups := []*model.BuildGroup{}
var curr *model.BuildGroup
@ -124,10 +122,10 @@ func ShowRepo(c *gin.Context) {
}
func ShowRepoConf(c *gin.Context) {
db := context.Database(c)
user := session.User(c)
repo := session.Repo(c)
key, _ := model.GetKey(db, repo)
key, _ := store.GetKey(c, repo)
token, _ := token.New(
token.CsrfToken,
@ -171,7 +169,6 @@ func ShowRepoBadges(c *gin.Context) {
}
func ShowBuild(c *gin.Context) {
db := context.Database(c)
user := session.User(c)
repo := session.Repo(c)
num, _ := strconv.Atoi(c.Param("number"))
@ -180,13 +177,13 @@ func ShowBuild(c *gin.Context) {
seq = 1
}
build, err := model.GetBuildNumber(db, repo, num)
build, err := store.GetBuildNumber(c, repo, num)
if err != nil {
c.AbortWithError(404, err)
return
}
jobs, err := model.GetJobList(db, build)
jobs, err := store.GetJobList(c, build)
if err != nil {
c.AbortWithError(404, err)
return

View file

@ -10,16 +10,16 @@ import (
"gopkg.in/yaml.v2"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/remote"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/shared/crypto"
"github.com/drone/drone/shared/httputil"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
)
func PostRepo(c *gin.Context) {
db := context.Database(c)
remote := context.Remote(c)
remote := remote.FromContext(c)
user := session.User(c)
owner := c.Param("owner")
name := c.Param("name")
@ -45,7 +45,7 @@ func PostRepo(c *gin.Context) {
}
// error if the repository already exists
_, err = model.GetRepoName(db, owner, name)
_, err = store.GetRepoOwnerName(c, owner, name)
if err == nil {
c.String(409, "Repository already exists.")
return
@ -91,32 +91,23 @@ func PostRepo(c *gin.Context) {
return
}
tx, err := db.Begin()
if err != nil {
c.AbortWithError(500, err)
return
}
defer tx.Rollback()
// persist the repository
err = model.CreateRepo(tx, r)
err = store.CreateRepo(c, r)
if err != nil {
c.AbortWithError(500, err)
return
}
keys.RepoID = r.ID
err = model.CreateKey(tx, keys)
err = store.CreateKey(c, keys)
if err != nil {
c.AbortWithError(500, err)
return
}
tx.Commit()
c.JSON(200, r)
}
func PatchRepo(c *gin.Context) {
db := context.Database(c)
repo := session.Repo(c)
user := session.User(c)
@ -152,7 +143,7 @@ func PatchRepo(c *gin.Context) {
repo.Timeout = *in.Timeout
}
err := model.UpdateRepo(db, repo)
err := store.UpdateRepo(c, repo)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
@ -166,9 +157,8 @@ func GetRepo(c *gin.Context) {
}
func GetRepoKey(c *gin.Context) {
db := context.Database(c)
repo := session.Repo(c)
keys, err := model.GetKey(db, repo)
keys, err := store.GetKey(c, repo)
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
} else {
@ -177,12 +167,11 @@ func GetRepoKey(c *gin.Context) {
}
func DeleteRepo(c *gin.Context) {
db := context.Database(c)
remote := context.Remote(c)
remote := remote.FromContext(c)
repo := session.Repo(c)
user := session.User(c)
err := model.DeleteRepo(db, repo)
err := store.DeleteRepo(c, repo)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
@ -193,7 +182,6 @@ func DeleteRepo(c *gin.Context) {
}
func PostSecure(c *gin.Context) {
db := context.Database(c)
repo := session.Repo(c)
in, err := ioutil.ReadAll(c.Request.Body)
@ -215,7 +203,7 @@ func PostSecure(c *gin.Context) {
return
}
key, err := model.GetKey(db, repo)
key, err := store.GetKey(c, repo)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return

View file

@ -1,10 +1,5 @@
package controller
/*
stream.Get("/:owner/:name", controller.GetRepoEvents)
stream.Get("/:owner/:name/:build/:number", controller.GetStream)
*/
import (
"io"
"strconv"
@ -13,9 +8,9 @@ import (
"github.com/docker/docker/pkg/stdcopy"
"github.com/drone/drone/engine"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/store"
log "github.com/Sirupsen/logrus"
@ -59,7 +54,7 @@ func GetRepoEvents(c *gin.Context) {
}
func GetStream(c *gin.Context) {
db := context.Database(c)
engine_ := context.Engine(c)
repo := session.Repo(c)
buildn, _ := strconv.Atoi(c.Param("build"))
@ -67,19 +62,19 @@ func GetStream(c *gin.Context) {
c.Writer.Header().Set("Content-Type", "text/event-stream")
build, err := model.GetBuildNumber(db, repo, buildn)
build, err := store.GetBuildNumber(c, repo, buildn)
if err != nil {
log.Debugln("stream cannot get build number.", err)
c.AbortWithError(404, err)
return
}
job, err := model.GetJobNumber(db, build, jobn)
job, err := store.GetJobNumber(c, build, jobn)
if err != nil {
log.Debugln("stream cannot get job number.", err)
c.AbortWithError(404, err)
return
}
node, err := model.GetNode(db, job.NodeID)
node, err := store.GetNode(c, job.NodeID)
if err != nil {
log.Debugln("stream cannot get node.", err)
c.AbortWithError(404, err)

View file

@ -6,9 +6,10 @@ import (
"github.com/gin-gonic/gin"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/remote"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
)
func GetSelf(c *gin.Context) {
@ -17,8 +18,7 @@ func GetSelf(c *gin.Context) {
func GetFeed(c *gin.Context) {
user := session.User(c)
db := context.Database(c)
feed, err := model.GetUserFeed(db, user, 25, 0)
feed, err := store.GetUserFeed(c, user, 25, 0)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
@ -28,8 +28,7 @@ func GetFeed(c *gin.Context) {
func GetRepos(c *gin.Context) {
user := session.User(c)
remote := context.Remote(c)
db := context.Database(c)
remote := remote.FromContext(c)
var repos []*model.RepoLite
// get the repository list from the cache
@ -47,7 +46,7 @@ func GetRepos(c *gin.Context) {
// for each repository in the remote system we get
// the intersection of those repostiories in Drone
repos_, err := model.GetRepoListOf(db, repos)
repos_, err := store.GetRepoListOf(c, repos)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
@ -59,7 +58,7 @@ func GetRepos(c *gin.Context) {
func GetRemoteRepos(c *gin.Context) {
user := session.User(c)
remote := context.Remote(c)
remote := remote.FromContext(c)
reposv, ok := c.Get("repos")
if ok {

View file

@ -6,14 +6,13 @@ import (
"github.com/gin-gonic/gin"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/shared/crypto"
"github.com/drone/drone/store"
)
func GetUsers(c *gin.Context) {
db := context.Database(c)
users, err := model.GetUserList(db)
users, err := store.GetUserList(c)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
@ -23,8 +22,7 @@ func GetUsers(c *gin.Context) {
}
func GetUser(c *gin.Context) {
db := context.Database(c)
user, err := model.GetUserLogin(db, c.Param("login"))
user, err := store.GetUserLogin(c, c.Param("login"))
if err != nil {
c.AbortWithStatus(http.StatusNotFound)
return
@ -35,7 +33,6 @@ func GetUser(c *gin.Context) {
func PatchUser(c *gin.Context) {
me := session.User(c)
db := context.Database(c)
in := &model.User{}
err := c.Bind(in)
if err != nil {
@ -43,7 +40,7 @@ func PatchUser(c *gin.Context) {
return
}
user, err := model.GetUserLogin(db, c.Param("login"))
user, err := store.GetUserLogin(c, c.Param("login"))
if err != nil {
c.AbortWithStatus(http.StatusNotFound)
return
@ -57,7 +54,7 @@ func PatchUser(c *gin.Context) {
return
}
err = model.UpdateUser(db, user)
err = store.UpdateUser(c, user)
if err != nil {
c.AbortWithStatus(http.StatusConflict)
return
@ -67,7 +64,6 @@ func PatchUser(c *gin.Context) {
}
func PostUser(c *gin.Context) {
db := context.Database(c)
in := &model.User{}
err := c.Bind(in)
if err != nil {
@ -83,7 +79,7 @@ func PostUser(c *gin.Context) {
user.Active = true
user.Hash = crypto.Rand()
err = model.CreateUser(db, user)
err = store.CreateUser(c, user)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
@ -94,9 +90,8 @@ func PostUser(c *gin.Context) {
func DeleteUser(c *gin.Context) {
me := session.User(c)
db := context.Database(c)
user, err := model.GetUserLogin(db, c.Param("login"))
user, err := store.GetUserLogin(c, c.Param("login"))
if err != nil {
c.AbortWithStatus(http.StatusNotFound)
return
@ -108,7 +103,7 @@ func DeleteUser(c *gin.Context) {
return
}
err = model.DeleteUser(db, user)
err = store.DeleteUser(c, user)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return

View file

@ -9,9 +9,9 @@ import (
"github.com/drone/drone/router/middleware/cache"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/router/middleware/header"
"github.com/drone/drone/shared/database"
"github.com/drone/drone/shared/envconfig"
"github.com/drone/drone/shared/server"
"github.com/drone/drone/store/datastore"
"github.com/Sirupsen/logrus"
)
@ -37,13 +37,13 @@ func main() {
env := envconfig.Load(*dotenv)
// Setup the database driver
database_ := database.Load(env)
store_ := datastore.Load(env)
// setup the remote driver
remote_ := remote.Load(env)
// setup the runner
engine_ := engine.Load(database_, env, remote_)
engine_ := engine.Load(env, store_)
// setup the server and start the listener
server_ := server.Load(env)
@ -51,7 +51,7 @@ func main() {
router.Load(
header.Version(build),
cache.Default(),
context.SetDatabase(database_),
context.SetStore(store_),
context.SetRemote(remote_),
context.SetEngine(engine_),
),

View file

@ -4,7 +4,6 @@ import (
"bytes"
"crypto/tls"
"crypto/x509"
"database/sql"
"errors"
"fmt"
"io"
@ -15,14 +14,15 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/stdcopy"
"github.com/drone/drone/model"
"github.com/drone/drone/remote"
"github.com/drone/drone/shared/docker"
"github.com/drone/drone/shared/envconfig"
"github.com/drone/drone/store"
"github.com/samalba/dockerclient"
"golang.org/x/net/context"
)
type Engine interface {
Schedule(*Task)
Schedule(context.Context, *Task)
Cancel(int64, int64, *model.Node) error
Stream(int64, int64, *model.Node) (io.ReadCloser, error)
Deallocate(*model.Node)
@ -51,7 +51,6 @@ var (
)
type engine struct {
db *sql.DB
bus *eventbus
updater *updater
pool *pool
@ -61,12 +60,11 @@ type engine struct {
// Load creates a new build engine, loaded with registered nodes from the
// database. The registered nodes are added to the pool of nodes to immediately
// start accepting workloads.
func Load(db *sql.DB, env envconfig.Env, remote remote.Remote) Engine {
func Load(env envconfig.Env, s store.Store) Engine {
engine := &engine{}
engine.bus = newEventbus()
engine.pool = newPool()
engine.db = db
engine.updater = &updater{engine.bus, db, remote}
engine.updater = &updater{engine.bus}
// quick fix to propogate HTTP_PROXY variables
// throughout the build environment.
@ -78,7 +76,7 @@ func Load(db *sql.DB, env envconfig.Env, remote remote.Remote) Engine {
}
}
nodes, err := model.GetNodeList(db)
nodes, err := s.Nodes().GetList()
if err != nil {
log.Fatalf("failed to get nodes from database. %s", err)
}
@ -154,7 +152,7 @@ func (e *engine) Deallocate(n *model.Node) {
}
}
func (e *engine) Schedule(req *Task) {
func (e *engine) Schedule(c context.Context, req *Task) {
node := <-e.pool.reserve()
// since we are probably running in a go-routine
@ -173,15 +171,9 @@ func (e *engine) Schedule(req *Task) {
// update the node that was allocated to each job
func(id int64) {
tx, err := e.db.Begin()
if err != nil {
log.Errorf("error updating job to persist node. %s", err)
return
}
defer tx.Commit()
for _, job := range req.Jobs {
job.NodeID = id
model.UpdateJob(e.db, job)
store.UpdateJob(c, job)
}
}(node.ID)
@ -195,12 +187,12 @@ func (e *engine) Schedule(req *Task) {
// had a non-success status
req.Build.Started = time.Now().UTC().Unix()
req.Build.Status = model.StatusRunning
e.updater.SetBuild(req)
e.updater.SetBuild(c, req)
// run all bulid jobs
for _, job := range req.Jobs {
req.Job = job
e.runJob(req, e.updater, client)
e.runJob(c, req, e.updater, client)
}
// update overall status based on each job
@ -212,7 +204,7 @@ func (e *engine) Schedule(req *Task) {
}
}
req.Build.Finished = time.Now().UTC().Unix()
err = e.updater.SetBuild(req)
err = e.updater.SetBuild(c, req)
if err != nil {
log.Errorf("error updating build completion status. %s", err)
}
@ -261,7 +253,7 @@ func newDockerClient(addr, cert, key, ca string) (dockerclient.Client, error) {
return dockerclient.NewDockerClient(addr, tlc)
}
func (e *engine) runJob(r *Task, updater *updater, client dockerclient.Client) error {
func (e *engine) runJob(c context.Context, r *Task, updater *updater, client dockerclient.Client) error {
name := fmt.Sprintf("drone_build_%d_job_%d", r.Build.ID, r.Job.ID)
@ -277,7 +269,7 @@ func (e *engine) runJob(r *Task, updater *updater, client dockerclient.Client) e
r.Job.Finished = time.Now().UTC().Unix()
r.Job.ExitCode = 255
}
updater.SetJob(r)
updater.SetJob(c, r)
client.KillContainer(name, "9")
client.RemoveContainer(name, true, true)
@ -327,7 +319,7 @@ func (e *engine) runJob(r *Task, updater *updater, client dockerclient.Client) e
// UPDATE STATUS
err = updater.SetJob(r)
err = updater.SetJob(c, r)
if err != nil {
log.Errorf("error updating job status as running. %s", err)
return err
@ -370,13 +362,13 @@ func (e *engine) runJob(r *Task, updater *updater, client dockerclient.Client) e
// update the task in the datastore
r.Job.Finished = time.Now().UTC().Unix()
err = updater.SetJob(r)
err = updater.SetJob(c, r)
if err != nil {
log.Errorf("error updating job after completion. %s", err)
return err
}
err = updater.SetLogs(r, ioutil.NopCloser(&buf))
err = updater.SetLogs(c, r, ioutil.NopCloser(&buf))
if err != nil {
log.Errorf("error updating logs. %s", err)
return err

View file

@ -1,28 +1,27 @@
package engine
import (
"database/sql"
"encoding/json"
"fmt"
"io"
"github.com/drone/drone/model"
"github.com/drone/drone/remote"
"github.com/drone/drone/store"
"golang.org/x/net/context"
)
type updater struct {
bus *eventbus
db *sql.DB
remote remote.Remote
bus *eventbus
}
func (u *updater) SetBuild(r *Task) error {
err := model.UpdateBuild(u.db, r.Build)
func (u *updater) SetBuild(c context.Context, r *Task) error {
err := store.UpdateBuild(c, r.Build)
if err != nil {
return err
}
err = u.remote.Status(r.User, r.Repo, r.Build, fmt.Sprintf("%s/%s/%d", r.System.Link, r.Repo.FullName, r.Build.Number))
err = remote.FromContext(c).Status(r.User, r.Repo, r.Build, fmt.Sprintf("%s/%s/%d", r.System.Link, r.Repo.FullName, r.Build.Number))
if err != nil {
// log err
}
@ -39,8 +38,8 @@ func (u *updater) SetBuild(r *Task) error {
return nil
}
func (u *updater) SetJob(r *Task) error {
err := model.UpdateJob(u.db, r.Job)
func (u *updater) SetJob(c context.Context, r *Task) error {
err := store.UpdateJob(c, r.Job)
if err != nil {
return err
}
@ -57,8 +56,8 @@ func (u *updater) SetJob(r *Task) error {
return nil
}
func (u *updater) SetLogs(r *Task, rc io.ReadCloser) error {
return model.SetLog(u.db, r.Job, rc)
func (u *updater) SetLogs(c context.Context, r *Task, rc io.ReadCloser) error {
return store.WriteLog(c, r.Job, rc)
}
type payload struct {

View file

@ -1,12 +1,5 @@
package model
import (
"time"
"github.com/drone/drone/shared/database"
"github.com/russross/meddler"
)
type Build struct {
ID int64 `json:"id" meddler:"build_id,pk"`
RepoID int64 `json:"-" meddler:"build_repo_id"`
@ -35,131 +28,3 @@ type BuildGroup struct {
Date string
Builds []*Build
}
func GetBuild(db meddler.DB, id int64) (*Build, error) {
var build = new(Build)
var err = meddler.Load(db, buildTable, build, id)
return build, err
}
func GetBuildNumber(db meddler.DB, repo *Repo, number int) (*Build, error) {
var build = new(Build)
var err = meddler.QueryRow(db, build, database.Rebind(buildNumberQuery), repo.ID, number)
return build, err
}
func GetBuildRef(db meddler.DB, repo *Repo, ref string) (*Build, error) {
var build = new(Build)
var err = meddler.QueryRow(db, build, database.Rebind(buildRefQuery), repo.ID, ref)
return build, err
}
func GetBuildCommit(db meddler.DB, repo *Repo, sha, branch string) (*Build, error) {
var build = new(Build)
var err = meddler.QueryRow(db, build, database.Rebind(buildCommitQuery), repo.ID, sha, branch)
return build, err
}
func GetBuildLast(db meddler.DB, repo *Repo, branch string) (*Build, error) {
var build = new(Build)
var err = meddler.QueryRow(db, build, database.Rebind(buildLastQuery), repo.ID, branch)
return build, err
}
func GetBuildLastBefore(db meddler.DB, repo *Repo, branch string, number int64) (*Build, error) {
var build = new(Build)
var err = meddler.QueryRow(db, build, database.Rebind(buildLastBeforeQuery), repo.ID, branch, number)
return build, err
}
func GetBuildList(db meddler.DB, repo *Repo) ([]*Build, error) {
var builds = []*Build{}
var err = meddler.QueryAll(db, &builds, database.Rebind(buildListQuery), repo.ID)
return builds, err
}
func CreateBuild(db meddler.DB, build *Build, jobs ...*Job) error {
var number int
db.QueryRow(database.Rebind(buildNumberLast), build.RepoID).Scan(&number)
build.Number = number + 1
build.Created = time.Now().UTC().Unix()
build.Enqueued = build.Created
err := meddler.Insert(db, buildTable, build)
if err != nil {
return err
}
for i, job := range jobs {
job.BuildID = build.ID
job.Number = i + 1
job.Enqueued = build.Created
err = InsertJob(db, job)
if err != nil {
return err
}
}
return nil
}
func UpdateBuild(db meddler.DB, build *Build) error {
return meddler.Update(db, buildTable, build)
}
const buildTable = "builds"
const buildListQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
ORDER BY build_number DESC
LIMIT 50
`
const buildNumberQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_number = ?
LIMIT 1;
`
const buildLastQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_branch = ?
ORDER BY build_number DESC
LIMIT 1
`
const buildLastBeforeQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_branch = ?
AND build_id < ?
ORDER BY build_number DESC
LIMIT 1
`
const buildCommitQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_commit = ?
AND build_branch = ?
LIMIT 1
`
const buildRefQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_ref = ?
LIMIT 1
`
const buildNumberLast = `
SELECT MAX(build_number)
FROM builds
WHERE build_repo_id = ?
`

View file

@ -1,10 +1,5 @@
package model
import (
"github.com/drone/drone/shared/database"
"github.com/russross/meddler"
)
type Job struct {
ID int64 `json:"id" meddler:"job_id,pk"`
BuildID int64 `json:"-" meddler:"job_build_id"`
@ -18,46 +13,3 @@ type Job struct {
Environment map[string]string `json:"environment" meddler:"job_environment,json"`
}
func GetJob(db meddler.DB, id int64) (*Job, error) {
var job = new(Job)
var err = meddler.Load(db, jobTable, job, id)
return job, err
}
func GetJobNumber(db meddler.DB, build *Build, number int) (*Job, error) {
var job = new(Job)
var err = meddler.QueryRow(db, job, database.Rebind(jobNumberQuery), build.ID, number)
return job, err
}
func GetJobList(db meddler.DB, build *Build) ([]*Job, error) {
var jobs = []*Job{}
var err = meddler.QueryAll(db, &jobs, database.Rebind(jobListQuery), build.ID)
return jobs, err
}
func InsertJob(db meddler.DB, job *Job) error {
return meddler.Insert(db, jobTable, job)
}
func UpdateJob(db meddler.DB, job *Job) error {
return meddler.Update(db, jobTable, job)
}
const jobTable = "jobs"
const jobListQuery = `
SELECT *
FROM jobs
WHERE job_build_id = ?
ORDER BY job_number ASC
`
const jobNumberQuery = `
SELECT *
FROM jobs
WHERE job_build_id = ?
AND job_number = ?
LIMIT 1
`

View file

@ -1,38 +1,8 @@
package model
import (
"github.com/drone/drone/shared/database"
"github.com/russross/meddler"
)
type Key struct {
ID int64 `json:"-" meddler:"key_id,pk"`
RepoID int64 `json:"-" meddler:"key_repo_id"`
Public string `json:"public" meddler:"key_public"`
Private string `json:"private" meddler:"key_private"`
}
func GetKey(db meddler.DB, repo *Repo) (*Key, error) {
var key = new(Key)
var err = meddler.QueryRow(db, key, database.Rebind(keyQuery), repo.ID)
return key, err
}
func CreateKey(db meddler.DB, key *Key) error {
return meddler.Save(db, keyTable, key)
}
func UpdateKey(db meddler.DB, key *Key) error {
return meddler.Save(db, keyTable, key)
}
func DeleteKey(db meddler.DB, repo *Repo) error {
var _, err = db.Exec(database.Rebind(keyDeleteStmt), repo.ID)
return err
}
const keyTable = "keys"
const keyQuery = "SELECT * FROM `keys` WHERE key_repo_id=? LIMIT 1"
const keyDeleteStmt = "DELETE FROM `keys` WHERE key_repo_id=?"

View file

@ -1,42 +1,7 @@
package model
import (
"bytes"
"io"
"io/ioutil"
"github.com/drone/drone/shared/database"
"github.com/russross/meddler"
)
type Log struct {
ID int64 `meddler:"log_id,pk"`
JobID int64 `meddler:"log_job_id"`
Data []byte `meddler:"log_data"`
}
func GetLog(db meddler.DB, job *Job) (io.ReadCloser, error) {
var log = new(Log)
var err = meddler.QueryRow(db, log, database.Rebind(logQuery), job.ID)
var buf = bytes.NewBuffer(log.Data)
return ioutil.NopCloser(buf), err
}
func SetLog(db meddler.DB, job *Job, r io.Reader) error {
var log = new(Log)
var err = meddler.QueryRow(db, log, database.Rebind(logQuery), job.ID)
if err != nil {
log = &Log{JobID: job.ID}
}
log.Data, _ = ioutil.ReadAll(r)
return meddler.Save(db, logTable, log)
}
const logTable = "logs"
const logQuery = `
SELECT *
FROM logs
WHERE log_job_id=?
LIMIT 1
`

View file

@ -1,57 +1,5 @@
package model
import (
"github.com/drone/drone/shared/database"
"github.com/russross/meddler"
)
type Node struct {
ID int64 `meddler:"node_id,pk" json:"id"`
Addr string `meddler:"node_addr" json:"address"`
Arch string `meddler:"node_arch" json:"architecture"`
Cert string `meddler:"node_cert" json:"-"`
Key string `meddler:"node_key" json:"-"`
CA string `meddler:"node_ca" json:"-"`
}
func GetNode(db meddler.DB, id int64) (*Node, error) {
var node = new(Node)
var err = meddler.Load(db, nodeTable, node, id)
return node, err
}
func GetNodeList(db meddler.DB) ([]*Node, error) {
var nodes = []*Node{}
var err = meddler.QueryAll(db, &nodes, database.Rebind(nodeListQuery))
return nodes, err
}
func InsertNode(db meddler.DB, node *Node) error {
return meddler.Insert(db, nodeTable, node)
}
func UpdateNode(db meddler.DB, node *Node) error {
return meddler.Update(db, nodeTable, node)
}
func DeleteNode(db meddler.DB, node *Node) error {
var _, err = db.Exec(database.Rebind(nodeDeleteStmt), node.ID)
return err
}
const nodeTable = "nodes"
const nodeListQuery = `
SELECT *
FROM nodes
ORDER BY node_addr
`
const nodeDeleteStmt = `
DELETE FROM nodes
WHERE node_id=?
`
const (
Freebsd_386 uint = iota
Freebsd_amd64
@ -77,3 +25,12 @@ var Archs = map[string]uint{
"windows_386": Windows_386,
"windows_amd64": Windows_amd64,
}
type Node struct {
ID int64 `meddler:"node_id,pk" json:"id"`
Addr string `meddler:"node_addr" json:"address"`
Arch string `meddler:"node_arch" json:"architecture"`
Cert string `meddler:"node_cert" json:"-"`
Key string `meddler:"node_key" json:"-"`
CA string `meddler:"node_ca" json:"-"`
}

View file

@ -1,11 +1,5 @@
package model
import (
"github.com/drone/drone/shared/database"
"github.com/russross/meddler"
"strings"
)
type RepoLite struct {
Owner string `json:"owner"`
Name string `json:"name"`
@ -33,85 +27,3 @@ type Repo struct {
AllowTag bool `json:"allow_tags" meddler:"repo_allow_tags"`
Hash string `json:"-" meddler:"repo_hash"`
}
func GetRepo(db meddler.DB, id int64) (*Repo, error) {
var repo = new(Repo)
var err = meddler.Load(db, repoTable, repo, id)
return repo, err
}
func GetRepoName(db meddler.DB, owner, name string) (*Repo, error) {
return GetRepoFullName(db, owner+"/"+name)
}
func GetRepoFullName(db meddler.DB, name string) (*Repo, error) {
var repo = new(Repo)
var err = meddler.QueryRow(db, repo, database.Rebind(repoNameQuery), name)
return repo, err
}
func GetRepoList(db meddler.DB, user *User) ([]*Repo, error) {
// we don't have real-time access to the intersection
// of github repos and drone repos. So we cheat by simply
// getting the distinct list of repos that the user
// has created builds for.
var repos = []*Repo{}
var err = meddler.QueryAll(db, &repos, database.Rebind(repoListQuery), user.Login)
return repos, err
}
func GetRepoListOf(db meddler.DB, listof []*RepoLite) ([]*Repo, error) {
var repos = []*Repo{}
var size = len(listof)
if size > 999 {
size = 999
listof = listof[:999]
}
var qs = make([]string, size, size)
var in = make([]interface{}, size, size)
for i, repo := range listof {
qs[i] = "?"
in[i] = repo.FullName
}
var stmt = "SELECT * FROM repos WHERE repo_full_name IN (" + strings.Join(qs, ",") + ") ORDER BY repo_name"
var err = meddler.QueryAll(db, &repos, database.Rebind(stmt), in...)
return repos, err
}
func CreateRepo(db meddler.DB, repo *Repo) error {
return meddler.Insert(db, repoTable, repo)
}
func UpdateRepo(db meddler.DB, repo *Repo) error {
return meddler.Update(db, repoTable, repo)
}
func DeleteRepo(db meddler.DB, repo *Repo) error {
var _, err = db.Exec(database.Rebind(repoDeleteStmt), repo.ID)
return err
}
const repoTable = "repos"
const repoNameQuery = `
SELECT *
FROM repos
WHERE repo_full_name = ?
LIMIT 1;
`
const repoListQuery = `
SELECT *
FROM repos
WHERE repo_id IN (
SELECT DISTINCT build_repo_id
FROM builds
WHERE build_author = ?
)
ORDER BY repo_full_name
`
const repoDeleteStmt = `
DELETE FROM repos
WHERE repo_id = ?
`

View file

@ -1,10 +1,5 @@
package model
import (
"github.com/drone/drone/shared/database"
"github.com/russross/meddler"
)
type User struct {
ID int64 `json:"id" meddler:"user_id,pk"`
Login string `json:"login" meddler:"user_login"`
@ -17,101 +12,3 @@ type User struct {
Admin bool `json:"admin," meddler:"user_admin"`
Hash string `json:"-" meddler:"user_hash"`
}
func GetUser(db meddler.DB, id int64) (*User, error) {
var usr = new(User)
var err = meddler.Load(db, userTable, usr, id)
return usr, err
}
func GetUserLogin(db meddler.DB, login string) (*User, error) {
var usr = new(User)
var err = meddler.QueryRow(db, usr, database.Rebind(userLoginQuery), login)
return usr, err
}
func GetUserList(db meddler.DB) ([]*User, error) {
var users = []*User{}
var err = meddler.QueryAll(db, &users, database.Rebind(userListQuery))
return users, err
}
func GetUserFeed(db meddler.DB, user *User, limit, offset int) ([]*Feed, error) {
var feed = []*Feed{}
var err = meddler.QueryAll(db, &feed, database.Rebind(userFeedQuery), user.Login, limit, offset)
return feed, err
}
func GetUserCount(db meddler.DB) (int, error) {
var count int
var err = db.QueryRow(database.Rebind(userCountQuery)).Scan(&count)
return count, err
}
func CreateUser(db meddler.DB, user *User) error {
return meddler.Insert(db, userTable, user)
}
func UpdateUser(db meddler.DB, user *User) error {
return meddler.Update(db, userTable, user)
}
func DeleteUser(db meddler.DB, user *User) error {
var _, err = db.Exec(database.Rebind(userDeleteStmt), user.ID)
return err
}
const userTable = "users"
const userLoginQuery = `
SELECT *
FROM users
WHERE user_login=?
LIMIT 1
`
const userListQuery = `
SELECT *
FROM users
ORDER BY user_login ASC
`
const userCountQuery = `
SELECT count(1)
FROM users
`
const userDeleteStmt = `
DELETE FROM users
WHERE user_id=?
`
const userFeedQuery = `
SELECT
repo_owner
,repo_name
,repo_full_name
,build_number
,build_event
,build_status
,build_created
,build_started
,build_finished
,build_commit
,build_branch
,build_ref
,build_refspec
,build_remote
,build_title
,build_message
,build_author
,build_email
,build_avatar
FROM
builds b
,repos r
WHERE b.build_repo_id = r.repo_id
AND b.build_author = ?
ORDER BY b.build_id DESC
LIMIT ? OFFSET ?
`

View file

@ -1,24 +1,19 @@
package context
import (
"database/sql"
"github.com/drone/drone/engine"
"github.com/drone/drone/remote"
"github.com/drone/drone/store"
"github.com/gin-gonic/gin"
)
func SetDatabase(db *sql.DB) gin.HandlerFunc {
func SetStore(s store.Store) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("database", db)
store.ToContext(c, s)
c.Next()
}
}
func Database(c *gin.Context) *sql.DB {
return c.MustGet("database").(*sql.DB)
}
func SetRemote(remote remote.Remote) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("remote", remote)

View file

@ -4,8 +4,9 @@ import (
"net/http"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/remote"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
log "github.com/Sirupsen/logrus"
"github.com/gin-gonic/gin"
@ -42,9 +43,8 @@ func SetRepo() gin.HandlerFunc {
name = c.Param("name")
)
db := context.Database(c)
user := User(c)
repo, err := model.GetRepoName(db, owner, name)
repo, err := store.GetRepoOwnerName(c, owner, name)
if err == nil {
c.Set("repo", repo)
c.Next()
@ -55,7 +55,7 @@ func SetRepo() gin.HandlerFunc {
// to see if the repository actually exists. If yes,
// we can prompt the user to add.
if user != nil {
remote := context.Remote(c)
remote := remote.FromContext(c)
repo, err = remote.Repo(user, owner, name)
if err != nil {
log.Errorf("Cannot find remote repository %s/%s for user %s. %s",
@ -107,7 +107,6 @@ func SetPerm() gin.HandlerFunc {
return func(c *gin.Context) {
user := User(c)
repo := Repo(c)
remote := context.Remote(c)
perm := &model.Perm{}
if user != nil {
@ -148,7 +147,7 @@ func SetPerm() gin.HandlerFunc {
// check the remote system to get the users permissiosn.
default:
var err error
perm, err = remote.Perm(user, repo.Owner, repo.Name)
perm, err = remote.FromContext(c).Perm(user, repo.Owner, repo.Name)
if err != nil {
perm.Pull = false
perm.Push = false

View file

@ -4,8 +4,8 @@ import (
"net/http"
"github.com/drone/drone/model"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/shared/token"
"github.com/drone/drone/store"
"github.com/gin-gonic/gin"
)
@ -39,9 +39,8 @@ func SetUser() gin.HandlerFunc {
var user *model.User
t, err := token.ParseRequest(c.Request, func(t *token.Token) (string, error) {
var db = context.Database(c)
var err error
user, err = model.GetUserLogin(db, t.Text)
user, err = store.GetUserLogin(c, t.Text)
return user.Hash, err
})
if err == nil {

View file

@ -3,10 +3,9 @@ package token
import (
"time"
"github.com/drone/drone/model"
"github.com/drone/drone/remote"
"github.com/drone/drone/router/middleware/context"
"github.com/drone/drone/router/middleware/session"
"github.com/drone/drone/store"
log "github.com/Sirupsen/logrus"
"github.com/gin-gonic/gin"
@ -21,7 +20,7 @@ func Refresh(c *gin.Context) {
// check if the remote includes the ability to
// refresh the user token.
remote_ := context.Remote(c)
remote_ := remote.FromContext(c)
refresher, ok := remote_.(remote.Refresher)
if !ok {
c.Next()
@ -41,8 +40,7 @@ func Refresh(c *gin.Context) {
// database.
ok, _ = refresher.Refresh(user)
if ok {
db := context.Database(c)
err := model.UpdateUser(db, user)
err := store.UpdateUser(c, user)
if err != nil {
// we only log the error at this time. not sure
// if we really want to fail the request, do we?

View file

@ -139,7 +139,7 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
auth.POST("/token", controller.GetLoginToken)
}
gitlab := e.Group("/api/gitlab/:owner/:name")
gitlab := e.Group("/gitlab/:owner/:name")
{
gitlab.Use(session.SetRepo())
gitlab.GET("/commits/:sha", controller.GetCommit)
@ -162,7 +162,7 @@ func normalize(h http.Handler) http.Handler {
parts := strings.Split(r.URL.Path, "/")[1:]
switch parts[0] {
case "settings", "api", "login", "logout", "", "authorize", "hook", "static":
case "settings", "api", "login", "logout", "", "authorize", "hook", "static", "gitlab":
// no-op
default:

View file

@ -1,71 +0,0 @@
package database
//go:generate go-bindata -pkg database -o database_gen.go sqlite3/ mysql/ postgres/
import (
"database/sql"
"os"
"github.com/drone/drone/shared/envconfig"
log "github.com/Sirupsen/logrus"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
"github.com/rubenv/sql-migrate"
"github.com/russross/meddler"
)
func Load(env envconfig.Env) *sql.DB {
var (
driver = env.String("DATABASE_DRIVER", "sqlite3")
config = env.String("DATABASE_CONFIG", "drone.sqlite")
)
log.Infof("using database driver %s", driver)
log.Infof("using database config %s", config)
return Open(driver, config)
}
// Open opens a database connection, runs the database migrations, and returns
// the database connection. Any errors connecting to the database or executing
// migrations will cause the application to exit.
func Open(driver, config string) *sql.DB {
var db, err = sql.Open(driver, config)
if err != nil {
log.Errorln(err)
log.Fatalln("database connection failed")
}
switch driver {
case "mysql":
meddler.Default = meddler.MySQL
case "postgres":
meddler.Default = meddler.PostgreSQL
}
var migrations = &migrate.AssetMigrationSource{
Asset: Asset,
AssetDir: AssetDir,
Dir: driver,
}
_, err = migrate.Exec(db, driver, migrations, migrate.Up)
if err != nil {
log.Errorln(err)
log.Fatalln("migration failed")
}
return db
}
func OpenTest() *sql.DB {
var (
driver = "sqlite3"
config = ":memory:"
)
if os.Getenv("DATABASE_DRIVER") != "" {
driver = os.Getenv("DATABASE_DRIVER")
config = os.Getenv("DATABASE_CONFIG")
}
return Open(driver, config)
}

71
store/builds.go Normal file
View file

@ -0,0 +1,71 @@
package store
import (
"github.com/drone/drone/model"
"golang.org/x/net/context"
)
type BuildStore interface {
// Get gets a build by unique ID.
Get(int64) (*model.Build, error)
// GetNumber gets a build by number.
GetNumber(*model.Repo, int) (*model.Build, error)
// GetRef gets a build by its ref.
GetRef(*model.Repo, string) (*model.Build, error)
// GetCommit gets a build by its commit sha.
GetCommit(*model.Repo, string, string) (*model.Build, error)
// GetLast gets the last build for the branch.
GetLast(*model.Repo, string) (*model.Build, error)
// GetLastBefore gets the last build before build number N.
GetLastBefore(*model.Repo, string, int64) (*model.Build, error)
// GetList gets a list of builds for the repository
GetList(*model.Repo) ([]*model.Build, error)
// Create creates a new build and jobs.
Create(*model.Build, ...*model.Job) error
// Update updates a build.
Update(*model.Build) error
}
func GetBuild(c context.Context, id int64) (*model.Build, error) {
return FromContext(c).Builds().Get(id)
}
func GetBuildNumber(c context.Context, repo *model.Repo, num int) (*model.Build, error) {
return FromContext(c).Builds().GetNumber(repo, num)
}
func GetBuildRef(c context.Context, repo *model.Repo, ref string) (*model.Build, error) {
return FromContext(c).Builds().GetRef(repo, ref)
}
func GetBuildCommit(c context.Context, repo *model.Repo, sha, branch string) (*model.Build, error) {
return FromContext(c).Builds().GetCommit(repo, sha, branch)
}
func GetBuildLast(c context.Context, repo *model.Repo, branch string) (*model.Build, error) {
return FromContext(c).Builds().GetLast(repo, branch)
}
func GetBuildLastBefore(c context.Context, repo *model.Repo, branch string, number int64) (*model.Build, error) {
return FromContext(c).Builds().GetLastBefore(repo, branch, number)
}
func GetBuildList(c context.Context, repo *model.Repo) ([]*model.Build, error) {
return FromContext(c).Builds().GetList(repo)
}
func CreateBuild(c context.Context, build *model.Build, jobs ...*model.Job) error {
return FromContext(c).Builds().Create(build, jobs...)
}
func UpdateBuild(c context.Context, build *model.Build) error {
return FromContext(c).Builds().Update(build)
}

23
store/context.go Normal file
View file

@ -0,0 +1,23 @@
package store
import (
"golang.org/x/net/context"
)
const key = "store"
// Setter defines a context that enables setting values.
type Setter interface {
Set(string, interface{})
}
// FromContext returns the Store associated with this context.
func FromContext(c context.Context) Store {
return c.Value(key).(Store)
}
// ToContext adds the Store to this context if it supports
// the Setter interface.
func ToContext(c Setter, store Store) {
c.Set(key, store)
}

141
store/datastore/builds.go Normal file
View file

@ -0,0 +1,141 @@
package datastore
import (
"database/sql"
"time"
"github.com/drone/drone/model"
"github.com/russross/meddler"
)
type buildstore struct {
*sql.DB
}
func (db *buildstore) Get(id int64) (*model.Build, error) {
var build = new(model.Build)
var err = meddler.Load(db, buildTable, build, id)
return build, err
}
func (db *buildstore) GetNumber(repo *model.Repo, num int) (*model.Build, error) {
var build = new(model.Build)
var err = meddler.QueryRow(db, build, rebind(buildNumberQuery), repo.ID, num)
return build, err
}
func (db *buildstore) GetRef(repo *model.Repo, ref string) (*model.Build, error) {
var build = new(model.Build)
var err = meddler.QueryRow(db, build, rebind(buildRefQuery), repo.ID, ref)
return build, err
}
func (db *buildstore) GetCommit(repo *model.Repo, sha, branch string) (*model.Build, error) {
var build = new(model.Build)
var err = meddler.QueryRow(db, build, rebind(buildCommitQuery), repo.ID, sha, branch)
return build, err
}
func (db *buildstore) GetLast(repo *model.Repo, branch string) (*model.Build, error) {
var build = new(model.Build)
var err = meddler.QueryRow(db, build, rebind(buildLastQuery), repo.ID, branch)
return build, err
}
func (db *buildstore) GetLastBefore(repo *model.Repo, branch string, num int64) (*model.Build, error) {
var build = new(model.Build)
var err = meddler.QueryRow(db, build, rebind(buildLastBeforeQuery), repo.ID, branch, num)
return build, err
}
func (db *buildstore) GetList(repo *model.Repo) ([]*model.Build, error) {
var builds = []*model.Build{}
var err = meddler.QueryAll(db, &builds, rebind(buildListQuery), repo.ID)
return builds, err
}
func (db *buildstore) Create(build *model.Build, jobs ...*model.Job) error {
var number int
db.QueryRow(rebind(buildNumberLast), build.RepoID).Scan(&number)
build.Number = number + 1
build.Created = time.Now().UTC().Unix()
build.Enqueued = build.Created
err := meddler.Insert(db, buildTable, build)
if err != nil {
return err
}
for i, job := range jobs {
job.BuildID = build.ID
job.Number = i + 1
job.Enqueued = build.Created
err = meddler.Insert(db, jobTable, job)
if err != nil {
return err
}
}
return nil
}
func (db *buildstore) Update(build *model.Build) error {
return meddler.Update(db, buildTable, build)
}
const buildTable = "builds"
const buildListQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
ORDER BY build_number DESC
LIMIT 50
`
const buildNumberQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_number = ?
LIMIT 1;
`
const buildLastQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_branch = ?
ORDER BY build_number DESC
LIMIT 1
`
const buildLastBeforeQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_branch = ?
AND build_id < ?
ORDER BY build_number DESC
LIMIT 1
`
const buildCommitQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_commit = ?
AND build_branch = ?
LIMIT 1
`
const buildRefQuery = `
SELECT *
FROM builds
WHERE build_repo_id = ?
AND build_ref = ?
LIMIT 1
`
const buildNumberLast = `
SELECT MAX(build_number)
FROM builds
WHERE build_repo_id = ?
`

View file

@ -1,16 +1,17 @@
package model
package datastore
import (
"testing"
"github.com/drone/drone/shared/database"
"github.com/drone/drone/model"
"github.com/franela/goblin"
)
func TestBuild(t *testing.T) {
db := database.OpenTest()
func Test_buildstore(t *testing.T) {
db := openTest()
defer db.Close()
s := From(db)
g := goblin.Goblin(t)
g.Describe("Builds", func() {
@ -22,12 +23,12 @@ func TestBuild(t *testing.T) {
})
g.It("Should Post a Build", func() {
build := Build{
build := model.Build{
RepoID: 1,
Status: StatusSuccess,
Status: model.StatusSuccess,
Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac",
}
err := CreateBuild(db, &build, []*Job{}...)
err := s.Builds().Create(&build, []*model.Job{}...)
g.Assert(err == nil).IsTrue()
g.Assert(build.ID != 0).IsTrue()
g.Assert(build.Number).Equal(1)
@ -35,16 +36,16 @@ func TestBuild(t *testing.T) {
})
g.It("Should Put a Build", func() {
build := Build{
build := model.Build{
RepoID: 1,
Number: 5,
Status: StatusSuccess,
Status: model.StatusSuccess,
Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac",
}
CreateBuild(db, &build, []*Job{}...)
build.Status = StatusRunning
err1 := UpdateBuild(db, &build)
getbuild, err2 := GetBuild(db, build.ID)
s.Builds().Create(&build, []*model.Job{}...)
build.Status = model.StatusRunning
err1 := s.Builds().Update(&build)
getbuild, err2 := s.Builds().Get(build.ID)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(build.ID).Equal(getbuild.ID)
@ -54,12 +55,12 @@ func TestBuild(t *testing.T) {
})
g.It("Should Get a Build", func() {
build := Build{
build := model.Build{
RepoID: 1,
Status: StatusSuccess,
Status: model.StatusSuccess,
}
CreateBuild(db, &build, []*Job{}...)
getbuild, err := GetBuild(db, build.ID)
s.Builds().Create(&build, []*model.Job{}...)
getbuild, err := s.Builds().Get(build.ID)
g.Assert(err == nil).IsTrue()
g.Assert(build.ID).Equal(getbuild.ID)
g.Assert(build.RepoID).Equal(getbuild.RepoID)
@ -67,17 +68,17 @@ func TestBuild(t *testing.T) {
})
g.It("Should Get a Build by Number", func() {
build1 := &Build{
build1 := &model.Build{
RepoID: 1,
Status: StatusPending,
Status: model.StatusPending,
}
build2 := &Build{
build2 := &model.Build{
RepoID: 1,
Status: StatusPending,
Status: model.StatusPending,
}
err1 := CreateBuild(db, build1, []*Job{}...)
err2 := CreateBuild(db, build2, []*Job{}...)
getbuild, err3 := GetBuildNumber(db, &Repo{ID: 1}, build2.Number)
err1 := s.Builds().Create(build1, []*model.Job{}...)
err2 := s.Builds().Create(build2, []*model.Job{}...)
getbuild, err3 := s.Builds().GetNumber(&model.Repo{ID: 1}, build2.Number)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsTrue()
@ -87,19 +88,19 @@ func TestBuild(t *testing.T) {
})
g.It("Should Get a Build by Ref", func() {
build1 := &Build{
build1 := &model.Build{
RepoID: 1,
Status: StatusPending,
Status: model.StatusPending,
Ref: "refs/pull/5",
}
build2 := &Build{
build2 := &model.Build{
RepoID: 1,
Status: StatusPending,
Status: model.StatusPending,
Ref: "refs/pull/6",
}
err1 := CreateBuild(db, build1, []*Job{}...)
err2 := CreateBuild(db, build2, []*Job{}...)
getbuild, err3 := GetBuildRef(db, &Repo{ID: 1}, "refs/pull/6")
err1 := s.Builds().Create(build1, []*model.Job{}...)
err2 := s.Builds().Create(build2, []*model.Job{}...)
getbuild, err3 := s.Builds().GetRef(&model.Repo{ID: 1}, "refs/pull/6")
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsTrue()
@ -110,19 +111,19 @@ func TestBuild(t *testing.T) {
})
g.It("Should Get a Build by Ref", func() {
build1 := &Build{
build1 := &model.Build{
RepoID: 1,
Status: StatusPending,
Status: model.StatusPending,
Ref: "refs/pull/5",
}
build2 := &Build{
build2 := &model.Build{
RepoID: 1,
Status: StatusPending,
Status: model.StatusPending,
Ref: "refs/pull/6",
}
err1 := CreateBuild(db, build1, []*Job{}...)
err2 := CreateBuild(db, build2, []*Job{}...)
getbuild, err3 := GetBuildRef(db, &Repo{ID: 1}, "refs/pull/6")
err1 := s.Builds().Create(build1, []*model.Job{}...)
err2 := s.Builds().Create(build2, []*model.Job{}...)
getbuild, err3 := s.Builds().GetRef(&model.Repo{ID: 1}, "refs/pull/6")
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsTrue()
@ -133,21 +134,21 @@ func TestBuild(t *testing.T) {
})
g.It("Should Get a Build by Commit", func() {
build1 := &Build{
build1 := &model.Build{
RepoID: 1,
Status: StatusPending,
Status: model.StatusPending,
Branch: "master",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac",
}
build2 := &Build{
build2 := &model.Build{
RepoID: 1,
Status: StatusPending,
Status: model.StatusPending,
Branch: "dev",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa",
}
err1 := CreateBuild(db, build1, []*Job{}...)
err2 := CreateBuild(db, build2, []*Job{}...)
getbuild, err3 := GetBuildCommit(db, &Repo{ID: 1}, build2.Commit, build2.Branch)
err1 := s.Builds().Create(build1, []*model.Job{}...)
err2 := s.Builds().Create(build2, []*model.Job{}...)
getbuild, err3 := s.Builds().GetCommit(&model.Repo{ID: 1}, build2.Commit, build2.Branch)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsTrue()
@ -159,21 +160,21 @@ func TestBuild(t *testing.T) {
})
g.It("Should Get the last Build", func() {
build1 := &Build{
build1 := &model.Build{
RepoID: 1,
Status: StatusFailure,
Status: model.StatusFailure,
Branch: "master",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac",
}
build2 := &Build{
build2 := &model.Build{
RepoID: 1,
Status: StatusSuccess,
Status: model.StatusSuccess,
Branch: "master",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa",
}
err1 := CreateBuild(db, build1, []*Job{}...)
err2 := CreateBuild(db, build2, []*Job{}...)
getbuild, err3 := GetBuildLast(db, &Repo{ID: 1}, build2.Branch)
err1 := s.Builds().Create(build1, []*model.Job{}...)
err2 := s.Builds().Create(build2, []*model.Job{}...)
getbuild, err3 := s.Builds().GetLast(&model.Repo{ID: 1}, build2.Branch)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsTrue()
@ -186,28 +187,28 @@ func TestBuild(t *testing.T) {
})
g.It("Should Get the last Build Before Build N", func() {
build1 := &Build{
build1 := &model.Build{
RepoID: 1,
Status: StatusFailure,
Status: model.StatusFailure,
Branch: "master",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac",
}
build2 := &Build{
build2 := &model.Build{
RepoID: 1,
Status: StatusSuccess,
Status: model.StatusSuccess,
Branch: "master",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa",
}
build3 := &Build{
build3 := &model.Build{
RepoID: 1,
Status: StatusRunning,
Status: model.StatusRunning,
Branch: "master",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa",
}
err1 := CreateBuild(db, build1, []*Job{}...)
err2 := CreateBuild(db, build2, []*Job{}...)
err3 := CreateBuild(db, build3, []*Job{}...)
getbuild, err4 := GetBuildLastBefore(db, &Repo{ID: 1}, build3.Branch, build3.ID)
err1 := s.Builds().Create(build1, []*model.Job{}...)
err2 := s.Builds().Create(build2, []*model.Job{}...)
err3 := s.Builds().Create(build3, []*model.Job{}...)
getbuild, err4 := s.Builds().GetLastBefore(&model.Repo{ID: 1}, build3.Branch, build3.ID)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsTrue()
@ -221,17 +222,17 @@ func TestBuild(t *testing.T) {
})
g.It("Should get recent Builds", func() {
build1 := &Build{
build1 := &model.Build{
RepoID: 1,
Status: StatusFailure,
Status: model.StatusFailure,
}
build2 := &Build{
build2 := &model.Build{
RepoID: 1,
Status: StatusSuccess,
Status: model.StatusSuccess,
}
CreateBuild(db, build1, []*Job{}...)
CreateBuild(db, build2, []*Job{}...)
builds, err := GetBuildList(db, &Repo{ID: 1})
s.Builds().Create(build1, []*model.Job{}...)
s.Builds().Create(build2, []*model.Job{}...)
builds, err := s.Builds().GetList(&model.Repo{ID: 1})
g.Assert(err == nil).IsTrue()
g.Assert(len(builds)).Equal(2)
g.Assert(builds[0].ID).Equal(build2.ID)

55
store/datastore/jobs.go Normal file
View file

@ -0,0 +1,55 @@
package datastore
import (
"database/sql"
"github.com/drone/drone/model"
"github.com/russross/meddler"
)
type jobstore struct {
*sql.DB
}
func (db *jobstore) Get(id int64) (*model.Job, error) {
var job = new(model.Job)
var err = meddler.Load(db, jobTable, job, id)
return job, err
}
func (db *jobstore) GetNumber(build *model.Build, num int) (*model.Job, error) {
var job = new(model.Job)
var err = meddler.QueryRow(db, job, rebind(jobNumberQuery), build.ID, num)
return job, err
}
func (db *jobstore) GetList(build *model.Build) ([]*model.Job, error) {
var jobs = []*model.Job{}
var err = meddler.QueryAll(db, &jobs, rebind(jobListQuery), build.ID)
return jobs, err
}
func (db *jobstore) Create(job *model.Job) error {
return meddler.Insert(db, jobTable, job)
}
func (db *jobstore) Update(job *model.Job) error {
return meddler.Update(db, jobTable, job)
}
const jobTable = "jobs"
const jobListQuery = `
SELECT *
FROM jobs
WHERE job_build_id = ?
ORDER BY job_number ASC
`
const jobNumberQuery = `
SELECT *
FROM jobs
WHERE job_build_id = ?
AND job_number = ?
LIMIT 1
`

View file

@ -1,16 +1,17 @@
package model
package datastore
import (
"testing"
"github.com/drone/drone/shared/database"
"github.com/drone/drone/model"
"github.com/franela/goblin"
)
func TestJob(t *testing.T) {
db := database.OpenTest()
func Test_jobstore(t *testing.T) {
db := openTest()
defer db.Close()
s := From(db)
g := goblin.Goblin(t)
g.Describe("Job", func() {
@ -21,38 +22,38 @@ func TestJob(t *testing.T) {
})
g.It("Should Set a job", func() {
job := &Job{
job := &model.Job{
BuildID: 1,
Status: "pending",
ExitCode: 0,
Number: 1,
}
err1 := InsertJob(db, job)
err1 := s.Jobs().Create(job)
g.Assert(err1 == nil).IsTrue()
g.Assert(job.ID != 0).IsTrue()
job.Status = "started"
err2 := UpdateJob(db, job)
err2 := s.Jobs().Update(job)
g.Assert(err2 == nil).IsTrue()
getjob, err3 := GetJob(db, job.ID)
getjob, err3 := s.Jobs().Get(job.ID)
g.Assert(err3 == nil).IsTrue()
g.Assert(getjob.Status).Equal(job.Status)
})
g.It("Should Get a Job by ID", func() {
job := &Job{
job := &model.Job{
BuildID: 1,
Status: "pending",
ExitCode: 1,
Number: 1,
Environment: map[string]string{"foo": "bar"},
}
err1 := InsertJob(db, job)
err1 := s.Jobs().Create(job)
g.Assert(err1 == nil).IsTrue()
g.Assert(job.ID != 0).IsTrue()
getjob, err2 := GetJob(db, job.ID)
getjob, err2 := s.Jobs().Get(job.ID)
g.Assert(err2 == nil).IsTrue()
g.Assert(getjob.ID).Equal(job.ID)
g.Assert(getjob.Status).Equal(job.Status)
@ -62,17 +63,17 @@ func TestJob(t *testing.T) {
})
g.It("Should Get a Job by Number", func() {
job := &Job{
job := &model.Job{
BuildID: 1,
Status: "pending",
ExitCode: 1,
Number: 1,
}
err1 := InsertJob(db, job)
err1 := s.Jobs().Create(job)
g.Assert(err1 == nil).IsTrue()
g.Assert(job.ID != 0).IsTrue()
getjob, err2 := GetJobNumber(db, &Build{ID: 1}, 1)
getjob, err2 := s.Jobs().GetNumber(&model.Build{ID: 1}, 1)
g.Assert(err2 == nil).IsTrue()
g.Assert(getjob.ID).Equal(job.ID)
g.Assert(getjob.Status).Equal(job.Status)
@ -80,38 +81,38 @@ func TestJob(t *testing.T) {
g.It("Should Get a List of Jobs by Commit", func() {
build := Build{
build := model.Build{
RepoID: 1,
Status: StatusSuccess,
Status: model.StatusSuccess,
}
jobs := []*Job{
&Job{
jobs := []*model.Job{
&model.Job{
BuildID: 1,
Status: "success",
ExitCode: 0,
Number: 1,
},
&Job{
&model.Job{
BuildID: 3,
Status: "error",
ExitCode: 1,
Number: 2,
},
&Job{
&model.Job{
BuildID: 5,
Status: "pending",
ExitCode: 0,
Number: 3,
},
}
//
err1 := CreateBuild(db, &build, jobs...)
err1 := s.Builds().Create(&build, jobs...)
g.Assert(err1 == nil).IsTrue()
getjobs, err2 := GetJobList(db, &build)
getjobs, err2 := s.Jobs().GetList(&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(StatusSuccess)
g.Assert(getjobs[0].Status).Equal(model.StatusSuccess)
})
})
}

37
store/datastore/keys.go Normal file
View file

@ -0,0 +1,37 @@
package datastore
import (
"database/sql"
"github.com/drone/drone/model"
"github.com/russross/meddler"
)
type keystore struct {
*sql.DB
}
func (db *keystore) Get(repo *model.Repo) (*model.Key, error) {
var key = new(model.Key)
var err = meddler.QueryRow(db, key, rebind(keyQuery), repo.ID)
return key, err
}
func (db *keystore) Create(key *model.Key) error {
return meddler.Save(db, keyTable, key)
}
func (db *keystore) Update(key *model.Key) error {
return meddler.Save(db, keyTable, key)
}
func (db *keystore) Delete(key *model.Key) error {
var _, err = db.Exec(rebind(keyDeleteStmt), key.ID)
return err
}
const keyTable = "keys"
const keyQuery = "SELECT * FROM `keys` WHERE key_repo_id=? LIMIT 1"
const keyDeleteStmt = "DELETE FROM `keys` WHERE key_id=?"

View file

@ -1,51 +1,52 @@
package model
package datastore
import (
"testing"
"github.com/drone/drone/shared/database"
"github.com/drone/drone/model"
"github.com/franela/goblin"
)
func TestKey(t *testing.T) {
db := database.OpenTest()
func Test_keystore(t *testing.T) {
db := openTest()
defer db.Close()
s := From(db)
g := goblin.Goblin(t)
g.Describe("Keys", func() {
// before each test be sure to purge the package
// table data from the database.
g.BeforeEach(func() {
db.Exec(database.Rebind("DELETE FROM `keys`"))
db.Exec(rebind("DELETE FROM `keys`"))
})
g.It("Should create a key", func() {
key := Key{
key := model.Key{
RepoID: 1,
Public: fakePublicKey,
Private: fakePrivateKey,
}
err := CreateKey(db, &key)
err := s.Keys().Create(&key)
g.Assert(err == nil).IsTrue()
g.Assert(key.ID != 0).IsTrue()
})
g.It("Should update a key", func() {
key := Key{
key := model.Key{
RepoID: 1,
Public: fakePublicKey,
Private: fakePrivateKey,
}
err := CreateKey(db, &key)
err := s.Keys().Create(&key)
g.Assert(err == nil).IsTrue()
g.Assert(key.ID != 0).IsTrue()
key.Private = ""
key.Public = ""
err1 := UpdateKey(db, &key)
getkey, err2 := GetKey(db, &Repo{ID: 1})
err1 := s.Keys().Update(&key)
getkey, err2 := s.Keys().Get(&model.Repo{ID: 1})
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(key.ID).Equal(getkey.ID)
@ -54,16 +55,16 @@ func TestKey(t *testing.T) {
})
g.It("Should get a key", func() {
key := Key{
key := model.Key{
RepoID: 1,
Public: fakePublicKey,
Private: fakePrivateKey,
}
err := CreateKey(db, &key)
err := s.Keys().Create(&key)
g.Assert(err == nil).IsTrue()
g.Assert(key.ID != 0).IsTrue()
getkey, err := GetKey(db, &Repo{ID: 1})
getkey, err := s.Keys().Get(&model.Repo{ID: 1})
g.Assert(err == nil).IsTrue()
g.Assert(key.ID).Equal(getkey.ID)
g.Assert(key.Public).Equal(getkey.Public)
@ -71,17 +72,17 @@ func TestKey(t *testing.T) {
})
g.It("Should delete a key", func() {
key := Key{
key := model.Key{
RepoID: 1,
Public: fakePublicKey,
Private: fakePrivateKey,
}
err1 := CreateKey(db, &key)
err2 := DeleteKey(db, &Repo{ID: 1})
err1 := s.Keys().Create(&key)
err2 := s.Keys().Delete(&key)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
_, err := GetKey(db, &Repo{ID: 1})
_, err := s.Keys().Get(&model.Repo{ID: 1})
g.Assert(err == nil).IsFalse()
})
})

41
store/datastore/logs.go Normal file
View file

@ -0,0 +1,41 @@
package datastore
import (
"bytes"
"database/sql"
"io"
"io/ioutil"
"github.com/drone/drone/model"
"github.com/russross/meddler"
)
type logstore struct {
*sql.DB
}
func (db *logstore) Read(job *model.Job) (io.ReadCloser, error) {
var log = new(model.Log)
var err = meddler.QueryRow(db, log, rebind(logQuery), job.ID)
var buf = bytes.NewBuffer(log.Data)
return ioutil.NopCloser(buf), err
}
func (db *logstore) Write(job *model.Job, r io.Reader) error {
var log = new(model.Log)
var err = meddler.QueryRow(db, log, rebind(logQuery), job.ID)
if err != nil {
log = &model.Log{JobID: job.ID}
}
log.Data, _ = ioutil.ReadAll(r)
return meddler.Save(db, logTable, log)
}
const logTable = "logs"
const logQuery = `
SELECT *
FROM logs
WHERE log_job_id=?
LIMIT 1
`

View file

@ -1,18 +1,19 @@
package model
package datastore
import (
"bytes"
"io/ioutil"
"testing"
"github.com/drone/drone/shared/database"
"github.com/drone/drone/model"
"github.com/franela/goblin"
)
func TestLog(t *testing.T) {
db := database.OpenTest()
func Test_logstore(t *testing.T) {
db := openTest()
defer db.Close()
s := From(db)
g := goblin.Goblin(t)
g.Describe("Logs", func() {
@ -23,14 +24,14 @@ func TestLog(t *testing.T) {
})
g.It("Should create a log", func() {
job := Job{
job := model.Job{
ID: 1,
}
buf := bytes.NewBufferString("echo hi")
err := SetLog(db, &job, buf)
err := s.Logs().Write(&job, buf)
g.Assert(err == nil).IsTrue()
rc, err := GetLog(db, &job)
rc, err := s.Logs().Read(&job)
g.Assert(err == nil).IsTrue()
defer rc.Close()
out, _ := ioutil.ReadAll(rc)
@ -38,17 +39,17 @@ func TestLog(t *testing.T) {
})
g.It("Should update a log", func() {
job := Job{
job := model.Job{
ID: 1,
}
buf1 := bytes.NewBufferString("echo hi")
buf2 := bytes.NewBufferString("echo allo?")
err1 := SetLog(db, &job, buf1)
err2 := SetLog(db, &job, buf2)
err1 := s.Logs().Write(&job, buf1)
err2 := s.Logs().Write(&job, buf2)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
rc, err := GetLog(db, &job)
rc, err := s.Logs().Read(&job)
g.Assert(err == nil).IsTrue()
defer rc.Close()
out, _ := ioutil.ReadAll(rc)

60
store/datastore/nodes.go Normal file
View file

@ -0,0 +1,60 @@
package datastore
import (
"database/sql"
"github.com/drone/drone/model"
"github.com/russross/meddler"
)
type nodestore struct {
*sql.DB
}
func (db *nodestore) Get(id int64) (*model.Node, error) {
var node = new(model.Node)
var err = meddler.Load(db, nodeTable, node, id)
return node, err
}
func (db *nodestore) GetList() ([]*model.Node, error) {
var nodes = []*model.Node{}
var err = meddler.QueryAll(db, &nodes, rebind(nodeListQuery))
return nodes, err
}
func (db *nodestore) Count() (int, error) {
var count int
var err = db.QueryRow(rebind(nodeCountQuery)).Scan(&count)
return count, err
}
func (db *nodestore) Create(node *model.Node) error {
return meddler.Insert(db, nodeTable, node)
}
func (db *nodestore) Update(node *model.Node) error {
return meddler.Update(db, nodeTable, node)
}
func (db *nodestore) Delete(node *model.Node) error {
var _, err = db.Exec(rebind(nodeDeleteStmt), node.ID)
return err
}
const nodeTable = "nodes"
const nodeListQuery = `
SELECT *
FROM nodes
ORDER BY node_addr
`
const nodeCountQuery = `
SELECT COUNT(*) FROM nodes
`
const nodeDeleteStmt = `
DELETE FROM nodes
WHERE node_id=?
`

View file

@ -1,15 +1,16 @@
package model
package datastore
import (
"testing"
"github.com/drone/drone/shared/database"
"github.com/drone/drone/model"
"github.com/franela/goblin"
)
func TestNode(t *testing.T) {
db := database.OpenTest()
func Test_nodestore(t *testing.T) {
db := openTest()
defer db.Close()
s := From(db)
g := goblin.Goblin(t)
g.Describe("Nodes", func() {
@ -21,28 +22,28 @@ func TestNode(t *testing.T) {
})
g.It("Should create a node", func() {
node := Node{
node := model.Node{
Addr: "unix:///var/run/docker/docker.sock",
Arch: "linux_amd64",
}
err := InsertNode(db, &node)
err := s.Nodes().Create(&node)
g.Assert(err == nil).IsTrue()
g.Assert(node.ID != 0).IsTrue()
})
g.It("Should update a node", func() {
node := Node{
node := model.Node{
Addr: "unix:///var/run/docker/docker.sock",
Arch: "linux_amd64",
}
err := InsertNode(db, &node)
err := s.Nodes().Create(&node)
g.Assert(err == nil).IsTrue()
g.Assert(node.ID != 0).IsTrue()
node.Addr = "unix:///var/run/docker.sock"
err1 := UpdateNode(db, &node)
getnode, err2 := GetNode(db, node.ID)
err1 := s.Nodes().Update(&node)
getnode, err2 := s.Nodes().Get(node.ID)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(node.ID).Equal(getnode.ID)
@ -51,15 +52,15 @@ func TestNode(t *testing.T) {
})
g.It("Should get a node", func() {
node := Node{
node := model.Node{
Addr: "unix:///var/run/docker/docker.sock",
Arch: "linux_amd64",
}
err := InsertNode(db, &node)
err := s.Nodes().Create(&node)
g.Assert(err == nil).IsTrue()
g.Assert(node.ID != 0).IsTrue()
getnode, err := GetNode(db, node.ID)
getnode, err := s.Nodes().Get(node.ID)
g.Assert(err == nil).IsTrue()
g.Assert(node.ID).Equal(getnode.ID)
g.Assert(node.Addr).Equal(getnode.Addr)
@ -67,33 +68,33 @@ func TestNode(t *testing.T) {
})
g.It("Should get a node list", func() {
node1 := Node{
node1 := model.Node{
Addr: "unix:///var/run/docker/docker.sock",
Arch: "linux_amd64",
}
node2 := Node{
node2 := model.Node{
Addr: "unix:///var/run/docker.sock",
Arch: "linux_386",
}
InsertNode(db, &node1)
InsertNode(db, &node2)
s.Nodes().Create(&node1)
s.Nodes().Create(&node2)
nodes, err := GetNodeList(db)
nodes, err := s.Nodes().GetList()
g.Assert(err == nil).IsTrue()
g.Assert(len(nodes)).Equal(2)
})
g.It("Should delete a node", func() {
node := Node{
node := model.Node{
Addr: "unix:///var/run/docker/docker.sock",
Arch: "linux_amd64",
}
err1 := InsertNode(db, &node)
err2 := DeleteNode(db, &node)
err1 := s.Nodes().Create(&node)
err2 := s.Nodes().Delete(&node)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
_, err := GetNode(db, node.ID)
_, err := s.Nodes().Get(node.ID)
g.Assert(err == nil).IsFalse()
})
})

91
store/datastore/repos.go Normal file
View file

@ -0,0 +1,91 @@
package datastore
import (
"database/sql"
"strings"
"github.com/drone/drone/model"
"github.com/russross/meddler"
)
type repostore struct {
*sql.DB
}
func (db *repostore) Get(id int64) (*model.Repo, error) {
var repo = new(model.Repo)
var err = meddler.Load(db, repoTable, repo, id)
return repo, err
}
func (db *repostore) GetName(name string) (*model.Repo, error) {
var repo = new(model.Repo)
var err = meddler.QueryRow(db, repo, rebind(repoNameQuery), name)
return repo, err
}
func (db *repostore) GetListOf(listof []*model.RepoLite) ([]*model.Repo, error) {
var repos = []*model.Repo{}
var size = len(listof)
if size > 999 {
size = 999
listof = listof[:999]
}
var qs = make([]string, size, size)
var in = make([]interface{}, size, size)
for i, repo := range listof {
qs[i] = "?"
in[i] = repo.FullName
}
var stmt = "SELECT * FROM repos WHERE repo_full_name IN (" + strings.Join(qs, ",") + ") ORDER BY repo_name"
var err = meddler.QueryAll(db, &repos, rebind(stmt), in...)
return repos, err
}
func (db *repostore) Count() (int, error) {
var count int
var err = db.QueryRow(rebind(repoCountQuery)).Scan(&count)
return count, err
}
func (db *repostore) Create(repo *model.Repo) error {
return meddler.Insert(db, repoTable, repo)
}
func (db *repostore) Update(repo *model.Repo) error {
return meddler.Update(db, repoTable, repo)
}
func (db *repostore) Delete(repo *model.Repo) error {
var _, err = db.Exec(rebind(repoDeleteStmt), repo.ID)
return err
}
const repoTable = "repos"
const repoNameQuery = `
SELECT *
FROM repos
WHERE repo_full_name = ?
LIMIT 1;
`
const repoListQuery = `
SELECT *
FROM repos
WHERE repo_id IN (
SELECT DISTINCT build_repo_id
FROM builds
WHERE build_author = ?
)
ORDER BY repo_full_name
`
const repoCountQuery = `
SELECT COUNT(*) FROM repos
`
const repoDeleteStmt = `
DELETE FROM repos
WHERE repo_id = ?
`

View file

@ -1,16 +1,17 @@
package model
package datastore
import (
"testing"
"github.com/drone/drone/shared/database"
"github.com/drone/drone/model"
"github.com/franela/goblin"
)
func TestRepostore(t *testing.T) {
db := database.OpenTest()
func Test_repostore(t *testing.T) {
db := openTest()
defer db.Close()
s := From(db)
g := goblin.Goblin(t)
g.Describe("Repo", func() {
@ -23,15 +24,15 @@ func TestRepostore(t *testing.T) {
})
g.It("Should Set a Repo", func() {
repo := Repo{
repo := model.Repo{
UserID: 1,
FullName: "bradrydzewski/drone",
Owner: "bradrydzewski",
Name: "drone",
}
err1 := CreateRepo(db, &repo)
err2 := UpdateRepo(db, &repo)
getrepo, err3 := GetRepo(db, repo.ID)
err1 := s.Repos().Create(&repo)
err2 := s.Repos().Update(&repo)
getrepo, err3 := s.Repos().Get(repo.ID)
if err3 != nil {
println("Get Repo Error")
println(err3.Error())
@ -43,26 +44,26 @@ func TestRepostore(t *testing.T) {
})
g.It("Should Add a Repo", func() {
repo := Repo{
repo := model.Repo{
UserID: 1,
FullName: "bradrydzewski/drone",
Owner: "bradrydzewski",
Name: "drone",
}
err := CreateRepo(db, &repo)
err := s.Repos().Create(&repo)
g.Assert(err == nil).IsTrue()
g.Assert(repo.ID != 0).IsTrue()
})
g.It("Should Get a Repo by ID", func() {
repo := Repo{
repo := model.Repo{
UserID: 1,
FullName: "bradrydzewski/drone",
Owner: "bradrydzewski",
Name: "drone",
}
CreateRepo(db, &repo)
getrepo, err := GetRepo(db, repo.ID)
s.Repos().Create(&repo)
getrepo, err := s.Repos().Get(repo.ID)
g.Assert(err == nil).IsTrue()
g.Assert(repo.ID).Equal(getrepo.ID)
g.Assert(repo.UserID).Equal(getrepo.UserID)
@ -71,14 +72,14 @@ func TestRepostore(t *testing.T) {
})
g.It("Should Get a Repo by Name", func() {
repo := Repo{
repo := model.Repo{
UserID: 1,
FullName: "bradrydzewski/drone",
Owner: "bradrydzewski",
Name: "drone",
}
CreateRepo(db, &repo)
getrepo, err := GetRepoName(db, repo.Owner, repo.Name)
s.Repos().Create(&repo)
getrepo, err := s.Repos().GetName(repo.FullName)
g.Assert(err == nil).IsTrue()
g.Assert(repo.ID).Equal(getrepo.ID)
g.Assert(repo.UserID).Equal(getrepo.UserID)
@ -86,62 +87,62 @@ func TestRepostore(t *testing.T) {
g.Assert(repo.Name).Equal(getrepo.Name)
})
g.It("Should Get a Repo List by User", func() {
repo1 := Repo{
UserID: 1,
FullName: "bradrydzewski/drone",
Owner: "bradrydzewski",
Name: "drone",
}
repo2 := Repo{
UserID: 1,
FullName: "bradrydzewski/drone-dart",
Owner: "bradrydzewski",
Name: "drone-dart",
}
CreateRepo(db, &repo1)
CreateRepo(db, &repo2)
CreateBuild(db, &Build{RepoID: repo1.ID, Author: "bradrydzewski"})
CreateBuild(db, &Build{RepoID: repo1.ID, Author: "johnsmith"})
repos, err := GetRepoList(db, &User{ID: 1, Login: "bradrydzewski"})
g.Assert(err == nil).IsTrue()
g.Assert(len(repos)).Equal(1)
g.Assert(repos[0].UserID).Equal(repo1.UserID)
g.Assert(repos[0].Owner).Equal(repo1.Owner)
g.Assert(repos[0].Name).Equal(repo1.Name)
})
// g.It("Should Get a Repo List by User", func() {
// repo1 := model.Repo{
// UserID: 1,
// FullName: "bradrydzewski/drone",
// Owner: "bradrydzewski",
// Name: "drone",
// }
// repo2 := model.Repo{
// UserID: 1,
// FullName: "bradrydzewski/drone-dart",
// Owner: "bradrydzewski",
// Name: "drone-dart",
// }
// s.Repos().Create(&repo1)
// s.Repos().Create(&repo2)
// CreateBuild(db, &Build{RepoID: repo1.ID, Author: "bradrydzewski"})
// CreateBuild(db, &Build{RepoID: repo1.ID, Author: "johnsmith"})
// repos, err := GetRepoList(db, &User{ID: 1, Login: "bradrydzewski"})
// g.Assert(err == nil).IsTrue()
// g.Assert(len(repos)).Equal(1)
// g.Assert(repos[0].UserID).Equal(repo1.UserID)
// g.Assert(repos[0].Owner).Equal(repo1.Owner)
// g.Assert(repos[0].Name).Equal(repo1.Name)
// })
g.It("Should Delete a Repo", func() {
repo := Repo{
repo := model.Repo{
UserID: 1,
FullName: "bradrydzewski/drone",
Owner: "bradrydzewski",
Name: "drone",
}
CreateRepo(db, &repo)
_, err1 := GetRepo(db, repo.ID)
err2 := DeleteRepo(db, &repo)
_, err3 := GetRepo(db, repo.ID)
s.Repos().Create(&repo)
_, err1 := s.Repos().Get(repo.ID)
err2 := s.Repos().Delete(&repo)
_, err3 := s.Repos().Get(repo.ID)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsFalse()
})
g.It("Should Enforce Unique Repo Name", func() {
repo1 := Repo{
repo1 := model.Repo{
UserID: 1,
FullName: "bradrydzewski/drone",
Owner: "bradrydzewski",
Name: "drone",
}
repo2 := Repo{
repo2 := model.Repo{
UserID: 2,
FullName: "bradrydzewski/drone",
Owner: "bradrydzewski",
Name: "drone",
}
err1 := CreateRepo(db, &repo1)
err2 := CreateRepo(db, &repo2)
err1 := s.Repos().Create(&repo1)
err2 := s.Repos().Create(&repo2)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsFalse()
})

103
store/datastore/store.go Normal file
View file

@ -0,0 +1,103 @@
package datastore
import (
"database/sql"
"os"
"github.com/drone/drone/shared/envconfig"
"github.com/drone/drone/store"
"github.com/drone/drone/store/migration"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
"github.com/rubenv/sql-migrate"
"github.com/russross/meddler"
log "github.com/Sirupsen/logrus"
)
// From creates a datastore from an existing database connection.
func From(db *sql.DB) store.Store {
return store.New(
&nodestore{db},
&userstore{db},
&repostore{db},
&keystore{db},
&buildstore{db},
&jobstore{db},
&logstore{db},
)
}
// Load opens a new database connection with the specified driver
// and connection string specified in the environment variables.
func Load(env envconfig.Env) store.Store {
var (
driver = env.String("DATABASE_DRIVER", "sqlite3")
config = env.String("DATABASE_CONFIG", "drone.sqlite")
)
log.Infof("using database driver %s", driver)
log.Infof("using database config %s", config)
return From(
Open(driver, config),
)
}
// Open opens a new database connection with the specified
// driver and connection string and returns a store.
func Open(driver, config string) *sql.DB {
db, err := sql.Open(driver, config)
if err != nil {
log.Errorln(err)
log.Fatalln("database connection failed")
}
setupMeddler(driver)
if err := setupDatabase(driver, db); err != nil {
log.Errorln(err)
log.Fatalln("migration failed")
}
return db
}
// OpenTest opens a new database connection for testing purposes.
// The database driver and connection string are provided by
// environment variables, with fallback to in-memory sqlite.
func openTest() *sql.DB {
var (
driver = "sqlite3"
config = ":memory:"
)
if os.Getenv("DATABASE_DRIVER") != "" {
driver = os.Getenv("DATABASE_DRIVER")
config = os.Getenv("DATABASE_CONFIG")
}
return Open(driver, config)
}
// helper function to setup the databsae by performing
// automated database migration steps.
func setupDatabase(driver string, db *sql.DB) error {
var migrations = &migrate.AssetMigrationSource{
Asset: migration.Asset,
AssetDir: migration.AssetDir,
Dir: driver,
}
_, err := migrate.Exec(db, driver, migrations, migrate.Up)
return err
}
// helper function to setup the meddler default driver
// based on the selected driver name.
func setupMeddler(driver string) {
switch driver {
case "sqlite3":
meddler.Default = meddler.SQLite
case "mysql":
meddler.Default = meddler.MySQL
case "postgres":
meddler.Default = meddler.PostgreSQL
}
}

111
store/datastore/users.go Normal file
View file

@ -0,0 +1,111 @@
package datastore
import (
"database/sql"
"github.com/drone/drone/model"
"github.com/russross/meddler"
)
type userstore struct {
*sql.DB
}
func (db *userstore) Get(id int64) (*model.User, error) {
var usr = new(model.User)
var err = meddler.Load(db, userTable, usr, id)
return usr, err
}
func (db *userstore) GetLogin(login string) (*model.User, error) {
var usr = new(model.User)
var err = meddler.QueryRow(db, usr, rebind(userLoginQuery), login)
return usr, err
}
func (db *userstore) GetList() ([]*model.User, error) {
var users = []*model.User{}
var err = meddler.QueryAll(db, &users, rebind(userListQuery))
return users, err
}
func (db *userstore) GetFeed(user *model.User, limit, offset int) ([]*model.Feed, error) {
// var feed = []*Feed{}
// var err = meddler.QueryAll(db, &feed, rebind(userFeedQuery), user.Login, limit, offset)
// return feed, err
return nil, nil
}
func (db *userstore) Count() (int, error) {
var count int
var err = db.QueryRow(rebind(userCountQuery)).Scan(&count)
return count, err
}
func (db *userstore) Create(user *model.User) error {
return meddler.Insert(db, userTable, user)
}
func (db *userstore) Update(user *model.User) error {
return meddler.Update(db, userTable, user)
}
func (db *userstore) Delete(user *model.User) error {
var _, err = db.Exec(rebind(userDeleteStmt), user.ID)
return err
}
const userTable = "users"
const userLoginQuery = `
SELECT *
FROM users
WHERE user_login=?
LIMIT 1
`
const userListQuery = `
SELECT *
FROM users
ORDER BY user_login ASC
`
const userCountQuery = `
SELECT count(1)
FROM users
`
const userDeleteStmt = `
DELETE FROM users
WHERE user_id=?
`
const userFeedQuery = `
SELECT
repo_owner
,repo_name
,repo_full_name
,build_number
,build_event
,build_status
,build_created
,build_started
,build_finished
,build_commit
,build_branch
,build_ref
,build_refspec
,build_remote
,build_title
,build_message
,build_author
,build_email
,build_avatar
FROM
builds b
,repos r
WHERE b.build_repo_id = r.repo_id
AND b.build_author = ?
ORDER BY b.build_id DESC
LIMIT ? OFFSET ?
`

View file

@ -1,15 +1,16 @@
package model
package datastore
import (
"testing"
"github.com/drone/drone/shared/database"
"github.com/drone/drone/model"
"github.com/franela/goblin"
)
func TestUserstore(t *testing.T) {
db := database.OpenTest()
func Test_userstore(t *testing.T) {
db := openTest()
defer db.Close()
s := From(db)
g := goblin.Goblin(t)
g.Describe("User", func() {
@ -24,14 +25,14 @@ func TestUserstore(t *testing.T) {
})
g.It("Should Update a User", func() {
user := User{
user := model.User{
Login: "joe",
Email: "foo@bar.com",
Token: "e42080dddf012c718e476da161d21ad5",
}
err1 := CreateUser(db, &user)
err2 := UpdateUser(db, &user)
getuser, err3 := GetUser(db, user.ID)
err1 := s.Users().Create(&user)
err2 := s.Users().Update(&user)
getuser, err3 := s.Users().Get(user.ID)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsTrue()
@ -39,18 +40,18 @@ func TestUserstore(t *testing.T) {
})
g.It("Should Add a new User", func() {
user := User{
user := model.User{
Login: "joe",
Email: "foo@bar.com",
Token: "e42080dddf012c718e476da161d21ad5",
}
err := CreateUser(db, &user)
err := s.Users().Create(&user)
g.Assert(err == nil).IsTrue()
g.Assert(user.ID != 0).IsTrue()
})
g.It("Should Get a User", func() {
user := User{
user := model.User{
Login: "joe",
Token: "f0b461ca586c27872b43a0685cbc2847",
Secret: "976f22a5eef7caacb7e678d6c52f49b1",
@ -60,8 +61,8 @@ func TestUserstore(t *testing.T) {
Admin: true,
}
CreateUser(db, &user)
getuser, err := GetUser(db, user.ID)
s.Users().Create(&user)
getuser, err := s.Users().Get(user.ID)
g.Assert(err == nil).IsTrue()
g.Assert(user.ID).Equal(getuser.ID)
g.Assert(user.Login).Equal(getuser.Login)
@ -74,49 +75,49 @@ func TestUserstore(t *testing.T) {
})
g.It("Should Get a User By Login", func() {
user := User{
user := model.User{
Login: "joe",
Email: "foo@bar.com",
Token: "e42080dddf012c718e476da161d21ad5",
}
CreateUser(db, &user)
getuser, err := GetUserLogin(db, user.Login)
s.Users().Create(&user)
getuser, err := s.Users().GetLogin(user.Login)
g.Assert(err == nil).IsTrue()
g.Assert(user.ID).Equal(getuser.ID)
g.Assert(user.Login).Equal(getuser.Login)
})
g.It("Should Enforce Unique User Login", func() {
user1 := User{
user1 := model.User{
Login: "joe",
Email: "foo@bar.com",
Token: "e42080dddf012c718e476da161d21ad5",
}
user2 := User{
user2 := model.User{
Login: "joe",
Email: "foo@bar.com",
Token: "ab20g0ddaf012c744e136da16aa21ad9",
}
err1 := CreateUser(db, &user1)
err2 := CreateUser(db, &user2)
err1 := s.Users().Create(&user1)
err2 := s.Users().Create(&user2)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsFalse()
})
g.It("Should Get a User List", func() {
user1 := User{
user1 := model.User{
Login: "jane",
Email: "foo@bar.com",
Token: "ab20g0ddaf012c744e136da16aa21ad9",
}
user2 := User{
user2 := model.User{
Login: "joe",
Email: "foo@bar.com",
Token: "e42080dddf012c718e476da161d21ad5",
}
CreateUser(db, &user1)
CreateUser(db, &user2)
users, err := GetUserList(db)
s.Users().Create(&user1)
s.Users().Create(&user2)
users, err := s.Users().GetList()
g.Assert(err == nil).IsTrue()
g.Assert(len(users)).Equal(2)
g.Assert(users[0].Login).Equal(user1.Login)
@ -125,84 +126,84 @@ func TestUserstore(t *testing.T) {
})
g.It("Should Get a User Count", func() {
user1 := User{
user1 := model.User{
Login: "jane",
Email: "foo@bar.com",
Token: "ab20g0ddaf012c744e136da16aa21ad9",
}
user2 := User{
user2 := model.User{
Login: "joe",
Email: "foo@bar.com",
Token: "e42080dddf012c718e476da161d21ad5",
}
CreateUser(db, &user1)
CreateUser(db, &user2)
count, err := GetUserCount(db)
s.Users().Create(&user1)
s.Users().Create(&user2)
count, err := s.Users().Count()
g.Assert(err == nil).IsTrue()
g.Assert(count).Equal(2)
})
g.It("Should Get a User Count Zero", func() {
count, err := GetUserCount(db)
count, err := s.Users().Count()
g.Assert(err == nil).IsTrue()
g.Assert(count).Equal(0)
})
g.It("Should Del a User", func() {
user := User{
user := model.User{
Login: "joe",
Email: "foo@bar.com",
Token: "e42080dddf012c718e476da161d21ad5",
}
CreateUser(db, &user)
_, err1 := GetUser(db, user.ID)
err2 := DeleteUser(db, &user)
_, err3 := GetUser(db, user.ID)
s.Users().Create(&user)
_, err1 := s.Users().Get(user.ID)
err2 := s.Users().Delete(&user)
_, err3 := s.Users().Get(user.ID)
g.Assert(err1 == nil).IsTrue()
g.Assert(err2 == nil).IsTrue()
g.Assert(err3 == nil).IsFalse()
})
g.It("Should get the Build feed for a User", func() {
repo1 := &Repo{
UserID: 1,
Owner: "bradrydzewski",
Name: "drone",
FullName: "bradrydzewski/drone",
}
repo2 := &Repo{
UserID: 2,
Owner: "drone",
Name: "drone",
FullName: "drone/drone",
}
CreateRepo(db, repo1)
CreateRepo(db, repo2)
// g.It("Should get the Build feed for a User", func() {
// repo1 := &Repo{
// UserID: 1,
// Owner: "bradrydzewski",
// Name: "drone",
// FullName: "bradrydzewski/drone",
// }
// repo2 := &Repo{
// UserID: 2,
// Owner: "drone",
// Name: "drone",
// FullName: "drone/drone",
// }
// CreateRepo(db, repo1)
// CreateRepo(db, repo2)
build1 := &Build{
RepoID: repo1.ID,
Status: StatusFailure,
Author: "bradrydzewski",
}
build2 := &Build{
RepoID: repo1.ID,
Status: StatusSuccess,
Author: "bradrydzewski",
}
build3 := &Build{
RepoID: repo2.ID,
Status: StatusSuccess,
Author: "octocat",
}
CreateBuild(db, build1)
CreateBuild(db, build2)
CreateBuild(db, build3)
// build1 := &Build{
// RepoID: repo1.ID,
// Status: StatusFailure,
// Author: "bradrydzewski",
// }
// build2 := &Build{
// RepoID: repo1.ID,
// Status: StatusSuccess,
// Author: "bradrydzewski",
// }
// build3 := &Build{
// RepoID: repo2.ID,
// Status: StatusSuccess,
// Author: "octocat",
// }
// CreateBuild(db, build1)
// CreateBuild(db, build2)
// CreateBuild(db, build3)
builds, err := GetUserFeed(db, &User{ID: 1, Login: "bradrydzewski"}, 20, 0)
g.Assert(err == nil).IsTrue()
g.Assert(len(builds)).Equal(2)
g.Assert(builds[0].Owner).Equal("bradrydzewski")
g.Assert(builds[0].Name).Equal("drone")
})
// builds, err := GetUserFeed(db, &User{ID: 1, Login: "bradrydzewski"}, 20, 0)
// g.Assert(err == nil).IsTrue()
// g.Assert(len(builds)).Equal(2)
// g.Assert(builds[0].Owner).Equal("bradrydzewski")
// g.Assert(builds[0].Name).Equal("drone")
// })
})
}

View file

@ -1,4 +1,4 @@
package database
package datastore
import (
"strconv"
@ -6,9 +6,9 @@ import (
"github.com/russross/meddler"
)
// Rebind is a helper function that changes the sql
// rebind is a helper function that changes the sql
// bind type from ? to $ for postgres queries.
func Rebind(query string) string {
func rebind(query string) string {
if meddler.Default != meddler.PostgreSQL {
return query
}

43
store/jobs.go Normal file
View file

@ -0,0 +1,43 @@
package store
import (
"github.com/drone/drone/model"
"golang.org/x/net/context"
)
type JobStore interface {
// Get gets a job by unique ID.
Get(int64) (*model.Job, error)
// GetNumber gets a job by number.
GetNumber(*model.Build, int) (*model.Job, error)
// GetList gets a list of all users in the system.
GetList(*model.Build) ([]*model.Job, error)
// Create creates a job.
Create(*model.Job) error
// Update updates a job.
Update(*model.Job) error
}
func GetJob(c context.Context, id int64) (*model.Job, error) {
return FromContext(c).Jobs().Get(id)
}
func GetJobNumber(c context.Context, build *model.Build, num int) (*model.Job, error) {
return FromContext(c).Jobs().GetNumber(build, num)
}
func GetJobList(c context.Context, build *model.Build) ([]*model.Job, error) {
return FromContext(c).Jobs().GetList(build)
}
func CreateJob(c context.Context, job *model.Job) error {
return FromContext(c).Jobs().Create(job)
}
func UpdateJob(c context.Context, job *model.Job) error {
return FromContext(c).Jobs().Update(job)
}

36
store/keys.go Normal file
View file

@ -0,0 +1,36 @@
package store
import (
"github.com/drone/drone/model"
"golang.org/x/net/context"
)
type KeyStore interface {
// Get gets a key by unique repository ID.
Get(*model.Repo) (*model.Key, error)
// Create creates a new key.
Create(*model.Key) error
// Update updates a user key.
Update(*model.Key) error
// Delete deletes a user key.
Delete(*model.Key) error
}
func GetKey(c context.Context, repo *model.Repo) (*model.Key, error) {
return FromContext(c).Keys().Get(repo)
}
func CreateKey(c context.Context, key *model.Key) error {
return FromContext(c).Keys().Create(key)
}
func UpdateKey(c context.Context, key *model.Key) error {
return FromContext(c).Keys().Update(key)
}
func DeleteKey(c context.Context, key *model.Key) error {
return FromContext(c).Keys().Delete(key)
}

24
store/logs.go Normal file
View file

@ -0,0 +1,24 @@
package store
import (
"io"
"github.com/drone/drone/model"
"golang.org/x/net/context"
)
type LogStore interface {
// Read reads the Job logs from the datastore.
Read(*model.Job) (io.ReadCloser, error)
// Write writes the job logs to the datastore.
Write(*model.Job, io.Reader) error
}
func ReadLog(c context.Context, job *model.Job) (io.ReadCloser, error) {
return FromContext(c).Logs().Read(job)
}
func WriteLog(c context.Context, job *model.Job, r io.Reader) error {
return FromContext(c).Logs().Write(job, r)
}

View file

@ -0,0 +1,3 @@
package migration
//go:generate go-bindata -pkg migration -o migration_gen.go sqlite3/ mysql/ postgres/

50
store/nodes.go Normal file
View file

@ -0,0 +1,50 @@
package store
import (
"github.com/drone/drone/model"
"golang.org/x/net/context"
)
type NodeStore interface {
// Get gets a user by unique ID.
Get(int64) (*model.Node, error)
// GetList gets a list of all nodes in the system.
GetList() ([]*model.Node, error)
// Count gets a count of all nodes in the system.
Count() (int, error)
// Create creates a node.
Create(*model.Node) error
// Update updates a node.
Update(*model.Node) error
// Delete deletes a node.
Delete(*model.Node) error
}
func GetNode(c context.Context, id int64) (*model.Node, error) {
return FromContext(c).Nodes().Get(id)
}
func GetNodeList(c context.Context) ([]*model.Node, error) {
return FromContext(c).Nodes().GetList()
}
func CountNodes(c context.Context) (int, error) {
return FromContext(c).Nodes().Count()
}
func CreateNode(c context.Context, node *model.Node) error {
return FromContext(c).Nodes().Create(node)
}
func UpdateNode(c context.Context, node *model.Node) error {
return FromContext(c).Nodes().Update(node)
}
func DeleteNode(c context.Context, node *model.Node) error {
return FromContext(c).Nodes().Delete(node)
}

61
store/repos.go Normal file
View file

@ -0,0 +1,61 @@
package store
import (
"github.com/drone/drone/model"
"golang.org/x/net/context"
)
type RepoStore interface {
// Get gets a repo by unique ID.
Get(int64) (*model.Repo, error)
// GetLogin gets a repo by its full name.
GetName(string) (*model.Repo, error)
// GetListOf gets the list of enumerated repos in the system.
GetListOf([]*model.RepoLite) ([]*model.Repo, error)
// Count gets a count of all repos in the system.
Count() (int, error)
// Create creates a new repository.
Create(*model.Repo) error
// Update updates a user repository.
Update(*model.Repo) error
// Delete deletes a user repository.
Delete(*model.Repo) error
}
func GetRepo(c context.Context, id int64) (*model.Repo, error) {
return FromContext(c).Repos().Get(id)
}
func GetRepoName(c context.Context, name string) (*model.Repo, error) {
return FromContext(c).Repos().GetName(name)
}
func GetRepoOwnerName(c context.Context, owner, name string) (*model.Repo, error) {
return FromContext(c).Repos().GetName(owner + "/" + name)
}
func GetRepoListOf(c context.Context, listof []*model.RepoLite) ([]*model.Repo, error) {
return FromContext(c).Repos().GetListOf(listof)
}
func CountRepos(c context.Context) (int, error) {
return FromContext(c).Repos().Count()
}
func CreateRepo(c context.Context, repo *model.Repo) error {
return FromContext(c).Repos().Create(repo)
}
func UpdateRepo(c context.Context, repo *model.Repo) error {
return FromContext(c).Repos().Update(repo)
}
func DeleteRepo(c context.Context, repo *model.Repo) error {
return FromContext(c).Repos().Update(repo)
}

49
store/store.go Normal file
View file

@ -0,0 +1,49 @@
package store
type Store interface {
Nodes() NodeStore
Users() UserStore
Repos() RepoStore
Keys() KeyStore
Builds() BuildStore
Jobs() JobStore
Logs() LogStore
}
type store struct {
nodes NodeStore
users UserStore
repos RepoStore
keys KeyStore
builds BuildStore
jobs JobStore
logs LogStore
}
func (s *store) Nodes() NodeStore { return s.nodes }
func (s *store) Users() UserStore { return s.users }
func (s *store) Repos() RepoStore { return s.repos }
func (s *store) Keys() KeyStore { return s.keys }
func (s *store) Builds() BuildStore { return s.builds }
func (s *store) Jobs() JobStore { return s.jobs }
func (s *store) Logs() LogStore { return s.logs }
func New(
nodes NodeStore,
users UserStore,
repos RepoStore,
keys KeyStore,
builds BuildStore,
jobs JobStore,
logs LogStore,
) Store {
return &store{
nodes,
users,
repos,
keys,
builds,
jobs,
logs,
}
}

64
store/users.go Normal file
View file

@ -0,0 +1,64 @@
package store
import (
"github.com/drone/drone/model"
"golang.org/x/net/context"
)
type UserStore interface {
// Get gets a user by unique ID.
Get(int64) (*model.User, error)
// GetLogin gets a user by unique Login name.
GetLogin(string) (*model.User, error)
// GetList gets a list of all users in the system.
GetList() ([]*model.User, error)
// GetFeed gets a user activity feed.
GetFeed(*model.User, int, int) ([]*model.Feed, error)
// Count gets a count of all users in the system.
Count() (int, error)
// Create creates a new user account.
Create(*model.User) error
// Update updates a user account.
Update(*model.User) error
// Delete deletes a user account.
Delete(*model.User) error
}
func GetUser(c context.Context, id int64) (*model.User, error) {
return FromContext(c).Users().Get(id)
}
func GetUserLogin(c context.Context, login string) (*model.User, error) {
return FromContext(c).Users().GetLogin(login)
}
func GetUserList(c context.Context) ([]*model.User, error) {
return FromContext(c).Users().GetList()
}
func GetUserFeed(c context.Context, user *model.User, limit, offset int) ([]*model.Feed, error) {
return FromContext(c).Users().GetFeed(user, limit, offset)
}
func CountUsers(c context.Context) (int, error) {
return FromContext(c).Users().Count()
}
func CreateUser(c context.Context, user *model.User) error {
return FromContext(c).Users().Create(user)
}
func UpdateUser(c context.Context, user *model.User) error {
return FromContext(c).Users().Update(user)
}
func DeleteUser(c context.Context, user *model.User) error {
return FromContext(c).Users().Delete(user)
}