Start working on specs implementation
This commit is contained in:
parent
2939e1356d
commit
2966d294fe
6 changed files with 125 additions and 63 deletions
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/drone/drone/Godeps/_workspace/src/github.com/elazarl/go-bindata-assetfs"
|
"github.com/drone/drone/Godeps/_workspace/src/github.com/elazarl/go-bindata-assetfs"
|
||||||
"github.com/drone/drone/pkg/config"
|
"github.com/drone/drone/pkg/config"
|
||||||
"github.com/drone/drone/pkg/remote/builtin/github"
|
"github.com/drone/drone/pkg/remote"
|
||||||
"github.com/drone/drone/pkg/server"
|
"github.com/drone/drone/pkg/server"
|
||||||
"github.com/drone/drone/pkg/server/session"
|
"github.com/drone/drone/pkg/server/session"
|
||||||
|
|
||||||
|
@ -49,7 +49,10 @@ func main() {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
remote := github.New(settings)
|
remote, err := remote.New(settings)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
session := session.New(settings)
|
session := session.New(settings)
|
||||||
eventbus_ := eventbus.New()
|
eventbus_ := eventbus.New()
|
||||||
queue_ := queue.New()
|
queue_ := queue.New()
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/drone/drone/Godeps/_workspace/src/github.com/naoina/toml"
|
"github.com/drone/drone/Godeps/_workspace/src/github.com/naoina/toml"
|
||||||
"github.com/drone/drone/Godeps/_workspace/src/github.com/vrischmann/envconfig"
|
"github.com/drone/drone/Godeps/_workspace/src/github.com/vrischmann/envconfig"
|
||||||
|
@ -9,12 +13,7 @@ import (
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Remote struct {
|
Remote struct {
|
||||||
Kind string `envconfig:"optional"`
|
Driver string `envconfig:"optional"`
|
||||||
Base string `envconfig:"optional"`
|
|
||||||
Orgs []string `envconfig:"optional"`
|
|
||||||
Open bool `envconfig:"optional"`
|
|
||||||
Private bool `envconfig:"optional"`
|
|
||||||
SkipVerify bool `envconfig:"optional"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth struct {
|
Auth struct {
|
||||||
|
@ -67,20 +66,14 @@ type Config struct {
|
||||||
Plugins []string `envconfig:"optional"`
|
Plugins []string `envconfig:"optional"`
|
||||||
|
|
||||||
Github struct {
|
Github struct {
|
||||||
Client string `envconfig:"optional"`
|
API string `envconfig:"optional"`
|
||||||
Secret string `envconfig:"optional"`
|
Host string `envconfig:"optional"`
|
||||||
Orgs []string `envconfig:"optional"`
|
Client string `envconfig:"optional"`
|
||||||
Open bool `envconfig:"optional"`
|
Secret string `envconfig:"optional"`
|
||||||
}
|
PrivateMode bool `envconfig:"optional"`
|
||||||
|
SkipVerify bool `envconfig:"optional"`
|
||||||
GithubEnterprise struct {
|
Open bool `envconfig:"optional"`
|
||||||
URL string `envconfig:"optional"`
|
Orgs []string `envconfig:"optional"`
|
||||||
Client string `envconfig:"optional"`
|
|
||||||
Secret string `envconfig:"optional"`
|
|
||||||
Private bool `envconfig:"optional"`
|
|
||||||
SkipVerify bool `envconfig:"optional"`
|
|
||||||
Open bool `envconfig:"optional"`
|
|
||||||
Orgs []string `envconfig:"optional"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitbucket struct {
|
Bitbucket struct {
|
||||||
|
@ -132,5 +125,29 @@ func applyDefaults(c *Config) *Config {
|
||||||
if len(c.Session.Secret) == 0 {
|
if len(c.Session.Secret) == 0 {
|
||||||
c.Session.Secret = c.Auth.Secret
|
c.Session.Secret = c.Auth.Secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent crash on start, use sqlite3
|
||||||
|
// driver as default if DRONE_DATABASE_DRIVER and
|
||||||
|
// DRONE_DATABASE_DATASOURCE not specifed
|
||||||
|
if len(c.Database.Driver) == 0 && len(c.Database.Datasource) == 0 {
|
||||||
|
c.Database.Driver = "sqlite3"
|
||||||
|
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Database.Datasource = path.Join(pwd, "drone.sqlite3")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default settings for remotes
|
||||||
|
switch strings.ToLower(c.Remote.Driver) {
|
||||||
|
case "github":
|
||||||
|
if len(c.Github.API) == 0 && len(c.Github.Host) == 0 {
|
||||||
|
c.Github.API = "https://api.github.com/"
|
||||||
|
c.Github.Host = "https://github.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package github
|
package github
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -10,14 +11,14 @@ import (
|
||||||
|
|
||||||
"github.com/drone/drone/Godeps/_workspace/src/github.com/hashicorp/golang-lru"
|
"github.com/drone/drone/Godeps/_workspace/src/github.com/hashicorp/golang-lru"
|
||||||
"github.com/drone/drone/pkg/config"
|
"github.com/drone/drone/pkg/config"
|
||||||
|
"github.com/drone/drone/pkg/oauth2"
|
||||||
common "github.com/drone/drone/pkg/types"
|
common "github.com/drone/drone/pkg/types"
|
||||||
|
"github.com/drone/drone/pkg/utils/httputil"
|
||||||
|
|
||||||
"github.com/drone/drone/Godeps/_workspace/src/github.com/google/go-github/github"
|
"github.com/drone/drone/Godeps/_workspace/src/github.com/google/go-github/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultAPI = "https://api.github.com/"
|
|
||||||
DefaultURL = "https://github.com"
|
|
||||||
DefaultScope = "repo,repo:status,user:email"
|
DefaultScope = "repo,repo:status,user:email"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@ type GitHub struct {
|
||||||
API string
|
API string
|
||||||
Client string
|
Client string
|
||||||
Secret string
|
Secret string
|
||||||
|
AllowedOrgs []string
|
||||||
|
Open bool
|
||||||
PrivateMode bool
|
PrivateMode bool
|
||||||
SkipVerify bool
|
SkipVerify bool
|
||||||
|
|
||||||
|
@ -34,12 +37,14 @@ type GitHub struct {
|
||||||
|
|
||||||
func New(conf *config.Config) *GitHub {
|
func New(conf *config.Config) *GitHub {
|
||||||
var github = GitHub{
|
var github = GitHub{
|
||||||
API: DefaultAPI,
|
API: conf.Github.API,
|
||||||
URL: DefaultURL,
|
URL: conf.Github.Host,
|
||||||
Client: conf.Auth.Client,
|
Client: conf.Github.Client,
|
||||||
Secret: conf.Auth.Secret,
|
Secret: conf.Github.Secret,
|
||||||
PrivateMode: conf.Remote.Private,
|
AllowedOrgs: conf.Github.Orgs,
|
||||||
SkipVerify: conf.Remote.SkipVerify,
|
Open: conf.Github.Open,
|
||||||
|
PrivateMode: conf.Github.PrivateMode,
|
||||||
|
SkipVerify: conf.Github.SkipVerify,
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
github.cache, err = lru.New(1028)
|
github.cache, err = lru.New(1028)
|
||||||
|
@ -47,12 +52,6 @@ func New(conf *config.Config) *GitHub {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if GitHub enterprise then ensure we're using the
|
|
||||||
// appropriate URLs
|
|
||||||
if !strings.HasPrefix(conf.Remote.Base, DefaultURL) && len(conf.Remote.Base) != 0 {
|
|
||||||
github.URL = conf.Remote.Base
|
|
||||||
github.API = conf.Remote.Base + "/api/v3/"
|
|
||||||
}
|
|
||||||
// the API must have a trailing slash
|
// the API must have a trailing slash
|
||||||
if !strings.HasSuffix(github.API, "/") {
|
if !strings.HasSuffix(github.API, "/") {
|
||||||
github.API += "/"
|
github.API += "/"
|
||||||
|
@ -66,7 +65,7 @@ func New(conf *config.Config) *GitHub {
|
||||||
|
|
||||||
func (g *GitHub) Login(token, secret string) (*common.User, error) {
|
func (g *GitHub) Login(token, secret string) (*common.User, error) {
|
||||||
client := NewClient(g.API, token, g.SkipVerify)
|
client := NewClient(g.API, token, g.SkipVerify)
|
||||||
login, err := GetUserEmail(client)
|
login, err := GetUserEmail(client, g.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -92,6 +91,16 @@ func (g *GitHub) Orgs(u *common.User) ([]string, error) {
|
||||||
return orgs_, nil
|
return orgs_, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accessor method, to allowed remote organizations field.
|
||||||
|
func (g *GitHub) GetOrgs() []string {
|
||||||
|
return g.AllowedOrgs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessor method, to open field.
|
||||||
|
func (g *GitHub) GetOpen() bool {
|
||||||
|
return g.Open
|
||||||
|
}
|
||||||
|
|
||||||
// Repo fetches the named repository from the remote system.
|
// Repo fetches the named repository from the remote system.
|
||||||
func (g *GitHub) Repo(u *common.User, owner, name string) (*common.Repo, error) {
|
func (g *GitHub) Repo(u *common.User, owner, name string) (*common.Repo, error) {
|
||||||
client := NewClient(g.API, u.Token, g.SkipVerify)
|
client := NewClient(g.API, u.Token, g.SkipVerify)
|
||||||
|
@ -281,6 +290,25 @@ func (g *GitHub) push(r *http.Request) (*common.Hook, error) {
|
||||||
return &common.Hook{Repo: repo, Commit: commit}, nil
|
return &common.Hook{Repo: repo, Commit: commit}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ¯\_(ツ)_/¯
|
||||||
|
func (g *GitHub) Oauth2Transport(r *http.Request) *oauth2.Transport {
|
||||||
|
return &oauth2.Transport{
|
||||||
|
Config: &oauth2.Config{
|
||||||
|
ClientId: g.Client,
|
||||||
|
ClientSecret: g.Secret,
|
||||||
|
Scope: DefaultScope,
|
||||||
|
AuthURL: fmt.Sprintf("%s/login/oauth/authorize", g.URL),
|
||||||
|
TokenURL: fmt.Sprintf("%s/login/oauth/access_token", g.URL),
|
||||||
|
RedirectURL: fmt.Sprintf("%s/authorize", httputil.GetURL(r)),
|
||||||
|
//settings.Server.Scheme, settings.Server.Hostname),
|
||||||
|
},
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: g.SkipVerify},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pullRequest parses a hook with event type `pullRequest`
|
// pullRequest parses a hook with event type `pullRequest`
|
||||||
// and returns the commit data.
|
// and returns the commit data.
|
||||||
func (g *GitHub) pullRequest(r *http.Request) (*common.Hook, error) {
|
func (g *GitHub) pullRequest(r *http.Request) (*common.Hook, error) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ func NewClient(uri, token string, skipVerify bool) *github.Client {
|
||||||
|
|
||||||
// GetUserEmail is a heper function that retrieves the currently
|
// GetUserEmail is a heper function that retrieves the currently
|
||||||
// authenticated user from GitHub + Email address.
|
// authenticated user from GitHub + Email address.
|
||||||
func GetUserEmail(client *github.Client) (*github.User, error) {
|
func GetUserEmail(client *github.Client, defaultURL string) (*github.User, error) {
|
||||||
user, _, err := client.Users.Get("")
|
user, _, err := client.Users.Get("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -58,7 +58,7 @@ func GetUserEmail(client *github.Client) (*github.User, error) {
|
||||||
// WARNING, HACK
|
// WARNING, HACK
|
||||||
// for out-of-date github enterprise editions the primary
|
// for out-of-date github enterprise editions the primary
|
||||||
// and verified fields won't exist.
|
// and verified fields won't exist.
|
||||||
if !strings.HasPrefix(*user.HTMLURL, DefaultURL) && len(emails) != 0 {
|
if !strings.HasPrefix(*user.HTMLURL, defaultURL) && len(emails) != 0 {
|
||||||
user.Email = emails[0].Email
|
user.Email = emails[0].Email
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
package remote
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/drone/drone/pkg/config"
|
||||||
|
"github.com/drone/drone/pkg/oauth2"
|
||||||
|
"github.com/drone/drone/pkg/remote/builtin/github"
|
||||||
common "github.com/drone/drone/pkg/types"
|
common "github.com/drone/drone/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,6 +51,27 @@ type Remote interface {
|
||||||
// and returns the required data in a standard format.
|
// and returns the required data in a standard format.
|
||||||
Hook(r *http.Request) (*common.Hook, error)
|
Hook(r *http.Request) (*common.Hook, error)
|
||||||
|
|
||||||
|
// Oauth2Transport
|
||||||
|
Oauth2Transport(r *http.Request) *oauth2.Transport
|
||||||
|
|
||||||
|
// GetOrgs returns all allowed organizations for remote.
|
||||||
|
GetOrgs() []string
|
||||||
|
|
||||||
|
// GetOpen returns boolean field with enabled or disabled
|
||||||
|
// registration.
|
||||||
|
GetOpen() bool
|
||||||
|
|
||||||
// Default scope for remote
|
// Default scope for remote
|
||||||
Scope() string
|
Scope() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func New(conf *config.Config) (Remote, error) {
|
||||||
|
switch strings.ToLower(conf.Remote.Driver) {
|
||||||
|
case "github":
|
||||||
|
return github.New(conf), nil
|
||||||
|
case "":
|
||||||
|
return nil, errors.New("Remote not specifed, please set env variable DRONE_REMOTE_DRIVER")
|
||||||
|
default:
|
||||||
|
return nil, errors.New(fmt.Sprintf("Remote driver not supported: DRONE_REMOTE_DRIVER=%s", conf.Remote.Driver))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin"
|
"github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin"
|
||||||
"github.com/drone/drone/Godeps/_workspace/src/github.com/ungerik/go-gravatar"
|
"github.com/drone/drone/Godeps/_workspace/src/github.com/ungerik/go-gravatar"
|
||||||
|
|
||||||
log "github.com/drone/drone/Godeps/_workspace/src/github.com/Sirupsen/logrus"
|
log "github.com/drone/drone/Godeps/_workspace/src/github.com/Sirupsen/logrus"
|
||||||
"github.com/drone/drone/pkg/oauth2"
|
|
||||||
common "github.com/drone/drone/pkg/types"
|
common "github.com/drone/drone/pkg/types"
|
||||||
"github.com/drone/drone/pkg/utils/httputil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetLogin accepts a request to authorize the user and to
|
// GetLogin accepts a request to authorize the user and to
|
||||||
|
@ -52,9 +48,9 @@ func GetLogin(c *gin.Context) {
|
||||||
login := ToUser(c)
|
login := ToUser(c)
|
||||||
|
|
||||||
// check organization membership, if applicable
|
// check organization membership, if applicable
|
||||||
if len(settings.Remote.Orgs) != 0 {
|
if len(remote.GetOrgs()) != 0 {
|
||||||
orgs, _ := remote.Orgs(login)
|
orgs, _ := remote.Orgs(login)
|
||||||
if !checkMembership(orgs, settings.Remote.Orgs) {
|
if !checkMembership(orgs, remote.GetOrgs()) {
|
||||||
c.Redirect(303, "/login#error=access_denied_org")
|
c.Redirect(303, "/login#error=access_denied_org")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -73,7 +69,7 @@ func GetLogin(c *gin.Context) {
|
||||||
// if self-registration is disabled we should
|
// if self-registration is disabled we should
|
||||||
// return a notAuthorized error. the only exception
|
// return a notAuthorized error. the only exception
|
||||||
// is if no users exist yet in the system we'll proceed.
|
// is if no users exist yet in the system we'll proceed.
|
||||||
if !settings.Remote.Open && count != 0 {
|
if !remote.GetOpen() && count != 0 {
|
||||||
log.Errorf("cannot register %s. registration closed", login.Login)
|
log.Errorf("cannot register %s. registration closed", login.Login)
|
||||||
c.Redirect(303, "/login#error=access_denied")
|
c.Redirect(303, "/login#error=access_denied")
|
||||||
return
|
return
|
||||||
|
@ -131,35 +127,26 @@ func GetLogin(c *gin.Context) {
|
||||||
// getLoginOauth2 is the default authorization implementation
|
// getLoginOauth2 is the default authorization implementation
|
||||||
// using the oauth2 protocol.
|
// using the oauth2 protocol.
|
||||||
func getLoginOauth2(c *gin.Context) {
|
func getLoginOauth2(c *gin.Context) {
|
||||||
var settings = ToSettings(c)
|
|
||||||
var remote = ToRemote(c)
|
var remote = ToRemote(c)
|
||||||
|
|
||||||
var scope = strings.Join(settings.Auth.Scope, ",")
|
// Bugagazavr: I think this must be moved to remote config
|
||||||
if scope == "" {
|
//var scope = strings.Join(settings.Auth.Scope, ",")
|
||||||
scope = remote.Scope()
|
//if scope == "" {
|
||||||
}
|
// scope = remote.Scope()
|
||||||
var config = &oauth2.Config{
|
//}
|
||||||
ClientId: settings.Auth.Client,
|
var transport = remote.Oauth2Transport(c.Request)
|
||||||
ClientSecret: settings.Auth.Secret,
|
|
||||||
Scope: scope,
|
|
||||||
AuthURL: settings.Auth.Authorize,
|
|
||||||
TokenURL: settings.Auth.AccessToken,
|
|
||||||
RedirectURL: fmt.Sprintf("%s/authorize", httputil.GetURL(c.Request)),
|
|
||||||
//settings.Server.Scheme, settings.Server.Hostname),
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the OAuth code
|
// get the OAuth code
|
||||||
var code = c.Request.FormValue("code")
|
var code = c.Request.FormValue("code")
|
||||||
//var state = c.Request.FormValue("state")
|
//var state = c.Request.FormValue("state")
|
||||||
if len(code) == 0 {
|
if len(code) == 0 {
|
||||||
// TODO this should be a random number, verified by a cookie
|
// TODO this should be a random number, verified by a cookie
|
||||||
c.Redirect(303, config.AuthCodeURL("random"))
|
c.Redirect(303, transport.AuthCodeURL("random"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// exhange for a token
|
// exhange for a token
|
||||||
var trans = &oauth2.Transport{Config: config}
|
var token, err = transport.Exchange(code)
|
||||||
var token, err = trans.Exchange(code)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("cannot get access_token. %s", err)
|
log.Errorf("cannot get access_token. %s", err)
|
||||||
c.Redirect(303, "/login#error=token_exchange")
|
c.Redirect(303, "/login#error=token_exchange")
|
||||||
|
|
Loading…
Reference in a new issue