woodpecker/server/database/commit.go
2014-06-12 16:41:04 -07:00

237 lines
6.1 KiB
Go

package database
import (
"database/sql"
"time"
"github.com/drone/drone/shared/model"
"github.com/russross/meddler"
)
type CommitManager interface {
// Find finds the commit by ID.
Find(id int64) (*model.Commit, error)
// FindSha finds the commit for the branch and sha.
FindSha(repo int64, branch, sha string) (*model.Commit, error)
// FindLatest finds the most recent commit for the branch.
FindLatest(repo int64, branch string) (*model.Commit, error)
// FindOutput finds the commit's output.
FindOutput(commit int64) ([]byte, error)
// List finds recent commits for the repository
List(repo int64) ([]*model.Commit, error)
// ListBranch finds recent commits for the repository and branch.
ListBranch(repo int64, branch string) ([]*model.Commit, error)
// ListBranches finds most recent commit for each branch.
ListBranches(repo int64) ([]*model.Commit, error)
// ListUser finds most recent commits for a user.
ListUser(repo int64) ([]*model.CommitRepo, error)
// Insert persists the commit to the datastore.
Insert(commit *model.Commit) error
// Update persists changes to the commit to the datastore.
Update(commit *model.Commit) error
// UpdateOutput persists a commit's stdout to the datastore.
UpdateOutput(commit *model.Commit, out []byte) error
// Delete removes the commit from the datastore.
Delete(commit *model.Commit) error
// CancelAll will update the status of all Started or Pending
// builds to a status of Killed (cancelled).
CancelAll() error
}
// commitManager manages a list of commits in a SQL database.
type commitManager struct {
*sql.DB
}
// NewCommitManager initiales a new CommitManager intended to
// manage and persist commits.
func NewCommitManager(db *sql.DB) CommitManager {
return &commitManager{db}
}
// SQL query to retrieve the latest Commits for each branch.
const listBranchesQuery = `
SELECT *
FROM commits
WHERE commit_id IN (
SELECT MAX(commit_id)
FROM commits
WHERE repo_id=?
AND commit_status NOT IN ('Started', 'Pending')
GROUP BY commit_branch)
ORDER BY commit_branch ASC
`
// SQL query to retrieve the latest Commits for a specific branch.
const listBranchQuery = `
SELECT *
FROM commits
WHERE repo_id=?
AND commit_branch=?
ORDER BY commit_id DESC
LIMIT 20
`
// SQL query to retrieve the latest Commits for a user's repositories.
const listUserCommitsQuery = `
SELECT r.repo_remote, r.repo_host, r.repo_owner, r.repo_name, c.*
FROM commits c, repos r, perms p
WHERE c.repo_id=r.repo_id
AND r.repo_id=p.repo_id
AND p.user_id=?
AND c.commit_status NOT IN ('Started', 'Pending')
ORDER BY commit_id DESC
LIMIT 20
`
// SQL query to retrieve the latest Commits across all branches.
const listCommitsQuery = `
SELECT *
FROM commits
WHERE repo_id=?
ORDER BY commit_id DESC
LIMIT 20
`
// SQL query to retrieve a Commit by branch and sha.
const findCommitQuery = `
SELECT *
FROM commits
WHERE repo_id=?
AND commit_branch=?
AND commit_sha=?
LIMIT 1
`
// SQL query to retrieve the most recent Commit for a branch.
const findLatestCommitQuery = `
SELECT *
FROM commits
WHERE commit_id IN (
SELECT MAX(commit_id)
FROM commits
WHERE repo_id=?
AND commit_branch=?)
`
// SQL query to retrieve a Commit's stdout.
const findOutputQuery = `
SELECT output_raw
FROM output
WHERE commit_id = ?
`
// SQL statement to insert a Commit's stdout.
const insertOutputStmt = `
INSERT INTO output (commit_id, output_raw) values (?,?);
`
// SQL statement to update a Commit's stdout.
const updateOutputStmt = `
UPDATE output SET output_raw = ? WHERE commit_id = ?;
`
// SQL statement to delete a Commit by ID.
const deleteCommitStmt = `
DELETE FROM commits WHERE commit_id = ?;
`
// SQL statement to cancel all running Commits.
const cancelCommitStmt = `
UPDATE commits SET
commit_status = ?,
commit_started = ?,
commit_finished = ?
WHERE commit_status IN ('Started', 'Pending');
`
func (db *commitManager) Find(id int64) (*model.Commit, error) {
dst := model.Commit{}
err := meddler.Load(db, "commits", &dst, id)
return &dst, err
}
func (db *commitManager) FindSha(repo int64, branch, sha string) (*model.Commit, error) {
dst := model.Commit{}
err := meddler.QueryRow(db, &dst, findCommitQuery, repo, branch, sha)
return &dst, err
}
func (db *commitManager) FindLatest(repo int64, branch string) (*model.Commit, error) {
dst := model.Commit{}
err := meddler.QueryRow(db, &dst, findLatestCommitQuery, repo, branch)
return &dst, err
}
func (db *commitManager) FindOutput(commit int64) ([]byte, error) {
var dst string
err := db.QueryRow(findOutputQuery, commit).Scan(&dst)
return []byte(dst), err
}
func (db *commitManager) List(repo int64) ([]*model.Commit, error) {
var dst []*model.Commit
err := meddler.QueryAll(db, &dst, listCommitsQuery, repo)
return dst, err
}
func (db *commitManager) ListBranch(repo int64, branch string) ([]*model.Commit, error) {
var dst []*model.Commit
err := meddler.QueryAll(db, &dst, listBranchQuery, repo, branch)
return dst, err
}
func (db *commitManager) ListBranches(repo int64) ([]*model.Commit, error) {
var dst []*model.Commit
err := meddler.QueryAll(db, &dst, listBranchesQuery, repo)
return dst, err
}
func (db *commitManager) ListUser(user int64) ([]*model.CommitRepo, error) {
var dst []*model.CommitRepo
err := meddler.QueryAll(db, &dst, listUserCommitsQuery, user)
return dst, err
}
func (db *commitManager) Insert(commit *model.Commit) error {
commit.Created = time.Now().Unix()
commit.Updated = time.Now().Unix()
return meddler.Insert(db, "commits", commit)
}
func (db *commitManager) Update(commit *model.Commit) error {
commit.Updated = time.Now().Unix()
return meddler.Update(db, "commits", commit)
}
func (db *commitManager) UpdateOutput(commit *model.Commit, out []byte) error {
_, err := db.Exec(insertOutputStmt, commit.ID, out)
if err != nil {
return nil
}
_, err = db.Exec(updateOutputStmt, out, commit.ID)
return err
}
func (db *commitManager) Delete(commit *model.Commit) error {
_, err := db.Exec(deleteCommitStmt, commit.ID)
return err
}
func (db *commitManager) CancelAll() error {
_, err := db.Exec(cancelCommitStmt, model.StatusKilled, time.Now().Unix(), time.Now().Unix())
return err
}