woodpecker/datastore/builtin/commit.go
2015-05-11 00:45:31 -07:00

169 lines
4 KiB
Go

package builtin
import (
"database/sql"
"time"
"github.com/drone/drone/common"
"github.com/russross/meddler"
)
type Commitstore struct {
*sql.DB
}
func NewCommitstore(db *sql.DB) *Commitstore {
return &Commitstore{db}
}
// Commit gets a commit by ID
func (db *Commitstore) Commit(id int64) (*common.Commit, error) {
var commit = new(common.Commit)
var err = meddler.Load(db, commitTable, commit, id)
return commit, err
}
// CommitSeq gets the specified commit sequence for the
// named repository and commit number
func (db *Commitstore) CommitSeq(repo *common.Repo, seq int) (*common.Commit, error) {
var commit = new(common.Commit)
var err = meddler.QueryRow(db, commit, rebind(commitNumberQuery), repo.ID, seq)
return commit, err
}
// CommitLast gets the last executed commit for the
// named repository.
func (db *Commitstore) CommitLast(repo *common.Repo, branch string) (*common.Commit, error) {
var commit = new(common.Commit)
var err = meddler.QueryRow(db, commit, rebind(commitLastQuery), repo.ID, branch)
return commit, err
}
// CommitList gets a list of recent commits for the
// named repository.
func (db *Commitstore) CommitList(repo *common.Repo, limit, offset int) ([]*common.Commit, error) {
var commits []*common.Commit
var err = meddler.QueryAll(db, &commits, rebind(commitListQuery), repo.ID, limit, offset)
return commits, err
}
// AddCommit inserts a new commit in the datastore.
func (db *Commitstore) AddCommit(commit *common.Commit) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
// extract the next commit number from the database
row := tx.QueryRow(rebind(commitNumberLast), commit.RepoID)
if row != nil {
row.Scan(&commit.Sequence)
}
commit.Sequence = commit.Sequence + 1 // increment
commit.Created = time.Now().UTC().Unix()
commit.Updated = time.Now().UTC().Unix()
err = meddler.Insert(tx, commitTable, commit)
if err != nil {
return err
}
for _, build := range commit.Builds {
build.CommitID = commit.ID
build.Created = commit.Created
build.Updated = commit.Updated
err := meddler.Insert(tx, buildTable, build)
if err != nil {
return err
}
}
return tx.Commit()
}
// SetCommit updates an existing commit and commit tasks.
func (db *Commitstore) SetCommit(commit *common.Commit) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
commit.Updated = time.Now().UTC().Unix()
err = meddler.Update(tx, commitTable, commit)
if err != nil {
return err
}
for _, build := range commit.Builds {
build.Updated = commit.Updated
err := meddler.Update(tx, buildTable, build)
if err != nil {
return err
}
}
return tx.Commit()
}
// KillCommits updates all pending or started commits
// in the datastore settings the status to killed.
func (db *Commitstore) KillCommits() error {
var _, err1 = db.Exec(rebind(buildKillStmt))
if err1 != nil {
return err1
}
var _, err2 = db.Exec(rebind(commitKillStmt))
return err2
}
// Commit table name in database.
const commitTable = "commits"
// SQL query to retrieve the latest commits across all branches.
const commitListQuery = `
SELECT *
FROM commits
WHERE repo_id = ?
ORDER BY commit_seq DESC
LIMIT ? OFFSET ?
`
// SQL query to retrieve a commit by number.
const commitNumberQuery = `
SELECT *
FROM commits
WHERE repo_id = ?
AND commit_seq = ?
LIMIT 1
`
// SQL query to retrieve the most recent commit.
// TODO exclude pull requests
const commitLastQuery = `
SELECT *
FROM commits
WHERE repo_id = ?
AND commit_branch = ?
ORDER BY commit_seq DESC
LIMIT 1
`
// SQL statement to cancel all running commits.
const commitKillStmt = `
UPDATE commits SET commit_state = 'killed'
WHERE commit_state IN ('pending', 'running');
`
// SQL statement to cancel all running commits.
const buildKillStmt = `
UPDATE builds SET build_state = 'killed'
WHERE build_state IN ('pending', 'running');
`
// SQL statement to retrieve the commit number for
// a commit
const commitNumberLast = `
SELECT MAX(commit_seq)
FROM commits
WHERE repo_id = ?
`