mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-26 03:41:01 +00:00
load all things via middleware
This commit is contained in:
parent
42d6d8d3b2
commit
9b306a1bc8
25 changed files with 289 additions and 408 deletions
|
@ -18,7 +18,6 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/router/middleware/context"
|
|
||||||
"github.com/drone/drone/router/middleware/session"
|
"github.com/drone/drone/router/middleware/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -130,7 +129,7 @@ func GetBuildLogs(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteBuild(c *gin.Context) {
|
func DeleteBuild(c *gin.Context) {
|
||||||
engine_ := context.Engine(c)
|
engine_ := engine.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
|
|
||||||
// parse the build number and job sequence number from
|
// parse the build number and job sequence number from
|
||||||
|
@ -281,7 +280,7 @@ func PostBuild(c *gin.Context) {
|
||||||
// on status change notifications
|
// on status change notifications
|
||||||
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
|
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
|
||||||
|
|
||||||
engine_ := context.Engine(c)
|
engine_ := engine.FromContext(c)
|
||||||
go engine_.Schedule(c.Copy(), &engine.Task{
|
go engine_.Schedule(c.Copy(), &engine.Task{
|
||||||
User: user,
|
User: user,
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"github.com/drone/drone/engine"
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/router/middleware/context"
|
|
||||||
"github.com/drone/drone/store"
|
"github.com/drone/drone/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ func GetNode(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostNode(c *gin.Context) {
|
func PostNode(c *gin.Context) {
|
||||||
engine := context.Engine(c)
|
engine := engine.FromContext(c)
|
||||||
|
|
||||||
in := struct {
|
in := struct {
|
||||||
Addr string `json:"address"`
|
Addr string `json:"address"`
|
||||||
|
@ -63,7 +63,7 @@ func PostNode(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteNode(c *gin.Context) {
|
func DeleteNode(c *gin.Context) {
|
||||||
engine := context.Engine(c)
|
engine := engine.FromContext(c)
|
||||||
|
|
||||||
id, _ := strconv.Atoi(c.Param("node"))
|
id, _ := strconv.Atoi(c.Param("node"))
|
||||||
node, err := store.GetNode(c, int64(id))
|
node, err := store.GetNode(c, int64(id))
|
||||||
|
|
30
drone.go
30
drone.go
|
@ -4,14 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/drone/drone/engine"
|
|
||||||
"github.com/drone/drone/remote"
|
|
||||||
"github.com/drone/drone/router"
|
"github.com/drone/drone/router"
|
||||||
"github.com/drone/drone/router/middleware/cache"
|
"github.com/drone/drone/router/middleware"
|
||||||
"github.com/drone/drone/router/middleware/context"
|
|
||||||
"github.com/drone/drone/router/middleware/header"
|
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
"github.com/drone/drone/store/datastore"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/gin-gonic/contrib/ginrus"
|
"github.com/gin-gonic/contrib/ginrus"
|
||||||
|
@ -37,26 +31,14 @@ func main() {
|
||||||
logrus.SetLevel(logrus.WarnLevel)
|
logrus.SetLevel(logrus.WarnLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the configuration from env file
|
|
||||||
env := envconfig.Load(".env")
|
|
||||||
|
|
||||||
// Setup the database driver
|
|
||||||
store_ := datastore.Load(env)
|
|
||||||
|
|
||||||
// setup the remote driver
|
|
||||||
remote_ := remote.Load(env)
|
|
||||||
|
|
||||||
// setup the runner
|
|
||||||
engine_ := engine.Load(env, store_)
|
|
||||||
|
|
||||||
// setup the server and start the listener
|
// setup the server and start the listener
|
||||||
handler := router.Load(
|
handler := router.Load(
|
||||||
ginrus.Ginrus(logrus.StandardLogger(), time.RFC3339, true),
|
ginrus.Ginrus(logrus.StandardLogger(), time.RFC3339, true),
|
||||||
header.Version,
|
middleware.Version,
|
||||||
cache.Default(),
|
middleware.Cache(),
|
||||||
context.SetStore(store_),
|
middleware.Store(),
|
||||||
context.SetRemote(remote_),
|
middleware.Remote(),
|
||||||
context.SetEngine(engine_),
|
middleware.Engine(),
|
||||||
)
|
)
|
||||||
|
|
||||||
if *cert != "" {
|
if *cert != "" {
|
||||||
|
|
23
engine/context.go
Normal file
23
engine/context.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package engine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const key = "engine"
|
||||||
|
|
||||||
|
// Setter defines a context that enables setting values.
|
||||||
|
type Setter interface {
|
||||||
|
Set(string, interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromContext returns the Engine associated with this context.
|
||||||
|
func FromContext(c context.Context) Engine {
|
||||||
|
return c.Value(key).(Engine)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToContext adds the Engine to this context if it supports
|
||||||
|
// the Setter interface.
|
||||||
|
func ToContext(c Setter, engine Engine) {
|
||||||
|
c.Set(key, engine)
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -15,7 +16,6 @@ import (
|
||||||
"github.com/docker/docker/pkg/stdcopy"
|
"github.com/docker/docker/pkg/stdcopy"
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/shared/docker"
|
"github.com/drone/drone/shared/docker"
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
"github.com/drone/drone/store"
|
"github.com/drone/drone/store"
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
@ -60,7 +60,7 @@ type engine struct {
|
||||||
// Load creates a new build engine, loaded with registered nodes from the
|
// Load creates a new build engine, loaded with registered nodes from the
|
||||||
// database. The registered nodes are added to the pool of nodes to immediately
|
// database. The registered nodes are added to the pool of nodes to immediately
|
||||||
// start accepting workloads.
|
// start accepting workloads.
|
||||||
func Load(env envconfig.Env, s store.Store) Engine {
|
func Load(s store.Store) Engine {
|
||||||
engine := &engine{}
|
engine := &engine{}
|
||||||
engine.bus = newEventbus()
|
engine.bus = newEventbus()
|
||||||
engine.pool = newPool()
|
engine.pool = newPool()
|
||||||
|
@ -70,7 +70,7 @@ func Load(env envconfig.Env, s store.Store) Engine {
|
||||||
// throughout the build environment.
|
// throughout the build environment.
|
||||||
var proxyVars = []string{"HTTP_PROXY", "http_proxy", "HTTPS_PROXY", "https_proxy", "NO_PROXY", "no_proxy"}
|
var proxyVars = []string{"HTTP_PROXY", "http_proxy", "HTTPS_PROXY", "https_proxy", "NO_PROXY", "no_proxy"}
|
||||||
for _, proxyVar := range proxyVars {
|
for _, proxyVar := range proxyVars {
|
||||||
proxyVal := env.Get(proxyVar)
|
proxyVal := os.Getenv(proxyVar)
|
||||||
if len(proxyVal) != 0 {
|
if len(proxyVal) != 0 {
|
||||||
engine.envs = append(engine.envs, proxyVar+"="+proxyVal)
|
engine.envs = append(engine.envs, proxyVar+"="+proxyVal)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
"github.com/drone/drone/shared/httputil"
|
"github.com/drone/drone/shared/httputil"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
@ -24,8 +23,7 @@ type Bitbucket struct {
|
||||||
Open bool
|
Open bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load(env envconfig.Env) *Bitbucket {
|
func Load(config string) *Bitbucket {
|
||||||
config := env.String("REMOTE_CONFIG", "")
|
|
||||||
|
|
||||||
// parse the remote DSN configuration string
|
// parse the remote DSN configuration string
|
||||||
url_, err := url.Parse(config)
|
url_, err := url.Parse(config)
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
"github.com/drone/drone/shared/httputil"
|
"github.com/drone/drone/shared/httputil"
|
||||||
"github.com/drone/drone/shared/oauth2"
|
"github.com/drone/drone/shared/oauth2"
|
||||||
|
|
||||||
|
@ -42,8 +41,7 @@ type Github struct {
|
||||||
GitSSH bool
|
GitSSH bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load(env envconfig.Env) *Github {
|
func Load(config string) *Github {
|
||||||
config := env.String("REMOTE_CONFIG", "")
|
|
||||||
|
|
||||||
// parse the remote DSN configuration string
|
// parse the remote DSN configuration string
|
||||||
url_, err := url.Parse(config)
|
url_, err := url.Parse(config)
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
"github.com/drone/drone/shared/httputil"
|
"github.com/drone/drone/shared/httputil"
|
||||||
"github.com/drone/drone/shared/oauth2"
|
"github.com/drone/drone/shared/oauth2"
|
||||||
"github.com/drone/drone/shared/token"
|
"github.com/drone/drone/shared/token"
|
||||||
|
@ -35,9 +34,7 @@ type Gitlab struct {
|
||||||
Search bool
|
Search bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load(env envconfig.Env) *Gitlab {
|
func Load(config string) *Gitlab {
|
||||||
config := env.String("REMOTE_CONFIG", "")
|
|
||||||
|
|
||||||
url_, err := url.Parse(config)
|
url_, err := url.Parse(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
"github.com/gogits/go-gogs-client"
|
"github.com/gogits/go-gogs-client"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
@ -22,9 +21,7 @@ type Gogs struct {
|
||||||
SkipVerify bool
|
SkipVerify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load(env envconfig.Env) *Gogs {
|
func Load(config string) *Gogs {
|
||||||
config := env.String("REMOTE_CONFIG", "")
|
|
||||||
|
|
||||||
// parse the remote DSN configuration string
|
// parse the remote DSN configuration string
|
||||||
url_, err := url.Parse(config)
|
url_, err := url.Parse(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -6,36 +6,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/remote/bitbucket"
|
|
||||||
"github.com/drone/drone/remote/github"
|
|
||||||
"github.com/drone/drone/remote/gitlab"
|
|
||||||
"github.com/drone/drone/remote/gogs"
|
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Load(env envconfig.Env) Remote {
|
|
||||||
driver := env.Get("REMOTE_DRIVER")
|
|
||||||
|
|
||||||
switch driver {
|
|
||||||
case "bitbucket":
|
|
||||||
return bitbucket.Load(env)
|
|
||||||
case "github":
|
|
||||||
return github.Load(env)
|
|
||||||
case "gitlab":
|
|
||||||
return gitlab.Load(env)
|
|
||||||
case "gogs":
|
|
||||||
return gogs.Load(env)
|
|
||||||
|
|
||||||
default:
|
|
||||||
logrus.Fatalf("unknown remote driver %s", driver)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Remote interface {
|
type Remote interface {
|
||||||
// Login authenticates the session and returns the
|
// Login authenticates the session and returns the
|
||||||
// remote user details.
|
// remote user details.
|
||||||
|
|
22
router/middleware/cache.go
Normal file
22
router/middleware/cache.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/drone/drone/cache"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/ianschenck/envflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ttl = envflag.Duration("CACHE_TTL", time.Minute*15, "")
|
||||||
|
|
||||||
|
// Cache is a middleware function that initializes the Cache and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Cache() gin.HandlerFunc {
|
||||||
|
cc := cache.NewTTL(*ttl)
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
cache.ToContext(c, cc)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
14
router/middleware/cache/cache.go
vendored
14
router/middleware/cache/cache.go
vendored
|
@ -1,14 +0,0 @@
|
||||||
package cache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone/cache"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Default() gin.HandlerFunc {
|
|
||||||
cc := cache.Default()
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
cache.ToContext(c, cc)
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package context
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone/engine"
|
|
||||||
"github.com/drone/drone/remote"
|
|
||||||
"github.com/drone/drone/store"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SetStore(s store.Store) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
store.ToContext(c, s)
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetRemote(remote remote.Remote) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
c.Set("remote", remote)
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Remote(c *gin.Context) remote.Remote {
|
|
||||||
return c.MustGet("remote").(remote.Remote)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetEngine(engine engine.Engine) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
c.Set("engine", engine)
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Engine(c *gin.Context) engine.Engine {
|
|
||||||
return c.MustGet("engine").(engine.Engine)
|
|
||||||
}
|
|
28
router/middleware/engine.go
Normal file
28
router/middleware/engine.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/drone/drone/engine"
|
||||||
|
"github.com/drone/drone/store"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Engine is a middleware function that initializes the Engine and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Engine() gin.HandlerFunc {
|
||||||
|
var once sync.Once
|
||||||
|
var engine_ engine.Engine
|
||||||
|
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
|
||||||
|
once.Do(func() {
|
||||||
|
store_ := store.FromContext(c)
|
||||||
|
engine_ = engine.Load(store_)
|
||||||
|
})
|
||||||
|
|
||||||
|
engine.ToContext(c, engine_)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,95 +0,0 @@
|
||||||
package location
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Resolve is a middleware function that resolves the hostname
|
|
||||||
// and scheme for the http.Request and adds to the context.
|
|
||||||
func Resolve(c *gin.Context) {
|
|
||||||
c.Set("host", resolveHost(c.Request))
|
|
||||||
c.Set("scheme", resolveScheme(c.Request))
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseHeader parses non unique headers value
|
|
||||||
// from a http.Request and return a slice of the values
|
|
||||||
// queried from the header
|
|
||||||
func parseHeader(r *http.Request, header string, token string) (val []string) {
|
|
||||||
for _, v := range r.Header[header] {
|
|
||||||
options := strings.Split(v, ";")
|
|
||||||
for _, o := range options {
|
|
||||||
keyvalue := strings.Split(o, "=")
|
|
||||||
var key, value string
|
|
||||||
if len(keyvalue) > 1 {
|
|
||||||
key, value = strings.TrimSpace(keyvalue[0]), strings.TrimSpace(keyvalue[1])
|
|
||||||
}
|
|
||||||
key = strings.ToLower(key)
|
|
||||||
if key == token {
|
|
||||||
val = append(val, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveScheme is a helper function that evaluates the http.Request
|
|
||||||
// and returns the scheme, HTTP or HTTPS. It is able to detect,
|
|
||||||
// using the X-Forwarded-Proto, if the original request was HTTPS
|
|
||||||
// and routed through a reverse proxy with SSL termination.
|
|
||||||
func resolveScheme(r *http.Request) string {
|
|
||||||
switch {
|
|
||||||
case r.URL.Scheme == "https":
|
|
||||||
return "https"
|
|
||||||
case r.TLS != nil:
|
|
||||||
return "https"
|
|
||||||
case strings.HasPrefix(r.Proto, "HTTPS"):
|
|
||||||
return "https"
|
|
||||||
case r.Header.Get("X-Forwarded-Proto") == "https":
|
|
||||||
return "https"
|
|
||||||
case len(r.Header.Get("Forwarded")) != 0 && len(parseHeader(r, "Forwarded", "proto")) != 0 && parseHeader(r, "Forwarded", "proto")[0] == "https":
|
|
||||||
return "https"
|
|
||||||
default:
|
|
||||||
return "http"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveHost is a helper function that evaluates the http.Request
|
|
||||||
// and returns the hostname. It is able to detect, using the
|
|
||||||
// X-Forarded-For header, the original hostname when routed
|
|
||||||
// through a reverse proxy.
|
|
||||||
func resolveHost(r *http.Request) string {
|
|
||||||
switch {
|
|
||||||
case len(r.Host) != 0:
|
|
||||||
return r.Host
|
|
||||||
case len(r.URL.Host) != 0:
|
|
||||||
return r.URL.Host
|
|
||||||
case len(r.Header.Get("X-Forwarded-For")) != 0:
|
|
||||||
return r.Header.Get("X-Forwarded-For")
|
|
||||||
case len(r.Header.Get("Forwarded")) != 0 && len(parseHeader(r, "Forwarded", "for")) != 0:
|
|
||||||
return parseHeader(r, "Forwarded", "for")[0]
|
|
||||||
case len(r.Header.Get("X-Host")) != 0:
|
|
||||||
return r.Header.Get("X-Host")
|
|
||||||
case len(r.Header.Get("Forwarded")) != 0 && len(parseHeader(r, "Forwarded", "host")) != 0:
|
|
||||||
return parseHeader(r, "Forwarded", "host")[0]
|
|
||||||
case len(r.Header.Get("XFF")) != 0:
|
|
||||||
return r.Header.Get("XFF")
|
|
||||||
case len(r.Header.Get("X-Real-IP")) != 0:
|
|
||||||
return r.Header.Get("X-Real-IP")
|
|
||||||
default:
|
|
||||||
return "localhost:8000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hostname returns the hostname associated with
|
|
||||||
// the current context.
|
|
||||||
func Hostname(c *gin.Context) (host string) {
|
|
||||||
v, ok := c.Get("host")
|
|
||||||
if ok {
|
|
||||||
host = v.(string)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package location
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/franela/goblin"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var mockHeader []string
|
|
||||||
var mockRequest *http.Request
|
|
||||||
|
|
||||||
var wronglyFormedHeader []string
|
|
||||||
var wronglyFormedRequest *http.Request
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
mockHeader = []string{"For= 110.0.2.2", "for = \"[::1]\"; Host=example.com; foR=10.2.3.4; pRoto =https ; By = 127.0.0.1"}
|
|
||||||
mockRequest = &http.Request{Header: map[string][]string{"Forwarded": mockHeader}}
|
|
||||||
wronglyFormedHeader = []string{"Fro= 110.0.2.2", "for = \"[:1]\"% Host=example:.com| foR=10.278.3.4% poto =https | Bi % 127.0.0.1", ""}
|
|
||||||
wronglyFormedRequest = &http.Request{Header: map[string][]string{"Forwarded": wronglyFormedHeader}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseForwardedHeadersProto(t *testing.T) {
|
|
||||||
g := goblin.Goblin(t)
|
|
||||||
|
|
||||||
g.Describe("Parse proto Forwarded Headers", func() {
|
|
||||||
g.It("Should parse a normal proto Forwarded header", func() {
|
|
||||||
parsedHeader := parseHeader(mockRequest, "Forwarded", "proto")
|
|
||||||
g.Assert("https" == parsedHeader[0]).IsTrue()
|
|
||||||
})
|
|
||||||
g.It("Should parse a normal for Forwarded header", func() {
|
|
||||||
parsedHeader := parseHeader(mockRequest, "Forwarded", "for")
|
|
||||||
g.Assert(reflect.DeepEqual([]string{"110.0.2.2", "\"[::1]\"", "10.2.3.4"}, parsedHeader)).IsTrue()
|
|
||||||
})
|
|
||||||
g.It("Should parse a normal host Forwarded header", func() {
|
|
||||||
parsedHeader := parseHeader(mockRequest, "Forwarded", "host")
|
|
||||||
g.Assert("example.com" == parsedHeader[0]).IsTrue()
|
|
||||||
})
|
|
||||||
g.It("Should parse a normal by Forwarded header", func() {
|
|
||||||
parsedHeader := parseHeader(mockRequest, "Forwarded", "by")
|
|
||||||
g.Assert("127.0.0.1" == parsedHeader[0]).IsTrue()
|
|
||||||
})
|
|
||||||
g.It("Should not crash if a wrongly formed Forwarder header is sent", func() {
|
|
||||||
parsedHeader := parseHeader(wronglyFormedRequest, "Forwarded", "by")
|
|
||||||
g.Assert(len(parsedHeader) == 0).IsTrue()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
45
router/middleware/remote.go
Normal file
45
router/middleware/remote.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/remote"
|
||||||
|
"github.com/drone/drone/remote/bitbucket"
|
||||||
|
"github.com/drone/drone/remote/github"
|
||||||
|
"github.com/drone/drone/remote/gitlab"
|
||||||
|
"github.com/drone/drone/remote/gogs"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/ianschenck/envflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
driver = envflag.String("REMOTE_DRIVER", "", "")
|
||||||
|
config = envflag.String("REMOTE_CONFIG", "", "")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Remote is a middleware function that initializes the Remote and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Remote() gin.HandlerFunc {
|
||||||
|
|
||||||
|
logrus.Infof("using remote driver %s", *driver)
|
||||||
|
logrus.Infof("using remote config %s", *config)
|
||||||
|
|
||||||
|
var remote_ remote.Remote
|
||||||
|
switch *driver {
|
||||||
|
case "github":
|
||||||
|
remote_ = github.Load(*config)
|
||||||
|
case "bitbucket":
|
||||||
|
remote_ = bitbucket.Load(*config)
|
||||||
|
case "gogs":
|
||||||
|
remote_ = gogs.Load(*config)
|
||||||
|
case "gitlab":
|
||||||
|
remote_ = gitlab.Load(*config)
|
||||||
|
default:
|
||||||
|
logrus.Fatalln("remote configuraiton not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
remote.ToContext(c, remote_)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
29
router/middleware/store.go
Normal file
29
router/middleware/store.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/store"
|
||||||
|
"github.com/drone/drone/store/datastore"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/ianschenck/envflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
database = envflag.String("DATABASE_DRIVER", "sqlite3", "")
|
||||||
|
datasource = envflag.String("DATABASE_CONFIG", "drone.sqlite", "")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store is a middleware function that initializes the Datastore and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Store() gin.HandlerFunc {
|
||||||
|
db := datastore.New(*database, *datasource)
|
||||||
|
|
||||||
|
logrus.Infof("using database driver %s", *database)
|
||||||
|
logrus.Infof("using database config %s", *datasource)
|
||||||
|
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
store.ToContext(c, db)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
14
router/middleware/version.go
Normal file
14
router/middleware/version.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/version"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Version is a middleware function that appends the Drone
|
||||||
|
// version information to the HTTP response. This is intended
|
||||||
|
// for debugging and troubleshooting.
|
||||||
|
func Version(c *gin.Context) {
|
||||||
|
c.Header("X-DRONE-VERSION", version.Version)
|
||||||
|
c.Next()
|
||||||
|
}
|
|
@ -8,7 +8,6 @@ import (
|
||||||
|
|
||||||
"github.com/drone/drone/api"
|
"github.com/drone/drone/api"
|
||||||
"github.com/drone/drone/router/middleware/header"
|
"github.com/drone/drone/router/middleware/header"
|
||||||
"github.com/drone/drone/router/middleware/location"
|
|
||||||
"github.com/drone/drone/router/middleware/session"
|
"github.com/drone/drone/router/middleware/session"
|
||||||
"github.com/drone/drone/router/middleware/token"
|
"github.com/drone/drone/router/middleware/token"
|
||||||
"github.com/drone/drone/static"
|
"github.com/drone/drone/static"
|
||||||
|
@ -23,7 +22,6 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
||||||
e.SetHTMLTemplate(template.Load())
|
e.SetHTMLTemplate(template.Load())
|
||||||
e.StaticFS("/static", static.FileSystem())
|
e.StaticFS("/static", static.FileSystem())
|
||||||
|
|
||||||
e.Use(location.Resolve)
|
|
||||||
e.Use(header.NoCache)
|
e.Use(header.NoCache)
|
||||||
e.Use(header.Options)
|
e.Use(header.Options)
|
||||||
e.Use(header.Secure)
|
e.Use(header.Secure)
|
||||||
|
@ -146,6 +144,7 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
||||||
{
|
{
|
||||||
bots.Use(session.MustUser())
|
bots.Use(session.MustUser())
|
||||||
bots.POST("/slack", web.Slack)
|
bots.POST("/slack", web.Slack)
|
||||||
|
bots.POST("/slack/:command", web.Slack)
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := e.Group("/authorize")
|
auth := e.Group("/authorize")
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
package envconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Env map[string]string
|
|
||||||
|
|
||||||
// Get returns the value of the environment variable named by the key.
|
|
||||||
func (env Env) Get(key string) string {
|
|
||||||
return env[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the string value of the environment variable named by the
|
|
||||||
// key. If the variable is not present, the default value is returned.
|
|
||||||
func (env Env) String(key, value string) string {
|
|
||||||
got, ok := env[key]
|
|
||||||
if ok {
|
|
||||||
value = got
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool returns the boolean value of the environment variable named by the key.
|
|
||||||
// If the variable is not present, the default value is returned.
|
|
||||||
func (env Env) Bool(name string, value bool) bool {
|
|
||||||
got, ok := env[name]
|
|
||||||
if ok {
|
|
||||||
value, _ = strconv.ParseBool(got)
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int returns the integer value of the environment variable named by the key.
|
|
||||||
// If the variable is not present, the default value is returned.
|
|
||||||
func (env Env) Int(name string, value int) int {
|
|
||||||
got, ok := env[name]
|
|
||||||
if ok {
|
|
||||||
value, _ = strconv.Atoi(got)
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load reads the environment file and reads variables in "key=value" format.
|
|
||||||
// Then it read the system environment variables. It returns the combined
|
|
||||||
// results in a key value map.
|
|
||||||
func Load(filepath string) Env {
|
|
||||||
var envs = map[string]string{}
|
|
||||||
|
|
||||||
// load the environment file
|
|
||||||
f, err := os.Open(filepath)
|
|
||||||
if err == nil {
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
r := bufio.NewReader(f)
|
|
||||||
for {
|
|
||||||
line, _, err := r.ReadLine()
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
key, val, err := parseln(string(line))
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Setenv(key, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the environment variables
|
|
||||||
for _, env := range os.Environ() {
|
|
||||||
key, val, err := parseln(env)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
envs[key] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
return Env(envs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function to parse a "key=value" environment variable string.
|
|
||||||
func parseln(line string) (key string, val string, err error) {
|
|
||||||
line = removeComments(line)
|
|
||||||
if len(line) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
splits := strings.SplitN(line, "=", 2)
|
|
||||||
|
|
||||||
if len(splits) < 2 {
|
|
||||||
err = errors.New("missing delimiter '='")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
key = strings.Trim(splits[0], " ")
|
|
||||||
val = strings.Trim(splits[1], ` "'`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function to trim comments and whitespace from a string.
|
|
||||||
func removeComments(s string) (_ string) {
|
|
||||||
if len(s) == 0 || string(s[0]) == "#" {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
index := strings.Index(s, " #")
|
|
||||||
if index > -1 {
|
|
||||||
s = strings.TrimSpace(s[0:index])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/drone/drone/shared/envconfig"
|
|
||||||
"github.com/drone/drone/store"
|
"github.com/drone/drone/store"
|
||||||
"github.com/drone/drone/store/datastore/ddl"
|
"github.com/drone/drone/store/datastore/ddl"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
@ -23,20 +22,6 @@ type datastore struct {
|
||||||
*sql.DB
|
*sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load opens a new database connection with the specified driver
|
|
||||||
// and connection string specified in the environment variables.
|
|
||||||
func Load(env envconfig.Env) store.Store {
|
|
||||||
var (
|
|
||||||
driver = env.String("DATABASE_DRIVER", "sqlite3")
|
|
||||||
config = env.String("DATABASE_CONFIG", "drone.sqlite")
|
|
||||||
)
|
|
||||||
|
|
||||||
logrus.Infof("using database driver %s", driver)
|
|
||||||
logrus.Infof("using database config %s", config)
|
|
||||||
|
|
||||||
return New(driver, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a database connection for the given driver and datasource
|
// New creates a database connection for the given driver and datasource
|
||||||
// and returns a new Store.
|
// and returns a new Store.
|
||||||
func New(driver, config string) store.Store {
|
func New(driver, config string) store.Store {
|
||||||
|
|
|
@ -14,7 +14,6 @@ import (
|
||||||
"github.com/drone/drone/engine/parser"
|
"github.com/drone/drone/engine/parser"
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/remote"
|
"github.com/drone/drone/remote"
|
||||||
"github.com/drone/drone/router/middleware/context"
|
|
||||||
"github.com/drone/drone/shared/httputil"
|
"github.com/drone/drone/shared/httputil"
|
||||||
"github.com/drone/drone/shared/token"
|
"github.com/drone/drone/shared/token"
|
||||||
"github.com/drone/drone/store"
|
"github.com/drone/drone/store"
|
||||||
|
@ -205,7 +204,7 @@ func PostHook(c *gin.Context) {
|
||||||
// on status change notifications
|
// on status change notifications
|
||||||
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
|
last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID)
|
||||||
|
|
||||||
engine_ := context.Engine(c)
|
engine_ := engine.FromContext(c)
|
||||||
go engine_.Schedule(c.Copy(), &engine.Task{
|
go engine_.Schedule(c.Copy(), &engine.Task{
|
||||||
User: user,
|
User: user,
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
|
|
108
web/slack.go
108
web/slack.go
|
@ -1,9 +1,113 @@
|
||||||
package web
|
package web
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/drone/drone/store"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
slashDeploy = "deploy"
|
||||||
|
slashRestart = "restart"
|
||||||
|
slashStatus = "status"
|
||||||
|
)
|
||||||
|
|
||||||
// Slack is handler function that handles Slack slash commands.
|
// Slack is handler function that handles Slack slash commands.
|
||||||
func Slack(c *gin.Context) {
|
func Slack(c *gin.Context) {
|
||||||
|
command := c.Param("command")
|
||||||
text := c.PostForm("text")
|
text := c.PostForm("text")
|
||||||
c.String(200, "received message %s", text)
|
args := strings.Split(text, " ")
|
||||||
|
|
||||||
|
if command == "" {
|
||||||
|
command = args[0]
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case slashStatus:
|
||||||
|
slackStatus(c, args)
|
||||||
|
|
||||||
|
case slashRestart:
|
||||||
|
slackRestart(c, args)
|
||||||
|
|
||||||
|
case slashDeploy:
|
||||||
|
slackDeploy(c, args)
|
||||||
|
|
||||||
|
default:
|
||||||
|
c.String(200, "sorry, I didn't understand [%s]", text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func slackDeploy(c *gin.Context, args []string) {
|
||||||
|
if len(args) != 3 {
|
||||||
|
c.String(200, "Invalid command. Please provide [repo] [build number] [environment]")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
repo = args[0]
|
||||||
|
num = args[1]
|
||||||
|
env = args[2]
|
||||||
|
)
|
||||||
|
owner, name, _ := parseRepoBranch(repo)
|
||||||
|
|
||||||
|
c.String(200, "deploying build %s/%s#%s to %s", owner, name, num, env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func slackRestart(c *gin.Context, args []string) {
|
||||||
|
var (
|
||||||
|
repo = args[0]
|
||||||
|
num = args[1]
|
||||||
|
)
|
||||||
|
owner, name, _ := parseRepoBranch(repo)
|
||||||
|
|
||||||
|
c.String(200, "restarting build %s/%s#%s", owner, name, num)
|
||||||
|
}
|
||||||
|
|
||||||
|
func slackStatus(c *gin.Context, args []string) {
|
||||||
|
var (
|
||||||
|
owner string
|
||||||
|
name string
|
||||||
|
branch string
|
||||||
|
)
|
||||||
|
if len(args) > 0 {
|
||||||
|
owner, name, branch = parseRepoBranch(args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
repo, err := store.GetRepoOwnerName(c, owner, name)
|
||||||
|
if err != nil {
|
||||||
|
c.String(200, "cannot find repository %s/%s", owner, name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if branch == "" {
|
||||||
|
branch = repo.Branch
|
||||||
|
}
|
||||||
|
build, err := store.GetBuildLast(c, repo, branch)
|
||||||
|
if err != nil {
|
||||||
|
c.String(200, "cannot find status for %s/%s@%s", owner, name, branch)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.String(200, "%s@%s build number %d finished with status %s",
|
||||||
|
repo.FullName,
|
||||||
|
build.Branch,
|
||||||
|
build.Number,
|
||||||
|
build.Status,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRepoBranch(repo string) (owner, name, branch string) {
|
||||||
|
|
||||||
|
parts := strings.Split(repo, "@")
|
||||||
|
if len(parts) == 2 {
|
||||||
|
branch = parts[1]
|
||||||
|
repo = parts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
parts = strings.Split(repo, "/")
|
||||||
|
if len(parts) == 2 {
|
||||||
|
owner = parts[0]
|
||||||
|
name = parts[1]
|
||||||
|
}
|
||||||
|
return owner, name, branch
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/stdcopy"
|
"github.com/docker/docker/pkg/stdcopy"
|
||||||
"github.com/drone/drone/engine"
|
"github.com/drone/drone/engine"
|
||||||
"github.com/drone/drone/router/middleware/context"
|
|
||||||
"github.com/drone/drone/router/middleware/session"
|
"github.com/drone/drone/router/middleware/session"
|
||||||
"github.com/drone/drone/store"
|
"github.com/drone/drone/store"
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ import (
|
||||||
// GetRepoEvents will upgrade the connection to a Websocket and will stream
|
// GetRepoEvents will upgrade the connection to a Websocket and will stream
|
||||||
// event updates to the browser.
|
// event updates to the browser.
|
||||||
func GetRepoEvents(c *gin.Context) {
|
func GetRepoEvents(c *gin.Context) {
|
||||||
engine_ := context.Engine(c)
|
engine_ := engine.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
c.Writer.Header().Set("Content-Type", "text/event-stream")
|
c.Writer.Header().Set("Content-Type", "text/event-stream")
|
||||||
|
|
||||||
|
@ -55,7 +54,7 @@ func GetRepoEvents(c *gin.Context) {
|
||||||
|
|
||||||
func GetStream(c *gin.Context) {
|
func GetStream(c *gin.Context) {
|
||||||
|
|
||||||
engine_ := context.Engine(c)
|
engine_ := engine.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
buildn, _ := strconv.Atoi(c.Param("build"))
|
buildn, _ := strconv.Atoi(c.Param("build"))
|
||||||
jobn, _ := strconv.Atoi(c.Param("number"))
|
jobn, _ := strconv.Atoi(c.Param("number"))
|
||||||
|
|
Loading…
Reference in a new issue