mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-10-22 04:40:11 +00:00
initial public commit
This commit is contained in:
71
pkg/database/builds.go
Normal file
71
pkg/database/builds.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
. "github.com/drone/drone/pkg/model"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// Name of the Build table in the database
|
||||
const buildTable = "builds"
|
||||
|
||||
// SQL Queries to retrieve a list of all Commits belonging to a Repo.
|
||||
const buildStmt = `
|
||||
SELECT id, commit_id, slug, status, started, finished, duration, created, updated, stdout
|
||||
FROM builds
|
||||
WHERE commit_id = ?
|
||||
ORDER BY slug ASC
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a Build by id.
|
||||
const buildFindStmt = `
|
||||
SELECT id, commit_id, slug, status, started, finished, duration, created, updated, stdout
|
||||
FROM builds
|
||||
WHERE id = ?
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a Commit by name and repo id.
|
||||
const buildFindSlugStmt = `
|
||||
SELECT id, commit_id, slug, status, started, finished, duration, created, updated, stdout
|
||||
FROM builds
|
||||
WHERE slug = ? AND commit_id = ?
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
// SQL Queries to delete a Commit.
|
||||
const buildDeleteStmt = `
|
||||
DELETE FROM builds WHERE id = ?
|
||||
`
|
||||
|
||||
// Returns the Build with the given ID.
|
||||
func GetBuild(id int64) (*Build, error) {
|
||||
build := Build{}
|
||||
err := meddler.QueryRow(db, &build, buildFindStmt, id)
|
||||
return &build, err
|
||||
}
|
||||
|
||||
// Returns the Build with the given slug.
|
||||
func GetBuildSlug(slug string, commit int64) (*Build, error) {
|
||||
build := Build{}
|
||||
err := meddler.QueryRow(db, &build, buildFindSlugStmt, slug, commit)
|
||||
return &build, err
|
||||
}
|
||||
|
||||
// Creates a new Build.
|
||||
func SaveBuild(build *Build) error {
|
||||
return meddler.Save(db, buildTable, build)
|
||||
}
|
||||
|
||||
// Deletes an existing Build.
|
||||
func DeleteBuild(id int64) error {
|
||||
_, err := db.Exec(buildDeleteStmt, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// Returns a list of all Builds associated
|
||||
// with the specified Commit ID and branch.
|
||||
func ListBuilds(id int64) ([]*Build, error) {
|
||||
var builds []*Build
|
||||
err := meddler.QueryAll(db, &builds, buildStmt, id)
|
||||
return builds, err
|
||||
}
|
174
pkg/database/commits.go
Normal file
174
pkg/database/commits.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/drone/drone/pkg/model"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// Name of the Commit table in the database
|
||||
const commitTable = "commits"
|
||||
|
||||
// SQL Queries to retrieve a list of all Commits belonging to a Repo.
|
||||
const commitStmt = `
|
||||
SELECT id, repo_id, status, started, finished, duration,
|
||||
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
|
||||
FROM commits
|
||||
WHERE repo_id = ? AND branch = ?
|
||||
ORDER BY created DESC
|
||||
LIMIT 10
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve the latest Commit.
|
||||
const commitLatestStmt = `
|
||||
SELECT id, repo_id, status, started, finished, duration,
|
||||
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
|
||||
FROM commits
|
||||
WHERE repo_id = ? AND branch = ?
|
||||
ORDER BY created DESC
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a Commit by id.
|
||||
const commitFindStmt = `
|
||||
SELECT id, repo_id, status, started, finished, duration,
|
||||
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
|
||||
FROM commits
|
||||
WHERE id = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a Commit by name and repo id.
|
||||
const commitFindHashStmt = `
|
||||
SELECT id, repo_id, status, started, finished, duration,
|
||||
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
|
||||
FROM commits
|
||||
WHERE hash = ? AND repo_id = ?
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
// SQL Query to retrieve a list of recent commits by user.
|
||||
const userCommitRecentStmt = `
|
||||
SELECT r.slug, r.host, r.owner, r.name,
|
||||
c.status, c.started, c.finished, c.duration, c.hash, c.branch, c.pull_request,
|
||||
c.author, c.gravatar, c.timestamp, c.message, c.created, c.updated
|
||||
FROM repos r, commits c
|
||||
WHERE r.user_id = ?
|
||||
AND r.team_id = 0
|
||||
AND r.id = c.repo_id
|
||||
AND c.status IN ('Success', 'Failure')
|
||||
ORDER BY c.created desc
|
||||
LIMIT 10
|
||||
`
|
||||
|
||||
// SQL Query to retrieve a list of recent commits by team.
|
||||
const teamCommitRecentStmt = `
|
||||
SELECT r.slug, r.host, r.owner, r.name,
|
||||
c.status, c.started, c.finished, c.duration, c.hash, c.branch, c.pull_request,
|
||||
c.author, c.gravatar, c.timestamp, c.message, c.created, c.updated
|
||||
FROM repos r, commits c
|
||||
WHERE r.team_id = ?
|
||||
AND r.id = c.repo_id
|
||||
AND c.status IN ('Success', 'Failure')
|
||||
ORDER BY c.created desc
|
||||
LIMIT 10
|
||||
`
|
||||
|
||||
// SQL Queries to delete a Commit.
|
||||
const commitDeleteStmt = `
|
||||
DELETE FROM commits WHERE id = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve the latest Commits for each branch.
|
||||
const commitBranchesStmt = `
|
||||
SELECT id, repo_id, status, started, finished, duration,
|
||||
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
|
||||
FROM commits
|
||||
WHERE id IN (
|
||||
SELECT MAX(id)
|
||||
FROM commits
|
||||
WHERE repo_id = ?
|
||||
GROUP BY branch)
|
||||
ORDER BY branch ASC
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve the latest Commits for each branch.
|
||||
const commitBranchStmt = `
|
||||
SELECT id, repo_id, status, started, finished, duration,
|
||||
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
|
||||
FROM commits
|
||||
WHERE id IN (
|
||||
SELECT MAX(id)
|
||||
FROM commits
|
||||
WHERE repo_id = ?
|
||||
AND branch = ?
|
||||
GROUP BY branch)
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
// Returns the Commit with the given ID.
|
||||
func GetCommit(id int64) (*Commit, error) {
|
||||
commit := Commit{}
|
||||
err := meddler.QueryRow(db, &commit, commitFindStmt, id)
|
||||
return &commit, err
|
||||
}
|
||||
|
||||
// Returns the Commit with the given hash.
|
||||
func GetCommitHash(hash string, repo int64) (*Commit, error) {
|
||||
commit := Commit{}
|
||||
err := meddler.QueryRow(db, &commit, commitFindHashStmt, hash, repo)
|
||||
return &commit, err
|
||||
}
|
||||
|
||||
// Returns the most recent Commit for the given branch.
|
||||
func GetBranch(repo int64, branch string) (*Commit, error) {
|
||||
commit := Commit{}
|
||||
err := meddler.QueryRow(db, &commit, commitBranchStmt, repo, branch)
|
||||
return &commit, err
|
||||
}
|
||||
|
||||
// Creates a new Commit.
|
||||
func SaveCommit(commit *Commit) error {
|
||||
if commit.ID == 0 {
|
||||
commit.Created = time.Now().UTC()
|
||||
}
|
||||
commit.Updated = time.Now().UTC()
|
||||
return meddler.Save(db, commitTable, commit)
|
||||
}
|
||||
|
||||
// Deletes an existing Commit.
|
||||
func DeleteCommit(id int64) error {
|
||||
_, err := db.Exec(commitDeleteStmt, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// Returns a list of all Commits associated
|
||||
// with the specified Repo ID.
|
||||
func ListCommits(repo int64, branch string) ([]*Commit, error) {
|
||||
var commits []*Commit
|
||||
err := meddler.QueryAll(db, &commits, commitStmt, repo, branch)
|
||||
return commits, err
|
||||
}
|
||||
|
||||
// Returns a list of recent Commits associated
|
||||
// with the specified User ID
|
||||
func ListCommitsUser(user int64) ([]*RepoCommit, error) {
|
||||
var commits []*RepoCommit
|
||||
err := meddler.QueryAll(db, &commits, userCommitRecentStmt, user)
|
||||
return commits, err
|
||||
}
|
||||
|
||||
// Returns a list of recent Commits associated
|
||||
// with the specified Team ID
|
||||
func ListCommitsTeam(team int64) ([]*RepoCommit, error) {
|
||||
var commits []*RepoCommit
|
||||
err := meddler.QueryAll(db, &commits, teamCommitRecentStmt, team)
|
||||
return commits, err
|
||||
}
|
||||
|
||||
// Returns a list of the most recent commits for each branch.
|
||||
func ListBranches(repo int64) ([]*Commit, error) {
|
||||
var commits []*Commit
|
||||
err := meddler.QueryAll(db, &commits, commitBranchesStmt, repo)
|
||||
return commits, err
|
||||
}
|
24
pkg/database/database.go
Normal file
24
pkg/database/database.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/drone/drone/pkg/database/schema"
|
||||
)
|
||||
|
||||
// global instance of our database connection.
|
||||
var db *sql.DB
|
||||
|
||||
// Set sets the default database.
|
||||
func Set(database *sql.DB) {
|
||||
// set the global database
|
||||
db = database
|
||||
|
||||
// load the database schema. If this is
|
||||
// a new database all the tables and
|
||||
// indexes will be created.
|
||||
if err := schema.Load(db); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
133
pkg/database/encrypt/encrypt.go
Normal file
133
pkg/database/encrypt/encrypt.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// EncryptedField handles encrypted and decryption of
|
||||
// values to and from database columns.
|
||||
type EncryptedField struct {
|
||||
Cipher cipher.Block
|
||||
}
|
||||
|
||||
// PreRead is called before a Scan operation. It is given a pointer to
|
||||
// the raw struct field, and returns the value that will be given to
|
||||
// the database driver.
|
||||
func (e *EncryptedField) PreRead(fieldAddr interface{}) (scanTarget interface{}, err error) {
|
||||
// give a pointer to a byte buffer to grab the raw data
|
||||
return new([]byte), nil
|
||||
}
|
||||
|
||||
// PostRead is called after a Scan operation. It is given the value returned
|
||||
// by PreRead and a pointer to the raw struct field. It is expected to fill
|
||||
// in the struct field if the two are different.
|
||||
func (e *EncryptedField) PostRead(fieldAddr interface{}, scanTarget interface{}) error {
|
||||
ptr := scanTarget.(*[]byte)
|
||||
if ptr == nil {
|
||||
return fmt.Errorf("encrypter.PostRead: nil pointer")
|
||||
}
|
||||
raw := *ptr
|
||||
|
||||
// ignore fields that aren't set at all
|
||||
if len(raw) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// decrypt value for gob decoding
|
||||
var err error
|
||||
raw, err = decrypt(e.Cipher, raw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Gob decryption error: %v", err)
|
||||
}
|
||||
|
||||
// decode gob
|
||||
gobDecoder := gob.NewDecoder(bytes.NewReader(raw))
|
||||
if err := gobDecoder.Decode(fieldAddr); err != nil {
|
||||
return fmt.Errorf("Gob decode error: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PreWrite is called before an Insert or Update operation. It is given
|
||||
// a pointer to the raw struct field, and returns the value that will be
|
||||
// given to the database driver.
|
||||
func (e *EncryptedField) PreWrite(field interface{}) (saveValue interface{}, err error) {
|
||||
buffer := new(bytes.Buffer)
|
||||
|
||||
// gob encode
|
||||
gobEncoder := gob.NewEncoder(buffer)
|
||||
if err := gobEncoder.Encode(field); err != nil {
|
||||
return nil, fmt.Errorf("Gob encoding error: %v", err)
|
||||
}
|
||||
// and then ecrypt
|
||||
encrypted, err := encrypt(e.Cipher, buffer.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Gob decryption error: %v", err)
|
||||
}
|
||||
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
// encrypt is a helper function to encrypt a slice
|
||||
// of bytes using the specified block cipher.
|
||||
func encrypt(block cipher.Block, v []byte) ([]byte, error) {
|
||||
// if no block cipher value exists we'll assume
|
||||
// the database is running in non-ecrypted mode.
|
||||
if block == nil {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
value := make([]byte, len(v))
|
||||
copy(value, v)
|
||||
|
||||
// Generate a random initialization vector
|
||||
iv := generateRandomKey(block.BlockSize())
|
||||
if len(iv) != block.BlockSize() {
|
||||
return nil, fmt.Errorf("Could not generate a valid initialization vector for encryption")
|
||||
}
|
||||
|
||||
// Encrypt it.
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(value, value)
|
||||
|
||||
// Return iv + ciphertext.
|
||||
return append(iv, value...), nil
|
||||
}
|
||||
|
||||
// decrypt is a helper function to decrypt a slice
|
||||
// using the specified block cipher.
|
||||
func decrypt(block cipher.Block, value []byte) ([]byte, error) {
|
||||
// if no block cipher value exists we'll assume
|
||||
// the database is running in non-ecrypted mode.
|
||||
if block == nil {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
size := block.BlockSize()
|
||||
if len(value) > size {
|
||||
// Extract iv.
|
||||
iv := value[:size]
|
||||
// Extract ciphertext.
|
||||
value = value[size:]
|
||||
// Decrypt it.
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(value, value)
|
||||
return value, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Could not decrypt the value")
|
||||
}
|
||||
|
||||
// GenerateRandomKey creates a random key of size length bytes
|
||||
func generateRandomKey(strength int) []byte {
|
||||
k := make([]byte, strength)
|
||||
if _, err := io.ReadFull(rand.Reader, k); err != nil {
|
||||
return nil
|
||||
}
|
||||
return k
|
||||
}
|
86
pkg/database/members.go
Normal file
86
pkg/database/members.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
. "github.com/drone/drone/pkg/model"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// Name of the Member table in the database
|
||||
const memberTable = "members"
|
||||
|
||||
// SQL Queries to retrieve a list of all members belonging to a team.
|
||||
const memberStmt = `
|
||||
SELECT user_id, name, email, gravatar, role
|
||||
FROM members, users
|
||||
WHERE users.id = members.user_id
|
||||
AND team_id = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a team by id and user.
|
||||
const memberFindStmt = `
|
||||
SELECT user_id, name, email, gravatar, role
|
||||
FROM members, users
|
||||
WHERE users.id = members.user_id
|
||||
AND user_id = ?
|
||||
AND team_id = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a team by name .
|
||||
const memberDeleteStmt = `
|
||||
DELETE FROM members
|
||||
WHERE user_id = ? AND team_id = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a member's role by id and user.
|
||||
const roleFindStmt = `
|
||||
SELECT role FROM members
|
||||
WHERE user_id = ? AND team_id = ?
|
||||
`
|
||||
|
||||
// Returns the Member with the given user and team IDs.
|
||||
func GetMember(user, team int64) (*Member, error) {
|
||||
member := Member{}
|
||||
err := meddler.QueryRow(db, &member, memberFindStmt, user, team)
|
||||
return &member, err
|
||||
}
|
||||
|
||||
// Returns true if the user is a member of the team
|
||||
func IsMember(user, team int64) (bool, error) {
|
||||
role := Role{}
|
||||
err := meddler.QueryRow(db, &role, roleFindStmt, user, team)
|
||||
return len(role.Role) > 0, err
|
||||
}
|
||||
|
||||
// Returns true is the user is an admin member of the team.
|
||||
func IsMemberAdmin(user, team int64) (bool, error) {
|
||||
role := Role{}
|
||||
err := meddler.QueryRow(db, &role, roleFindStmt, user, team)
|
||||
return role.Role == RoleAdmin || role.Role == RoleOwner, err
|
||||
}
|
||||
|
||||
// Creates a new Member.
|
||||
func SaveMember(user, team int64, role string) error {
|
||||
r := Role{}
|
||||
if err := meddler.QueryRow(db, &r, roleFindStmt, user, team); err == nil {
|
||||
r.Role = role
|
||||
return meddler.Save(db, memberTable, &r)
|
||||
}
|
||||
|
||||
r.UserID = user
|
||||
r.TeamID = team
|
||||
r.Role = role
|
||||
return meddler.Save(db, memberTable, &r)
|
||||
}
|
||||
|
||||
// Deletes an existing Member.
|
||||
func DeleteMember(user, team int64) error {
|
||||
_, err := db.Exec(memberDeleteStmt, user, team)
|
||||
return err
|
||||
}
|
||||
|
||||
// Returns a list of all Team members.
|
||||
func ListMembers(team int64) ([]*Member, error) {
|
||||
var members []*Member
|
||||
err := meddler.QueryAll(db, &members, memberStmt, team)
|
||||
return members, err
|
||||
}
|
92
pkg/database/repos.go
Normal file
92
pkg/database/repos.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/drone/drone/pkg/model"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// Name of the Repos table in the database
|
||||
const repoTable = "repos"
|
||||
|
||||
// SQL Queries to retrieve a list of all repos belonging to a User.
|
||||
const repoStmt = `
|
||||
SELECT id, slug, host, owner, name, private, disabled, disabled_pr, scm, url, username, password,
|
||||
public_key, private_key, params, timeout, priveleged, created, updated, user_id, team_id
|
||||
FROM repos
|
||||
WHERE user_id = ? AND team_id = 0
|
||||
ORDER BY slug ASC
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a list of all repos belonging to a Team.
|
||||
const repoTeamStmt = `
|
||||
SELECT id, slug, host, owner, name, private, disabled, disabled_pr, scm, url, username, password,
|
||||
public_key, private_key, params, timeout, priveleged, created, updated, user_id, team_id
|
||||
FROM repos
|
||||
WHERE team_id = ?
|
||||
ORDER BY slug ASC
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a repo by id.
|
||||
const repoFindStmt = `
|
||||
SELECT id, slug, host, owner, name, private, disabled, disabled_pr, scm, url, username, password,
|
||||
public_key, private_key, params, timeout, priveleged, created, updated, user_id, team_id
|
||||
FROM repos
|
||||
WHERE id = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a repo by name.
|
||||
const repoFindSlugStmt = `
|
||||
SELECT id, slug, host, owner, name, private, disabled, disabled_pr, scm, url, username, password,
|
||||
public_key, private_key, params, timeout, priveleged, created, updated, user_id, team_id
|
||||
FROM repos
|
||||
WHERE slug = ?
|
||||
`
|
||||
|
||||
// Returns the Repo with the given ID.
|
||||
func GetRepo(id int64) (*Repo, error) {
|
||||
repo := Repo{}
|
||||
err := meddler.QueryRow(db, &repo, repoFindStmt, id)
|
||||
return &repo, err
|
||||
}
|
||||
|
||||
// Returns the Repo with the given slug.
|
||||
func GetRepoSlug(slug string) (*Repo, error) {
|
||||
repo := Repo{}
|
||||
err := meddler.QueryRow(db, &repo, repoFindSlugStmt, slug)
|
||||
return &repo, err
|
||||
}
|
||||
|
||||
// Creates a new Repository.
|
||||
func SaveRepo(repo *Repo) error {
|
||||
if repo.ID == 0 {
|
||||
repo.Created = time.Now().UTC()
|
||||
}
|
||||
repo.Updated = time.Now().UTC()
|
||||
return meddler.Save(db, repoTable, repo)
|
||||
}
|
||||
|
||||
// Deletes an existing Repository.
|
||||
// TODO need to delete builds too.
|
||||
func DeleteRepo(id int64) error {
|
||||
_, err := db.Exec("DELETE FROM repos WHERE id = ?", id)
|
||||
db.Exec("DELETE FROM commits WHERE repo_id = ?", id)
|
||||
return err
|
||||
}
|
||||
|
||||
// Returns a list of all Repos associated
|
||||
// with the specified User ID.
|
||||
func ListRepos(id int64) ([]*Repo, error) {
|
||||
var repos []*Repo
|
||||
err := meddler.QueryAll(db, &repos, repoStmt, id)
|
||||
return repos, err
|
||||
}
|
||||
|
||||
// Returns a list of all Repos associated
|
||||
// with the specified Team ID.
|
||||
func ListReposTeam(id int64) ([]*Repo, error) {
|
||||
var repos []*Repo
|
||||
err := meddler.QueryAll(db, &repos, repoTeamStmt, id)
|
||||
return repos, err
|
||||
}
|
126
pkg/database/schema/sample.sql
Normal file
126
pkg/database/schema/sample.sql
Normal file
@@ -0,0 +1,126 @@
|
||||
DELETE FROM builds;
|
||||
DELETE FROM commits;
|
||||
DELETE FROM repos;
|
||||
DELETE FROM members;
|
||||
DELETE FROM teams;
|
||||
DELETE FROM users;
|
||||
DELETE FROM settings;
|
||||
|
||||
-- insert users (default password is "password")
|
||||
INSERT INTO users values (1, 'brad.rydzewski@gmail.com' , '$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS', 'nPmsbl6YNLUIUo0I7gkMcQ' ,'Brad Rydzewski', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, '', '', '', '', '');
|
||||
INSERT INTO users values (2, 'thomas.d.burke@gmail.com' , '$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS', 'sal5Tzy6S10yZCaE0jl6QA', 'Thomas Burke', 'c62f7126273f7fa786274274a5dec8ce', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, '', '', '', '', '');
|
||||
INSERT INTO users values (3, 'carlos.morales.duran@gmail.com', '$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS', 'bq87o8AmDUOahKApEy2tVQ', 'Carlos Morales', 'c2180a539620d90d68eaeb848364f1c2', '2013-09-16 00:00:00', '2013-09-17 00:00:00', 1, '', '', '', '', '');
|
||||
|
||||
-- insert teams
|
||||
insert into teams values (1, 'drone', 'Drone' , 'brad@drone.io' , '0057e90a8036c29b1ddb22d0fd08b72c', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
|
||||
insert into teams values (2, 'google', 'Google', 'dev@google.com' , '24ba30616d2a20673f54c2aee36d159e', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
|
||||
insert into teams values (3, 'gradle', 'Gradle', 'dev@gradle.com' , '5cc3b557e3a3978d52036da9a5be2a08', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
|
||||
insert into teams values (4, 'dart', 'Dart' , 'dev@dartlang.org', 'f41fe13f979f2f93cc8b971e1875bdf8', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
|
||||
|
||||
-- insert team members
|
||||
insert into members values (1, 1, 1, 'Owner');
|
||||
insert into members values (2, 1, 2, 'Admin');
|
||||
insert into members values (3, 1, 3, 'Write');
|
||||
|
||||
-- insert repository
|
||||
insert into repos values (1, 'github.com/drone/jkl', 'github.com', 'drone', 'jkl', 0, 0, 0, 0, 900, 'git', 'git://github.com/drone/jkl.git', '', '', '', '', '', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, 1);
|
||||
insert into repos values (2, 'github.com/drone/drone', 'github.com', 'drone', 'drone', 1, 0, 0, 0, 900, 'git', 'git@github.com:drone/drone.git', '', '', '', '', '', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, 1);
|
||||
insert into repos values (3, 'github.com/bradrydzewski/drone', 'github.com', 'bradrydzewski', 'drone', 1, 0, 0, 0, 900, 'git', 'git@github.com:bradrydzewski/drone.git', '', '', '', '', '', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, 1);
|
||||
insert into repos values (4, 'github.com/bradrydzewski/blog', 'github.com', 'bradrydzewski', 'blog', 0, 0, 0, 0, 900, 'git', 'git://github.com/bradrydzewski/blog.git', '', '', '', '', '', '2013-09-16 00:00:00', '2013-09-16 00:00:00', 1, 0);
|
||||
|
||||
-- insert commits
|
||||
|
||||
insert into commits values (1, 1, 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, 'ef2221722e6f07a6eaf8af8907b45324428a891d', 'master', '','brad.rydzewski@gmail.com', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', 'Fixed mock db class for entity', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
|
||||
insert into commits values (2, 1, 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '867477aa487d01df28522cee84cd06f5aa154e53', 'master', '','brad.rydzewski@gmail.com', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', 'Fixed mock db class for entity', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
|
||||
insert into commits values (3, 1, 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, 'e43427ab462417cb3d53b8702c298c1675deb926', 'master', '','brad.rydzewski@gmail.com', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', 'Save deleted entity data to database', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
|
||||
insert into commits values (4, 1, 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, 'a43427ab462417cb3d53b8702c298c1675deb926', 'dev', '','brad.rydzewski@gmail.com', '8c58a0be77ee441bb8f8595b7f1b4e87', '2013-09-16 00:00:00', 'Save deleted entity data to database', '2013-09-16 00:00:00', '2013-09-16 00:00:00');
|
||||
|
||||
-- insert builds
|
||||
|
||||
insert into builds values (1, 1, 'node_0.10', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
insert into builds values (2, 1, 'node_0.90', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
insert into builds values (3, 1, 'node_0.80', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
insert into builds values (4, 2, 'node_0.10', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
insert into builds values (5, 2, 'node_0.90', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
insert into builds values (6, 2, 'node_0.80', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
insert into builds values (7, 3, 'node_0.10', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
insert into builds values (8, 3, 'node_0.90', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
insert into builds values (9, 3, 'node_0.80', 'Success', '2013-09-16 00:00:00','2013-09-16 00:00:00', 60, '2013-09-16 00:00:00','2013-09-16 00:00:00', '');
|
||||
|
||||
-- insert default, dummy settings
|
||||
|
||||
insert into settings values (1,'','','','','','','','','','localhost:8080','http');
|
||||
|
||||
-- add public & private keys to all repositories
|
||||
|
||||
update repos set public_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCybgl9+Y0VY0mKng3AB3CwCMAOVvg+Xh4X/4lP7SR815GaeEJQusaA0p33HkZfS/2XREWYMtiopHP0bZuBIht76JdhrJlHh1AcLoPQvWJROFvRGol6igVEVZzs9sUdZaPrexFz1CS/j6BJFzPsHnL4gXT3s4PYYST9++pThI90Aw==';
|
||||
|
||||
update repos set private_key = '-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICWwIBAAKBgQCybgl9+Y0VY0mKng3AB3CwCMAOVvg+Xh4X/4lP7SR815GaeEJQ
|
||||
usaA0p33HkZfS/2XREWYMtiopHP0bZuBIht76JdhrJlHh1AcLoPQvWJROFvRGol6
|
||||
igVEVZzs9sUdZaPrexFz1CS/j6BJFzPsHnL4gXT3s4PYYST9++pThI90AwIDAQAB
|
||||
AoGAaxvs7MdaLsWcRu7cGDMfLT0DdVg1ytKaxBMsrWMQrTSGfjDEtkt4j6pfExIE
|
||||
cn5ea2ibUmLrdkjKJqeJWrpLvlOZGhahBcL/SueFOfr6Lm+m8LvlTrX6JhyLXpx5
|
||||
NbeEFr0mN16PC6JqkN0xRCN9BfV9m6gnpuP/ojD3RKYMZtkCQQDFbSX/ddEfp9ME
|
||||
vRNAYif+bFxI6PEgMmwrCIjJGHOsq7zba3Z7KWjW034x2rJ3Cbhs8xtyTcA5qy9F
|
||||
OzL3pFs3AkEA514SUXowIiqjh6ypnSvUBaQZsWjexDxTXN09DTYPt+Ck1qdzTHWP
|
||||
9nerg2G3B6bTOWZBftHMaZ/plZ/eyV0LlQJACU1rTO4wPF2cA80k6xO07rgMYSMY
|
||||
uXumvSBZ0Z/lU22EKJKXspXw6q5sc8zqO9GpbvjFgk1HkXAPeiOf8ys7YQJAD1CI
|
||||
wd/mo7xSyr5BE+g8xorQMJASfsbHddQnIGK9s5wpDRRUa3E0sEnHjpC/PsBqJth/
|
||||
6VcVwsAVBBRq+MUx6QJAS9KKxKcMf8JpnDheV7jh+WJKckabA1L2bq8sN6kXfPn0
|
||||
o7deiE1FKJizXKJ6gd6anfuG3m7VAs7wJhzc685yMg==
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
|
||||
-- add standard output to all builds
|
||||
|
||||
update builds set stdout = '$ mvn test
|
||||
-------------------------------------------------------
|
||||
T E S T S
|
||||
-------------------------------------------------------
|
||||
Running brooklyn.qa.longevity.MonitorUtilsTest
|
||||
Configuring TestNG with: TestNG652Configurator
|
||||
[GC 69952K->6701K(253440K), 0.0505760 secs]
|
||||
2013-08-21 21:12:58,327 INFO TESTNG RUNNING: Suite: "Command line test" containing "7" Tests (config: null)
|
||||
2013-08-21 21:12:58,342 INFO BrooklynLeakListener.onStart attempting to terminate all extant ManagementContexts: name=Command line test; includedGroups=[]; excludedGroups=[Integration, Acceptance, Live, WIP]; suiteName=brooklyn.qa.longevity.MonitorUtilsTest; outDir=/scratch/jenkins/workspace/brooklyncentral/brooklyn/usage/qa/target/surefire-reports/brooklyn.qa.longevity.MonitorUtilsTest
|
||||
2013-08-21 21:12:58,473 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testFindOwnPid()
|
||||
2013-08-21 21:12:58,939 INFO executing cmd: ps -p 7484
|
||||
2013-08-21 21:12:59,030 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testFindOwnPid() finished in 595 ms
|
||||
2013-08-21 21:12:59,033 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testGetRunningPids()
|
||||
2013-08-21 21:12:59,035 INFO executing cmd: ps ax
|
||||
2013-08-21 21:12:59,137 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testGetRunningPids() finished in 104 ms
|
||||
2013-08-21 21:12:59,139 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testGroovyExecuteAndWaitForConsumingOutputStream()
|
||||
2013-08-21 21:12:59,295 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testGroovyExecuteAndWaitForConsumingOutputStream() finished in 155 ms
|
||||
2013-08-21 21:12:59,298 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testIsPidRunning()
|
||||
2013-08-21 21:12:59,300 INFO executing cmd: ps ax
|
||||
2013-08-21 21:12:59,384 INFO executing cmd: ps -p 7484
|
||||
2013-08-21 21:12:59,391 INFO executing cmd: ps -p 10000
|
||||
2013-08-21 21:12:59,443 INFO pid 10000 not running:
|
||||
2013-08-21 21:12:59,446 INFO executing cmd: ps -p 1234567
|
||||
2013-08-21 21:12:59,455 INFO pid 1234567 not running:
|
||||
2013-08-21 21:12:59,456 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testIsPidRunning() finished in 158 ms
|
||||
2013-08-21 21:12:59,481 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testIsUrlUp()
|
||||
[GC 76653K->7013K(253440K), 0.0729880 secs]
|
||||
2013-08-21 21:13:00,726 INFO Error reading URL http://localhost/thispathdoesnotexist: org.apache.http.conn.HttpHostConnectException: Connection to http://localhost refused
|
||||
2013-08-21 21:13:00,727 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testIsUrlUp() finished in 1246 ms
|
||||
2013-08-21 21:13:00,760 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testMemoryUsage()
|
||||
2013-08-21 21:13:00,762 INFO executing cmd: jmap -histo 7484
|
||||
2013-08-21 21:13:02,275 INFO executing cmd: jmap -histo 7484
|
||||
2013-08-21 21:13:03,690 INFO executing cmd: jmap -histo 7484
|
||||
2013-08-21 21:13:04,725 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testMemoryUsage() finished in 3965 ms
|
||||
2013-08-21 21:13:04,752 INFO TESTNG INVOKING: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testSearchLog()
|
||||
2013-08-21 21:13:04,816 INFO executing cmd: grep -E line1 /tmp/monitorUtilsTest.testSearchLog2369184699231420767.txt
|
||||
2013-08-21 21:13:04,848 INFO executing cmd: grep -E line1|line2 /tmp/monitorUtilsTest.testSearchLog2369184699231420767.txt
|
||||
2013-08-21 21:13:04,854 INFO executing cmd: grep -E textnotthere /tmp/monitorUtilsTest.testSearchLog2369184699231420767.txt
|
||||
2013-08-21 21:13:04,858 INFO executing cmd: grep -E line /tmp/monitorUtilsTest.testSearchLog2369184699231420767.txt
|
||||
2013-08-21 21:13:04,897 INFO TESTNG PASSED: "Command line test" - brooklyn.qa.longevity.MonitorUtilsTest.testSearchLog() finished in 145 ms
|
||||
2013-08-21 21:13:04,917 INFO TESTNG
|
||||
===============================================
|
||||
Command line test
|
||||
Tests run: 7, Failures: 0, Skips: 0
|
||||
===============================================
|
||||
2013-08-21 21:13:04,944 INFO BrooklynLeakListener.onFinish attempting to terminate all extant ManagementContexts: name=Command line test; includedGroups=[]; excludedGroups=[Integration, Acceptance, Live, WIP]; suiteName=brooklyn.qa.longevity.MonitorUtilsTest; outDir=/scratch/jenkins/workspace/brooklyncentral/brooklyn/usage/qa/target/surefire-reports/brooklyn.qa.longevity.MonitorUtilsTest
|
||||
Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.849 sec
|
||||
|
||||
Results :
|
||||
|
||||
Tests run: 7, Failures: 0, Errors: 0, Skipped: 0';
|
198
pkg/database/schema/schema.go
Normal file
198
pkg/database/schema/schema.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// SQL statement to create the User Table.
|
||||
var userTableStmt = `
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,email VARCHAR(255) UNIQUE
|
||||
,password VARCHAR(255)
|
||||
,token VARCHAR(255) UNIQUE
|
||||
,name VARCHAR(255)
|
||||
,gravatar VARCHAR(255)
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
,admin BOOLEAN
|
||||
,github_login VARCHAR(255)
|
||||
,github_token VARCHAR(255)
|
||||
,bitbucket_login VARCHAR(255)
|
||||
,bitbucket_token VARCHAR(255)
|
||||
,bitbucket_secret VARCHAR(255)
|
||||
);
|
||||
`
|
||||
|
||||
// SQL statement to create the Team Table.
|
||||
var teamTableStmt = `
|
||||
CREATE TABLE teams (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,slug VARCHAR(255) UNIQUE
|
||||
,name VARCHAR(255)
|
||||
,email VARCHAR(255)
|
||||
,gravatar VARCHAR(255)
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
);
|
||||
`
|
||||
|
||||
// SQL statement to create the Member Table.
|
||||
var memberTableStmt = `
|
||||
CREATE TABLE members (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,team_id INTEGER
|
||||
,user_id INTEGER
|
||||
,role INTEGER
|
||||
);
|
||||
`
|
||||
|
||||
// SQL statement to create the Repo Table.
|
||||
var repoTableStmt = `
|
||||
CREATE TABLE repos (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,slug VARCHAR(1024) UNIQUE
|
||||
,host VARCHAR(255)
|
||||
,owner VARCHAR(255)
|
||||
,name VARCHAR(255)
|
||||
,private BOOLEAN
|
||||
,disabled BOOLEAN
|
||||
,disabled_pr BOOLEAN
|
||||
,priveleged BOOLEAN
|
||||
,timeout INTEGER
|
||||
,scm VARCHAR(25)
|
||||
,url VARCHAR(1024)
|
||||
,username VARCHAR(255)
|
||||
,password VARCHAR(255)
|
||||
,public_key VARCHAR(1024)
|
||||
,private_key VARCHAR(1024)
|
||||
,params VARCHAR(2000)
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
,user_id INTEGER
|
||||
,team_id INTEGER
|
||||
);
|
||||
`
|
||||
|
||||
// SQL statement to create the Commit Table.
|
||||
var commitTableStmt = `
|
||||
CREATE TABLE commits (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,repo_id INTEGER
|
||||
,status VARCHAR(255)
|
||||
,started TIMESTAMP
|
||||
,finished TIMESTAMP
|
||||
,duration INTEGER
|
||||
,attempts INTEGER
|
||||
,hash VARCHAR(255)
|
||||
,branch VARCHAR(255)
|
||||
,pull_request VARCHAR(255)
|
||||
,author VARCHAR(255)
|
||||
,gravatar VARCHAR(255)
|
||||
,timestamp VARCHAR(255)
|
||||
,message VARCHAR(255)
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
);
|
||||
`
|
||||
|
||||
// SQL statement to create the Build Table.
|
||||
var buildTableStmt = `
|
||||
CREATE TABLE builds (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,commit_id INTEGER
|
||||
,slug VARCHAR(255)
|
||||
,status VARCHAR(255)
|
||||
,started TIMESTAMP
|
||||
,finished TIMESTAMP
|
||||
,duration INTEGER
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
,stdout BLOB
|
||||
);
|
||||
`
|
||||
|
||||
// SQL statement to create the Settings
|
||||
var settingsTableStmt = `
|
||||
CREATE TABLE settings (
|
||||
id INTEGER PRIMARY KEY
|
||||
,github_key VARCHAR(255)
|
||||
,github_secret VARCHAR(255)
|
||||
,bitbucket_key VARCHAR(255)
|
||||
,bitbucket_secret VARCHAR(255)
|
||||
,smtp_server VARCHAR(1024)
|
||||
,smtp_port VARCHAR(5)
|
||||
,smtp_address VARCHAR(1024)
|
||||
,smtp_username VARCHAR(1024)
|
||||
,smtp_password VARCHAR(1024)
|
||||
,hostname VARCHAR(1024)
|
||||
,scheme VARCHAR(5)
|
||||
);
|
||||
`
|
||||
|
||||
var memberUniqueIndex = `
|
||||
CREATE UNIQUE INDEX member_uix ON members (team_id, user_id);
|
||||
`
|
||||
|
||||
var memberTeamIndex = `
|
||||
CREATE INDEX member_team_ix ON members (team_id);
|
||||
`
|
||||
|
||||
var memberUserIndex = `
|
||||
CREATE INDEX member_user_ix ON members (user_id);
|
||||
`
|
||||
|
||||
var commitUniqueIndex = `
|
||||
CREATE UNIQUE INDEX commits_uix ON commits (repo_id, hash, branch);
|
||||
`
|
||||
|
||||
var commitRepoIndex = `
|
||||
CREATE INDEX commits_repo_ix ON commits (repo_id);
|
||||
`
|
||||
|
||||
var commitBranchIndex = `
|
||||
CREATE INDEX commits_repo_ix ON commits (repo_id, branch);
|
||||
`
|
||||
|
||||
var repoTeamIndex = `
|
||||
CREATE INDEX repo_team_ix ON repos (team_id);
|
||||
`
|
||||
|
||||
var repoUserIndex = `
|
||||
CREATE INDEX repo_user_ix ON repos (user_id);
|
||||
`
|
||||
|
||||
var buildCommitIndex = `
|
||||
CREATE INDEX builds_commit_ix ON builds (commit_id);
|
||||
`
|
||||
|
||||
var buildSlugIndex = `
|
||||
CREATE INDEX builds_commit_slug_ix ON builds (commit_id, slug);
|
||||
`
|
||||
|
||||
// Load will apply the DDL commands to
|
||||
// the provided database.
|
||||
func Load(db *sql.DB) error {
|
||||
|
||||
// created tables
|
||||
db.Exec(userTableStmt)
|
||||
db.Exec(teamTableStmt)
|
||||
db.Exec(memberTableStmt)
|
||||
db.Exec(repoTableStmt)
|
||||
db.Exec(commitTableStmt)
|
||||
db.Exec(buildTableStmt)
|
||||
db.Exec(settingsTableStmt)
|
||||
|
||||
db.Exec(memberUniqueIndex)
|
||||
db.Exec(memberTeamIndex)
|
||||
db.Exec(memberUserIndex)
|
||||
db.Exec(commitUniqueIndex)
|
||||
db.Exec(commitRepoIndex)
|
||||
db.Exec(commitBranchIndex)
|
||||
db.Exec(repoTeamIndex)
|
||||
db.Exec(repoUserIndex)
|
||||
db.Exec(buildCommitIndex)
|
||||
db.Exec(buildSlugIndex)
|
||||
|
||||
return nil
|
||||
}
|
127
pkg/database/schema/schema.sql
Normal file
127
pkg/database/schema/schema.sql
Normal file
@@ -0,0 +1,127 @@
|
||||
DROP TABLE IF EXISTS builds;
|
||||
DROP TABLE IF EXISTS commits;
|
||||
DROP TABLE IF EXISTS repos;
|
||||
DROP TABLE IF EXISTS members;
|
||||
DROP TABLE IF EXISTS teams;
|
||||
DROP TABLE IF EXISTS users;
|
||||
DROP TABLE IF EXISTS settings;
|
||||
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,email VARCHAR(255) UNIQUE
|
||||
,password VARCHAR(255)
|
||||
,token VARCHAR(255) UNIQUE
|
||||
,name VARCHAR(255)
|
||||
,gravatar VARCHAR(255)
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
,admin BOOLEAN
|
||||
|
||||
,github_login VARCHAR(255)
|
||||
,github_token VARCHAR(255)
|
||||
|
||||
,bitbucket_login VARCHAR(255)
|
||||
,bitbucket_token VARCHAR(255)
|
||||
,bitbucket_secret VARCHAR(255)
|
||||
);
|
||||
|
||||
CREATE TABLE teams (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,slug VARCHAR(255) UNIQUE
|
||||
,name VARCHAR(255) UNIQUE
|
||||
,email VARCHAR(255)
|
||||
,gravatar VARCHAR(255)
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE members (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,team_id INTEGER
|
||||
,user_id INTEGER
|
||||
,role INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE repos (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,slug VARCHAR(1024) UNIQUE
|
||||
,host VARCHAR(255)
|
||||
,owner VARCHAR(255)
|
||||
,name VARCHAR(255)
|
||||
,private BOOLEAN
|
||||
,disabled BOOLEAN
|
||||
,disabled_pr BOOLEAN
|
||||
,priveleged BOOLEAN
|
||||
,timeout INTEGER
|
||||
|
||||
,scm VARCHAR(25)
|
||||
,url VARCHAR(1024)
|
||||
,username VARCHAR(255)
|
||||
,password VARCHAR(255)
|
||||
,public_key VARCHAR(1024)
|
||||
,private_key VARCHAR(1024)
|
||||
,params VARCHAR(2000)
|
||||
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
,user_id INTEGER
|
||||
,team_id INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE commits (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,repo_id INTEGER
|
||||
,status VARCHAR(255)
|
||||
,started TIMESTAMP
|
||||
,finished TIMESTAMP
|
||||
,duration INTEGER
|
||||
,hash VARCHAR(255)
|
||||
,branch VARCHAR(255)
|
||||
,pull_request VARCHAR(255)
|
||||
,author VARCHAR(255)
|
||||
,gravatar VARCHAR(255)
|
||||
,timestamp VARCHAR(255)
|
||||
,message VARCHAR(255)
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE builds (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,commit_id INTEGER
|
||||
,slug VARCHAR(255)
|
||||
,status VARCHAR(255)
|
||||
,started TIMESTAMP
|
||||
,finished TIMESTAMP
|
||||
,duration INTEGER
|
||||
,created TIMESTAMP
|
||||
,updated TIMESTAMP
|
||||
,stdout BLOB
|
||||
);
|
||||
|
||||
CREATE TABLE settings (
|
||||
id INTEGER PRIMARY KEY
|
||||
,github_key VARCHAR(255)
|
||||
,github_secret VARCHAR(255)
|
||||
,bitbucket_key VARCHAR(255)
|
||||
,bitbucket_secret VARCHAR(255)
|
||||
,smtp_server VARCHAR(1024)
|
||||
,smtp_port VARCHAR(5)
|
||||
,smtp_address VARCHAR(1024)
|
||||
,smtp_username VARCHAR(1024)
|
||||
,smtp_password VARCHAR(1024)
|
||||
,hostname VARCHAR(1024)
|
||||
,scheme VARCHAR(5)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX member_uix ON members (team_id, user_id);
|
||||
CREATE UNIQUE INDEX commits_uix ON commits (repo_id, hash, branch);
|
||||
|
||||
CREATE INDEX member_team_ix ON members (team_id);
|
||||
CREATE INDEX member_user_ix ON members (user_id);
|
||||
CREATE INDEX repo_team_ix ON repos (team_id);
|
||||
CREATE INDEX repo_user_ix ON repos (user_id);
|
||||
CREATE INDEX commits_repo_ix ON commits (repo_id);
|
||||
CREATE INDEX commits_repo_branch_ix ON commits (repo_id, branch);
|
||||
CREATE INDEX builds_commit_ix ON builds (commit_id);
|
||||
CREATE INDEX builds_commit_slug_ix ON builds (commit_id, slug);
|
72
pkg/database/settings.go
Normal file
72
pkg/database/settings.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
. "github.com/drone/drone/pkg/model"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// Name of the Settings table in the database
|
||||
const settingsTable = "settings"
|
||||
|
||||
// SQL Queries to retrieve the system settings
|
||||
const settingsStmt = `
|
||||
SELECT id, github_key, github_secret, bitbucket_key, bitbucket_secret,
|
||||
smtp_server, smtp_port, smtp_address, smtp_username, smtp_password, hostname, scheme
|
||||
FROM settings WHERE id = 1
|
||||
`
|
||||
|
||||
//var (
|
||||
// // mutex for locking the local settings cache
|
||||
// settingsLock sync.Mutex
|
||||
//
|
||||
// // cached settings
|
||||
// settingsCache = &Settings{}
|
||||
//)
|
||||
|
||||
// Returns the system Settings.
|
||||
func GetSettings() (*Settings, error) {
|
||||
//settingsLock.Lock()
|
||||
//defer settingsLock.Unlock()
|
||||
|
||||
// return a copy of the settings
|
||||
//if settingsCache.ID == 0 {
|
||||
/// settingsCopy := &Settings{}
|
||||
// *settingsCopy = *settingsCache
|
||||
// return settingsCopy, nil
|
||||
//}
|
||||
|
||||
settings := Settings{}
|
||||
err := meddler.QueryRow(db, &settings, settingsStmt)
|
||||
//if err == sql.ErrNoRows {
|
||||
// // we ignore the NoRows error in case this
|
||||
// // is the first time the system is being used
|
||||
// err = nil
|
||||
//}
|
||||
return &settings, err
|
||||
}
|
||||
|
||||
// Returns the system Settings. This is expected
|
||||
// always pass, and will panic on failure.
|
||||
func SettingsMust() *Settings {
|
||||
settings, err := GetSettings()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return settings
|
||||
}
|
||||
|
||||
// Saves the system Settings.
|
||||
func SaveSettings(settings *Settings) error {
|
||||
//settingsLock.Lock()
|
||||
//defer settingsLock.Unlock()
|
||||
|
||||
// persist changes to settings
|
||||
err := meddler.Save(db, settingsTable, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// store updated settings in cache
|
||||
//*settingsCache = *settings
|
||||
return nil
|
||||
}
|
73
pkg/database/teams.go
Normal file
73
pkg/database/teams.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/drone/drone/pkg/model"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// Name of the Team table in the database
|
||||
const teamTable = "teams"
|
||||
|
||||
// SQL Queries to retrieve a list of all teams belonging to a user.
|
||||
const teamStmt = `
|
||||
SELECT id, slug, name, email, gravatar, created, updated
|
||||
FROM teams
|
||||
WHERE id IN (select team_id from members where user_id = ?)
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a team by id and user.
|
||||
const teamFindStmt = `
|
||||
SELECT id, slug, name, email, gravatar, created, updated
|
||||
FROM teams
|
||||
WHERE id = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a team by slug.
|
||||
const teamFindSlugStmt = `
|
||||
SELECT id, slug, name, email, gravatar, created, updated
|
||||
FROM teams
|
||||
WHERE slug = ?
|
||||
`
|
||||
|
||||
// Returns the Team with the given ID.
|
||||
func GetTeam(id int64) (*Team, error) {
|
||||
team := Team{}
|
||||
err := meddler.QueryRow(db, &team, teamFindStmt, id)
|
||||
return &team, err
|
||||
}
|
||||
|
||||
// Returns the Team with the given slug.
|
||||
func GetTeamSlug(slug string) (*Team, error) {
|
||||
team := Team{}
|
||||
err := meddler.QueryRow(db, &team, teamFindSlugStmt, slug)
|
||||
return &team, err
|
||||
}
|
||||
|
||||
// Saves a Team.
|
||||
func SaveTeam(team *Team) error {
|
||||
if team.ID == 0 {
|
||||
team.Created = time.Now().UTC()
|
||||
}
|
||||
team.Updated = time.Now().UTC()
|
||||
return meddler.Save(db, teamTable, team)
|
||||
}
|
||||
|
||||
// Deletes an existing Team account.
|
||||
func DeleteTeam(id int64) error {
|
||||
// disassociate all repos with this team
|
||||
db.Exec("UPDATE repos SET team_id = 0 WHERE team_id = ?", id)
|
||||
// delete the team memberships and the team itself
|
||||
db.Exec("DELETE FROM members WHERE team_id = ?", id)
|
||||
db.Exec("DELETE FROM teams WHERE id = ?", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns a list of all Teams associated
|
||||
// with the specified User ID.
|
||||
func ListTeams(id int64) ([]*Team, error) {
|
||||
var teams []*Team
|
||||
err := meddler.QueryAll(db, &teams, teamStmt, id)
|
||||
return teams, err
|
||||
}
|
136
pkg/database/testing/builds_test.go
Normal file
136
pkg/database/testing/builds_test.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
)
|
||||
|
||||
func TestGetBuild(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
build, err := database.GetBuild(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if build.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, build.ID)
|
||||
}
|
||||
|
||||
if build.Slug != "node_0.10" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "node_0.10", build.Slug)
|
||||
}
|
||||
|
||||
if build.Status != "Success" {
|
||||
t.Errorf("Exepected Status %s, got %s", "Success", build.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBuildSlug(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
build, err := database.GetBuildSlug("node_0.10", 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if build.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, build.ID)
|
||||
}
|
||||
|
||||
if build.Slug != "node_0.10" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "node_0.10", build.Slug)
|
||||
}
|
||||
|
||||
if build.Status != "Success" {
|
||||
t.Errorf("Exepected Status %s, got %s", "Success", build.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveBbuild(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// get the build we plan to update
|
||||
build, err := database.GetBuild(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// update fields
|
||||
build.Status = "Failing"
|
||||
|
||||
// update the database
|
||||
if err := database.SaveBuild(build); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// get the updated build
|
||||
updatedBuild, err := database.GetBuild(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if build.ID != updatedBuild.ID {
|
||||
t.Errorf("Exepected ID %d, got %d", updatedBuild.ID, build.ID)
|
||||
}
|
||||
|
||||
if build.Slug != updatedBuild.Slug {
|
||||
t.Errorf("Exepected Slug %s, got %s", updatedBuild.Slug, build.Slug)
|
||||
}
|
||||
|
||||
if build.Status != updatedBuild.Status {
|
||||
t.Errorf("Exepected Status %s, got %s", updatedBuild.Status, build.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteBuild(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
if err := database.DeleteBuild(1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// try to get the deleted row
|
||||
_, err := database.GetBuild(1)
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListBuilds(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// builds for commit_id = 1
|
||||
builds, err := database.ListBuilds(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify user count
|
||||
if len(builds) != 2 {
|
||||
t.Errorf("Exepected %d builds in database, got %d", 2, len(builds))
|
||||
return
|
||||
}
|
||||
|
||||
// get the first user in the list and verify
|
||||
// fields are being populated correctly
|
||||
build := builds[1]
|
||||
|
||||
if build.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, build.ID)
|
||||
}
|
||||
|
||||
if build.Slug != "node_0.10" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "node_0.10", build.Slug)
|
||||
}
|
||||
|
||||
if build.Status != "Success" {
|
||||
t.Errorf("Exepected Status %s, got %s", "Success", build.Status)
|
||||
}
|
||||
}
|
164
pkg/database/testing/commits_test.go
Normal file
164
pkg/database/testing/commits_test.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
)
|
||||
|
||||
func TestGetCommit(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
commit, err := database.GetCommit(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if commit.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, commit.ID)
|
||||
}
|
||||
|
||||
if commit.Status != "Success" {
|
||||
t.Errorf("Exepected Status %s, got %s", "Success", commit.Status)
|
||||
}
|
||||
|
||||
if commit.Hash != "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608" {
|
||||
t.Errorf("Exepected Hash %s, got %s", "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608", commit.Hash)
|
||||
}
|
||||
|
||||
if commit.Branch != "master" {
|
||||
t.Errorf("Exepected Branch %s, got %s", "master", commit.Branch)
|
||||
}
|
||||
|
||||
if commit.Author != "brad.rydzewski@gmail.com" {
|
||||
t.Errorf("Exepected Author %s, got %s", "master", commit.Author)
|
||||
}
|
||||
|
||||
if commit.Message != "commit message" {
|
||||
t.Errorf("Exepected Message %s, got %s", "master", commit.Message)
|
||||
}
|
||||
|
||||
if commit.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", commit.Gravatar)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCommitHash(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
commit, err := database.GetCommitHash("4f4c4594be6d6ddbc1c0dd521334f7ecba92b608", 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if commit.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, commit.ID)
|
||||
}
|
||||
|
||||
if commit.Hash != "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608" {
|
||||
t.Errorf("Exepected Hash %s, got %s", "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608", commit.Hash)
|
||||
}
|
||||
|
||||
if commit.Status != "Success" {
|
||||
t.Errorf("Exepected Status %s, got %s", "Success", commit.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveCommit(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// get the commit we plan to update
|
||||
commit, err := database.GetCommit(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// update fields
|
||||
commit.Status = "Failing"
|
||||
|
||||
// update the database
|
||||
if err := database.SaveCommit(commit); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// get the updated commit
|
||||
updatedCommit, err := database.GetCommit(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if commit.Hash != updatedCommit.Hash {
|
||||
t.Errorf("Exepected Hash %s, got %s", updatedCommit.Hash, commit.Hash)
|
||||
}
|
||||
|
||||
if commit.Status != "Failing" {
|
||||
t.Errorf("Exepected Status %s, got %s", updatedCommit.Status, commit.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteCommit(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
if err := database.DeleteCommit(1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// try to get the deleted row
|
||||
_, err := database.GetCommit(1)
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListCommits(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// commits for repo_id = 1
|
||||
commits, err := database.ListCommits(1, "master")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify commit count
|
||||
if len(commits) != 2 {
|
||||
t.Errorf("Exepected %d commits in database, got %d", 2, len(commits))
|
||||
return
|
||||
}
|
||||
|
||||
// get the first user in the list and verify
|
||||
// fields are being populated correctly
|
||||
commit := commits[1] // TODO something strange is happening with ordering here
|
||||
|
||||
if commit.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, commit.ID)
|
||||
}
|
||||
|
||||
if commit.Status != "Success" {
|
||||
t.Errorf("Exepected Status %s, got %s", "Success", commit.Status)
|
||||
}
|
||||
|
||||
if commit.Hash != "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608" {
|
||||
t.Errorf("Exepected Hash %s, got %s", "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608", commit.Hash)
|
||||
}
|
||||
|
||||
if commit.Branch != "master" {
|
||||
t.Errorf("Exepected Branch %s, got %s", "master", commit.Branch)
|
||||
}
|
||||
|
||||
if commit.Author != "brad.rydzewski@gmail.com" {
|
||||
t.Errorf("Exepected Author %s, got %s", "master", commit.Author)
|
||||
}
|
||||
|
||||
if commit.Message != "commit message" {
|
||||
t.Errorf("Exepected Message %s, got %s", "master", commit.Message)
|
||||
}
|
||||
|
||||
if commit.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", commit.Gravatar)
|
||||
}
|
||||
}
|
140
pkg/database/testing/members_test.go
Normal file
140
pkg/database/testing/members_test.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
"github.com/drone/drone/pkg/model"
|
||||
)
|
||||
|
||||
// TODO unit test to verify unique constraint on Team.Name
|
||||
|
||||
// TestGetMember tests the ability to retrieve a Team
|
||||
// Member from the database by Unique ID.
|
||||
func TestGetMember(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// get member by user_id and team_id
|
||||
member, err := database.GetMember(1, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if member.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, member.ID)
|
||||
}
|
||||
|
||||
if member.Name != "Brad Rydzewski" {
|
||||
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", member.Name)
|
||||
}
|
||||
|
||||
if member.Email != "brad.rydzewski@gmail.com" {
|
||||
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", member.Email)
|
||||
}
|
||||
|
||||
if member.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", member.Gravatar)
|
||||
}
|
||||
|
||||
if member.Role != model.RoleOwner {
|
||||
t.Errorf("Exepected Role %s, got %s", model.RoleOwner, member.Role)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsMember(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
ok, err := database.IsMember(1, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Errorf("Expected IsMember to return true, returned false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsMemberAdmin(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// expecting user is Owner
|
||||
if ok, err := database.IsMemberAdmin(1, 1); err != nil {
|
||||
t.Error(err)
|
||||
} else if !ok {
|
||||
t.Errorf("Expected IsMemberAdmin to return true, returned false")
|
||||
}
|
||||
|
||||
// expecting user is Admin
|
||||
if ok, err := database.IsMemberAdmin(2, 1); err != nil {
|
||||
t.Error(err)
|
||||
} else if !ok {
|
||||
t.Errorf("Expected IsMemberAdmin to return true, returned false")
|
||||
}
|
||||
|
||||
// expecting user is NOT Admin (Write role)
|
||||
if ok, err := database.IsMemberAdmin(3, 1); err != nil {
|
||||
t.Error(err)
|
||||
} else if ok {
|
||||
t.Errorf("Expected IsMemberAdmin to return false, returned true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteMember(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// delete member by user_id and team_id
|
||||
if err := database.DeleteMember(1, 1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// get member by user_id and team_id
|
||||
if _, err := database.GetMember(1, 1); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestListMembers(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// list members by team_id
|
||||
members, err := database.ListMembers(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify team count
|
||||
if len(members) != 3 {
|
||||
t.Errorf("Exepected %d Team Members in database, got %d", 3, len(members))
|
||||
return
|
||||
}
|
||||
|
||||
// get the first member in the list and verify
|
||||
// fields are being populated correctly
|
||||
member := members[0]
|
||||
|
||||
if member.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, member.ID)
|
||||
}
|
||||
|
||||
if member.Name != "Brad Rydzewski" {
|
||||
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", member.Name)
|
||||
}
|
||||
|
||||
if member.Email != "brad.rydzewski@gmail.com" {
|
||||
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", member.Email)
|
||||
}
|
||||
|
||||
if member.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", member.Gravatar)
|
||||
}
|
||||
|
||||
if member.Role != model.RoleOwner {
|
||||
t.Errorf("Exepected Role %s, got %s", model.RoleOwner, member.Role)
|
||||
}
|
||||
}
|
403
pkg/database/testing/repos_test.go
Normal file
403
pkg/database/testing/repos_test.go
Normal file
@@ -0,0 +1,403 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
)
|
||||
|
||||
// TODO unit test to verify unique constraint on Member.UserID and Member.TeamID
|
||||
|
||||
// TestGetRepo tests the ability to retrieve a Repo
|
||||
// from the database by Unique ID.
|
||||
func TestGetRepo(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
repo, err := database.GetRepo(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if repo.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.ID)
|
||||
}
|
||||
|
||||
if repo.Slug != "github.com/drone/drone" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "github.com/drone/drone", repo.Slug)
|
||||
}
|
||||
|
||||
if repo.Host != "github.com" {
|
||||
t.Errorf("Exepected Host %s, got %s", "github.com", repo.Host)
|
||||
}
|
||||
|
||||
if repo.Owner != "drone" {
|
||||
t.Errorf("Exepected Owner %s, got %s", "drone", repo.Owner)
|
||||
}
|
||||
|
||||
if repo.Name != "drone" {
|
||||
t.Errorf("Exepected Name %s, got %s", "drone", repo.Name)
|
||||
}
|
||||
|
||||
if repo.Private != true {
|
||||
t.Errorf("Exepected Private %v, got %v", true, repo.Private)
|
||||
}
|
||||
|
||||
if repo.Disabled != false {
|
||||
t.Errorf("Exepected Private %v, got %v", false, repo.Disabled)
|
||||
}
|
||||
|
||||
if repo.SCM != "git" {
|
||||
t.Errorf("Exepected Type %s, got %s", "git", repo.SCM)
|
||||
}
|
||||
|
||||
if repo.URL != "git@github.com:drone/drone.git" {
|
||||
t.Errorf("Exepected URL %s, got %s", "git@github.com:drone/drone.git", repo.URL)
|
||||
}
|
||||
|
||||
if repo.Username != "no username" {
|
||||
t.Errorf("Exepected Username %s, got %s", "no username", repo.Username)
|
||||
}
|
||||
|
||||
if repo.Password != "no password" {
|
||||
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
|
||||
}
|
||||
|
||||
if repo.PublicKey != "public key" {
|
||||
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
|
||||
}
|
||||
|
||||
if repo.PrivateKey != "private key" {
|
||||
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
|
||||
}
|
||||
|
||||
if repo.UserID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.UserID)
|
||||
}
|
||||
|
||||
if repo.TeamID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.TeamID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetRepoSlug tests the ability to retrieve a Repo
|
||||
// from the database by it's Canonical Name.
|
||||
func TestGetRepoSlug(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
repo, err := database.GetRepoSlug("github.com/drone/drone")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if repo.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.ID)
|
||||
}
|
||||
|
||||
if repo.Slug != "github.com/drone/drone" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "github.com/drone/drone", repo.Slug)
|
||||
}
|
||||
|
||||
if repo.Host != "github.com" {
|
||||
t.Errorf("Exepected Host %s, got %s", "github.com", repo.Host)
|
||||
}
|
||||
|
||||
if repo.Owner != "drone" {
|
||||
t.Errorf("Exepected Owner %s, got %s", "drone", repo.Owner)
|
||||
}
|
||||
|
||||
if repo.Name != "drone" {
|
||||
t.Errorf("Exepected Name %s, got %s", "drone", repo.Name)
|
||||
}
|
||||
|
||||
if repo.Private != true {
|
||||
t.Errorf("Exepected Private %v, got %v", true, repo.Private)
|
||||
}
|
||||
|
||||
if repo.Disabled != false {
|
||||
t.Errorf("Exepected Private %v, got %v", false, repo.Disabled)
|
||||
}
|
||||
|
||||
if repo.SCM != "git" {
|
||||
t.Errorf("Exepected Type %s, got %s", "git", repo.SCM)
|
||||
}
|
||||
|
||||
if repo.URL != "git@github.com:drone/drone.git" {
|
||||
t.Errorf("Exepected URL %s, got %s", "git@github.com:drone/drone.git", repo.URL)
|
||||
}
|
||||
|
||||
if repo.Username != "no username" {
|
||||
t.Errorf("Exepected Username %s, got %s", "no username", repo.Username)
|
||||
}
|
||||
|
||||
if repo.Password != "no password" {
|
||||
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
|
||||
}
|
||||
|
||||
if repo.PublicKey != "public key" {
|
||||
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
|
||||
}
|
||||
|
||||
if repo.PrivateKey != "private key" {
|
||||
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
|
||||
}
|
||||
|
||||
if repo.UserID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.UserID)
|
||||
}
|
||||
|
||||
if repo.TeamID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.TeamID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveRepo(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// get the repo we plan to update
|
||||
repo, err := database.GetRepo(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// update fields
|
||||
repo.Slug = "bitbucket.org/drone/drone"
|
||||
repo.Host = "bitbucket.org"
|
||||
repo.Private = false
|
||||
repo.Disabled = true
|
||||
repo.SCM = "hg"
|
||||
repo.URL = "https://bitbucket.org/drone/drone"
|
||||
repo.Username = "brad"
|
||||
repo.Password = "password"
|
||||
repo.TeamID = 0
|
||||
|
||||
// update the database
|
||||
if err := database.SaveRepo(repo); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// get the updated repo
|
||||
updatedRepo, err := database.GetRepo(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if updatedRepo.Slug != repo.Slug {
|
||||
t.Errorf("Exepected Slug %s, got %s", updatedRepo.Slug, repo.Slug)
|
||||
}
|
||||
|
||||
if updatedRepo.Host != repo.Host {
|
||||
t.Errorf("Exepected Host %s, got %s", updatedRepo.Host, repo.Host)
|
||||
}
|
||||
|
||||
if updatedRepo.Private != repo.Private {
|
||||
t.Errorf("Exepected Private %v, got %v", updatedRepo.Private, repo.Private)
|
||||
}
|
||||
|
||||
if updatedRepo.Disabled != repo.Disabled {
|
||||
t.Errorf("Exepected Private %v, got %v", updatedRepo.Disabled, repo.Disabled)
|
||||
}
|
||||
|
||||
if updatedRepo.SCM != repo.SCM {
|
||||
t.Errorf("Exepected Type %s, got %s", true, repo.SCM)
|
||||
}
|
||||
|
||||
if updatedRepo.URL != repo.URL {
|
||||
t.Errorf("Exepected URL %s, got %s", updatedRepo.URL, repo.URL)
|
||||
}
|
||||
|
||||
if updatedRepo.Username != repo.Username {
|
||||
t.Errorf("Exepected Username %s, got %s", updatedRepo.Username, repo.Username)
|
||||
}
|
||||
|
||||
if updatedRepo.Password != repo.Password {
|
||||
t.Errorf("Exepected Password %s, got %s", updatedRepo.Password, repo.Password)
|
||||
}
|
||||
|
||||
if updatedRepo.TeamID != repo.TeamID {
|
||||
t.Errorf("Exepected TeamID %d, got %d", updatedRepo.TeamID, repo.TeamID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRepo(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
if err := database.DeleteRepo(1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// try to get the deleted row
|
||||
_, err := database.GetRepo(1)
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestListRepos(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// repos for user_id = 1
|
||||
repos, err := database.ListRepos(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify user count
|
||||
if len(repos) != 2 {
|
||||
t.Errorf("Exepected %d repos in database, got %d", 2, len(repos))
|
||||
return
|
||||
}
|
||||
|
||||
// get the second repo in the list and verify
|
||||
// fields are being populated correctly
|
||||
// NOTE: we get the 2nd repo due to sorting
|
||||
repo := repos[1]
|
||||
|
||||
if repo.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.ID)
|
||||
}
|
||||
|
||||
if repo.Name != "github.com/drone/drone" {
|
||||
t.Errorf("Exepected Name %s, got %s", "github.com/drone/drone", repo.Name)
|
||||
}
|
||||
|
||||
if repo.Host != "github.com" {
|
||||
t.Errorf("Exepected Host %s, got %s", "github.com", repo.Host)
|
||||
}
|
||||
|
||||
if repo.Owner != "drone" {
|
||||
t.Errorf("Exepected Owner %s, got %s", "drone", repo.Owner)
|
||||
}
|
||||
|
||||
if repo.Slug != "drone" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "drone", repo.Slug)
|
||||
}
|
||||
|
||||
if repo.Private != true {
|
||||
t.Errorf("Exepected Private %v, got %v", true, repo.Private)
|
||||
}
|
||||
|
||||
if repo.Disabled != false {
|
||||
t.Errorf("Exepected Private %v, got %v", false, repo.Disabled)
|
||||
}
|
||||
|
||||
if repo.SCM != "git" {
|
||||
t.Errorf("Exepected Type %s, got %s", "git", repo.SCM)
|
||||
}
|
||||
|
||||
if repo.URL != "git@github.com:drone/drone.git" {
|
||||
t.Errorf("Exepected URL %s, got %s", "git@github.com:drone/drone.git", repo.URL)
|
||||
}
|
||||
|
||||
if repo.Username != "no username" {
|
||||
t.Errorf("Exepected Username %s, got %s", "no username", repo.Username)
|
||||
}
|
||||
|
||||
if repo.Password != "no password" {
|
||||
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
|
||||
}
|
||||
|
||||
if repo.PublicKey != "public key" {
|
||||
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
|
||||
}
|
||||
|
||||
if repo.PrivateKey != "private key" {
|
||||
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
|
||||
}
|
||||
|
||||
if repo.UserID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.UserID)
|
||||
}
|
||||
|
||||
if repo.TeamID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.TeamID)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func TestListReposTeam(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// repos for team_id = 1
|
||||
repos, err := database.ListReposTeam(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify user count
|
||||
if len(repos) != 2 {
|
||||
t.Errorf("Exepected %d repos in database, got %d", 2, len(repos))
|
||||
return
|
||||
}
|
||||
|
||||
// get the second repo in the list and verify
|
||||
// fields are being populated correctly
|
||||
// NOTE: we get the 2nd repo due to sorting
|
||||
repo := repos[1]
|
||||
|
||||
if repo.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.ID)
|
||||
}
|
||||
|
||||
if repo.Slug != "github.com/drone/drone" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "github.com/drone/drone", repo.Slug)
|
||||
}
|
||||
|
||||
if repo.Host != "github.com" {
|
||||
t.Errorf("Exepected Host %s, got %s", "github.com", repo.Host)
|
||||
}
|
||||
|
||||
if repo.Owner != "drone" {
|
||||
t.Errorf("Exepected Owner %s, got %s", "drone", repo.Owner)
|
||||
}
|
||||
|
||||
if repo.Name != "drone" {
|
||||
t.Errorf("Exepected Name %s, got %s", "drone", repo.Name)
|
||||
}
|
||||
|
||||
if repo.Private != true {
|
||||
t.Errorf("Exepected Private %v, got %v", true, repo.Private)
|
||||
}
|
||||
|
||||
if repo.Disabled != false {
|
||||
t.Errorf("Exepected Private %v, got %v", false, repo.Disabled)
|
||||
}
|
||||
|
||||
if repo.SCM != "git" {
|
||||
t.Errorf("Exepected Type %s, got %s", "git", repo.SCM)
|
||||
}
|
||||
|
||||
if repo.URL != "git@github.com:drone/drone.git" {
|
||||
t.Errorf("Exepected URL %s, got %s", "git@github.com:drone/drone.git", repo.URL)
|
||||
}
|
||||
|
||||
if repo.Username != "no username" {
|
||||
t.Errorf("Exepected Username %s, got %s", "no username", repo.Username)
|
||||
}
|
||||
|
||||
if repo.Password != "no password" {
|
||||
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
|
||||
}
|
||||
|
||||
if repo.PublicKey != "public key" {
|
||||
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
|
||||
}
|
||||
|
||||
if repo.PrivateKey != "private key" {
|
||||
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
|
||||
}
|
||||
|
||||
if repo.UserID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.UserID)
|
||||
}
|
||||
|
||||
if repo.TeamID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, repo.TeamID)
|
||||
}
|
||||
}
|
63
pkg/database/testing/settings_test.go
Normal file
63
pkg/database/testing/settings_test.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
)
|
||||
|
||||
func TestGetSettings(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// even though no settings exist yet, we should
|
||||
// not see an error since we supress the msg
|
||||
settings, err := database.GetSettings()
|
||||
//if err != nil {
|
||||
// t.Error(err)
|
||||
//}
|
||||
|
||||
// add some settings
|
||||
//settings := &modelSettings{}
|
||||
settings.Scheme = "https"
|
||||
settings.Domain = "foo.com"
|
||||
settings.BitbucketKey = "bitbucketkey"
|
||||
settings.BitbucketSecret = "bitbucketsecret"
|
||||
settings.GitHubKey = "githubkey"
|
||||
settings.GitHubSecret = "githubsecret"
|
||||
settings.SmtpAddress = "noreply@foo.bar"
|
||||
settings.SmtpServer = "0.0.0.0"
|
||||
settings.SmtpUsername = "username"
|
||||
settings.SmtpPassword = "password"
|
||||
|
||||
// save the updated settings
|
||||
if err := database.SaveSettings(settings); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// re-retrieve the settings post-save
|
||||
settings, err = database.GetSettings()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if settings.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, settings.ID)
|
||||
}
|
||||
|
||||
if settings.Scheme != "https" {
|
||||
t.Errorf("Exepected Scheme %s, got %s", "https", settings.Scheme)
|
||||
}
|
||||
|
||||
if settings.Domain != "foo.com" {
|
||||
t.Errorf("Exepected Domain %s, got %s", "foo.com", settings.Domain)
|
||||
}
|
||||
|
||||
// Verify caching works and is threadsafe
|
||||
settingsA, _ := database.GetSettings()
|
||||
settingsB, _ := database.GetSettings()
|
||||
settingsA.Domain = "foo.bar.baz"
|
||||
if settingsA.Domain == settingsB.Domain {
|
||||
t.Errorf("Exepected Domain ThreadSafe and unchanged")
|
||||
}
|
||||
}
|
169
pkg/database/testing/teams_test.go
Normal file
169
pkg/database/testing/teams_test.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
)
|
||||
|
||||
// TODO unit test to verify unique constraint on Member.UserID and Member.TeamID
|
||||
|
||||
// TestGetTeam tests the ability to retrieve a Team
|
||||
// from the database by Unique ID.
|
||||
func TestGetTeam(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
team, err := database.GetTeam(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if team.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, team.ID)
|
||||
}
|
||||
|
||||
if team.Name != "Drone" {
|
||||
t.Errorf("Exepected Name %s, got %s", "Drone", team.Name)
|
||||
}
|
||||
|
||||
if team.Slug != "drone" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "drone", team.Slug)
|
||||
}
|
||||
|
||||
if team.Email != "support@drone.io" {
|
||||
t.Errorf("Exepected Email %s, got %s", "brad@drone.io", team.Email)
|
||||
}
|
||||
|
||||
if team.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", team.Gravatar)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetTeamName tests the ability to retrieve a Team
|
||||
// from the database by Unique Team Name (aka Slug).
|
||||
func TestGetTeamSlug(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
team, err := database.GetTeamSlug("drone")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if team.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, team.ID)
|
||||
}
|
||||
|
||||
if team.Name != "Drone" {
|
||||
t.Errorf("Exepected Name %s, got %s", "Drone", team.Name)
|
||||
}
|
||||
|
||||
if team.Slug != "drone" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "drone", team.Slug)
|
||||
}
|
||||
|
||||
if team.Email != "support@drone.io" {
|
||||
t.Errorf("Exepected Email %s, got %s", "brad@drone.io", team.Email)
|
||||
}
|
||||
|
||||
if team.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", team.Gravatar)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUpdateTeam tests the ability to updatee an
|
||||
// existing Team in the database.
|
||||
func TestUpdateTeam(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// get the user we plan to update
|
||||
team, err := database.GetTeam(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// update fields
|
||||
team.Email = "brad@drone.io"
|
||||
team.Gravatar = "61024896f291303615bcd4f7a0dcfb74"
|
||||
|
||||
// update the database
|
||||
if err := database.SaveTeam(team); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// get the updated team
|
||||
updatedTeam, err := database.GetTeam(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify the updated fields
|
||||
if team.Email != updatedTeam.Email {
|
||||
t.Errorf("Exepected Email %s, got %s", team.Email, updatedTeam.Email)
|
||||
}
|
||||
|
||||
if team.Gravatar != updatedTeam.Gravatar {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", team.Gravatar, updatedTeam.Gravatar)
|
||||
}
|
||||
}
|
||||
|
||||
// Test the ability to delete a Team.
|
||||
func TestDeleteTeam(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// get the team we plan to update
|
||||
if err := database.DeleteTeam(1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// now try to get the team from the database
|
||||
_, err := database.GetTeam(1)
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// Test the ability to get a list of Teams
|
||||
// to which a User belongs.
|
||||
func TestListTeam(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
teams, err := database.ListTeams(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify team count
|
||||
if len(teams) != 3 {
|
||||
t.Errorf("Exepected %d teams in database, got %d", 3, len(teams))
|
||||
return
|
||||
}
|
||||
|
||||
// get the first user in the list and verify
|
||||
// fields are being populated correctly
|
||||
team := teams[0]
|
||||
|
||||
if team.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, team.ID)
|
||||
}
|
||||
|
||||
if team.Name != "Drone" {
|
||||
t.Errorf("Exepected Name %s, got %s", "Drone", team.Name)
|
||||
}
|
||||
|
||||
if team.Slug != "drone" {
|
||||
t.Errorf("Exepected Slug %s, got %s", "drone", team.Slug)
|
||||
}
|
||||
|
||||
if team.Email != "support@drone.io" {
|
||||
t.Errorf("Exepected Email %s, got %s", "brad@drone.io", team.Email)
|
||||
}
|
||||
|
||||
if team.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", team.Gravatar)
|
||||
}
|
||||
}
|
207
pkg/database/testing/testing.go
Normal file
207
pkg/database/testing/testing.go
Normal file
@@ -0,0 +1,207 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
"github.com/drone/drone/pkg/database/encrypt"
|
||||
. "github.com/drone/drone/pkg/model"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// in-memory database used for
|
||||
// unit testing purposes.
|
||||
var db *sql.DB
|
||||
|
||||
func init() {
|
||||
// create a cipher for ecnrypting and decrypting
|
||||
// database fields
|
||||
cipher, err := aes.NewCipher([]byte("38B241096B8DA08131563770F4CDDFAC"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// register function with meddler to encrypt and
|
||||
// decrypt database fields.
|
||||
meddler.Register("gobencrypt", &encrypt.EncryptedField{cipher})
|
||||
|
||||
// notify meddler that we are working with sqlite
|
||||
meddler.Default = meddler.SQLite
|
||||
}
|
||||
|
||||
func Setup() {
|
||||
// create an in-memory database
|
||||
db, _ = sql.Open("sqlite3", ":memory:")
|
||||
|
||||
// make sure all the tables and indexes are created
|
||||
database.Set(db)
|
||||
|
||||
// create dummy user data
|
||||
user1 := User{
|
||||
Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS",
|
||||
Name: "Brad Rydzewski",
|
||||
Email: "brad.rydzewski@gmail.com",
|
||||
Gravatar: "8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
Token: "123",
|
||||
Admin: true}
|
||||
user2 := User{
|
||||
Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS",
|
||||
Name: "Thomas Burke",
|
||||
Email: "cavepig@gmail.com",
|
||||
Gravatar: "c62f7126273f7fa786274274a5dec8ce",
|
||||
Token: "456",
|
||||
Admin: false}
|
||||
user3 := User{
|
||||
Password: "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS",
|
||||
Name: "Carlos Morales",
|
||||
Email: "ytsejammer@gmail.com",
|
||||
Gravatar: "c2180a539620d90d68eaeb848364f1c2",
|
||||
Token: "789",
|
||||
Admin: false}
|
||||
|
||||
database.SaveUser(&user1)
|
||||
database.SaveUser(&user2)
|
||||
database.SaveUser(&user3)
|
||||
|
||||
// create dummy team data
|
||||
team1 := Team{
|
||||
Slug: "drone",
|
||||
Name: "Drone",
|
||||
Email: "support@drone.io",
|
||||
Gravatar: "8c58a0be77ee441bb8f8595b7f1b4e87"}
|
||||
team2 := Team{
|
||||
Slug: "github",
|
||||
Name: "Github",
|
||||
Email: "support@github.com",
|
||||
Gravatar: "61024896f291303615bcd4f7a0dcfb74"}
|
||||
team3 := Team{
|
||||
Slug: "golang",
|
||||
Name: "Golang",
|
||||
Email: "support@golang.org",
|
||||
Gravatar: "991695cc770c6b8354b68cd18c280b95"}
|
||||
|
||||
database.SaveTeam(&team1)
|
||||
database.SaveTeam(&team2)
|
||||
database.SaveTeam(&team3)
|
||||
|
||||
// create team membership data
|
||||
database.SaveMember(user1.ID, team1.ID, RoleOwner)
|
||||
database.SaveMember(user2.ID, team1.ID, RoleAdmin)
|
||||
database.SaveMember(user3.ID, team1.ID, RoleWrite)
|
||||
database.SaveMember(user1.ID, team2.ID, RoleOwner)
|
||||
database.SaveMember(user2.ID, team2.ID, RoleAdmin)
|
||||
database.SaveMember(user3.ID, team2.ID, RoleWrite)
|
||||
database.SaveMember(user1.ID, team3.ID, RoleOwner)
|
||||
|
||||
// create dummy repo data
|
||||
repo1 := Repo{
|
||||
Slug: "github.com/drone/drone",
|
||||
Host: "github.com",
|
||||
Owner: "drone",
|
||||
Name: "drone",
|
||||
Private: true,
|
||||
Disabled: false,
|
||||
SCM: "git",
|
||||
URL: "git@github.com:drone/drone.git",
|
||||
Username: "no username",
|
||||
Password: "no password",
|
||||
PublicKey: "public key",
|
||||
PrivateKey: "private key",
|
||||
UserID: user1.ID,
|
||||
TeamID: team1.ID,
|
||||
}
|
||||
repo2 := Repo{
|
||||
Slug: "bitbucket.org/drone/test",
|
||||
Host: "bitbucket.org",
|
||||
Owner: "drone",
|
||||
Name: "test",
|
||||
Private: false,
|
||||
Disabled: false,
|
||||
SCM: "hg",
|
||||
URL: "https://bitbucket.org/drone/test",
|
||||
Username: "no username",
|
||||
Password: "no password",
|
||||
PublicKey: "public key",
|
||||
PrivateKey: "private key",
|
||||
UserID: user1.ID,
|
||||
TeamID: team1.ID,
|
||||
}
|
||||
repo3 := Repo{
|
||||
Slug: "bitbucket.org/brydzewski/test",
|
||||
Host: "bitbucket.org",
|
||||
Owner: "brydzewski",
|
||||
Name: "test",
|
||||
Private: false,
|
||||
Disabled: false,
|
||||
SCM: "hg",
|
||||
URL: "https://bitbucket.org/brydzewski/test",
|
||||
Username: "no username",
|
||||
Password: "no password",
|
||||
PublicKey: "public key",
|
||||
PrivateKey: "private key",
|
||||
UserID: user2.ID,
|
||||
}
|
||||
|
||||
database.SaveRepo(&repo1)
|
||||
database.SaveRepo(&repo2)
|
||||
database.SaveRepo(&repo3)
|
||||
|
||||
commit1 := Commit{
|
||||
RepoID: repo1.ID,
|
||||
Status: "Success",
|
||||
Hash: "4f4c4594be6d6ddbc1c0dd521334f7ecba92b608",
|
||||
Branch: "master",
|
||||
Author: user1.Email,
|
||||
Gravatar: user1.Gravatar,
|
||||
Message: "commit message",
|
||||
}
|
||||
commit2 := Commit{
|
||||
RepoID: repo1.ID,
|
||||
Status: "Failure",
|
||||
Hash: "0eb2fa13e9f4139e803b6ad37831708d4786c74a",
|
||||
Branch: "master",
|
||||
Author: user1.Email,
|
||||
Gravatar: user1.Gravatar,
|
||||
Message: "commit message",
|
||||
}
|
||||
commit3 := Commit{
|
||||
RepoID: repo1.ID,
|
||||
Status: "Failure",
|
||||
Hash: "60a7fe87ccf01d0152e53242528399e05acaf047",
|
||||
Branch: "dev",
|
||||
Author: user1.Email,
|
||||
Gravatar: user1.Gravatar,
|
||||
Message: "commit message",
|
||||
}
|
||||
commit4 := Commit{
|
||||
RepoID: repo2.ID,
|
||||
Status: "Success",
|
||||
Hash: "a4078d1e9a0842cdd214adbf0512578799a4f2ba",
|
||||
Branch: "master",
|
||||
Author: user1.Email,
|
||||
Gravatar: user1.Gravatar,
|
||||
Message: "commit message",
|
||||
}
|
||||
|
||||
// create dummy commit data
|
||||
database.SaveCommit(&commit1)
|
||||
database.SaveCommit(&commit2)
|
||||
database.SaveCommit(&commit3)
|
||||
database.SaveCommit(&commit4)
|
||||
|
||||
// create dummy build data
|
||||
database.SaveBuild(&Build{CommitID: commit1.ID, Slug: "node_0.10", Status: "Success", Duration: 60})
|
||||
database.SaveBuild(&Build{CommitID: commit1.ID, Slug: "node_0.09", Status: "Success", Duration: 70})
|
||||
database.SaveBuild(&Build{CommitID: commit2.ID, Slug: "node_0.10", Status: "Success", Duration: 10})
|
||||
database.SaveBuild(&Build{CommitID: commit2.ID, Slug: "node_0.09", Status: "Failure", Duration: 65})
|
||||
database.SaveBuild(&Build{CommitID: commit3.ID, Slug: "node_0.10", Status: "Failure", Duration: 50})
|
||||
database.SaveBuild(&Build{CommitID: commit3.ID, Slug: "node_0.09", Status: "Failure", Duration: 55})
|
||||
}
|
||||
|
||||
func Teardown() {
|
||||
db.Close()
|
||||
}
|
169
pkg/database/testing/users_test.go
Normal file
169
pkg/database/testing/users_test.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
)
|
||||
|
||||
// TODO unit test to verify unique constraint on User.Username
|
||||
// TODO unit test to verify unique constraint on User.Email
|
||||
|
||||
// TestGetUser tests the ability to retrieve a User
|
||||
// from the database by Unique ID.
|
||||
func TestGetUser(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
u, err := database.GetUser(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if u.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, u.ID)
|
||||
}
|
||||
|
||||
if u.Password != "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS" {
|
||||
t.Errorf("Exepected Password %s, got %s", "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", u.Password)
|
||||
}
|
||||
|
||||
if u.Name != "Brad Rydzewski" {
|
||||
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", u.Name)
|
||||
}
|
||||
|
||||
if u.Email != "brad.rydzewski@gmail.com" {
|
||||
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", u.Email)
|
||||
}
|
||||
|
||||
if u.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", u.Gravatar)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetUseEmail tests the ability to retrieve a User
|
||||
// from the database by Email address.
|
||||
func TestGetUserEmail(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
u, err := database.GetUserEmail("brad.rydzewski@gmail.com")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if u.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, u.ID)
|
||||
}
|
||||
|
||||
if u.Password != "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS" {
|
||||
t.Errorf("Exepected Password %s, got %s", "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", u.Password)
|
||||
}
|
||||
|
||||
if u.Name != "Brad Rydzewski" {
|
||||
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", u.Name)
|
||||
}
|
||||
|
||||
if u.Email != "brad.rydzewski@gmail.com" {
|
||||
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", u.Email)
|
||||
}
|
||||
|
||||
if u.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", u.Gravatar)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUpdateUser tests the ability to updatee an
|
||||
// existing User in the database.
|
||||
func TestUpdateUser(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// get the user we plan to update
|
||||
user, err := database.GetUser(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// update fields
|
||||
user.Email = "brad@drone.io"
|
||||
user.Password = "password"
|
||||
|
||||
// update the database
|
||||
if err := database.SaveUser(user); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// get the updated user
|
||||
updatedUser, err := database.GetUser(1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify the updated fields
|
||||
if user.Email != updatedUser.Email {
|
||||
t.Errorf("Exepected Email %s, got %s", user.Email, updatedUser.Email)
|
||||
}
|
||||
|
||||
if user.Password != updatedUser.Password {
|
||||
t.Errorf("Exepected Password %s, got %s", user.Email, updatedUser.Password)
|
||||
}
|
||||
}
|
||||
|
||||
// Deletes an existing User account.
|
||||
func TestDeleteUser(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
// get the user we plan to update
|
||||
if err := database.DeleteUser(1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// now try to get the user from the database
|
||||
_, err := database.GetUser(1)
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a list of all Users.
|
||||
func TestListUsers(t *testing.T) {
|
||||
Setup()
|
||||
defer Teardown()
|
||||
|
||||
users, err := database.ListUsers()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// verify user count
|
||||
if len(users) != 3 {
|
||||
t.Errorf("Exepected %d users in database, got %d", 3, len(users))
|
||||
return
|
||||
}
|
||||
|
||||
// get the first user in the list and verify
|
||||
// fields are being populated correctly
|
||||
u := users[0]
|
||||
|
||||
if u.ID != 1 {
|
||||
t.Errorf("Exepected ID %d, got %d", 1, u.ID)
|
||||
}
|
||||
|
||||
if u.Password != "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS" {
|
||||
t.Errorf("Exepected Password %s, got %s", "$2a$10$b8d63QsTL38vx7lj0HEHfOdbu1PCAg6Gfca74UavkXooIBx9YxopS", u.Password)
|
||||
}
|
||||
|
||||
if u.Name != "Brad Rydzewski" {
|
||||
t.Errorf("Exepected Name %s, got %s", "Brad Rydzewski", u.Name)
|
||||
}
|
||||
|
||||
if u.Email != "brad.rydzewski@gmail.com" {
|
||||
t.Errorf("Exepected Email %s, got %s", "brad.rydzewski@gmail.com", u.Email)
|
||||
}
|
||||
|
||||
if u.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" {
|
||||
t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", u.Gravatar)
|
||||
}
|
||||
}
|
90
pkg/database/users.go
Normal file
90
pkg/database/users.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/drone/drone/pkg/model"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// Name of the User table in the database
|
||||
const userTable = "users"
|
||||
|
||||
// SQL Queries to retrieve a user by their unique database key
|
||||
const userFindIdStmt = `
|
||||
SELECT id, email, password, name, gravatar, created, updated, admin,
|
||||
github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret
|
||||
FROM users WHERE id = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a user by their email address
|
||||
const userFindEmailStmt = `
|
||||
SELECT id, email, password, name, gravatar, created, updated, admin,
|
||||
github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret
|
||||
FROM users WHERE email = ?
|
||||
`
|
||||
|
||||
// SQL Queries to retrieve a list of all users
|
||||
const userStmt = `
|
||||
SELECT id, email, password, name, gravatar, created, updated, admin,
|
||||
github_login, github_token, bitbucket_login, bitbucket_token, bitbucket_secret
|
||||
FROM users
|
||||
ORDER BY name ASC
|
||||
`
|
||||
|
||||
// Returns the User with the given ID.
|
||||
func GetUser(id int64) (*User, error) {
|
||||
user := User{}
|
||||
err := meddler.QueryRow(db, &user, userFindIdStmt, id)
|
||||
return &user, err
|
||||
}
|
||||
|
||||
// Returns the User with the given email address.
|
||||
func GetUserEmail(email string) (*User, error) {
|
||||
user := User{}
|
||||
err := meddler.QueryRow(db, &user, userFindEmailStmt, email)
|
||||
return &user, err
|
||||
}
|
||||
|
||||
// Returns the User Password Hash for the given
|
||||
// email address.
|
||||
func GetPassEmail(email string) ([]byte, error) {
|
||||
user, err := GetUserEmail(email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []byte(user.Password), nil
|
||||
}
|
||||
|
||||
// Saves the User account.
|
||||
func SaveUser(user *User) error {
|
||||
if user.ID == 0 {
|
||||
user.Created = time.Now().UTC()
|
||||
}
|
||||
user.Updated = time.Now().UTC()
|
||||
return meddler.Save(db, userTable, user)
|
||||
}
|
||||
|
||||
// Deletes an existing User account.
|
||||
func DeleteUser(id int64) error {
|
||||
db.Exec("DELETE FROM members WHERE user_id = ?", id)
|
||||
db.Exec("DELETE FROM users WHERE id = ?", id)
|
||||
// TODO delete all projects
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns a list of all Users.
|
||||
func ListUsers() ([]*User, error) {
|
||||
var users []*User
|
||||
err := meddler.QueryAll(db, &users, userStmt)
|
||||
return users, err
|
||||
}
|
||||
|
||||
// Returns a list of Users within the specified
|
||||
// range (for pagination purposes).
|
||||
func ListUsersRange(limit, offset int) ([]*User, error) {
|
||||
var users []*User
|
||||
err := meddler.QueryAll(db, &users, userStmt)
|
||||
return users, err
|
||||
}
|
Reference in New Issue
Block a user