Merge remote-tracking branch 'origin'

This commit is contained in:
Brad Rydzewski 2017-01-03 13:54:33 -05:00
commit ba5ec0ae37
12 changed files with 372 additions and 22 deletions

View file

@ -10,19 +10,7 @@ Drone's prime directive is to help teams [ship code like GitHub](https://github.
### Documentation
Drone documentation is organized into several categories:
* [Setup Guide](http://readme.drone.io/setup/overview)
* [Build Guide](http://readme.drone.io/usage/overview)
* [Plugin Guide](http://readme.drone.io/devs/plugins)
* [CLI Reference](http://readme.drone.io/devs/cli/)
* [API Reference](http://readme.drone.io/devs/api/builds)
### Documentation for 0.5 (unstable)
If you are using the 0.5 unstable release (master branch) please see the updated [documentation](http://readme.drone.io/0.5).
Documentation is published to [readme.drone.io](http://readme.drone.io)
### Community, Help
@ -30,7 +18,7 @@ Contributions, questions, and comments are welcomed and encouraged. Drone develo
### Installation
Please see our [installation guide](http://readme.drone.io/setup/overview) to install the official Docker image.
Please see our [installation guide](http://readme.drone.io/admin/) to install the official Docker image.
### From Source

View file

@ -30,12 +30,13 @@ func getRepo(c *gin.Context) {
}
func getRepoFile(c *gin.Context) {
switch c.Param("file") {
case "file_not_found":
if c.Param("file") == "file_not_found" {
c.String(404, "")
default:
}
if c.Param("commit") == "v1.0.0" || c.Param("commit") == "9ecad50" {
c.String(200, repoFilePayload)
}
c.String(404, "")
}
func createRepoHook(c *gin.Context) {

View file

@ -83,3 +83,55 @@ var HookPushTag = `{
"avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
}
}`
// HookPullRequest is a sample pull_request webhook payload
var HookPullRequest = `{
"action": "opened",
"number": 1,
"pull_request": {
"html_url": "http://gogs.golang.org/gordon/hello-world/pull/1",
"state": "open",
"title": "Update the README with new information",
"body": "please merge",
"user": {
"id": 1,
"username": "gordon",
"full_name": "Gordon the Gopher",
"email": "gordon@golang.org",
"avatar_url": "http://gogs.golang.org///1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
},
"base": {
"label": "master",
"ref": "master",
"sha": "9353195a19e45482665306e466c832c46560532d"
},
"head": {
"label": "feature/changes",
"ref": "feature/changes",
"sha": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c"
}
},
"repository": {
"id": 35129377,
"name": "hello-world",
"full_name": "gordon/hello-world",
"owner": {
"id": 1,
"username": "gordon",
"full_name": "Gordon the Gopher",
"email": "gordon@golang.org",
"avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
},
"private": true,
"html_url": "http://gogs.golang.org/gordon/hello-world",
"clone_url": "https://gogs.golang.org/gordon/hello-world.git",
"default_branch": "master"
},
"sender": {
"id": 1,
"username": "gordon",
"full_name": "Gordon the Gopher",
"email": "gordon@golang.org",
"avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
}
}`

View file

@ -6,6 +6,7 @@ import (
"net"
"net/http"
"net/url"
"strings"
"github.com/drone/drone/model"
"github.com/drone/drone/remote"
@ -176,7 +177,14 @@ func (c *client) File(u *model.User, r *model.Repo, b *model.Build, f string) ([
client := c.newClientToken(u.Token)
buildRef := b.Commit
if buildRef == "" {
buildRef = b.Ref
// Remove refs/tags or refs/heads, Gogs needs a short ref
buildRef = strings.TrimPrefix(
strings.TrimPrefix(
b.Ref,
"refs/heads/",
),
"refs/tags/",
)
}
cfg, err := client.GetFile(r.Owner, r.Name, buildRef, f)
return cfg, err

View file

@ -128,6 +128,12 @@ func Test_gogs(t *testing.T) {
g.Assert(string(raw)).Equal("{ platform: linux/amd64 }")
})
g.It("Should return a repository file from a ref", func() {
raw, err := c.File(fakeUser, fakeRepo, fakeBuildWithRef, ".drone.yml")
g.Assert(err == nil).IsTrue()
g.Assert(string(raw)).Equal("{ platform: linux/amd64 }")
})
g.Describe("Given an authentication request", func() {
g.It("Should redirect to login form")
g.It("Should create an access token")
@ -178,4 +184,8 @@ var (
fakeBuild = &model.Build{
Commit: "9ecad50",
}
fakeBuildWithRef = &model.Build{
Ref: "refs/tags/v1.0.0",
}
)

View file

@ -112,6 +112,30 @@ func buildFromTag(hook *pushHook) *model.Build {
}
}
// helper function that extracts the Build data from a Gogs pull_request hook
func buildFromPullRequest(hook *pullRequestHook) *model.Build {
avatar := expandAvatar(
hook.Repo.URL,
fixMalformedAvatar(hook.PullRequest.User.Avatar),
)
build := &model.Build{
Event: model.EventPull,
Commit: hook.PullRequest.Head.Sha,
Link: hook.PullRequest.URL,
Ref: fmt.Sprintf("refs/pull/%d/head", hook.Number),
Branch: hook.PullRequest.Base.Ref,
Message: hook.PullRequest.Title,
Author: hook.PullRequest.User.Username,
Avatar: avatar,
Title: hook.PullRequest.Title,
Refspec: fmt.Sprintf("%s:%s",
hook.PullRequest.Head.Ref,
hook.PullRequest.Base.Ref,
),
}
return build
}
// helper function that extracts the Repository data from a Gogs push hook
func repoFromPush(hook *pushHook) *model.Repo {
return &model.Repo{
@ -122,6 +146,16 @@ func repoFromPush(hook *pushHook) *model.Repo {
}
}
// helper function that extracts the Repository data from a Gogs pull_request hook
func repoFromPullRequest(hook *pullRequestHook) *model.Repo {
return &model.Repo{
Name: hook.Repo.Name,
Owner: hook.Repo.Owner.Username,
FullName: hook.Repo.FullName,
Link: hook.Repo.URL,
}
}
// helper function that parses a push hook from a read closer.
func parsePush(r io.Reader) (*pushHook, error) {
push := new(pushHook)
@ -129,6 +163,12 @@ func parsePush(r io.Reader) (*pushHook, error) {
return push, err
}
func parsePullRequest(r io.Reader) (*pullRequestHook, error) {
pr := new(pullRequestHook)
err := json.NewDecoder(r).Decode(pr)
return pr, err
}
// fixMalformedAvatar is a helper function that fixes an avatar url if malformed
// (currently a known bug with gogs)
func fixMalformedAvatar(url string) string {

View file

@ -53,6 +53,32 @@ func Test_parse(t *testing.T) {
g.Assert(hook.Sender.Avatar).Equal("https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87")
})
g.It("Should parse pull_request hook payload", func() {
buf := bytes.NewBufferString(fixtures.HookPullRequest)
hook, err := parsePullRequest(buf)
g.Assert(err == nil).IsTrue()
g.Assert(hook.Action).Equal("opened")
g.Assert(hook.Number).Equal(int64(1))
g.Assert(hook.Repo.Name).Equal("hello-world")
g.Assert(hook.Repo.URL).Equal("http://gogs.golang.org/gordon/hello-world")
g.Assert(hook.Repo.FullName).Equal("gordon/hello-world")
g.Assert(hook.Repo.Owner.Email).Equal("gordon@golang.org")
g.Assert(hook.Repo.Owner.Username).Equal("gordon")
g.Assert(hook.Repo.Private).Equal(true)
g.Assert(hook.Sender.Username).Equal("gordon")
g.Assert(hook.Sender.Avatar).Equal("https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87")
g.Assert(hook.PullRequest.Title).Equal("Update the README with new information")
g.Assert(hook.PullRequest.Body).Equal("please merge")
g.Assert(hook.PullRequest.State).Equal("open")
g.Assert(hook.PullRequest.User.Username).Equal("gordon")
g.Assert(hook.PullRequest.Base.Label).Equal("master")
g.Assert(hook.PullRequest.Base.Ref).Equal("master")
g.Assert(hook.PullRequest.Head.Label).Equal("feature/changes")
g.Assert(hook.PullRequest.Head.Ref).Equal("feature/changes")
})
g.It("Should return a Build struct from a push hook", func() {
buf := bytes.NewBufferString(fixtures.HookPush)
hook, _ := parsePush(buf)
@ -78,6 +104,31 @@ func Test_parse(t *testing.T) {
g.Assert(repo.Link).Equal(hook.Repo.URL)
})
g.It("Should return a Build struct from a pull_request hook", func() {
buf := bytes.NewBufferString(fixtures.HookPullRequest)
hook, _ := parsePullRequest(buf)
build := buildFromPullRequest(hook)
g.Assert(build.Event).Equal(model.EventPull)
g.Assert(build.Commit).Equal(hook.PullRequest.Head.Sha)
g.Assert(build.Ref).Equal("refs/pull/1/head")
g.Assert(build.Link).Equal(hook.PullRequest.URL)
g.Assert(build.Branch).Equal("master")
g.Assert(build.Message).Equal(hook.PullRequest.Title)
g.Assert(build.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87")
g.Assert(build.Author).Equal(hook.PullRequest.User.Username)
})
g.It("Should return a Repo struct from a pull_request hook", func() {
buf := bytes.NewBufferString(fixtures.HookPullRequest)
hook, _ := parsePullRequest(buf)
repo := repoFromPullRequest(hook)
g.Assert(repo.Name).Equal(hook.Repo.Name)
g.Assert(repo.Owner).Equal(hook.Repo.Owner.Username)
g.Assert(repo.FullName).Equal("gordon/hello-world")
g.Assert(repo.Link).Equal(hook.Repo.URL)
})
g.It("Should return a Perm struct from a Gogs Perm", func() {
perms := []gogs.Permission{
{true, true, true},

View file

@ -8,9 +8,15 @@ import (
)
const (
hookEvent = "X-Gogs-Event"
hookPush = "push"
hookCreated = "create"
hookEvent = "X-Gogs-Event"
hookPush = "push"
hookCreated = "create"
hookPullRequest = "pull_request"
actionOpen = "opened"
actionSync = "synchronize"
stateOpen = "open"
refBranch = "branch"
refTag = "tag"
@ -24,6 +30,8 @@ func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
return parsePushHook(r.Body)
case hookCreated:
return parseCreatedHook(r.Body)
case hookPullRequest:
return parsePullRequestHook(r.Body)
}
return nil, nil, nil
}
@ -72,3 +80,28 @@ func parseCreatedHook(payload io.Reader) (*model.Repo, *model.Build, error) {
build = buildFromTag(push)
return repo, build, err
}
// parsePullRequestHook parses a pull_request hook and returns the Repo and Build details.
func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Build, error) {
var (
repo *model.Repo
build *model.Build
)
pr, err := parsePullRequest(payload)
if err != nil {
return nil, nil, err
}
// Don't trigger builds for non-code changes, or if PR is not open
if pr.Action != actionOpen && pr.Action != actionSync {
return nil, nil, nil
}
if pr.PullRequest.State != stateOpen {
return nil, nil, nil
}
repo = repoFromPullRequest(pr)
build = buildFromPullRequest(pr)
return repo, build, err
}

View file

@ -40,3 +40,85 @@ type pushHook struct {
Avatar string `json:"avatar_url"`
} `json:"sender"`
}
type pullRequestHook struct {
Action string `json:"action"`
Number int64 `json:"number"`
PullRequest struct {
ID int64 `json:"id"`
User struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"full_name"`
Email string `json:"email"`
Avatar string `json:"avatar_url"`
} `json:"user"`
Title string `json:"title"`
Body string `json:"body"`
Labels []string `json:"labels"`
State string `json:"state"`
URL string `json:"html_url"`
Mergeable bool `json:"mergeable"`
Merged bool `json:"merged"`
MergeBase string `json:"merge_base"`
Base struct {
Label string `json:"label"`
Ref string `json:"ref"`
Sha string `json:"sha"`
Repo struct {
ID int64 `json:"id"`
Name string `json:"name"`
FullName string `json:"full_name"`
URL string `json:"html_url"`
Private bool `json:"private"`
Owner struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"full_name"`
Email string `json:"email"`
Avatar string `json:"avatar_url"`
} `json:"owner"`
} `json:"repo"`
} `json:"base"`
Head struct {
Label string `json:"label"`
Ref string `json:"ref"`
Sha string `json:"sha"`
Repo struct {
ID int64 `json:"id"`
Name string `json:"name"`
FullName string `json:"full_name"`
URL string `json:"html_url"`
Private bool `json:"private"`
Owner struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"full_name"`
Email string `json:"email"`
Avatar string `json:"avatar_url"`
} `json:"owner"`
} `json:"repo"`
} `json:"head"`
} `json:"pull_request"`
Repo struct {
ID int64 `json:"id"`
Name string `json:"name"`
FullName string `json:"full_name"`
URL string `json:"html_url"`
Private bool `json:"private"`
Owner struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"full_name"`
Email string `json:"email"`
Avatar string `json:"avatar_url"`
} `json:"owner"`
} `json:"repository"`
Sender struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"full_name"`
Email string `json:"email"`
Avatar string `json:"avatar_url"`
} `json:"sender"`
}

View file

@ -31,7 +31,7 @@ func Broker(cli *cli.Context) gin.HandlerFunc {
// setup broker logging.
log := redlog.New(os.Stderr)
log.SetLevel(0)
log.SetLevel(2)
logger.SetLogger(log)
if cli.Bool("broker-debug") {
log.SetLevel(1)

View file

@ -153,6 +153,21 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
agents.GET("", server.GetAgents)
}
debug := e.Group("/api/debug")
{
debug.Use(session.MustAdmin())
debug.GET("/pprof/", server.IndexHandler())
debug.GET("/pprof/heap", server.HeapHandler())
debug.GET("/pprof/goroutine", server.GoroutineHandler())
debug.GET("/pprof/block", server.BlockHandler())
debug.GET("/pprof/threadcreate", server.ThreadCreateHandler())
debug.GET("/pprof/cmdline", server.CmdlineHandler())
debug.GET("/pprof/profile", server.ProfileHandler())
debug.GET("/pprof/symbol", server.SymbolHandler())
debug.POST("/pprof/symbol", server.SymbolHandler())
debug.GET("/pprof/trace", server.TraceHandler())
}
// DELETE THESE
// gitlab := e.Group("/gitlab/:owner/:name")
// {

70
server/debug.go Normal file
View file

@ -0,0 +1,70 @@
package server
import (
"net/http/pprof"
"github.com/gin-gonic/gin"
)
// IndexHandler will pass the call from /debug/pprof to pprof
func IndexHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Index(c.Writer, c.Request)
}
}
// HeapHandler will pass the call from /debug/pprof/heap to pprof
func HeapHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Handler("heap").ServeHTTP(c.Writer, c.Request)
}
}
// GoroutineHandler will pass the call from /debug/pprof/goroutine to pprof
func GoroutineHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Handler("goroutine").ServeHTTP(c.Writer, c.Request)
}
}
// BlockHandler will pass the call from /debug/pprof/block to pprof
func BlockHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Handler("block").ServeHTTP(c.Writer, c.Request)
}
}
// ThreadCreateHandler will pass the call from /debug/pprof/threadcreate to pprof
func ThreadCreateHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Handler("threadcreate").ServeHTTP(c.Writer, c.Request)
}
}
// CmdlineHandler will pass the call from /debug/pprof/cmdline to pprof
func CmdlineHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Cmdline(c.Writer, c.Request)
}
}
// ProfileHandler will pass the call from /debug/pprof/profile to pprof
func ProfileHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Profile(c.Writer, c.Request)
}
}
// SymbolHandler will pass the call from /debug/pprof/symbol to pprof
func SymbolHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Symbol(c.Writer, c.Request)
}
}
// TraceHandler will pass the call from /debug/pprof/trace to pprof
func TraceHandler() gin.HandlerFunc {
return func(c *gin.Context) {
pprof.Trace(c.Writer, c.Request)
}
}