176 lines
4.2 KiB
Go
176 lines
4.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"xorm.io/xorm"
|
|
|
|
"github.com/forgeo/forgebucket/internal/api/middleware"
|
|
"github.com/forgeo/forgebucket/internal/models"
|
|
)
|
|
|
|
type PRHandler struct {
|
|
db *xorm.Engine
|
|
}
|
|
|
|
func NewPRHandler(db *xorm.Engine) *PRHandler {
|
|
return &PRHandler{db: db}
|
|
}
|
|
|
|
func (h *PRHandler) List(w http.ResponseWriter, r *http.Request) {
|
|
repoID, ok := h.repoIDFromURL(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
status := r.URL.Query().Get("status")
|
|
|
|
sess := h.db.Where("repo_id = ?", repoID)
|
|
if status != "" {
|
|
sess = sess.And("status = ?", status)
|
|
}
|
|
|
|
var prs []models.PullRequest
|
|
if err := sess.Find(&prs); err != nil {
|
|
jsonError(w, "could not list pull requests", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if prs == nil {
|
|
prs = []models.PullRequest{}
|
|
}
|
|
jsonOK(w, prs)
|
|
}
|
|
|
|
func (h *PRHandler) Create(w http.ResponseWriter, r *http.Request) {
|
|
repoID, ok := h.repoIDFromURL(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
authorID, _ := middleware.UserIDFromContext(r.Context())
|
|
|
|
var body struct {
|
|
Title string `json:"title"`
|
|
Body string `json:"body"`
|
|
SourceBranch string `json:"sourceBranch"`
|
|
TargetBranch string `json:"targetBranch"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
|
jsonError(w, "invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
if body.Title == "" || body.SourceBranch == "" {
|
|
jsonError(w, "title and sourceBranch are required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
if body.TargetBranch == "" {
|
|
body.TargetBranch = "main"
|
|
}
|
|
|
|
pr := &models.PullRequest{
|
|
RepoID: repoID,
|
|
AuthorID: authorID,
|
|
Title: body.Title,
|
|
Body: body.Body,
|
|
SourceBranch: body.SourceBranch,
|
|
TargetBranch: body.TargetBranch,
|
|
Status: models.PRStatusOpen,
|
|
}
|
|
if _, err := h.db.Insert(pr); err != nil {
|
|
jsonError(w, "could not create pull request", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
json.NewEncoder(w).Encode(pr)
|
|
}
|
|
|
|
func (h *PRHandler) Get(w http.ResponseWriter, r *http.Request) {
|
|
pr, ok := h.lookupPR(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
jsonOK(w, pr)
|
|
}
|
|
|
|
func (h *PRHandler) Merge(w http.ResponseWriter, r *http.Request) {
|
|
pr, ok := h.lookupPR(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if pr.Status != models.PRStatusOpen {
|
|
jsonError(w, "pull request is not open", http.StatusConflict)
|
|
return
|
|
}
|
|
|
|
pr.Status = models.PRStatusMerged
|
|
if _, err := h.db.ID(pr.ID).Cols("status").Update(pr); err != nil {
|
|
jsonError(w, "could not merge pull request", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
jsonOK(w, pr)
|
|
}
|
|
|
|
func (h *PRHandler) Close(w http.ResponseWriter, r *http.Request) {
|
|
pr, ok := h.lookupPR(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if pr.Status != models.PRStatusOpen {
|
|
jsonError(w, "pull request is not open", http.StatusConflict)
|
|
return
|
|
}
|
|
|
|
pr.Status = models.PRStatusClosed
|
|
if _, err := h.db.ID(pr.ID).Cols("status").Update(pr); err != nil {
|
|
jsonError(w, "could not close pull request", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
jsonOK(w, pr)
|
|
}
|
|
|
|
func (h *PRHandler) repoIDFromURL(w http.ResponseWriter, r *http.Request) (int64, bool) {
|
|
ownerName := chi.URLParam(r, "owner")
|
|
repoName := chi.URLParam(r, "repo")
|
|
|
|
var owner models.User
|
|
found, err := h.db.Where("username = ?", ownerName).Get(&owner)
|
|
if err != nil || !found {
|
|
jsonError(w, "repository not found", http.StatusNotFound)
|
|
return 0, false
|
|
}
|
|
|
|
var repo models.Repository
|
|
found, err = h.db.Where("owner_id = ? AND name = ?", owner.ID, repoName).Get(&repo)
|
|
if err != nil || !found {
|
|
jsonError(w, "repository not found", http.StatusNotFound)
|
|
return 0, false
|
|
}
|
|
return repo.ID, true
|
|
}
|
|
|
|
func (h *PRHandler) lookupPR(w http.ResponseWriter, r *http.Request) (*models.PullRequest, bool) {
|
|
repoID, ok := h.repoIDFromURL(w, r)
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
|
|
prIDStr := chi.URLParam(r, "prID")
|
|
prID, err := strconv.ParseInt(prIDStr, 10, 64)
|
|
if err != nil {
|
|
jsonError(w, "invalid pull request ID", http.StatusBadRequest)
|
|
return nil, false
|
|
}
|
|
|
|
var pr models.PullRequest
|
|
found, err := h.db.Where("id = ? AND repo_id = ?", prID, repoID).Get(&pr)
|
|
if err != nil || !found {
|
|
jsonError(w, "pull request not found", http.StatusNotFound)
|
|
return nil, false
|
|
}
|
|
return &pr, true
|
|
}
|