Files
mpbot-github/pr/db/dbutil.go
2019-01-06 02:11:40 +00:00

244 lines
5.9 KiB
Go

package db
import (
"database/sql"
"errors"
"log"
"os"
"strings"
"time"
// PostgreSQL driver
_ "github.com/lib/pq"
)
type Maintainer struct {
GithubHandle string
Email string
}
type PortMaintainer struct {
Primary *Maintainer
Others []*Maintainer
NoMaintainer bool
OpenMaintainer bool
}
type PullRequest struct {
Number int
Processed bool
PendingReview bool
Maintainers []string
}
type DBHelper interface {
GetGitHubHandle(email string) (string, error)
GetPortMaintainer(port string) (*PortMaintainer, error)
NewPR(number int, maintainers []string) error
GetPR(number int) (*PullRequest, error)
GetTimeoutPRs() ([]*PullRequest, error)
SetPRProcessed(number int, processed bool) error
SetPRPendingReview(number int, pendingReview bool) error
}
func NewDBHelper() (DBHelper, error) {
// TODO: move os.Getenv to main
tracDB, err := sql.Open("postgres", os.Getenv("TRAC_DB"))
if err != nil {
return nil, err
}
err = tracDB.Ping()
if err != nil {
return nil, err
}
wwwDB, err := sql.Open("postgres", os.Getenv("WWW_DB"))
if err != nil {
return nil, err
}
err = wwwDB.Ping()
if err != nil {
return nil, err
}
prDB, err := sql.Open("postgres", os.Getenv("PR_DB"))
if err != nil {
return nil, err
}
err = prDB.Ping()
if err != nil {
return nil, err
}
_, err = prDB.Exec(`CREATE TABLE IF NOT EXISTS pull_requests
(
number INT PRIMARY KEY,
created TIMESTAMP NOT NULL,
processed BOOLEAN NOT NULL,
pending_review BOOLEAN NOT NULL,
maintainers TEXT NOT NULL
);`)
if err != nil {
return nil, err
}
return &sqlDBHelper{
tracDB: tracDB,
wwwDB: wwwDB,
prDB: prDB,
}, nil
}
type sqlDBHelper struct {
tracDB, wwwDB, prDB *sql.DB
}
func (sqlDB *sqlDBHelper) GetGitHubHandle(email string) (string, error) {
sid := ""
err := sqlDB.tracDB.QueryRow("SELECT sid "+
"FROM trac_macports.session_attribute "+
"WHERE value = $1 "+
"AND name = 'email' "+
"AND authenticated = 1 "+
"LIMIT 1", email).
Scan(&sid)
if err != nil {
return "", err
}
return sid, nil
}
// GetPortMaintainer returns the maintainers of a port
func (sqlDB *sqlDBHelper) GetPortMaintainer(port string) (*PortMaintainer, error) {
rows, err := sqlDB.wwwDB.Query("SELECT maintainer, is_primary "+
"FROM public.maintainers "+
"WHERE portfile = $1", port)
if err != nil {
return nil, err
}
defer rows.Close()
maintainer := new(PortMaintainer)
maintainerCursor := ""
isPrimary := false
rowExist := false
for rows.Next() {
if err := rows.Scan(&maintainerCursor, &isPrimary); err != nil {
return nil, err
}
rowExist = true
switch maintainerCursor {
case "nomaintainer":
maintainer.NoMaintainer = true
continue
case "openmaintainer":
maintainer.OpenMaintainer = true
continue
}
if isPrimary {
maintainer.Primary = sqlDB.parseMaintainer(maintainerCursor)
} else {
maintainer.Others = append(maintainer.Others, sqlDB.parseMaintainer(maintainerCursor))
}
}
err = rows.Err()
if err != nil {
return nil, err
}
if !rowExist {
return nil, errors.New("port not found")
}
if maintainer.Primary == nil && len(maintainer.Others) > 0 {
maintainer.Primary = maintainer.Others[0]
maintainer.Others = maintainer.Others[1:]
}
return maintainer, nil
}
func (sqlDB *sqlDBHelper) NewPR(number int, maintainers []string) error {
_, err := sqlDB.prDB.Exec("INSERT INTO pull_requests VALUES ($1, $2, $3, $4, $5)",
number, time.Now(), false, false, strings.Join(maintainers, " "))
return err
}
func (sqlDB *sqlDBHelper) GetPR(number int) (*PullRequest, error) {
pr := new(PullRequest)
var maintainerString string
err := sqlDB.prDB.QueryRow(
"SELECT number, processed, pending_review, maintainers FROM pull_requests WHERE number = $1", number).
Scan(&pr.Number, &pr.Processed, &pr.PendingReview, &maintainerString)
if err != nil {
return nil, err
}
pr.Maintainers = strings.Split(maintainerString, " ")
return pr, nil
}
func (sqlDB *sqlDBHelper) GetTimeoutPRs() ([]*PullRequest, error) {
var prs []*PullRequest
rows, err := sqlDB.prDB.Query("SELECT number, processed, pending_review, maintainers "+
"FROM pull_requests "+
"WHERE created <= $1 AND pending_review = true", time.Now().AddDate(0, 0, -3))
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
pr := new(PullRequest)
var maintainerString string
if err := rows.Scan(&pr.Number, &pr.Processed, &pr.PendingReview, &maintainerString); err != nil {
return nil, err
}
pr.Maintainers = strings.Split(maintainerString, " ")
prs = append(prs, pr)
}
err = rows.Err()
if err != nil {
log.Println(err)
}
return prs, nil
}
func (sqlDB *sqlDBHelper) SetPRProcessed(number int, processed bool) error {
_, err := sqlDB.prDB.Exec("UPDATE pull_requests SET processed = $1 WHERE number = $2", processed, number)
return err
}
func (sqlDB *sqlDBHelper) SetPRPendingReview(number int, pendingReview bool) error {
_, err := sqlDB.prDB.Exec("UPDATE pull_requests SET pending_review = $1 WHERE number = $2", pendingReview, number)
return err
}
func (sqlDB *sqlDBHelper) parseMaintainer(maintainerFullString string) *Maintainer {
maintainer := parseMaintainerString(maintainerFullString)
if maintainer.GithubHandle == "" && maintainer.Email != "" {
if handle, err := sqlDB.GetGitHubHandle(maintainer.Email); err == nil {
maintainer.GithubHandle = handle
}
}
return maintainer
}
func parseMaintainerString(maintainerFullString string) *Maintainer {
maintainerStrings := strings.Split(maintainerFullString, " ")
maintainer := new(Maintainer)
for _, maintainerString := range maintainerStrings {
if strings.HasPrefix(maintainerString, "@") {
maintainer.GithubHandle = maintainerString[1:]
} else if strings.Count(maintainerString, ":") == 1 {
emailParts := strings.Split(maintainerString, ":")
maintainer.Email = emailParts[1] + "@" + emailParts[0]
} else {
maintainer.Email = maintainerString + "@macports.org"
}
}
return maintainer
}