diff --git a/plugin/notify/notification.go b/plugin/notify/notification.go index d6a809403..dede5082d 100644 --- a/plugin/notify/notification.go +++ b/plugin/notify/notification.go @@ -1,9 +1,7 @@ package notify import ( - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/shared/model" ) // Context represents the context of an @@ -13,13 +11,13 @@ type Context struct { Host string // User that owns the repository - User *user.User + User *model.User // Repository being built. - Repo *repo.Repo + Repo *model.Repo // Commit being built - Commit *commit.Commit + Commit *model.Commit } type Sender interface { diff --git a/plugin/notify/slack_test.go b/plugin/notify/slack_test.go index 4e8a2f617..48d795bc1 100644 --- a/plugin/notify/slack_test.go +++ b/plugin/notify/slack_test.go @@ -1,20 +1,19 @@ package notify import ( - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/repo" + "github.com/drone/drone/shared/model" "testing" ) func Test_getBuildUrl(t *testing.T) { c := &Context{ Host: "http://examplehost.com", - Repo: &repo.Repo{ + Repo: &model.Repo{ Host: "examplegit.com", Owner: "owner", Name: "repo", }, - Commit: &commit.Commit{ + Commit: &model.Commit{ Sha: "abc", Branch: "example", }, diff --git a/plugin/notify/webhook.go b/plugin/notify/webhook.go index b382a2c9a..a18493270 100644 --- a/plugin/notify/webhook.go +++ b/plugin/notify/webhook.go @@ -5,9 +5,7 @@ import ( "encoding/json" "net/http" - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/shared/model" ) type Webhook struct { @@ -31,9 +29,9 @@ func (w *Webhook) Send(context *Context) error { func (w *Webhook) send(context *Context) error { // data will get posted in this format data := struct { - Owner *user.User `json:"owner"` - Repo *repo.Repo `json:"repository"` - Commit *commit.Commit `json:"commit"` + Owner *model.User `json:"owner"` + Repo *model.Repo `json:"repository"` + Commit *model.Commit `json:"commit"` }{context.User, context.Repo, context.Commit} // data json encoded diff --git a/server/resource/commit/manager.go b/server/database/commit.go similarity index 66% rename from server/resource/commit/manager.go rename to server/database/commit.go index 96bf8766d..2e6a101fd 100644 --- a/server/resource/commit/manager.go +++ b/server/database/commit.go @@ -1,48 +1,49 @@ -package commit +package database import ( "database/sql" "time" + "github.com/drone/drone/shared/model" "github.com/russross/meddler" ) type CommitManager interface { // Find finds the commit by ID. - Find(id int64) (*Commit, error) + Find(id int64) (*model.Commit, error) // FindSha finds the commit for the branch and sha. - FindSha(repo int64, branch, sha string) (*Commit, error) + FindSha(repo int64, branch, sha string) (*model.Commit, error) // FindLatest finds the most recent commit for the branch. - FindLatest(repo int64, branch string) (*Commit, error) + FindLatest(repo int64, branch string) (*model.Commit, error) // FindOutput finds the commit's output. FindOutput(commit int64) ([]byte, error) // List finds recent commits for the repository - List(repo int64) ([]*Commit, error) + List(repo int64) ([]*model.Commit, error) // ListBranch finds recent commits for the repository and branch. - ListBranch(repo int64, branch string) ([]*Commit, error) + ListBranch(repo int64, branch string) ([]*model.Commit, error) // ListBranches finds most recent commit for each branch. - ListBranches(repo int64) ([]*Commit, error) + ListBranches(repo int64) ([]*model.Commit, error) // ListUser finds most recent commits for a user. - ListUser(repo int64) ([]*CommitRepo, error) + ListUser(repo int64) ([]*model.CommitRepo, error) // Insert persists the commit to the datastore. - Insert(commit *Commit) error + Insert(commit *model.Commit) error // Update persists changes to the commit to the datastore. - Update(commit *Commit) error + Update(commit *model.Commit) error // UpdateOutput persists a commit's stdout to the datastore. - UpdateOutput(commit *Commit, out []byte) error + UpdateOutput(commit *model.Commit, out []byte) error // Delete removes the commit from the datastore. - Delete(commit *Commit) error + Delete(commit *model.Commit) error // CancelAll will update the status of all Started or Pending // builds to a status of Killed (cancelled). @@ -54,9 +55,9 @@ type commitManager struct { *sql.DB } -// NewManager initiales a new CommitManager intended to +// NewCommitManager initiales a new CommitManager intended to // manage and persist commits. -func NewManager(db *sql.DB) CommitManager { +func NewCommitManager(db *sql.DB) CommitManager { return &commitManager{db} } @@ -84,7 +85,7 @@ LIMIT 20 ` // SQL query to retrieve the latest Commits for a user's repositories. -const listUserQuery = ` +const listUserCommitsQuery = ` SELECT r.repo_remote, r.repo_host, r.repo_owner, r.repo_name, c.* FROM commits c, repos r, perms p WHERE c.repo_id=r.repo_id @@ -96,7 +97,7 @@ LIMIT 20 ` // SQL query to retrieve the latest Commits across all branches. -const listQuery = ` +const listCommitsQuery = ` SELECT * FROM commits WHERE repo_id=? @@ -105,7 +106,7 @@ LIMIT 20 ` // SQL query to retrieve a Commit by branch and sha. -const findQuery = ` +const findCommitQuery = ` SELECT * FROM commits WHERE repo_id=? @@ -115,7 +116,7 @@ LIMIT 1 ` // SQL query to retrieve the most recent Commit for a branch. -const findLatestQuery = ` +const findLatestCommitQuery = ` SELECT * FROM commits WHERE commit_id IN ( @@ -143,12 +144,12 @@ UPDATE output SET output_raw = ? WHERE commit_id = ?; ` // SQL statement to delete a Commit by ID. -const deleteStmt = ` +const deleteCommitStmt = ` DELETE FROM commits WHERE commit_id = ?; ` // SQL statement to cancel all running Commits. -const cancelStmt = ` +const cancelCommitStmt = ` UPDATE commits SET commit_status = ?, commit_started = ?, @@ -156,21 +157,21 @@ commit_finished = ? WHERE commit_status IN ('Started', 'Pending'); ` -func (db *commitManager) Find(id int64) (*Commit, error) { - dst := Commit{} +func (db *commitManager) Find(id int64) (*model.Commit, error) { + dst := model.Commit{} err := meddler.Load(db, "commits", &dst, id) return &dst, err } -func (db *commitManager) FindSha(repo int64, branch, sha string) (*Commit, error) { - dst := Commit{} - err := meddler.QueryRow(db, &dst, findQuery, repo, branch, sha) +func (db *commitManager) FindSha(repo int64, branch, sha string) (*model.Commit, error) { + dst := model.Commit{} + err := meddler.QueryRow(db, &dst, findCommitQuery, repo, branch, sha) return &dst, err } -func (db *commitManager) FindLatest(repo int64, branch string) (*Commit, error) { - dst := Commit{} - err := meddler.QueryRow(db, &dst, findLatestQuery, repo, branch) +func (db *commitManager) FindLatest(repo int64, branch string) (*model.Commit, error) { + dst := model.Commit{} + err := meddler.QueryRow(db, &dst, findLatestCommitQuery, repo, branch) return &dst, err } @@ -180,42 +181,42 @@ func (db *commitManager) FindOutput(commit int64) ([]byte, error) { return []byte(dst), err } -func (db *commitManager) List(repo int64) ([]*Commit, error) { - var dst []*Commit - err := meddler.QueryAll(db, &dst, listQuery, repo) +func (db *commitManager) List(repo int64) ([]*model.Commit, error) { + var dst []*model.Commit + err := meddler.QueryAll(db, &dst, listCommitsQuery, repo) return dst, err } -func (db *commitManager) ListBranch(repo int64, branch string) ([]*Commit, error) { - var dst []*Commit +func (db *commitManager) ListBranch(repo int64, branch string) ([]*model.Commit, error) { + var dst []*model.Commit err := meddler.QueryAll(db, &dst, listBranchQuery, repo, branch) return dst, err } -func (db *commitManager) ListBranches(repo int64) ([]*Commit, error) { - var dst []*Commit +func (db *commitManager) ListBranches(repo int64) ([]*model.Commit, error) { + var dst []*model.Commit err := meddler.QueryAll(db, &dst, listBranchesQuery, repo) return dst, err } -func (db *commitManager) ListUser(user int64) ([]*CommitRepo, error) { - var dst []*CommitRepo - err := meddler.QueryAll(db, &dst, listUserQuery, user) +func (db *commitManager) ListUser(user int64) ([]*model.CommitRepo, error) { + var dst []*model.CommitRepo + err := meddler.QueryAll(db, &dst, listUserCommitsQuery, user) return dst, err } -func (db *commitManager) Insert(commit *Commit) error { +func (db *commitManager) Insert(commit *model.Commit) error { commit.Created = time.Now().Unix() commit.Updated = time.Now().Unix() return meddler.Insert(db, "commits", commit) } -func (db *commitManager) Update(commit *Commit) error { +func (db *commitManager) Update(commit *model.Commit) error { commit.Updated = time.Now().Unix() return meddler.Update(db, "commits", commit) } -func (db *commitManager) UpdateOutput(commit *Commit, out []byte) error { +func (db *commitManager) UpdateOutput(commit *model.Commit, out []byte) error { _, err := db.Exec(insertOutputStmt, commit.ID, out) if err != nil { return nil @@ -224,12 +225,12 @@ func (db *commitManager) UpdateOutput(commit *Commit, out []byte) error { return err } -func (db *commitManager) Delete(commit *Commit) error { - _, err := db.Exec(deleteStmt, commit.ID) +func (db *commitManager) Delete(commit *model.Commit) error { + _, err := db.Exec(deleteCommitStmt, commit.ID) return err } func (db *commitManager) CancelAll() error { - _, err := db.Exec(cancelStmt, StatusKilled, time.Now().Unix(), time.Now().Unix()) + _, err := db.Exec(cancelCommitStmt, model.StatusKilled, time.Now().Unix(), time.Now().Unix()) return err } diff --git a/server/resource/commit/manager_test.go b/server/database/commit_test.go similarity index 79% rename from server/resource/commit/manager_test.go rename to server/database/commit_test.go index 4bda13355..a19908179 100644 --- a/server/resource/commit/manager_test.go +++ b/server/database/commit_test.go @@ -1,35 +1,18 @@ -package commit +package database import ( "database/sql" "testing" "time" - "github.com/drone/drone/server/database/schema" - "github.com/drone/drone/server/database/testdata" - "github.com/drone/drone/server/database/testdatabase" + "github.com/drone/drone/shared/model" ) -// in-memory database instance for unit testing -var db *sql.DB - -// setup the test database and test fixtures -func setup() { - db, _ = testdatabase.Open() - schema.Load(db) - testdata.Load(db) -} - -// teardown the test database -func teardown() { - db.Close() -} - -func TestFind(t *testing.T) { +func TestCommitFind(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) commit, err := commits.Find(3) if err != nil { t.Errorf("Want Commit from ID, got %s", err) @@ -38,11 +21,11 @@ func TestFind(t *testing.T) { testCommit(t, commit) } -func TestFindSha(t *testing.T) { +func TestCommitFindSha(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) commit, err := commits.FindSha(2, "master", "7253f6545caed41fb8f5a6fcdb3abc0b81fa9dbf") if err != nil { t.Errorf("Want Commit from SHA, got %s", err) @@ -51,11 +34,11 @@ func TestFindSha(t *testing.T) { testCommit(t, commit) } -func TestFindLatest(t *testing.T) { +func TestCommitFindLatest(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) commit, err := commits.FindLatest(2, "master") if err != nil { t.Errorf("Want Latest Commit, got %s", err) @@ -64,11 +47,11 @@ func TestFindLatest(t *testing.T) { testCommit(t, commit) } -func TestFindOutput(t *testing.T) { +func TestCommitFindOutput(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) out, err := commits.FindOutput(1) if err != nil { t.Errorf("Want Commit stdout, got %s", err) @@ -80,11 +63,11 @@ func TestFindOutput(t *testing.T) { } } -func TestList(t *testing.T) { +func TestCommitList(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) list, err := commits.List(2) if err != nil { t.Errorf("Want List from RepoID, got %s", err) @@ -98,11 +81,11 @@ func TestList(t *testing.T) { testCommit(t, list[0]) } -func TestListBranch(t *testing.T) { +func TestCommitListBranch(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) list, err := commits.ListBranch(2, "master") if err != nil { t.Errorf("Want List from RepoID, got %s", err) @@ -116,11 +99,11 @@ func TestListBranch(t *testing.T) { testCommit(t, list[0]) } -func TestListBranches(t *testing.T) { +func TestCommitListBranches(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) list, err := commits.ListBranches(2) if err != nil { t.Errorf("Want Branch List from RepoID, got %s", err) @@ -134,35 +117,35 @@ func TestListBranches(t *testing.T) { testCommit(t, list[1]) } -func TestInsert(t *testing.T) { +func TestCommitInsert(t *testing.T) { setup() defer teardown() - commit := Commit{RepoID: 3, Branch: "foo", Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac"} - commits := NewManager(db) + commit := model.Commit{RepoID: 3, Branch: "foo", Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac"} + commits := NewCommitManager(db) if err := commits.Insert(&commit); err != nil { t.Errorf("Want Commit created, got %s", err) } // verify that it is ok to add same sha for different branch - var err = commits.Insert(&Commit{RepoID: 3, Branch: "bar", Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac"}) + var err = commits.Insert(&model.Commit{RepoID: 3, Branch: "bar", Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac"}) if err != nil { t.Errorf("Want Commit created, got %s", err) } // verify unique remote + remote id constraint - err = commits.Insert(&Commit{RepoID: 3, Branch: "bar", Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac"}) + err = commits.Insert(&model.Commit{RepoID: 3, Branch: "bar", Sha: "85f8c029b902ed9400bc600bac301a0aadb144ac"}) if err == nil { t.Error("Want unique constraint violated") } } -func TestUpdate(t *testing.T) { +func TestCommitUpdate(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) commit, err := commits.Find(5) if err != nil { t.Errorf("Want Commit from ID, got %s", err) @@ -198,11 +181,11 @@ func TestUpdate(t *testing.T) { } } -func TestDelete(t *testing.T) { +func TestCommitDelete(t *testing.T) { setup() defer teardown() - commits := NewManager(db) + commits := NewCommitManager(db) commit, err := commits.Find(1) if err != nil { t.Errorf("Want Commit from ID, got %s", err) @@ -221,7 +204,7 @@ func TestDelete(t *testing.T) { // testCommit is a helper function that compares the commit // to an expected set of fixed field values. -func testCommit(t *testing.T, commit *Commit) { +func testCommit(t *testing.T, commit *model.Commit) { var got, want = commit.Status, "Success" if got != want { t.Errorf("Want Status %v, got %v", want, got) diff --git a/server/resource/perm/manager.go b/server/database/perm.go similarity index 67% rename from server/resource/perm/manager.go rename to server/database/perm.go index 84d5f8752..d10fe339e 100644 --- a/server/resource/perm/manager.go +++ b/server/database/perm.go @@ -1,33 +1,32 @@ -package perm +package database import ( "database/sql" "time" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/shared/model" "github.com/russross/meddler" ) type PermManager interface { // Grant will grant the user read, write and admin persmissions // to the specified repository. - Grant(u *user.User, r *repo.Repo, read, write, admin bool) error + Grant(u *model.User, r *model.Repo, read, write, admin bool) error // Revoke will revoke all user permissions to the specified repository. - Revoke(u *user.User, r *repo.Repo) error + Revoke(u *model.User, r *model.Repo) error // Read returns true if the specified user has read // access to the repository. - Read(u *user.User, r *repo.Repo) (bool, error) + Read(u *model.User, r *model.Repo) (bool, error) // Write returns true if the specified user has write // access to the repository. - Write(u *user.User, r *repo.Repo) (bool, error) + Write(u *model.User, r *model.Repo) (bool, error) // Admin returns true if the specified user is an // administrator of the repository. - Admin(u *user.User, r *repo.Repo) (bool, error) + Admin(u *model.User, r *model.Repo) (bool, error) } // permManager manages user permissions to access repositories. @@ -37,7 +36,7 @@ type permManager struct { // SQL query to retrieve a user's permission to // access a repository. -const findQuery = ` +const findPermQuery = ` SELECT * FROM perms WHERE user_id=? @@ -46,19 +45,30 @@ LIMIT 1 ` // SQL statement to delete a permission. -const deleteStmt = ` +const deletePermStmt = ` DELETE FROM perms WHERE user_id=? AND repo_id=? ` +type perm struct { + ID int64 `meddler:"perm_id,pk"` + UserID int64 `meddler:"user_id"` + RepoID int64 `meddler:"repo_id"` + Read bool `meddler:"perm_read"` + Write bool `meddler:"perm_write"` + Admin bool `meddler:"perm_admin"` + Created int64 `meddler:"perm_created"` + Updated int64 `meddler:"perm_updated"` +} + // NewManager initiales a new PermManager intended to // manage user permission and access control. -func NewManager(db *sql.DB) PermManager { +func NewPermManager(db *sql.DB) PermManager { return &permManager{db} } // Grant will grant the user read, write and admin persmissions // to the specified repository. -func (db *permManager) Grant(u *user.User, r *repo.Repo, read, write, admin bool) error { +func (db *permManager) Grant(u *model.User, r *model.Repo, read, write, admin bool) error { // attempt to get existing permissions from the database perm, err := db.find(u, r) if err != nil && err != sql.ErrNoRows { @@ -84,12 +94,12 @@ func (db *permManager) Grant(u *user.User, r *repo.Repo, read, write, admin bool } // Revoke will revoke all user permissions to the specified repository. -func (db *permManager) Revoke(u *user.User, r *repo.Repo) error { - _, err := db.Exec(deleteStmt, u.ID, r.ID) +func (db *permManager) Revoke(u *model.User, r *model.Repo) error { + _, err := db.Exec(deletePermStmt, u.ID, r.ID) return err } -func (db *permManager) Read(u *user.User, r *repo.Repo) (bool, error) { +func (db *permManager) Read(u *model.User, r *model.Repo) (bool, error) { switch { // if the repo is public, grant access. case r.Private == false: @@ -107,7 +117,7 @@ func (db *permManager) Read(u *user.User, r *repo.Repo) (bool, error) { return perm.Read, err } -func (db *permManager) Write(u *user.User, r *repo.Repo) (bool, error) { +func (db *permManager) Write(u *model.User, r *model.Repo) (bool, error) { switch { // if the user is nil, deny access case u == nil: @@ -122,7 +132,7 @@ func (db *permManager) Write(u *user.User, r *repo.Repo) (bool, error) { return perm.Write, err } -func (db *permManager) Admin(u *user.User, r *repo.Repo) (bool, error) { +func (db *permManager) Admin(u *model.User, r *model.Repo) (bool, error) { switch { // if the user is nil, deny access case u == nil: @@ -137,8 +147,8 @@ func (db *permManager) Admin(u *user.User, r *repo.Repo) (bool, error) { return perm.Admin, err } -func (db *permManager) find(u *user.User, r *repo.Repo) (*perm, error) { +func (db *permManager) find(u *model.User, r *model.Repo) (*perm, error) { var dst = perm{} - var err = meddler.QueryRow(db, &dst, findQuery, u.ID, r.ID) + var err = meddler.QueryRow(db, &dst, findPermQuery, u.ID, r.ID) return &dst, err } diff --git a/server/resource/perm/manager_test.go b/server/database/perm_test.go similarity index 83% rename from server/resource/perm/manager_test.go rename to server/database/perm_test.go index c7f138db6..cf107741c 100644 --- a/server/resource/perm/manager_test.go +++ b/server/database/perm_test.go @@ -1,37 +1,18 @@ -package perm +package database import ( "database/sql" "testing" - "github.com/drone/drone/server/database/schema" - "github.com/drone/drone/server/database/testdata" - "github.com/drone/drone/server/database/testdatabase" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/shared/model" ) -// in-memory database instance for unit testing -var db *sql.DB - -// setup the test database and test fixtures -func setup() { - db, _ = testdatabase.Open() - schema.Load(db) - testdata.Load(db) -} - -// teardown the test database -func teardown() { - db.Close() -} - func Test_find(t *testing.T) { setup() defer teardown() - manager := NewManager(db).(*permManager) - perm, err := manager.find(&user.User{ID: 101}, &repo.Repo{ID: 200}) + manager := NewPermManager(db).(*permManager) + perm, err := manager.find(&model.User{ID: 101}, &model.Repo{ID: 200}) if err != nil { t.Errorf("Want permission, got %s", err) } @@ -78,20 +59,20 @@ func Test_find(t *testing.T) { // test that we get the appropriate error message when // no permissions are found in the database. - _, err = manager.find(&user.User{ID: 102}, &repo.Repo{ID: 201}) + _, err = manager.find(&model.User{ID: 102}, &model.Repo{ID: 201}) if err != sql.ErrNoRows { t.Errorf("Want ErrNoRows, got %s", err) } } -func TestRead(t *testing.T) { +func TestPermRead(t *testing.T) { setup() defer teardown() - var manager = NewManager(db) + var manager = NewPermManager(db) // dummy admin and repo - u := user.User{ID: 101, Admin: false} - r := repo.Repo{ID: 201, Private: false} + u := model.User{ID: 101, Admin: false} + r := model.Repo{ID: 201, Private: false} // public repos should always be accessible if read, err := manager.Read(&u, &r); !read || err != nil { @@ -131,14 +112,14 @@ func TestRead(t *testing.T) { } } -func TestWrite(t *testing.T) { +func TestPermWrite(t *testing.T) { setup() defer teardown() - var manager = NewManager(db) + var manager = NewPermManager(db) // dummy admin and repo - u := user.User{ID: 101, Admin: false} - r := repo.Repo{ID: 201, Private: false} + u := model.User{ID: 101, Admin: false} + r := model.Repo{ID: 201, Private: false} // repos should not be accessible to nil users r.Private = true @@ -172,14 +153,14 @@ func TestWrite(t *testing.T) { } } -func TestAdmin(t *testing.T) { +func TestPermAdmin(t *testing.T) { setup() defer teardown() - var manager = NewManager(db) + var manager = NewPermManager(db) // dummy admin and repo - u := user.User{ID: 101, Admin: false} - r := repo.Repo{ID: 201, Private: false} + u := model.User{ID: 101, Admin: false} + r := model.Repo{ID: 201, Private: false} // repos should not be accessible to nil users r.Private = true @@ -213,15 +194,15 @@ func TestAdmin(t *testing.T) { } } -func TestRevoke(t *testing.T) { +func TestPermRevoke(t *testing.T) { setup() defer teardown() // dummy admin and repo - u := user.User{ID: 101} - r := repo.Repo{ID: 200} + u := model.User{ID: 101} + r := model.Repo{ID: 200} - manager := NewManager(db) + manager := NewPermManager(db) admin, err := manager.Admin(&u, &r) if !admin || err != nil { t.Errorf("Want Admin permission, got Admin %v, error %s", admin, err) @@ -238,15 +219,15 @@ func TestRevoke(t *testing.T) { } } -func TestGrant(t *testing.T) { +func TestPermGrant(t *testing.T) { setup() defer teardown() // dummy admin and repo - u := user.User{ID: 104} - r := repo.Repo{ID: 200} + u := model.User{ID: 104} + r := model.Repo{ID: 200} - manager := NewManager(db).(*permManager) + manager := NewPermManager(db).(*permManager) if err := manager.Grant(&u, &r, true, true, true); err != nil { t.Errorf("Want permissions granted, got %s", err) } diff --git a/server/resource/repo/manager.go b/server/database/repo.go similarity index 59% rename from server/resource/repo/manager.go rename to server/database/repo.go index 87c8cc7b5..88a364674 100644 --- a/server/resource/repo/manager.go +++ b/server/database/repo.go @@ -1,36 +1,37 @@ -package repo +package database import ( "database/sql" "time" + "github.com/drone/drone/shared/model" "github.com/russross/meddler" ) type RepoManager interface { // Find retrieves the Repo by ID. - Find(id int64) (*Repo, error) + Find(id int64) (*model.Repo, error) // FindName retrieves the Repo by the remote, owner and name. - FindName(remote, owner, name string) (*Repo, error) + FindName(remote, owner, name string) (*model.Repo, error) // Insert persists a new Repo to the datastore. - Insert(repo *Repo) error + Insert(repo *model.Repo) error // Insert persists a modified Repo to the datastore. - Update(repo *Repo) error + Update(repo *model.Repo) error // Delete removes a Repo from the datastore. - Delete(repo *Repo) error + Delete(repo *model.Repo) error // List retrieves all repositories from the datastore. - List(user int64) ([]*Repo, error) + List(user int64) ([]*model.Repo, error) // List retrieves all public repositories from the datastore. //ListPublic(user int64) ([]*Repo, error) } -func NewManager(db *sql.DB) RepoManager { +func NewRepoManager(db *sql.DB) RepoManager { return &repoManager{db} } @@ -38,46 +39,39 @@ type repoManager struct { *sql.DB } -func (db *repoManager) Find(id int64) (*Repo, error) { +func (db *repoManager) Find(id int64) (*model.Repo, error) { const query = "select * from repos where repo_id = ?" - var repo = Repo{} + var repo = model.Repo{} var err = meddler.QueryRow(db, &repo, query, id) return &repo, err } -func (db *repoManager) FindName(remote, owner, name string) (*Repo, error) { +func (db *repoManager) FindName(remote, owner, name string) (*model.Repo, error) { const query = "select * from repos where repo_host = ? and repo_owner = ? and repo_name = ?" - var repo = Repo{} + var repo = model.Repo{} var err = meddler.QueryRow(db, &repo, query, remote, owner, name) return &repo, err } -func (db *repoManager) List(user int64) ([]*Repo, error) { +func (db *repoManager) List(user int64) ([]*model.Repo, error) { const query = "select * from repos where repo_id IN (select repo_id from perms where user_id = ?)" - var repos []*Repo + var repos []*model.Repo err := meddler.QueryAll(db, &repos, query, user) return repos, err } -//func (db *repoManager) ListPublic(user int64) ([]*Repo, error) { -// const query = "select * from repos where repo_id IN (select repo_id from perms where user_id = ?) AND repo_private=0" -// var repos []*Repo -// err := meddler.QueryAll(db, &repos, query, user) -// return repos, err -//} - -func (db *repoManager) Insert(repo *Repo) error { +func (db *repoManager) Insert(repo *model.Repo) error { repo.Created = time.Now().Unix() repo.Updated = time.Now().Unix() return meddler.Insert(db, "repos", repo) } -func (db *repoManager) Update(repo *Repo) error { +func (db *repoManager) Update(repo *model.Repo) error { repo.Updated = time.Now().Unix() return meddler.Update(db, "repos", repo) } -func (db *repoManager) Delete(repo *Repo) error { +func (db *repoManager) Delete(repo *model.Repo) error { const stmt = "delete from repos where repo_id = ?" _, err := db.Exec(stmt, repo.ID) return err diff --git a/server/resource/repo/manager_test.go b/server/database/repo_test.go similarity index 82% rename from server/resource/repo/manager_test.go rename to server/database/repo_test.go index 46d3f73e5..bc039adbc 100644 --- a/server/resource/repo/manager_test.go +++ b/server/database/repo_test.go @@ -1,34 +1,17 @@ -package repo +package database import ( "database/sql" "testing" - "github.com/drone/drone/server/database/schema" - "github.com/drone/drone/server/database/testdata" - "github.com/drone/drone/server/database/testdatabase" + "github.com/drone/drone/shared/model" ) -// in-memory database instance for unit testing -var db *sql.DB - -// setup the test database and test fixtures -func setup() { - db, _ = testdatabase.Open() - schema.Load(db) - testdata.Load(db) -} - -// teardown the test database -func teardown() { - db.Close() -} - -func TestFind(t *testing.T) { +func TestRepoFind(t *testing.T) { setup() defer teardown() - repos := NewManager(db) + repos := NewRepoManager(db) repo, err := repos.Find(1) if err != nil { t.Errorf("Want Repo from ID, got %s", err) @@ -37,11 +20,11 @@ func TestFind(t *testing.T) { testRepo(t, repo) } -func TestName(t *testing.T) { +func TestRepoFindName(t *testing.T) { setup() defer teardown() - repos := NewManager(db) + repos := NewRepoManager(db) user, err := repos.FindName("github.com", "lhofstadter", "lenwoloppali") if err != nil { t.Errorf("Want Repo by Name, got %s", err) @@ -50,11 +33,11 @@ func TestName(t *testing.T) { testRepo(t, user) } -func TestList(t *testing.T) { +func TestRepoList(t *testing.T) { setup() defer teardown() - repos := NewManager(db) + repos := NewRepoManager(db) all, err := repos.List(1) if err != nil { t.Errorf("Want Repos, got %s", err) @@ -68,28 +51,28 @@ func TestList(t *testing.T) { testRepo(t, all[0]) } -func TestInsert(t *testing.T) { +func TestRepoInsert(t *testing.T) { setup() defer teardown() - repo, _ := New("github.com", "mrwolowitz", "lenwoloppali") - repos := NewManager(db) + repo, _ := model.NewRepo("github.com", "mrwolowitz", "lenwoloppali") + repos := NewRepoManager(db) if err := repos.Insert(repo); err != nil { t.Errorf("Want Repo created, got %s", err) } // verify unique remote + owner + name login constraint - var err = repos.Insert(&Repo{Host: repo.Host, Owner: repo.Owner, Name: repo.Name}) + var err = repos.Insert(&model.Repo{Host: repo.Host, Owner: repo.Owner, Name: repo.Name}) if err == nil { t.Error("Want unique constraint violated") } } -func TestUpdate(t *testing.T) { +func TestRepoUpdate(t *testing.T) { setup() defer teardown() - repos := NewManager(db) + repos := NewRepoManager(db) repo, err := repos.Find(1) if err != nil { t.Errorf("Want Repo from ID, got %s", err) @@ -132,11 +115,11 @@ func TestUpdate(t *testing.T) { } } -func TestDelete(t *testing.T) { +func TestRepoDelete(t *testing.T) { setup() defer teardown() - repos := NewManager(db) + repos := NewRepoManager(db) repo, err := repos.Find(1) if err != nil { t.Errorf("Want Repo from ID, got %s", err) @@ -155,7 +138,7 @@ func TestDelete(t *testing.T) { // testRepo is a helper function that compares the repo // to an expected set of fixed field values. -func testRepo(t *testing.T, repo *Repo) { +func testRepo(t *testing.T, repo *model.Repo) { var got, want = repo.Remote, "github.com" if got != want { t.Errorf("Want Remote %v, got %v", want, got) diff --git a/server/resource/user/manager.go b/server/database/user.go similarity index 50% rename from server/resource/user/manager.go rename to server/database/user.go index 61dd3d233..7268c0071 100644 --- a/server/resource/user/manager.go +++ b/server/database/user.go @@ -1,33 +1,34 @@ -package user +package database import ( "database/sql" "time" + "github.com/drone/drone/shared/model" "github.com/russross/meddler" ) type UserManager interface { // Find finds the User by ID. - Find(id int64) (*User, error) + Find(id int64) (*model.User, error) // FindLogin finds the User by remote login. - FindLogin(remote, login string) (*User, error) + FindLogin(remote, login string) (*model.User, error) // FindToken finds the User by token. - FindToken(token string) (*User, error) + FindToken(token string) (*model.User, error) // List finds all registered users of the system. - List() ([]*User, error) + List() ([]*model.User, error) // Insert persists the User to the datastore. - Insert(user *User) error + Insert(user *model.User) error // Update persists changes to the User to the datastore. - Update(user *User) error + Update(user *model.User) error // Delete removes the User from the datastore. - Delete(user *User) error + Delete(user *model.User) error } // userManager manages a list of users in a SQL database. @@ -36,7 +37,7 @@ type userManager struct { } // SQL query to retrieve a User by remote login. -const findLoginQuery = ` +const findUserLoginQuery = ` SELECT * FROM users WHERE user_remote=? @@ -45,7 +46,7 @@ LIMIT 1 ` // SQL query to retrieve a User by remote login. -const findTokenQuery = ` +const findUserTokenQuery = ` SELECT * FROM users WHERE user_token=? @@ -53,59 +54,59 @@ LIMIT 1 ` // SQL query to retrieve a list of all users. -const listQuery = ` +const listUserQuery = ` SELECT * FROM users ORDER BY user_name ASC ` // SQL statement to delete a User by ID. -const deleteStmt = ` +const deleteUserStmt = ` DELETE FROM users WHERE user_id=? ` -// NewManager initiales a new UserManager intended to +// NewUserManager initiales a new UserManager intended to // manage and persist commits. -func NewManager(db *sql.DB) UserManager { +func NewUserManager(db *sql.DB) UserManager { return &userManager{db} } -func (db *userManager) Find(id int64) (*User, error) { - dst := User{} +func (db *userManager) Find(id int64) (*model.User, error) { + dst := model.User{} err := meddler.Load(db, "users", &dst, id) return &dst, err } -func (db *userManager) FindLogin(remote, login string) (*User, error) { - dst := User{} - err := meddler.QueryRow(db, &dst, findLoginQuery, remote, login) +func (db *userManager) FindLogin(remote, login string) (*model.User, error) { + dst := model.User{} + err := meddler.QueryRow(db, &dst, findUserLoginQuery, remote, login) return &dst, err } -func (db *userManager) FindToken(token string) (*User, error) { - dst := User{} - err := meddler.QueryRow(db, &dst, findTokenQuery, token) +func (db *userManager) FindToken(token string) (*model.User, error) { + dst := model.User{} + err := meddler.QueryRow(db, &dst, findUserTokenQuery, token) return &dst, err } -func (db *userManager) List() ([]*User, error) { - var dst []*User - err := meddler.QueryAll(db, &dst, listQuery) +func (db *userManager) List() ([]*model.User, error) { + var dst []*model.User + err := meddler.QueryAll(db, &dst, listUserQuery) return dst, err } -func (db *userManager) Insert(user *User) error { +func (db *userManager) Insert(user *model.User) error { user.Created = time.Now().Unix() user.Updated = time.Now().Unix() return meddler.Insert(db, "users", user) } -func (db *userManager) Update(user *User) error { +func (db *userManager) Update(user *model.User) error { user.Updated = time.Now().Unix() return meddler.Update(db, "users", user) } -func (db *userManager) Delete(user *User) error { - _, err := db.Exec(deleteStmt, user.ID) +func (db *userManager) Delete(user *model.User) error { + _, err := db.Exec(deleteUserStmt, user.ID) return err } diff --git a/server/resource/user/manager_test.go b/server/database/user_test.go similarity index 84% rename from server/resource/user/manager_test.go rename to server/database/user_test.go index 17fb9a6c8..c36c5f9a8 100644 --- a/server/resource/user/manager_test.go +++ b/server/database/user_test.go @@ -1,4 +1,4 @@ -package user +package database import ( "database/sql" @@ -7,6 +7,7 @@ import ( "github.com/drone/drone/server/database/schema" "github.com/drone/drone/server/database/testdata" "github.com/drone/drone/server/database/testdatabase" + "github.com/drone/drone/shared/model" ) // in-memory database instance for unit testing @@ -24,11 +25,11 @@ func teardown() { db.Close() } -func TestFind(t *testing.T) { +func TestUserFind(t *testing.T) { setup() defer teardown() - users := NewManager(db) + users := NewUserManager(db) user, err := users.Find(1) if err != nil { t.Errorf("Want User from ID, got %s", err) @@ -37,11 +38,11 @@ func TestFind(t *testing.T) { testUser(t, user) } -func TestFindLogin(t *testing.T) { +func TestUserFindLogin(t *testing.T) { setup() defer teardown() - users := NewManager(db) + users := NewUserManager(db) user, err := users.FindLogin("github.com", "smellypooper") if err != nil { t.Errorf("Want User from Login, got %s", err) @@ -50,11 +51,11 @@ func TestFindLogin(t *testing.T) { testUser(t, user) } -func TestFindToken(t *testing.T) { +func TestUserFindToken(t *testing.T) { setup() defer teardown() - users := NewManager(db) + users := NewUserManager(db) user, err := users.FindToken("e42080dddf012c718e476da161d21ad5") if err != nil { t.Errorf("Want User from Token, got %s", err) @@ -63,11 +64,11 @@ func TestFindToken(t *testing.T) { testUser(t, user) } -func TestList(t *testing.T) { +func TestUserList(t *testing.T) { setup() defer teardown() - users := NewManager(db) + users := NewUserManager(db) all, err := users.List() if err != nil { t.Errorf("Want Users, got %s", err) @@ -81,12 +82,12 @@ func TestList(t *testing.T) { testUser(t, all[0]) } -func TestInsert(t *testing.T) { +func TestUserInsert(t *testing.T) { setup() defer teardown() - user := New("github.com", "winkle", "winkle@caltech.edu") - users := NewManager(db) + user := model.NewUser("github.com", "winkle", "winkle@caltech.edu") + users := NewUserManager(db) if err := users.Insert(user); err != nil { t.Errorf("Want User created, got %s", err) } @@ -97,23 +98,23 @@ func TestInsert(t *testing.T) { } // verify unique remote + remote login constraint - var err = users.Insert(&User{Remote: user.Remote, Login: user.Login, Token: "f71eb4a81a2cca56035dd7f6f2942e41"}) + var err = users.Insert(&model.User{Remote: user.Remote, Login: user.Login, Token: "f71eb4a81a2cca56035dd7f6f2942e41"}) if err == nil { t.Error("Want Token unique constraint violated") } // verify unique token constraint - err = users.Insert(&User{Remote: "gitlab.com", Login: user.Login, Token: user.Token}) + err = users.Insert(&model.User{Remote: "gitlab.com", Login: user.Login, Token: user.Token}) if err == nil { t.Error("Want Token unique constraint violated") } } -func TestUpdate(t *testing.T) { +func TestUserUpdate(t *testing.T) { setup() defer teardown() - users := NewManager(db) + users := NewUserManager(db) user, err := users.Find(4) if err != nil { t.Errorf("Want User from ID, got %s", err) @@ -138,11 +139,11 @@ func TestUpdate(t *testing.T) { } } -func TestDelete(t *testing.T) { +func TestUserDelete(t *testing.T) { setup() defer teardown() - users := NewManager(db) + users := NewUserManager(db) user, err := users.Find(1) if err != nil { t.Errorf("Want User from ID, got %s", err) @@ -161,7 +162,7 @@ func TestDelete(t *testing.T) { // testUser is a helper function that compares the user // to an expected set of fixed field values. -func testUser(t *testing.T, user *User) { +func testUser(t *testing.T, user *model.User) { var got, want = user.Login, "smellypooper" if got != want { t.Errorf("Want Token %v, got %v", want, got) diff --git a/server/handler/badge.go b/server/handler/badge.go index 103bb14f0..965e42753 100644 --- a/server/handler/badge.go +++ b/server/handler/badge.go @@ -4,8 +4,8 @@ import ( "net/http" "time" - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/repo" + "github.com/drone/drone/server/database" + "github.com/drone/drone/shared/model" "github.com/gorilla/pat" ) @@ -20,11 +20,11 @@ var ( ) type BadgeHandler struct { - commits commit.CommitManager - repos repo.RepoManager + commits database.CommitManager + repos database.RepoManager } -func NewBadgeHandler(repos repo.RepoManager, commits commit.CommitManager) *BadgeHandler { +func NewBadgeHandler(repos database.RepoManager, commits database.CommitManager) *BadgeHandler { return &BadgeHandler{commits, repos} } @@ -54,7 +54,7 @@ func (h *BadgeHandler) GetStatus(w http.ResponseWriter, r *http.Request) error { // if no branch, use the default if len(branch) == 0 { - branch = repo.DefaultBranch + branch = model.DefaultBranch } // get the latest commit @@ -69,13 +69,13 @@ func (h *BadgeHandler) GetStatus(w http.ResponseWriter, r *http.Request) error { // determine which badge to load switch c.Status { - case commit.StatusSuccess: + case model.StatusSuccess: w.Write(badgeSuccess) - case commit.StatusFailure: + case model.StatusFailure: w.Write(badgeFailure) - case commit.StatusError: + case model.StatusError: w.Write(badgeError) - case commit.StatusEnqueue, commit.StatusStarted: + case model.StatusEnqueue, model.StatusStarted: w.Write(badgeStarted) default: w.Write(badgeNone) diff --git a/server/handler/branch.go b/server/handler/branch.go index c94824283..190cd2322 100644 --- a/server/handler/branch.go +++ b/server/handler/branch.go @@ -4,21 +4,19 @@ import ( "encoding/json" "net/http" - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/perm" - "github.com/drone/drone/server/resource/repo" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/session" "github.com/gorilla/pat" ) type BranchHandler struct { - perms perm.PermManager - repos repo.RepoManager - commits commit.CommitManager + perms database.PermManager + repos database.RepoManager + commits database.CommitManager sess session.Session } -func NewBranchHandler(repos repo.RepoManager, commits commit.CommitManager, perms perm.PermManager, sess session.Session) *BranchHandler { +func NewBranchHandler(repos database.RepoManager, commits database.CommitManager, perms database.PermManager, sess session.Session) *BranchHandler { return &BranchHandler{perms, repos, commits, sess} } diff --git a/server/handler/commit.go b/server/handler/commit.go index 030a8535f..d47fc1567 100644 --- a/server/handler/commit.go +++ b/server/handler/commit.go @@ -4,23 +4,22 @@ import ( "encoding/json" "net/http" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/queue" - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/perm" - "github.com/drone/drone/server/resource/repo" "github.com/drone/drone/server/session" + "github.com/drone/drone/shared/model" "github.com/gorilla/pat" ) type CommitHandler struct { - perms perm.PermManager - repos repo.RepoManager - commits commit.CommitManager + perms database.PermManager + repos database.RepoManager + commits database.CommitManager sess session.Session queue *queue.Queue } -func NewCommitHandler(repos repo.RepoManager, commits commit.CommitManager, perms perm.PermManager, sess session.Session, queue *queue.Queue) *CommitHandler { +func NewCommitHandler(repos database.RepoManager, commits database.CommitManager, perms database.PermManager, sess session.Session, queue *queue.Queue) *CommitHandler { return &CommitHandler{perms, repos, commits, sess, queue} } @@ -146,11 +145,11 @@ func (h *CommitHandler) PostCommit(w http.ResponseWriter, r *http.Request) error } // we can't start an already started build - if c.Status == commit.StatusStarted || c.Status == commit.StatusEnqueue { + if c.Status == model.StatusStarted || c.Status == model.StatusEnqueue { return badRequest{} } - c.Status = commit.StatusEnqueue + c.Status = model.StatusEnqueue c.Started = 0 c.Finished = 0 c.Duration = 0 diff --git a/server/handler/hook.go b/server/handler/hook.go index feac90709..8b4f2916a 100644 --- a/server/handler/hook.go +++ b/server/handler/hook.go @@ -3,23 +3,22 @@ package handler import ( "net/http" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/queue" - "github.com/drone/drone/server/resource/commit" "github.com/drone/drone/server/resource/config" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/shared/model" "github.com/gorilla/pat" ) type HookHandler struct { - users user.UserManager - repos repo.RepoManager - commits commit.CommitManager + users database.UserManager + repos database.RepoManager + commits database.CommitManager queue *queue.Queue conf *config.Config } -func NewHookHandler(users user.UserManager, repos repo.RepoManager, commits commit.CommitManager, conf *config.Config, queue *queue.Queue) *HookHandler { +func NewHookHandler(users database.UserManager, repos database.RepoManager, commits database.CommitManager, conf *config.Config, queue *queue.Queue) *HookHandler { return &HookHandler{users, repos, commits, queue, conf} } @@ -76,9 +75,9 @@ func (h *HookHandler) PostHook(w http.ResponseWriter, r *http.Request) error { return badRequest{err} } - c := commit.Commit{ + c := model.Commit{ RepoID: repo.ID, - Status: commit.StatusEnqueue, + Status: model.StatusEnqueue, Sha: hook.Sha, Branch: hook.Branch, PullRequest: hook.PullRequest, diff --git a/server/handler/login.go b/server/handler/login.go index 640a64434..111b3b0a6 100644 --- a/server/handler/login.go +++ b/server/handler/login.go @@ -5,23 +5,22 @@ import ( "net/http" "time" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/resource/config" - "github.com/drone/drone/server/resource/perm" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" "github.com/drone/drone/server/session" + "github.com/drone/drone/shared/model" "github.com/gorilla/pat" ) type LoginHandler struct { - users user.UserManager - repos repo.RepoManager - perms perm.PermManager + users database.UserManager + repos database.RepoManager + perms database.PermManager sess session.Session conf *config.Config } -func NewLoginHandler(users user.UserManager, repos repo.RepoManager, perms perm.PermManager, sess session.Session, conf *config.Config) *LoginHandler { +func NewLoginHandler(users database.UserManager, repos database.RepoManager, perms database.PermManager, sess session.Session, conf *config.Config) *LoginHandler { return &LoginHandler{users, repos, perms, sess, conf} } @@ -56,7 +55,7 @@ func (h *LoginHandler) GetLogin(w http.ResponseWriter, r *http.Request) error { } // create the user account - u = user.New(remote.GetName(), login.Login, login.Email) + u = model.NewUser(remote.GetName(), login.Login, login.Email) u.Name = login.Name u.SetEmail(login.Email) @@ -86,7 +85,7 @@ func (h *LoginHandler) GetLogin(w http.ResponseWriter, r *http.Request) error { // TODO this should move to a server/sync package and // should be injected into this struct, just like // the database code. - if u.Stale() { + if u.IsStale() { log.Println("sync user account.", u.Login) // sync inside a goroutine. This should eventually be moved to @@ -109,7 +108,7 @@ func (h *LoginHandler) GetLogin(w http.ResponseWriter, r *http.Request) error { // insert all repositories for _, remoteRepo := range repos { - repo, _ := repo.New(remote.GetName(), remoteRepo.Owner, remoteRepo.Name) + repo, _ := model.NewRepo(remote.GetName(), remoteRepo.Owner, remoteRepo.Name) repo.Private = remoteRepo.Private repo.Host = remoteRepo.Host repo.CloneURL = remoteRepo.Clone diff --git a/server/handler/repo.go b/server/handler/repo.go index d161726ff..c1a996d99 100644 --- a/server/handler/repo.go +++ b/server/handler/repo.go @@ -5,10 +5,8 @@ import ( "fmt" "net/http" - "github.com/drone/drone/server/resource/commit" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/resource/config" - "github.com/drone/drone/server/resource/perm" - "github.com/drone/drone/server/resource/repo" "github.com/drone/drone/server/session" "github.com/drone/drone/shared/httputil" "github.com/drone/drone/shared/sshutil" @@ -17,14 +15,14 @@ import ( type RepoHandler struct { conf *config.Config - commits commit.CommitManager - perms perm.PermManager - repos repo.RepoManager + commits database.CommitManager + perms database.PermManager + repos database.RepoManager sess session.Session } -func NewRepoHandler(repos repo.RepoManager, commits commit.CommitManager, - perms perm.PermManager, sess session.Session, conf *config.Config) *RepoHandler { +func NewRepoHandler(repos database.RepoManager, commits database.CommitManager, + perms database.PermManager, sess session.Session, conf *config.Config) *RepoHandler { return &RepoHandler{conf, commits, perms, repos, sess} } diff --git a/server/handler/site.go b/server/handler/site.go index 883e00463..b670d3074 100644 --- a/server/handler/site.go +++ b/server/handler/site.go @@ -5,27 +5,25 @@ import ( "net/http" "github.com/drone/drone/server/channel" - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/perm" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/session" "github.com/drone/drone/shared/httputil" + "github.com/drone/drone/shared/model" "github.com/gorilla/pat" ) type Renderer func(wr io.Writer, name string, data interface{}) error type SiteHandler struct { - users user.UserManager - repos repo.RepoManager - commits commit.CommitManager - perms perm.PermManager + users database.UserManager + repos database.RepoManager + commits database.CommitManager + perms database.PermManager sess session.Session render Renderer } -func NewSiteHandler(users user.UserManager, repos repo.RepoManager, commits commit.CommitManager, perms perm.PermManager, sess session.Session, render Renderer) *SiteHandler { +func NewSiteHandler(users database.UserManager, repos database.RepoManager, commits database.CommitManager, perms database.PermManager, sess session.Session, render Renderer) *SiteHandler { return &SiteHandler{users, repos, commits, perms, sess, render} } @@ -39,15 +37,15 @@ func (s *SiteHandler) GetIndex(w http.ResponseWriter, r *http.Request) error { } feed, _ := s.commits.ListUser(u.ID) data := struct { - User *user.User - Feed []*commit.CommitRepo + User *model.User + Feed []*model.CommitRepo }{u, feed} return s.render(w, "user_feed.html", &data) } // GetLogin serves the account login page func (s *SiteHandler) GetLogin(w http.ResponseWriter, r *http.Request) error { - return s.render(w, "login.html", struct{ User *user.User }{nil}) + return s.render(w, "login.html", struct{ User *model.User }{nil}) } // GetUser serves the account settings page. @@ -56,7 +54,7 @@ func (s *SiteHandler) GetUser(w http.ResponseWriter, r *http.Request) error { if u == nil { return s.render(w, "404.html", nil) } - return s.render(w, "user_conf.html", struct{ User *user.User }{u}) + return s.render(w, "user_conf.html", struct{ User *model.User }{u}) } func (s *SiteHandler) GetUsers(w http.ResponseWriter, r *http.Request) error { @@ -64,7 +62,7 @@ func (s *SiteHandler) GetUsers(w http.ResponseWriter, r *http.Request) error { if u == nil || u.Admin == false { return s.render(w, "404.html", nil) } - return s.render(w, "admin_users.html", struct{ User *user.User }{u}) + return s.render(w, "admin_users.html", struct{ User *model.User }{u}) } func (s *SiteHandler) GetConfig(w http.ResponseWriter, r *http.Request) error { @@ -72,7 +70,7 @@ func (s *SiteHandler) GetConfig(w http.ResponseWriter, r *http.Request) error { if u == nil || u.Admin == false { return s.render(w, "404.html", nil) } - return s.render(w, "admin_conf.html", struct{ User *user.User }{u}) + return s.render(w, "admin_conf.html", struct{ User *model.User }{u}) } func (s *SiteHandler) GetRepo(w http.ResponseWriter, r *http.Request) error { @@ -89,14 +87,14 @@ func (s *SiteHandler) GetRepo(w http.ResponseWriter, r *http.Request) error { return s.render(w, "404.html", nil) } data := struct { - User *user.User - Repo *repo.Repo + User *model.User + Repo *model.Repo Branch string Channel string Stream string - Branches []*commit.Commit - Commits []*commit.Commit - Commit *commit.Commit + Branches []*model.Commit + Commits []*model.Commit + Commit *model.Commit }{User: usr, Repo: arepo} // generate a token for connecting to the streaming server @@ -148,8 +146,8 @@ func (s *SiteHandler) GetRepoAdmin(w http.ResponseWriter, r *http.Request) error return s.render(w, "404.html", nil) } data := struct { - User *user.User - Repo *repo.Repo + User *model.User + Repo *model.Repo Host string Scheme string }{u, arepo, httputil.GetHost(r), httputil.GetScheme(r)} @@ -167,8 +165,8 @@ func (s *SiteHandler) GetRepos(w http.ResponseWriter, r *http.Request) error { s.render(w, "500.html", nil) } data := struct { - User *user.User - Repos []*repo.Repo + User *model.User + Repos []*model.Repo }{u, repos} return s.render(w, "user_repos.html", &data) } diff --git a/server/handler/user.go b/server/handler/user.go index 3d21deb15..f7a03774d 100644 --- a/server/handler/user.go +++ b/server/handler/user.go @@ -4,21 +4,20 @@ import ( "encoding/json" "net/http" - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/session" + "github.com/drone/drone/shared/model" "github.com/gorilla/pat" ) type UserHandler struct { - commits commit.CommitManager - repos repo.RepoManager - users user.UserManager + commits database.CommitManager + repos database.RepoManager + users database.UserManager sess session.Session } -func NewUserHandler(users user.UserManager, repos repo.RepoManager, commits commit.CommitManager, sess session.Session) *UserHandler { +func NewUserHandler(users database.UserManager, repos database.RepoManager, commits database.CommitManager, sess session.Session) *UserHandler { return &UserHandler{commits, repos, users, sess} } @@ -35,7 +34,7 @@ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) error { // requesting their own data, and will need to display // the Token on the website. data := struct { - *user.User + *model.User Token string `json:"token"` }{u, u.Token} return json.NewEncoder(w).Encode(&data) @@ -52,7 +51,7 @@ func (h *UserHandler) PutUser(w http.ResponseWriter, r *http.Request) error { // unmarshal the repository from the payload defer r.Body.Close() - in := user.User{} + in := model.User{} if err := json.NewDecoder(r.Body).Decode(&in); err != nil { return badRequest{err} } diff --git a/server/handler/users.go b/server/handler/users.go index 68008b75c..78fd4b817 100644 --- a/server/handler/users.go +++ b/server/handler/users.go @@ -4,17 +4,17 @@ import ( "encoding/json" "net/http" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/session" "github.com/gorilla/pat" ) type UsersHandler struct { - users user.UserManager + users database.UserManager sess session.Session } -func NewUsersHandler(users user.UserManager, sess session.Session) *UsersHandler { +func NewUsersHandler(users database.UserManager, sess session.Session) *UsersHandler { return &UsersHandler{users, sess} } diff --git a/server/main.go b/server/main.go index f5056ce1a..74eb0f051 100644 --- a/server/main.go +++ b/server/main.go @@ -10,14 +10,11 @@ import ( "code.google.com/p/go.net/websocket" "github.com/drone/drone/server/channel" + "github.com/drone/drone/server/database" "github.com/drone/drone/server/database/schema" "github.com/drone/drone/server/handler" "github.com/drone/drone/server/queue" - "github.com/drone/drone/server/resource/commit" "github.com/drone/drone/server/resource/config" - "github.com/drone/drone/server/resource/perm" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" "github.com/drone/drone/server/session" "github.com/drone/drone/shared/build/docker" "github.com/drone/drone/shared/build/log" @@ -95,10 +92,10 @@ func main() { schema.Load(db) // setup the database managers - repos := repo.NewManager(db) - users := user.NewManager(db) - perms := perm.NewManager(db) - commits := commit.NewManager(db) + repos := database.NewRepoManager(db) + users := database.NewUserManager(db) + perms := database.NewPermManager(db) + commits := database.NewCommitManager(db) // cancel all previously running builds go commits.CancelAll() diff --git a/server/queue/queue.go b/server/queue/queue.go index 3b041ae55..299c98105 100644 --- a/server/queue/queue.go +++ b/server/queue/queue.go @@ -1,9 +1,8 @@ package queue import ( - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/repo" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/server/database" + "github.com/drone/drone/shared/model" "github.com/drone/drone/shared/build/script" ) @@ -16,9 +15,9 @@ type Queue struct { // BuildTasks represents a build that is pending // execution. type BuildTask struct { - User *user.User - Repo *repo.Repo - Commit *commit.Commit + User *model.User + Repo *model.Repo + Commit *model.Commit // Build instructions from the .drone.yml // file, unmarshalled. @@ -26,7 +25,7 @@ type BuildTask struct { } // Start N workers with the given build runner. -func Start(workers int, commits commit.CommitManager, runner BuildRunner) *Queue { +func Start(workers int, commits database.CommitManager, runner BuildRunner) *Queue { tasks := make(chan *BuildTask) queue := &Queue{tasks: tasks} diff --git a/server/queue/worker.go b/server/queue/worker.go index aa9a0d668..da63fbc68 100644 --- a/server/queue/worker.go +++ b/server/queue/worker.go @@ -4,20 +4,19 @@ import ( "bytes" "fmt" "github.com/drone/drone/server/channel" + "github.com/drone/drone/server/database" "github.com/drone/drone/shared/build/git" - r "github.com/drone/drone/shared/build/repo" + "github.com/drone/drone/shared/build/repo" "github.com/drone/drone/shared/build/script" + "github.com/drone/drone/shared/model" "io" "log" "path/filepath" "time" - - "github.com/drone/drone/server/resource/commit" - "github.com/drone/drone/server/resource/repo" ) type worker struct { - commits commit.CommitManager + commits database.CommitManager runner BuildRunner } @@ -52,7 +51,7 @@ func (w *worker) execute(task *BuildTask) error { if e := recover(); e != nil { task.Commit.Finished = time.Now().Unix() task.Commit.Duration = task.Commit.Finished - task.Commit.Started - task.Commit.Status = commit.StatusError + task.Commit.Status = model.StatusError w.commits.Update(task.Commit) } }() @@ -66,7 +65,7 @@ func (w *worker) execute(task *BuildTask) error { } // update commit and build status - task.Commit.Status = commit.StatusStarted + task.Commit.Status = model.StatusStarted task.Commit.Started = time.Now().Unix() // persist the commit to the database @@ -132,14 +131,14 @@ func (w *worker) execute(task *BuildTask) error { task.Commit.Finished = time.Now().Unix() task.Commit.Duration = task.Commit.Finished - task.Commit.Started - task.Commit.Status = commit.StatusSuccess + task.Commit.Status = model.StatusSuccess // capture build output stdout := buf.buf.String() // if exit code != 0 set to failure if passed { - task.Commit.Status = commit.StatusFailure + task.Commit.Status = model.StatusFailure if buildErr != nil && len(stdout) == 0 { // TODO: If you wanted to have very friendly error messages, you could do that here stdout = fmt.Sprintf("%s\n", buildErr.Error()) @@ -173,7 +172,7 @@ func (w *worker) runBuild(task *BuildTask, buf io.Writer) (bool, error) { var path = filepath.Join(task.Repo.Host, task.Repo.Owner, task.Repo.Name) path = git.GitPath(task.Script.Git, path) - repo := &r.Repo{ + repo := &repo.Repo{ Name: task.Repo.Host + task.Repo.Owner + task.Repo.Name, Path: task.Repo.CloneURL, Branch: task.Commit.Branch, @@ -200,7 +199,7 @@ func (w *worker) runBuild(task *BuildTask, buf io.Writer) (bool, error) { // updateGitHubStatus is a helper function that will send // the build status to GitHub using the Status API. // see https://github.com/blog/1227-commit-status-api -func updateGitHubStatus(repo *repo.Repo, commit *commit.Commit) error { +func updateGitHubStatus(repo *repo.Repo, commit *model.Commit) error { /* // convert from drone status to github status var message, status string diff --git a/server/resource/perm/model.go b/server/resource/perm/model.go deleted file mode 100644 index 9954f1cd3..000000000 --- a/server/resource/perm/model.go +++ /dev/null @@ -1,12 +0,0 @@ -package perm - -type perm struct { - ID int64 `meddler:"perm_id,pk"` - UserID int64 `meddler:"user_id"` - RepoID int64 `meddler:"repo_id"` - Read bool `meddler:"perm_read"` - Write bool `meddler:"perm_write"` - Admin bool `meddler:"perm_admin"` - Created int64 `meddler:"perm_created"` - Updated int64 `meddler:"perm_updated"` -} diff --git a/server/resource/user/model_test.go b/server/resource/user/model_test.go deleted file mode 100644 index 354633e46..000000000 --- a/server/resource/user/model_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package user - -import ( - "testing" -) - -func TestSetEmail(t *testing.T) { - user := User{} - user.SetEmail("winkle@caltech.edu") - - // make sure the email was correctly set - var got, want = user.Email, "winkle@caltech.edu" - if got != want { - t.Errorf("Want Email %s, got %s", want, got) - } - - // make sure the gravatar hash was correctly calculated - got, want = user.Gravatar, "ab23a88a3ed77ecdfeb894c0eaf2817a" - if got != want { - t.Errorf("Want Gravatar %s, got %s", want, got) - } -} diff --git a/server/session/session.go b/server/session/session.go index 458dc2158..c6b41565f 100644 --- a/server/session/session.go +++ b/server/session/session.go @@ -3,7 +3,8 @@ package session import ( "net/http" - "github.com/drone/drone/server/resource/user" + "github.com/drone/drone/server/database" + "github.com/drone/drone/shared/model" "github.com/gorilla/securecookie" "github.com/gorilla/sessions" ) @@ -13,25 +14,25 @@ var cookies = sessions.NewCookieStore( securecookie.GenerateRandomKey(64)) type Session interface { - User(r *http.Request) *user.User - UserToken(r *http.Request) *user.User - UserCookie(r *http.Request) *user.User - SetUser(w http.ResponseWriter, r *http.Request, u *user.User) + User(r *http.Request) *model.User + UserToken(r *http.Request) *model.User + UserCookie(r *http.Request) *model.User + SetUser(w http.ResponseWriter, r *http.Request, u *model.User) Clear(w http.ResponseWriter, r *http.Request) } type session struct { - users user.UserManager + users database.UserManager } -func NewSession(users user.UserManager) Session { +func NewSession(users database.UserManager) Session { return &session{ users: users, } } // User gets the currently authenticated user from the secure cookie session. -func (s *session) User(r *http.Request) *user.User { +func (s *session) User(r *http.Request) *model.User { //if true { // user, _ := s.users.Find(1) // return user @@ -47,14 +48,14 @@ func (s *session) User(r *http.Request) *user.User { } // UserToken gets the currently authenticated user for the given auth token. -func (s *session) UserToken(r *http.Request) *user.User { +func (s *session) UserToken(r *http.Request) *model.User { token := r.FormValue("access_token") user, _ := s.users.FindToken(token) return user } // UserCookie gets the currently authenticated user from the secure cookie session. -func (s *session) UserCookie(r *http.Request) *user.User { +func (s *session) UserCookie(r *http.Request) *model.User { sess, err := cookies.Get(r, "_sess") if err != nil { return nil @@ -70,7 +71,7 @@ func (s *session) UserCookie(r *http.Request) *user.User { } // SetUser writes the specified username to the session. -func (s *session) SetUser(w http.ResponseWriter, r *http.Request, u *user.User) { +func (s *session) SetUser(w http.ResponseWriter, r *http.Request, u *model.User) { sess, _ := cookies.Get(r, "_sess") sess.Values["uid"] = u.ID sess.Save(r, w) diff --git a/server/resource/commit/model.go b/shared/model/commit.go similarity index 91% rename from server/resource/commit/model.go rename to shared/model/commit.go index 3af1bdd38..af86023a7 100644 --- a/server/resource/commit/model.go +++ b/shared/model/commit.go @@ -1,20 +1,9 @@ -package commit +package model import ( - "github.com/drone/drone/server/resource/util" "time" ) -const ( - StatusNone = "None" - StatusEnqueue = "Pending" - StatusStarted = "Started" - StatusSuccess = "Success" - StatusFailure = "Failure" - StatusError = "Error" - StatusKilled = "Killed" -) - type Commit struct { ID int64 `meddler:"commit_id,pk" json:"id"` RepoID int64 `meddler:"repo_id" json:"-"` @@ -37,7 +26,7 @@ type Commit struct { // SetAuthor sets the author's email address and calculate the Gravatar hash. func (c *Commit) SetAuthor(email string) { c.Author = email - c.Gravatar = util.CreateGravatar(email) + c.Gravatar = createGravatar(email) } // Returns the Short (--short) Commit Hash. diff --git a/shared/model/config.go b/shared/model/config.go new file mode 100644 index 000000000..8b5379070 --- /dev/null +++ b/shared/model/config.go @@ -0,0 +1 @@ +package model diff --git a/server/resource/repo/model.go b/shared/model/repo.go similarity index 73% rename from server/resource/repo/model.go rename to shared/model/repo.go index 795476519..ad1a07181 100644 --- a/server/resource/repo/model.go +++ b/shared/model/repo.go @@ -1,4 +1,4 @@ -package repo +package model import ( "gopkg.in/yaml.v1" @@ -11,12 +11,9 @@ var ( DefaultTimeout int64 = 7200 ) -const ( - HostGitlab = "gitlab.com" - HostGithub = "github.com" - HostGithubEnterprise = "enterprise.github.com" - HostBitbucket = "bitbucket.org" -) +// RepoParams represents a set of private key value parameters +// for each Repository. +type RepoParams map[string]string type Repo struct { ID int64 `meddler:"repo_id,pk" json:"-"` @@ -44,23 +41,7 @@ type Repo struct { Updated int64 `meddler:"repo_updated" json:"updated_at"` } -func NewGithub(owner, name string) (*Repo, error) { - return New(HostGithub, owner, name) -} - -func NewGithubEnterprise(owner, name string) (*Repo, error) { - return New(HostGithubEnterprise, owner, name) -} - -func NewGitlab(owner, name string) (*Repo, error) { - return New(HostGitlab, owner, name) -} - -func NewBitbucket(owner, name string) (*Repo, error) { - return New(HostBitbucket, owner, name) -} - -func New(remote, owner, name string) (*Repo, error) { +func NewRepo(remote, owner, name string) (*Repo, error) { repo := Repo{} repo.Remote = remote repo.Owner = owner diff --git a/shared/model/status.go b/shared/model/status.go new file mode 100644 index 000000000..6e274d118 --- /dev/null +++ b/shared/model/status.go @@ -0,0 +1,11 @@ +package model + +const ( + StatusNone = "None" + StatusEnqueue = "Pending" + StatusStarted = "Started" + StatusSuccess = "Success" + StatusFailure = "Failure" + StatusError = "Error" + StatusKilled = "Killed" +) diff --git a/server/resource/user/model.go b/shared/model/user.go similarity index 81% rename from server/resource/user/model.go rename to shared/model/user.go index d1d81c6af..156b12adb 100644 --- a/server/resource/user/model.go +++ b/shared/model/user.go @@ -1,7 +1,6 @@ -package user +package model import ( - "github.com/drone/drone/server/resource/util" "time" ) @@ -23,9 +22,9 @@ type User struct { Synced int64 `meddler:"user_synced" json:"synced_at"` } -func New(remote, login, email string) *User { +func NewUser(remote, login, email string) *User { user := User{} - user.Token = util.GenerateToken() + user.Token = generateToken() user.Login = login user.Remote = remote user.Active = true @@ -36,15 +35,15 @@ func New(remote, login, email string) *User { // SetEmail sets the email address and calculate the Gravatar hash. func (u *User) SetEmail(email string) { u.Email = email - u.Gravatar = util.CreateGravatar(email) + u.Gravatar = createGravatar(email) } -func (u *User) Stale() bool { +func (u *User) IsStale() bool { switch { case u.Synced == 0: return true // refresh every 24 hours - case u.Synced+expires < time.Now().Unix(): + case u.Synced+DefaultExpires < time.Now().Unix(): return true default: return false @@ -53,4 +52,4 @@ func (u *User) Stale() bool { // by default, let's expire the user // cache after 72 hours -var expires = int64(time.Hour.Seconds() * 72) +var DefaultExpires = int64(time.Hour.Seconds() * 72) diff --git a/shared/model/util.go b/shared/model/util.go new file mode 100644 index 000000000..d8c252623 --- /dev/null +++ b/shared/model/util.go @@ -0,0 +1,48 @@ +package model + +import ( + "crypto/md5" + "crypto/rand" + "fmt" + "io" + "strings" +) + +// standard characters allowed in token string. +var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + +// default token length +var length = 40 + +// generateToken generates random strings good for use in URIs to +// identify unique objects. +func generateToken() string { + b := make([]byte, length) + r := make([]byte, length+(length/4)) // storage for random bytes. + clen := byte(len(chars)) + maxrb := byte(256 - (256 % len(chars))) + i := 0 + for { + io.ReadFull(rand.Reader, r) + for _, c := range r { + if c >= maxrb { + // Skip this number to avoid modulo bias. + continue + } + b[i] = chars[c%clen] + i++ + if i == length { + return string(b) + } + } + } +} + +// helper function to create a Gravatar Hash +// for the given Email address. +func createGravatar(email string) string { + email = strings.ToLower(strings.TrimSpace(email)) + hash := md5.New() + hash.Write([]byte(email)) + return fmt.Sprintf("%x", hash.Sum(nil)) +}