package handler import ( "encoding/xml" "net/http" "time" "github.com/drone/drone/server/database" "github.com/drone/drone/shared/httputil" "github.com/drone/drone/shared/model" "github.com/gorilla/pat" ) // badges that indicate the current build status for a repository // and branch combination. var ( badgeSuccess = []byte(`buildbuildsuccesssuccess`) badgeFailure = []byte(`buildbuildfailurefailure`) badgeStarted = []byte(`buildbuildstartedstarted`) badgeError = []byte(`buildbuilderrorerror`) badgeNone = []byte(`buildbuildnonenone`) ) type BadgeHandler struct { commits database.CommitManager repos database.RepoManager } func NewBadgeHandler(repos database.RepoManager, commits database.CommitManager) *BadgeHandler { return &BadgeHandler{commits, repos} } // GetStatus gets the build status badge. // GET /v1/badge/:host/:owner/:name/status.svg func (h *BadgeHandler) GetStatus(w http.ResponseWriter, r *http.Request) error { host, owner, name := parseRepo(r) branch := r.FormValue("branch") // github has insanely aggressive caching so we'll set almost // every parameter possible to try to prevent caching. w.Header().Set("Content-Type", "image/svg+xml") w.Header().Add("Cache-Control", "no-cache") w.Header().Add("Cache-Control", "no-store") w.Header().Add("Cache-Control", "max-age=0") w.Header().Add("Cache-Control", "must-revalidate") w.Header().Add("Cache-Control", "value") w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) w.Header().Set("Expires", "Thu, 01 Jan 1970 00:00:00 GMT") // get the repository from the database arepo, err := h.repos.FindName(host, owner, name) if err != nil { w.Write(badgeNone) return nil } // if no branch, use the default if len(branch) == 0 { branch = model.DefaultBranch } // get the latest commit c, _ := h.commits.FindLatest(arepo.ID, branch) // if no commit was found then display // the 'none' badge if c == nil { w.Write(badgeNone) return nil } // determine which badge to load switch c.Status { case model.StatusSuccess: w.Write(badgeSuccess) case model.StatusFailure: w.Write(badgeFailure) case model.StatusError: w.Write(badgeError) case model.StatusEnqueue, model.StatusStarted: w.Write(badgeStarted) default: w.Write(badgeNone) } return nil } // GetCoverage gets the build status badge. // GET /v1/badges/:host/:owner/:name/coverage.svg func (h *BadgeHandler) GetCoverage(w http.ResponseWriter, r *http.Request) error { return notImplemented{} } func (h *BadgeHandler) GetCC(w http.ResponseWriter, r *http.Request) error { host, owner, name := parseRepo(r) // get the repository from the database repo, err := h.repos.FindName(host, owner, name) if err != nil { return notFound{err} } // get the latest commits for the repo commits, err := h.commits.List(repo.ID) if err != nil || len(commits) == 0 { return notFound{} } commit := commits[0] // generate the URL for the repository url := httputil.GetURL(r) + "/" + repo.Host + "/" + repo.Owner + "/" + repo.Name proj := model.NewCC(repo, commit, url) return xml.NewEncoder(w).Encode(proj) } func (h *BadgeHandler) Register(r *pat.Router) { r.Get("/v1/badge/{host}/{owner}/{name}/coverage.svg", errorHandler(h.GetCoverage)) r.Get("/v1/badge/{host}/{owner}/{name}/status.svg", errorHandler(h.GetStatus)) r.Get("/v1/badge/{host}/{owner}/{name}/cc.xml", errorHandler(h.GetCC)) }