woodpecker/pkg/store/builtin/build.go
2015-08-30 01:18:45 +03:00

222 lines
5.3 KiB
Go

package builtin
import (
"database/sql"
"github.com/drone/drone/pkg/types"
)
type Buildstore struct {
*sql.DB
}
func NewBuildstore(db *sql.DB) *Buildstore {
return &Buildstore{db}
}
// Build gets a build by ID
func (db *Buildstore) Build(id int64) (*types.Build, error) {
return getBuild(db, rebind(stmtBuildSelect), id)
}
// BuildNumber gets the specified build number for the
// named repository and build number
func (db *Buildstore) BuildNumber(repo *types.Repo, seq int) (*types.Build, error) {
return getBuild(db, rebind(stmtBuildSelectBuildNumber), repo.ID, seq)
}
// BuildPullRequest gets the specific build for the
// named repository and pull request number
func (db *Buildstore) BuildPullRequestNumber(repo *types.Repo, seq int) (*types.Build, error) {
return getBuild(db, rebind(stmtBuildSelectPullRequestNumber), repo.ID, seq)
}
// BuildSha gets the specific build for the
// named repository and sha
func (db *Buildstore) BuildSha(repo *types.Repo, sha, branch string) (*types.Build, error) {
return getBuild(db, rebind(stmtBuildSelectSha), repo.ID, sha, branch)
}
// BuildLast gets the last executed build for the
// named repository.
func (db *Buildstore) BuildLast(repo *types.Repo, branch string) (*types.Build, error) {
return getBuild(db, rebind(buildLastQuery), repo.ID, branch)
}
// BuildList gets a list of recent builds for the
// named repository.
func (db *Buildstore) BuildList(repo *types.Repo, limit, offset int) ([]*types.Build, error) {
return getBuilds(db, rebind(buildListQuery), repo.ID, limit, offset)
}
// AddBuild inserts a new build in the datastore.
func (db *Buildstore) AddBuild(build *types.Build) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
// extract the next build number from the database
row := tx.QueryRow(rebind(buildNumberLast), build.RepoID)
if row != nil {
row.Scan(&build.Number)
}
build.Number = build.Number + 1 // increment
err = createBuild(tx, rebind(stmtBuildInsert), build)
if err != nil {
return err
}
for _, job := range build.Jobs {
job.BuildID = build.ID
err := createJob(tx, rebind(stmtJobInsert), job)
if err != nil {
return err
}
}
return tx.Commit()
}
// SetBuild updates an existing build and build jobs.
func (db *Buildstore) SetBuild(build *types.Build) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
err = updateBuild(tx, rebind(stmtBuildUpdate), build)
if err != nil {
return err
}
for _, job := range build.Jobs {
err = updateJob(tx, rebind(stmtJobUpdate), job)
if err != nil {
return err
}
}
return tx.Commit()
}
// KillBuilds updates all pending or started builds
// in the datastore settings the status to killed.
func (db *Buildstore) KillBuilds() error {
var _, err1 = db.Exec(rebind(buildKillStmt))
if err1 != nil {
return err1
}
var _, err2 = db.Exec(rebind(jobKillStmt))
return err2
}
const stmtBuildSelectPullRequestNumber = stmtBuildSelectList + `
WHERE build_repo_id = ?
AND build_pull_request_number = ?
ORDER BY build_number DESC
LIMIT 1
`
const stmtBuildSelectSha = stmtBuildSelectList + `
WHERE build_repo_id = ?
AND build_commit_sha = ?
AND build_commit_branch = ?
ORDER BY build_number DESC
LIMIT 1
`
// SQL query to retrieve the latest builds across all branches.
const buildListQuery = `
SELECT
build_id
,build_repo_id
,build_number
,build_status
,build_started
,build_finished
,build_commit_sha
,build_commit_ref
,build_commit_link
,build_commit_branch
,build_commit_message
,build_commit_timestamp
,build_commit_remote
,build_commit_author_login
,build_commit_author_email
,build_pull_request_number
,build_pull_request_title
,build_pull_request_link
,build_pull_request_base_sha
,build_pull_request_base_ref
,build_pull_request_base_link
,build_pull_request_base_branch
,build_pull_request_base_message
,build_pull_request_base_timestamp
,build_pull_request_base_remote
,build_pull_request_base_author_login
,build_pull_request_base_author_email
FROM builds
WHERE build_repo_id = ?
ORDER BY build_number DESC
LIMIT ? OFFSET ?
`
// SQL query to retrieve the most recent build.
// TODO exclude pull requests
const buildLastQuery = `
SELECT
build_id
,build_repo_id
,build_number
,build_status
,build_started
,build_finished
,build_commit_sha
,build_commit_ref
,build_commit_link
,build_commit_branch
,build_commit_message
,build_commit_timestamp
,build_commit_remote
,build_commit_author_login
,build_commit_author_email
,build_pull_request_number
,build_pull_request_title
,build_pull_request_link
,build_pull_request_base_sha
,build_pull_request_base_ref
,build_pull_request_base_link
,build_pull_request_base_branch
,build_pull_request_base_message
,build_pull_request_base_timestamp
,build_pull_request_base_remote
,build_pull_request_base_author_login
,build_pull_request_base_author_email
FROM builds
WHERE build_repo_id = ?
AND build_commit_branch = ?
ORDER BY build_number DESC
LIMIT 1
`
// SQL statement to cancel all running builds.
const buildKillStmt = `
UPDATE builds SET build_status = 'killed'
WHERE build_status IN ('pending', 'running');
`
// SQL statement to cancel all running build jobs.
const jobKillStmt = `
UPDATE jobs SET job_status = 'killed'
WHERE job_status IN ('pending', 'running');
`
// SQL statement to retrieve the latest sequential
// build number for a build
const buildNumberLast = `
SELECT MAX(build_number)
FROM builds
WHERE build_repo_id = ?
`