refactoring remotes to remove deprecated variables, adding tests
This commit is contained in:
parent
b978ed12eb
commit
ebd547deac
21 changed files with 797 additions and 696 deletions
59
api/repo.go
59
api/repo.go
|
@ -2,13 +2,11 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/drone/drone/cache"
|
"github.com/drone/drone/cache"
|
||||||
"github.com/drone/drone/model"
|
|
||||||
"github.com/drone/drone/remote"
|
"github.com/drone/drone/remote"
|
||||||
"github.com/drone/drone/router/middleware/session"
|
"github.com/drone/drone/router/middleware/session"
|
||||||
"github.com/drone/drone/shared/crypto"
|
"github.com/drone/drone/shared/crypto"
|
||||||
|
@ -72,19 +70,9 @@ func PostRepo(c *gin.Context) {
|
||||||
sig,
|
sig,
|
||||||
)
|
)
|
||||||
|
|
||||||
// generate an RSA key and add to the repo
|
|
||||||
key, err := crypto.GeneratePrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
c.String(500, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keys := new(model.Key)
|
|
||||||
keys.Public = string(crypto.MarshalPublicKey(&key.PublicKey))
|
|
||||||
keys.Private = string(crypto.MarshalPrivateKey(key))
|
|
||||||
|
|
||||||
// activate the repository before we make any
|
// activate the repository before we make any
|
||||||
// local changes to the database.
|
// local changes to the database.
|
||||||
err = remote.Activate(user, r, keys, link)
|
err = remote.Activate(user, r, link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(500, err.Error())
|
c.String(500, err.Error())
|
||||||
return
|
return
|
||||||
|
@ -96,12 +84,6 @@ func PostRepo(c *gin.Context) {
|
||||||
c.String(500, err.Error())
|
c.String(500, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keys.RepoID = r.ID
|
|
||||||
err = store.CreateKey(c, keys)
|
|
||||||
if err != nil {
|
|
||||||
c.String(500, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(200, r)
|
c.JSON(200, r)
|
||||||
}
|
}
|
||||||
|
@ -155,45 +137,6 @@ func GetRepo(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, session.Repo(c))
|
c.JSON(http.StatusOK, session.Repo(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRepoKey(c *gin.Context) {
|
|
||||||
repo := session.Repo(c)
|
|
||||||
keys, err := store.GetKey(c, repo)
|
|
||||||
if err != nil {
|
|
||||||
c.String(404, "Error fetching repository key")
|
|
||||||
} else {
|
|
||||||
c.String(http.StatusOK, keys.Public)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostRepoKey(c *gin.Context) {
|
|
||||||
repo := session.Repo(c)
|
|
||||||
keys, err := store.GetKey(c, repo)
|
|
||||||
if err != nil {
|
|
||||||
c.String(404, "Error fetching repository key")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
body, err := ioutil.ReadAll(c.Request.Body)
|
|
||||||
if err != nil {
|
|
||||||
c.String(500, "Error reading private key from body. %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pkey := crypto.UnmarshalPrivateKey(body)
|
|
||||||
if pkey == nil {
|
|
||||||
c.String(500, "Cannot unmarshal private key. Invalid format.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.Public = string(crypto.MarshalPublicKey(&pkey.PublicKey))
|
|
||||||
keys.Private = string(crypto.MarshalPrivateKey(pkey))
|
|
||||||
|
|
||||||
err = store.UpdateKey(c, keys)
|
|
||||||
if err != nil {
|
|
||||||
c.String(500, "Error updating repository key")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.String(201, keys.Public)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteRepo(c *gin.Context) {
|
func DeleteRepo(c *gin.Context) {
|
||||||
remote := remote.FromContext(c)
|
remote := remote.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
|
|
107
drone/daemon.go
107
drone/daemon.go
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
@ -159,6 +158,16 @@ var DaemonCmd = cli.Command{
|
||||||
Usage: "gogs server address",
|
Usage: "gogs server address",
|
||||||
Value: "https://github.com",
|
Value: "https://github.com",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "DRONE_GOGS_GIT_USERNAME",
|
||||||
|
Name: "gogs-git-username",
|
||||||
|
Usage: "gogs service account username",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "DRONE_GOGS_GIT_PASSWORD",
|
||||||
|
Name: "gogs-git-password",
|
||||||
|
Usage: "gogs service account password",
|
||||||
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
EnvVar: "DRONE_GOGS_PRIVATE_MODE",
|
EnvVar: "DRONE_GOGS_PRIVATE_MODE",
|
||||||
Name: "gogs-private-mode",
|
Name: "gogs-private-mode",
|
||||||
|
@ -205,6 +214,16 @@ var DaemonCmd = cli.Command{
|
||||||
Name: "gitlab-sercret",
|
Name: "gitlab-sercret",
|
||||||
Usage: "gitlab oauth2 client secret",
|
Usage: "gitlab oauth2 client secret",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "DRONE_GITLAB_GIT_USERNAME",
|
||||||
|
Name: "gitlab-git-username",
|
||||||
|
Usage: "gitlab service account username",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "DRONE_GITLAB_GIT_PASSWORD",
|
||||||
|
Name: "gitlab-git-password",
|
||||||
|
Usage: "gitlab service account password",
|
||||||
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
EnvVar: "DRONE_GITLAB_SKIP_VERIFY",
|
EnvVar: "DRONE_GITLAB_SKIP_VERIFY",
|
||||||
Name: "gitlab-skip-verify",
|
Name: "gitlab-skip-verify",
|
||||||
|
@ -245,7 +264,11 @@ var DaemonCmd = cli.Command{
|
||||||
Name: "stash-git-password",
|
Name: "stash-git-password",
|
||||||
Usage: "stash service account password",
|
Usage: "stash service account password",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
EnvVar: "DRONE_STASH_SKIP_VERIFY",
|
||||||
|
Name: "stash-skip-verify",
|
||||||
|
Usage: "stash skip ssl verification",
|
||||||
|
},
|
||||||
//
|
//
|
||||||
// remove these eventually
|
// remove these eventually
|
||||||
//
|
//
|
||||||
|
@ -347,60 +370,70 @@ func setupStore(c *cli.Context) store.Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupRemote(c *cli.Context) remote.Remote {
|
func setupRemote(c *cli.Context) remote.Remote {
|
||||||
|
var remote remote.Remote
|
||||||
|
var err error
|
||||||
switch {
|
switch {
|
||||||
case c.Bool("github"):
|
case c.Bool("github"):
|
||||||
return setupGithub(c)
|
remote, err = setupGithub(c)
|
||||||
case c.Bool("gitlab"):
|
case c.Bool("gitlab"):
|
||||||
return setupGitlab(c)
|
remote, err = setupGitlab(c)
|
||||||
case c.Bool("bitbucket"):
|
case c.Bool("bitbucket"):
|
||||||
return setupBitbucket(c)
|
remote, err = setupBitbucket(c)
|
||||||
case c.Bool("stash"):
|
case c.Bool("stash"):
|
||||||
return setupStash(c)
|
remote, err = setupStash(c)
|
||||||
case c.Bool("gogs"):
|
case c.Bool("gogs"):
|
||||||
return setupGogs(c)
|
remote, err = setupGogs(c)
|
||||||
default:
|
default:
|
||||||
logrus.Fatalln("version control system not configured")
|
err = fmt.Errorf("version control system not configured")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalln(err)
|
||||||
|
}
|
||||||
|
return remote
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupBitbucket(c *cli.Context) remote.Remote {
|
func setupBitbucket(c *cli.Context) (remote.Remote, error) {
|
||||||
return bitbucket.New(
|
return bitbucket.New(
|
||||||
c.String("bitbucket-client"),
|
c.String("bitbucket-client"),
|
||||||
c.String("bitbucket-server"),
|
c.String("bitbucket-server"),
|
||||||
)
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupGogs(c *cli.Context) remote.Remote {
|
func setupGogs(c *cli.Context) (remote.Remote, error) {
|
||||||
return gogs.New(
|
return gogs.New(gogs.Opts{
|
||||||
c.String("gogs-server"),
|
URL: c.String("gogs-server"),
|
||||||
c.Bool("gogs-private-mode"),
|
Username: c.String("gogs-git-username"),
|
||||||
c.Bool("gogs-skip-verify"),
|
Password: c.String("gogs-git-password"),
|
||||||
)
|
PrivateMode: c.Bool("gogs-private-mode"),
|
||||||
|
SkipVerify: c.Bool("gogs-skip-verify"),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupStash(c *cli.Context) remote.Remote {
|
func setupStash(c *cli.Context) (remote.Remote, error) {
|
||||||
return bitbucketserver.New(
|
return bitbucketserver.New(bitbucketserver.Opts{
|
||||||
c.String("stash-server"),
|
URL: c.String("stash-server"),
|
||||||
c.String("stash-consumer-key"),
|
Username: c.String("stash-git-username"),
|
||||||
c.String("stash-consumer-rsa"),
|
Password: c.String("stash-git-password"),
|
||||||
c.String("stash-git-username"),
|
ConsumerKey: c.String("stash-consumer-key"),
|
||||||
c.String("stash-git-password"),
|
ConsumerRSA: c.String("stash-consumer-rsa"),
|
||||||
)
|
SkipVerify: c.Bool("stash-skip-verify"),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupGitlab(c *cli.Context) remote.Remote {
|
func setupGitlab(c *cli.Context) (remote.Remote, error) {
|
||||||
return gitlab.New(
|
return gitlab.New(gitlab.Opts{
|
||||||
c.String("gitlab-server"),
|
URL: c.String("gitlab-server"),
|
||||||
c.String("gitlab-client"),
|
Client: c.String("gitlab-client"),
|
||||||
c.String("gitlab-sercret"),
|
Secret: c.String("gitlab-sercret"),
|
||||||
c.Bool("gitlab-private-mode"),
|
Username: c.String("gitlab-git-username"),
|
||||||
c.Bool("gitlab-skip-verify"),
|
Password: c.String("gitlab-git-password"),
|
||||||
)
|
PrivateMode: c.Bool("gitlab-private-mode"),
|
||||||
|
SkipVerify: c.Bool("gitlab-skip-verify"),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupGithub(c *cli.Context) remote.Remote {
|
func setupGithub(c *cli.Context) (remote.Remote, error) {
|
||||||
g, err := github.New(
|
return github.New(
|
||||||
c.String("github-server"),
|
c.String("github-server"),
|
||||||
c.String("github-client"),
|
c.String("github-client"),
|
||||||
c.String("github-sercret"),
|
c.String("github-sercret"),
|
||||||
|
@ -409,10 +442,6 @@ func setupGithub(c *cli.Context) remote.Remote {
|
||||||
c.Bool("github-skip-verify"),
|
c.Bool("github-skip-verify"),
|
||||||
c.BoolT("github-merge-ref"),
|
c.BoolT("github-merge-ref"),
|
||||||
)
|
)
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
return g
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func printSecret(c *cli.Context) error {
|
func printSecret(c *cli.Context) error {
|
||||||
|
|
|
@ -132,7 +132,6 @@ func (c *config) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||||
accounts = append(accounts, team.Login)
|
accounts = append(accounts, team.Login)
|
||||||
}
|
}
|
||||||
|
|
||||||
// for each account, get the list of repos
|
|
||||||
for _, account := range accounts {
|
for _, account := range accounts {
|
||||||
repos, err := client.ListReposAll(account)
|
repos, err := client.ListReposAll(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -142,7 +141,6 @@ func (c *config) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||||
all = append(all, convertRepoLite(repo))
|
all = append(all, convertRepoLite(repo))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return all, nil
|
return all, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,8 +166,7 @@ func (c *config) Perm(u *model.User, owner, name string) (*model.Perm, error) {
|
||||||
return perms, nil
|
return perms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// File fetches the file from the Bitbucket repository and returns its contents
|
// File fetches the file from the Bitbucket repository and returns its contents.
|
||||||
// in string format.
|
|
||||||
func (c *config) File(u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
func (c *config) File(u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
||||||
config, err := c.newClient(u).FindSource(r.Owner, r.Name, b.Commit, f)
|
config, err := c.newClient(u).FindSource(r.Owner, r.Name, b.Commit, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,23 +1,17 @@
|
||||||
package bitbucketserver
|
package bitbucketserver
|
||||||
|
|
||||||
// Requires the following to be set
|
// WARNING! This is an work-in-progress patch and does not yet conform to the coding,
|
||||||
// REMOTE_DRIVER=bitbucketserver
|
// quality or security standards expected of this project. Please use with caution.
|
||||||
// REMOTE_CONFIG=https://{servername}?consumer_key={key added on the stash server for oath1}&git_username={username for clone}&git_password={password for clone}&consumer_rsa=/path/to/pem.file&open={not used yet}
|
|
||||||
// Configure application links in the bitbucket server --
|
|
||||||
// application url needs to be the base url to drone
|
|
||||||
// incoming auth needs to have the consumer key (same as the key in REMOTE_CONFIG)
|
|
||||||
// set the public key (public key from the private key added to /var/lib/bitbucketserver/private_key.pem name matters)
|
|
||||||
// consumer call back is the base url to drone plus /authorize/
|
|
||||||
// Needs a pem private key added to /var/lib/bitbucketserver/private_key.pem
|
|
||||||
// After that you should be good to go
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
|
@ -25,132 +19,132 @@ import (
|
||||||
"github.com/mrjones/oauth"
|
"github.com/mrjones/oauth"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BitbucketServer struct {
|
// Opts defines configuration options.
|
||||||
|
type Opts struct {
|
||||||
|
URL string // Stash server url.
|
||||||
|
Username string // Git machine account username.
|
||||||
|
Password string // Git machine account password.
|
||||||
|
ConsumerKey string // Oauth1 consumer key.
|
||||||
|
ConsumerRSA string // Oauth1 consumer key file.
|
||||||
|
|
||||||
|
SkipVerify bool // Skip ssl verification.
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a Remote implementation that integrates with Bitbucket Server,
|
||||||
|
// the on-premise edition of Bitbucket Cloud, formerly known as Stash.
|
||||||
|
func New(opts Opts) (remote.Remote, error) {
|
||||||
|
bb := &client{
|
||||||
|
URL: opts.URL,
|
||||||
|
ConsumerKey: opts.ConsumerKey,
|
||||||
|
ConsumerRSA: opts.ConsumerRSA,
|
||||||
|
GitUserName: opts.Username,
|
||||||
|
GitPassword: opts.Password,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case bb.GitUserName == "":
|
||||||
|
return nil, fmt.Errorf("Must have a git machine account username")
|
||||||
|
case bb.GitPassword == "":
|
||||||
|
return nil, fmt.Errorf("Must have a git machine account password")
|
||||||
|
case bb.ConsumerKey == "":
|
||||||
|
return nil, fmt.Errorf("Must have a oauth1 consumer key")
|
||||||
|
case bb.ConsumerRSA == "":
|
||||||
|
return nil, fmt.Errorf("Must have a oauth1 consumer key file")
|
||||||
|
}
|
||||||
|
|
||||||
|
keyfile, err := ioutil.ReadFile(bb.ConsumerRSA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
block, _ := pem.Decode(keyfile)
|
||||||
|
bb.PrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO de-referencing is a bit weird and may not behave as expected, and could
|
||||||
|
// have race conditions. Instead store the parsed key (I already did this above)
|
||||||
|
// and then pass the parsed private key when creating the Bitbucket client.
|
||||||
|
bb.Consumer = *NewClient(bb.ConsumerRSA, bb.ConsumerKey, bb.URL)
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
URL string
|
URL string
|
||||||
ConsumerKey string
|
ConsumerKey string
|
||||||
GitUserName string
|
GitUserName string
|
||||||
GitPassword string
|
GitPassword string
|
||||||
ConsumerRSA string
|
ConsumerRSA string
|
||||||
Open bool
|
PrivateKey *rsa.PrivateKey
|
||||||
Consumer oauth.Consumer
|
Consumer oauth.Consumer
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(url, key, rsa, username, password string) remote.Remote {
|
func (c *client) Login(res http.ResponseWriter, req *http.Request) (*model.User, error) {
|
||||||
bb := &BitbucketServer{
|
requestToken, url, err := c.Consumer.GetRequestTokenAndUrl("oob")
|
||||||
URL: url,
|
|
||||||
ConsumerKey: key,
|
|
||||||
GitUserName: username,
|
|
||||||
GitPassword: password,
|
|
||||||
ConsumerRSA: rsa,
|
|
||||||
}
|
|
||||||
bb.Consumer = *NewClient(bb.ConsumerRSA, bb.ConsumerKey, bb.URL)
|
|
||||||
|
|
||||||
return bb
|
|
||||||
}
|
|
||||||
|
|
||||||
func Load(config string) *BitbucketServer {
|
|
||||||
|
|
||||||
url_, err := url.Parse(config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("unable to parse remote dsn. %s", err)
|
return nil, err
|
||||||
}
|
|
||||||
params := url_.Query()
|
|
||||||
url_.Path = ""
|
|
||||||
url_.RawQuery = ""
|
|
||||||
|
|
||||||
bitbucketserver := BitbucketServer{}
|
|
||||||
bitbucketserver.URL = url_.String()
|
|
||||||
bitbucketserver.GitUserName = params.Get("git_username")
|
|
||||||
if bitbucketserver.GitUserName == "" {
|
|
||||||
log.Fatalln("Must have a git_username")
|
|
||||||
}
|
|
||||||
bitbucketserver.GitPassword = params.Get("git_password")
|
|
||||||
if bitbucketserver.GitPassword == "" {
|
|
||||||
log.Fatalln("Must have a git_password")
|
|
||||||
}
|
|
||||||
bitbucketserver.ConsumerKey = params.Get("consumer_key")
|
|
||||||
if bitbucketserver.ConsumerKey == "" {
|
|
||||||
log.Fatalln("Must have a consumer_key")
|
|
||||||
}
|
|
||||||
bitbucketserver.ConsumerRSA = params.Get("consumer_rsa")
|
|
||||||
if bitbucketserver.ConsumerRSA == "" {
|
|
||||||
log.Fatalln("Must have a consumer_rsa")
|
|
||||||
}
|
|
||||||
|
|
||||||
bitbucketserver.Open, _ = strconv.ParseBool(params.Get("open"))
|
|
||||||
|
|
||||||
bitbucketserver.Consumer = *NewClient(bitbucketserver.ConsumerRSA, bitbucketserver.ConsumerKey, bitbucketserver.URL)
|
|
||||||
|
|
||||||
return &bitbucketserver
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bs *BitbucketServer) Login(res http.ResponseWriter, req *http.Request) (*model.User, bool, error) {
|
|
||||||
log.Info("Starting to login for bitbucketServer")
|
|
||||||
|
|
||||||
log.Info("getting the requestToken")
|
|
||||||
requestToken, url, err := bs.Consumer.GetRequestTokenAndUrl("oob")
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var code = req.FormValue("oauth_verifier")
|
var code = req.FormValue("oauth_verifier")
|
||||||
if len(code) == 0 {
|
if len(code) == 0 {
|
||||||
log.Info("redirecting to %s", url)
|
|
||||||
http.Redirect(res, req, url, http.StatusSeeOther)
|
http.Redirect(res, req, url, http.StatusSeeOther)
|
||||||
return nil, false, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var request_oauth_token = req.FormValue("oauth_token")
|
requestToken.Token = req.FormValue("oauth_token")
|
||||||
requestToken.Token = request_oauth_token
|
accessToken, err := c.Consumer.AuthorizeToken(requestToken, code)
|
||||||
accessToken, err := bs.Consumer.AuthorizeToken(requestToken, code)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := bs.Consumer.MakeHttpClient(accessToken)
|
client, err := c.Consumer.MakeHttpClient(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.Get(fmt.Sprintf("%s/plugins/servlet/applinks/whoami", bs.URL))
|
response, err := client.Get(fmt.Sprintf("%s/plugins/servlet/applinks/whoami", c.URL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
bits, err := ioutil.ReadAll(response.Body)
|
bits, err := ioutil.ReadAll(response.Body)
|
||||||
userName := string(bits)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
login := string(bits)
|
||||||
|
|
||||||
response1, err := client.Get(fmt.Sprintf("%s/rest/api/1.0/users/%s", bs.URL, userName))
|
// TODO errors should never be ignored like this
|
||||||
|
response1, err := client.Get(fmt.Sprintf("%s/rest/api/1.0/users/%s", c.URL, login))
|
||||||
contents, err := ioutil.ReadAll(response1.Body)
|
contents, err := ioutil.ReadAll(response1.Body)
|
||||||
defer response1.Body.Close()
|
defer response1.Body.Close()
|
||||||
var mUser User
|
var mUser User // TODO prefixing with m* is not a common convention in Go
|
||||||
json.Unmarshal(contents, &mUser)
|
json.Unmarshal(contents, &mUser) // TODO should not ignore error
|
||||||
|
|
||||||
user := model.User{}
|
return &model.User{
|
||||||
user.Login = userName
|
Login: login,
|
||||||
user.Email = mUser.EmailAddress
|
Email: mUser.EmailAddress,
|
||||||
user.Token = accessToken.Token
|
Token: accessToken.Token,
|
||||||
|
Avatar: avatarLink(mUser.EmailAddress),
|
||||||
user.Avatar = avatarLink(mUser.EmailAddress)
|
}, nil
|
||||||
|
|
||||||
return &user, bs.Open, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Auth(token, secret string) (string, error) {
|
// Auth is not supported by the Stash driver.
|
||||||
log.Info("Staring to auth for bitbucketServer. %s", token)
|
func (*client) Auth(token, secret string) (string, error) {
|
||||||
if len(token) == 0 {
|
return "", fmt.Errorf("Not Implemented")
|
||||||
return "", fmt.Errorf("Hasn't logged in yet")
|
|
||||||
}
|
|
||||||
return token, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
// Teams is not supported by the Stash driver.
|
||||||
log.Info("Staring repo for bitbucketServer with user " + u.Login + " " + owner + " " + name)
|
func (*client) Teams(u *model.User) ([]*model.Team, error) {
|
||||||
|
var teams []*model.Team
|
||||||
|
return teams, nil
|
||||||
|
}
|
||||||
|
|
||||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||||
|
|
||||||
|
client := NewClientWithToken(&c.Consumer, u.Token)
|
||||||
|
|
||||||
|
url := fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s", c.URL, owner, name)
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s", bs.URL, owner, name)
|
|
||||||
log.Info("Trying to get " + url)
|
|
||||||
response, err := client.Get(url)
|
response, err := client.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
@ -160,40 +154,36 @@ func (bs *BitbucketServer) Repo(u *model.User, owner, name string) (*model.Repo,
|
||||||
bsRepo := BSRepo{}
|
bsRepo := BSRepo{}
|
||||||
json.Unmarshal(contents, &bsRepo)
|
json.Unmarshal(contents, &bsRepo)
|
||||||
|
|
||||||
cloneLink := ""
|
repo := &model.Repo{
|
||||||
repoLink := ""
|
Name: bsRepo.Slug,
|
||||||
|
Owner: bsRepo.Project.Key,
|
||||||
|
Branch: "master",
|
||||||
|
Kind: model.RepoGit,
|
||||||
|
IsPrivate: !bsRepo.Project.Public, // TODO(josmo) verify this is corrrect
|
||||||
|
FullName: fmt.Sprintf("%s/%s", bsRepo.Project.Key, bsRepo.Slug),
|
||||||
|
}
|
||||||
|
|
||||||
for _, item := range bsRepo.Links.Clone {
|
for _, item := range bsRepo.Links.Clone {
|
||||||
if item.Name == "http" {
|
if item.Name == "http" {
|
||||||
cloneLink = item.Href
|
repo.Clone = item.Href
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, item := range bsRepo.Links.Self {
|
for _, item := range bsRepo.Links.Self {
|
||||||
if item.Href != "" {
|
if item.Href != "" {
|
||||||
repoLink = item.Href
|
repo.Link = item.Href
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: get the real allow tag+ infomration
|
|
||||||
repo := &model.Repo{}
|
|
||||||
repo.Clone = cloneLink
|
|
||||||
repo.Link = repoLink
|
|
||||||
repo.Name = bsRepo.Slug
|
|
||||||
repo.Owner = bsRepo.Project.Key
|
|
||||||
repo.AllowPush = true
|
|
||||||
repo.FullName = fmt.Sprintf("%s/%s", bsRepo.Project.Key, bsRepo.Slug)
|
|
||||||
repo.Branch = "master"
|
|
||||||
repo.Kind = model.RepoGit
|
|
||||||
|
|
||||||
return repo, nil
|
return repo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Repos(u *model.User) ([]*model.RepoLite, error) {
|
func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||||
log.Info("Staring repos for bitbucketServer " + u.Login)
|
|
||||||
var repos = []*model.RepoLite{}
|
var repos = []*model.RepoLite{}
|
||||||
|
|
||||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
client := NewClientWithToken(&c.Consumer, u.Token)
|
||||||
|
|
||||||
response, err := client.Get(fmt.Sprintf("%s/rest/api/1.0/repos?limit=10000", bs.URL))
|
response, err := client.Get(fmt.Sprintf("%s/rest/api/1.0/repos?limit=10000", c.URL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -213,10 +203,8 @@ func (bs *BitbucketServer) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||||
return repos, nil
|
return repos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Perm(u *model.User, owner, repo string) (*model.Perm, error) {
|
func (c *client) Perm(u *model.User, owner, repo string) (*model.Perm, error) {
|
||||||
|
// TODO need to fetch real permissions here
|
||||||
//TODO: find the real permissions
|
|
||||||
log.Info("Staring perm for bitbucketServer")
|
|
||||||
perms := new(model.Perm)
|
perms := new(model.Perm)
|
||||||
perms.Pull = true
|
perms.Pull = true
|
||||||
perms.Admin = true
|
perms.Admin = true
|
||||||
|
@ -224,11 +212,11 @@ func (bs *BitbucketServer) Perm(u *model.User, owner, repo string) (*model.Perm,
|
||||||
return perms, nil
|
return perms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) File(u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
func (c *client) File(u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
||||||
log.Info(fmt.Sprintf("Staring file for bitbucketServer login: %s repo: %s buildevent: %s string: %s", u.Login, r.Name, b.Event, f))
|
log.Info(fmt.Sprintf("Staring file for bitbucketServer login: %s repo: %s buildevent: %s string: %s", u.Login, r.Name, b.Event, f))
|
||||||
|
|
||||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
client := NewClientWithToken(&c.Consumer, u.Token)
|
||||||
fileURL := fmt.Sprintf("%s/projects/%s/repos/%s/browse/%s?raw", bs.URL, r.Owner, r.Name, f)
|
fileURL := fmt.Sprintf("%s/projects/%s/repos/%s/browse/%s?raw", c.URL, r.Owner, r.Name, f)
|
||||||
log.Info(fileURL)
|
log.Info(fileURL)
|
||||||
response, err := client.Get(fileURL)
|
response, err := client.Get(fileURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -246,28 +234,26 @@ func (bs *BitbucketServer) File(u *model.User, r *model.Repo, b *model.Build, f
|
||||||
return responseBytes, nil
|
return responseBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Status(u *model.User, r *model.Repo, b *model.Build, link string) error {
|
// Status is not supported by the Gogs driver.
|
||||||
log.Info("Staring status for bitbucketServer")
|
func (*client) Status(*model.User, *model.Repo, *model.Build, string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) {
|
func (c *client) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||||
log.Info("Starting the Netrc lookup")
|
u, err := url.Parse(c.URL) // TODO strip port from url
|
||||||
u, err := url.Parse(bs.URL)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &model.Netrc{
|
return &model.Netrc{
|
||||||
Machine: u.Host,
|
Machine: u.Host,
|
||||||
Login: bs.GitUserName,
|
Login: c.GitUserName,
|
||||||
Password: bs.GitPassword,
|
Password: c.GitPassword,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Activate(u *model.User, r *model.Repo, k *model.Key, link string) error {
|
func (c *client) Activate(u *model.User, r *model.Repo, link string) error {
|
||||||
log.Info(fmt.Sprintf("Staring activate for bitbucketServer user: %s repo: %s key: %s link: %s", u.Login, r.Name, k, link))
|
client := NewClientWithToken(&c.Consumer, u.Token)
|
||||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
hook, err := c.CreateHook(client, r.Owner, r.Name, "com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook", link)
|
||||||
hook, err := bs.CreateHook(client, r.Owner, r.Name, "com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook", link)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -275,50 +261,38 @@ func (bs *BitbucketServer) Activate(u *model.User, r *model.Repo, k *model.Key,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Deactivate(u *model.User, r *model.Repo, link string) error {
|
func (c *client) Deactivate(u *model.User, r *model.Repo, link string) error {
|
||||||
log.Info(fmt.Sprintf("Staring deactivating for bitbucketServer user: %s repo: %s link: %s", u.Login, r.Name, link))
|
client := NewClientWithToken(&c.Consumer, u.Token)
|
||||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
err := c.DeleteHook(client, r.Owner, r.Name, "com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook", link)
|
||||||
err := bs.DeleteHook(client, r.Owner, r.Name, "com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook", link)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitbucketServer) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
func (c *client) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
||||||
log.Info("Staring hook for bitbucketServer")
|
hook := new(postHook)
|
||||||
defer r.Body.Close()
|
if err := json.NewDecoder(r.Body).Decode(hook); err != nil {
|
||||||
contents, err := ioutil.ReadAll(r.Body)
|
return nil, nil, err
|
||||||
if err != nil {
|
|
||||||
log.Info(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var hookPost postHook
|
build := &model.Build{
|
||||||
json.Unmarshal(contents, &hookPost)
|
Event: model.EventPush,
|
||||||
|
Ref: hook.RefChanges[0].RefID, // TODO check for index Values
|
||||||
|
Author: hook.Changesets.Values[0].ToCommit.Author.EmailAddress, // TODO check for index Values
|
||||||
|
Commit: hook.RefChanges[0].ToHash, // TODO check for index value
|
||||||
|
Avatar: avatarLink(hook.Changesets.Values[0].ToCommit.Author.EmailAddress),
|
||||||
|
}
|
||||||
|
|
||||||
buildModel := &model.Build{}
|
repo := &model.Repo{
|
||||||
buildModel.Event = model.EventPush
|
Name: hook.Repository.Slug,
|
||||||
buildModel.Ref = hookPost.RefChanges[0].RefID
|
Owner: hook.Repository.Project.Key,
|
||||||
buildModel.Author = hookPost.Changesets.Values[0].ToCommit.Author.EmailAddress
|
FullName: fmt.Sprintf("%s/%s", hook.Repository.Project.Key, hook.Repository.Slug),
|
||||||
buildModel.Commit = hookPost.RefChanges[0].ToHash
|
Branch: "master",
|
||||||
buildModel.Avatar = avatarLink(hookPost.Changesets.Values[0].ToCommit.Author.EmailAddress)
|
Kind: model.RepoGit,
|
||||||
|
}
|
||||||
|
|
||||||
//All you really need is the name and owner. That's what creates the lookup key, so it needs to match the repo info. Just an FYI
|
return repo, build, nil
|
||||||
repo := &model.Repo{}
|
|
||||||
repo.Name = hookPost.Repository.Slug
|
|
||||||
repo.Owner = hookPost.Repository.Project.Key
|
|
||||||
repo.AllowTag = false
|
|
||||||
repo.AllowDeploy = false
|
|
||||||
repo.AllowPull = false
|
|
||||||
repo.AllowPush = true
|
|
||||||
repo.FullName = fmt.Sprintf("%s/%s", hookPost.Repository.Project.Key, hookPost.Repository.Slug)
|
|
||||||
repo.Branch = "master"
|
|
||||||
repo.Kind = model.RepoGit
|
|
||||||
|
|
||||||
return repo, buildModel, nil
|
|
||||||
}
|
|
||||||
func (bs *BitbucketServer) String() string {
|
|
||||||
return "bitbucketserver"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type HookDetail struct {
|
type HookDetail struct {
|
||||||
|
@ -336,7 +310,7 @@ type Hook struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable hook for named repository
|
// Enable hook for named repository
|
||||||
func (bs *BitbucketServer) CreateHook(client *http.Client, project, slug, hook_key, link string) (*Hook, error) {
|
func (bs *client) CreateHook(client *http.Client, project, slug, hook_key, link string) (*Hook, error) {
|
||||||
|
|
||||||
// Set hook
|
// Set hook
|
||||||
hookBytes := []byte(fmt.Sprintf(`{"hook-url-0":"%s"}`, link))
|
hookBytes := []byte(fmt.Sprintf(`{"hook-url-0":"%s"}`, link))
|
||||||
|
@ -351,7 +325,7 @@ func (bs *BitbucketServer) CreateHook(client *http.Client, project, slug, hook_k
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable hook for named repository
|
// Disable hook for named repository
|
||||||
func (bs *BitbucketServer) DeleteHook(client *http.Client, project, slug, hook_key, link string) error {
|
func (bs *client) DeleteHook(client *http.Client, project, slug, hook_key, link string) error {
|
||||||
enablePath := fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s/enabled",
|
enablePath := fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s/enabled",
|
||||||
project, slug, hook_key)
|
project, slug, hook_key)
|
||||||
doDelete(client, bs.URL+enablePath)
|
doDelete(client, bs.URL+enablePath)
|
||||||
|
|
|
@ -272,7 +272,7 @@ func (g *Github) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||||
|
|
||||||
// Activate activates a repository by creating the post-commit hook and
|
// Activate activates a repository by creating the post-commit hook and
|
||||||
// adding the SSH deploy key, if applicable.
|
// adding the SSH deploy key, if applicable.
|
||||||
func (g *Github) Activate(u *model.User, r *model.Repo, k *model.Key, link string) error {
|
func (g *Github) Activate(u *model.User, r *model.Repo, link string) error {
|
||||||
client := NewClient(g.API, u.Token, g.SkipVerify)
|
client := NewClient(g.API, u.Token, g.SkipVerify)
|
||||||
_, err := CreateUpdateHook(client, r.Owner, r.Name, link)
|
_, err := CreateUpdateHook(client, r.Owner, r.Name, link)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -13,38 +14,59 @@ import (
|
||||||
"github.com/drone/drone/remote"
|
"github.com/drone/drone/remote"
|
||||||
"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/remote/gitlab/client"
|
"github.com/drone/drone/remote/gitlab/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const DefaultScope = "api"
|
||||||
DefaultScope = "api"
|
|
||||||
)
|
// Opts defines configuration options.
|
||||||
|
type Opts struct {
|
||||||
|
URL string // Gogs server url.
|
||||||
|
Client string // Oauth2 client id.
|
||||||
|
Secret string // Oauth2 client secret.
|
||||||
|
Username string // Optional machine account username.
|
||||||
|
Password string // Optional machine account password.
|
||||||
|
PrivateMode bool // Gogs is running in private mode.
|
||||||
|
SkipVerify bool // Skip ssl verification.
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a Remote implementation that integrates with Gitlab, an open
|
||||||
|
// source Git service. See https://gitlab.com
|
||||||
|
func New(opts Opts) (remote.Remote, error) {
|
||||||
|
url, err := url.Parse(opts.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
host, _, err := net.SplitHostPort(url.Host)
|
||||||
|
if err == nil {
|
||||||
|
url.Host = host
|
||||||
|
}
|
||||||
|
return &Gitlab{
|
||||||
|
URL: opts.URL,
|
||||||
|
Client: opts.Client,
|
||||||
|
Secret: opts.Secret,
|
||||||
|
Machine: url.Host,
|
||||||
|
Username: opts.Username,
|
||||||
|
Password: opts.Password,
|
||||||
|
PrivateMode: opts.PrivateMode,
|
||||||
|
SkipVerify: opts.SkipVerify,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type Gitlab struct {
|
type Gitlab struct {
|
||||||
URL string
|
URL string
|
||||||
Client string
|
Client string
|
||||||
Secret string
|
Secret string
|
||||||
AllowedOrgs []string
|
Machine string
|
||||||
CloneMode string
|
Username string
|
||||||
Open bool
|
Password string
|
||||||
PrivateMode bool
|
PrivateMode bool
|
||||||
SkipVerify bool
|
SkipVerify bool
|
||||||
HideArchives bool
|
HideArchives bool
|
||||||
Search bool
|
Search bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(url, client, secret string, private, skipverify bool) remote.Remote {
|
|
||||||
return &Gitlab{
|
|
||||||
URL: url,
|
|
||||||
Client: client,
|
|
||||||
Secret: secret,
|
|
||||||
PrivateMode: private,
|
|
||||||
SkipVerify: skipverify,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Load(config string) *Gitlab {
|
func Load(config string) *Gitlab {
|
||||||
url_, err := url.Parse(config)
|
url_, err := url.Parse(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -57,17 +79,17 @@ func Load(config string) *Gitlab {
|
||||||
gitlab.URL = url_.String()
|
gitlab.URL = url_.String()
|
||||||
gitlab.Client = params.Get("client_id")
|
gitlab.Client = params.Get("client_id")
|
||||||
gitlab.Secret = params.Get("client_secret")
|
gitlab.Secret = params.Get("client_secret")
|
||||||
gitlab.AllowedOrgs = params["orgs"]
|
// gitlab.AllowedOrgs = params["orgs"]
|
||||||
gitlab.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify"))
|
gitlab.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify"))
|
||||||
gitlab.HideArchives, _ = strconv.ParseBool(params.Get("hide_archives"))
|
gitlab.HideArchives, _ = strconv.ParseBool(params.Get("hide_archives"))
|
||||||
gitlab.Open, _ = strconv.ParseBool(params.Get("open"))
|
// gitlab.Open, _ = strconv.ParseBool(params.Get("open"))
|
||||||
|
|
||||||
switch params.Get("clone_mode") {
|
// switch params.Get("clone_mode") {
|
||||||
case "oauth":
|
// case "oauth":
|
||||||
gitlab.CloneMode = "oauth"
|
// gitlab.CloneMode = "oauth"
|
||||||
default:
|
// default:
|
||||||
gitlab.CloneMode = "token"
|
// gitlab.CloneMode = "token"
|
||||||
}
|
// }
|
||||||
|
|
||||||
// this is a temp workaround
|
// this is a temp workaround
|
||||||
gitlab.Search, _ = strconv.ParseBool(params.Get("search"))
|
gitlab.Search, _ = strconv.ParseBool(params.Get("search"))
|
||||||
|
@ -77,7 +99,7 @@ func Load(config string) *Gitlab {
|
||||||
|
|
||||||
// Login authenticates the session and returns the
|
// Login authenticates the session and returns the
|
||||||
// remote user details.
|
// remote user details.
|
||||||
func (g *Gitlab) Login(res http.ResponseWriter, req *http.Request) (*model.User, bool, error) {
|
func (g *Gitlab) Login(res http.ResponseWriter, req *http.Request) (*model.User, error) {
|
||||||
|
|
||||||
var config = &oauth2.Config{
|
var config = &oauth2.Config{
|
||||||
ClientId: g.Client,
|
ClientId: g.Client,
|
||||||
|
@ -97,41 +119,41 @@ func (g *Gitlab) Login(res http.ResponseWriter, req *http.Request) (*model.User,
|
||||||
var code = req.FormValue("code")
|
var code = req.FormValue("code")
|
||||||
if len(code) == 0 {
|
if len(code) == 0 {
|
||||||
http.Redirect(res, req, config.AuthCodeURL("drone"), http.StatusSeeOther)
|
http.Redirect(res, req, config.AuthCodeURL("drone"), http.StatusSeeOther)
|
||||||
return nil, false, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var trans = &oauth2.Transport{Config: config, Transport: trans_}
|
var trans = &oauth2.Transport{Config: config, Transport: trans_}
|
||||||
var token_, err = trans.Exchange(code)
|
var token_, err = trans.Exchange(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("Error exchanging token. %s", err)
|
return nil, fmt.Errorf("Error exchanging token. %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewClient(g.URL, token_.AccessToken, g.SkipVerify)
|
client := NewClient(g.URL, token_.AccessToken, g.SkipVerify)
|
||||||
login, err := client.CurrentUser()
|
login, err := client.CurrentUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(g.AllowedOrgs) != 0 {
|
// if len(g.AllowedOrgs) != 0 {
|
||||||
groups, err := client.AllGroups()
|
// groups, err := client.AllGroups()
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return nil, false, fmt.Errorf("Could not check org membership. %s", err)
|
// return nil, fmt.Errorf("Could not check org membership. %s", err)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
var member bool
|
// var member bool
|
||||||
for _, group := range groups {
|
// for _, group := range groups {
|
||||||
for _, allowedOrg := range g.AllowedOrgs {
|
// for _, allowedOrg := range g.AllowedOrgs {
|
||||||
if group.Path == allowedOrg {
|
// if group.Path == allowedOrg {
|
||||||
member = true
|
// member = true
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if !member {
|
// if !member {
|
||||||
return nil, false, fmt.Errorf("User does not belong to correct group. Must belong to %v", g.AllowedOrgs)
|
// return nil, false, fmt.Errorf("User does not belong to correct group. Must belong to %v", g.AllowedOrgs)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
user := &model.User{}
|
user := &model.User{}
|
||||||
user.Login = login.Username
|
user.Login = login.Username
|
||||||
|
@ -145,7 +167,7 @@ func (g *Gitlab) Login(res http.ResponseWriter, req *http.Request) (*model.User,
|
||||||
user.Avatar = g.URL + "/" + login.AvatarUrl
|
user.Avatar = g.URL + "/" + login.AvatarUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, g.Open, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gitlab) Auth(token, secret string) (string, error) {
|
func (g *Gitlab) Auth(token, secret string) (string, error) {
|
||||||
|
@ -157,6 +179,21 @@ func (g *Gitlab) Auth(token, secret string) (string, error) {
|
||||||
return login.Username, nil
|
return login.Username, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Gitlab) Teams(u *model.User) ([]*model.Team, error) {
|
||||||
|
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
||||||
|
groups, err := client.AllGroups()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var teams []*model.Team
|
||||||
|
for _, group := range groups {
|
||||||
|
teams = append(teams, &model.Team{
|
||||||
|
Login: group.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return teams, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Repo fetches the named repository from the remote system.
|
// Repo fetches the named repository from the remote system.
|
||||||
func (g *Gitlab) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
func (g *Gitlab) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
||||||
|
@ -295,29 +332,47 @@ func (g *Gitlab) Status(u *model.User, repo *model.Repo, b *model.Build, link st
|
||||||
|
|
||||||
// Netrc returns a .netrc file that can be used to clone
|
// Netrc returns a .netrc file that can be used to clone
|
||||||
// private repositories from a remote system.
|
// private repositories from a remote system.
|
||||||
func (g *Gitlab) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
// func (g *Gitlab) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||||
url_, err := url.Parse(g.URL)
|
// url_, err := url.Parse(g.URL)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
netrc := &model.Netrc{}
|
// netrc := &model.Netrc{}
|
||||||
netrc.Machine = url_.Host
|
// netrc.Machine = url_.Host
|
||||||
|
//
|
||||||
|
// switch g.CloneMode {
|
||||||
|
// case "oauth":
|
||||||
|
// netrc.Login = "oauth2"
|
||||||
|
// netrc.Password = u.Token
|
||||||
|
// case "token":
|
||||||
|
// t := token.New(token.HookToken, r.FullName)
|
||||||
|
// netrc.Login = "drone-ci-token"
|
||||||
|
// netrc.Password, err = t.Sign(r.Hash)
|
||||||
|
// }
|
||||||
|
// return netrc, err
|
||||||
|
// }
|
||||||
|
|
||||||
switch g.CloneMode {
|
// Netrc returns a netrc file capable of authenticating Gitlab requests and
|
||||||
case "oauth":
|
// cloning Gitlab repositories. The netrc will use the global machine account
|
||||||
netrc.Login = "oauth2"
|
// when configured.
|
||||||
netrc.Password = u.Token
|
func (g *Gitlab) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||||
case "token":
|
if g.Password != "" {
|
||||||
t := token.New(token.HookToken, r.FullName)
|
return &model.Netrc{
|
||||||
netrc.Login = "drone-ci-token"
|
Login: g.Username,
|
||||||
netrc.Password, err = t.Sign(r.Hash)
|
Password: g.Password,
|
||||||
|
Machine: g.Machine,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
return netrc, err
|
return &model.Netrc{
|
||||||
|
Login: "oauth2",
|
||||||
|
Password: u.Token,
|
||||||
|
Machine: g.Machine,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate activates a repository by adding a Post-commit hook and
|
// Activate activates a repository by adding a Post-commit hook and
|
||||||
// a Public Deploy key, if applicable.
|
// a Public Deploy key, if applicable.
|
||||||
func (g *Gitlab) Activate(user *model.User, repo *model.Repo, k *model.Key, link string) error {
|
func (g *Gitlab) Activate(user *model.User, repo *model.Repo, link string) error {
|
||||||
var client = NewClient(g.URL, user.Token, g.SkipVerify)
|
var client = NewClient(g.URL, user.Token, g.SkipVerify)
|
||||||
id, err := GetProjectId(g, client, repo.Owner, repo.Name)
|
id, err := GetProjectId(g, client, repo.Owner, repo.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -94,13 +94,13 @@ func Test_Gitlab(t *testing.T) {
|
||||||
// Test activate method
|
// Test activate method
|
||||||
g.Describe("Activate", func() {
|
g.Describe("Activate", func() {
|
||||||
g.It("Should be success", func() {
|
g.It("Should be success", func() {
|
||||||
err := gitlab.Activate(&user, &repo, &model.Key{}, "http://example.com/api/hook/test/test?access_token=token")
|
err := gitlab.Activate(&user, &repo, "http://example.com/api/hook/test/test?access_token=token")
|
||||||
|
|
||||||
g.Assert(err == nil).IsTrue()
|
g.Assert(err == nil).IsTrue()
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should be failed, when token not given", func() {
|
g.It("Should be failed, when token not given", func() {
|
||||||
err := gitlab.Activate(&user, &repo, &model.Key{}, "http://example.com/api/hook/test/test")
|
err := gitlab.Activate(&user, &repo, "http://example.com/api/hook/test/test")
|
||||||
|
|
||||||
g.Assert(err != nil).IsTrue()
|
g.Assert(err != nil).IsTrue()
|
||||||
})
|
})
|
||||||
|
|
109
remote/gogs/fixtures/handler.go
Normal file
109
remote/gogs/fixtures/handler.go
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
package fixtures
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler returns an http.Handler that is capable of handling a variety of mock
|
||||||
|
// Bitbucket requests and returning mock responses.
|
||||||
|
func Handler() http.Handler {
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
e := gin.New()
|
||||||
|
e.GET("/api/v1/repos/:owner/:name", getRepo)
|
||||||
|
e.GET("/api/v1/repos/:owner/:name/raw/:commit/:file", getRepoFile)
|
||||||
|
e.POST("/api/v1/repos/:owner/:name/hooks", createRepoHook)
|
||||||
|
e.GET("/api/v1/user/repos", getUserRepos)
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRepo(c *gin.Context) {
|
||||||
|
switch c.Param("name") {
|
||||||
|
case "repo_not_found":
|
||||||
|
c.String(404, "")
|
||||||
|
default:
|
||||||
|
c.String(200, repoPayload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRepoFile(c *gin.Context) {
|
||||||
|
switch c.Param("file") {
|
||||||
|
case "file_not_found":
|
||||||
|
c.String(404, "")
|
||||||
|
default:
|
||||||
|
c.String(200, repoFilePayload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRepoHook(c *gin.Context) {
|
||||||
|
in := struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Conf struct {
|
||||||
|
Type string `json:"content_type"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"config"`
|
||||||
|
}{}
|
||||||
|
c.BindJSON(&in)
|
||||||
|
if in.Type != "gogs" ||
|
||||||
|
in.Conf.Type != "json" ||
|
||||||
|
in.Conf.URL != "http://localhost" {
|
||||||
|
c.String(500, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.String(200, "{}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserRepos(c *gin.Context) {
|
||||||
|
switch c.Request.Header.Get("Authorization") {
|
||||||
|
case "token repos_not_found":
|
||||||
|
c.String(404, "")
|
||||||
|
default:
|
||||||
|
c.String(200, userRepoPayload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const repoPayload = `
|
||||||
|
{
|
||||||
|
"owner": {
|
||||||
|
"username": "test_name",
|
||||||
|
"email": "octocat@github.com",
|
||||||
|
"avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||||
|
},
|
||||||
|
"full_name": "test_name\/repo_name",
|
||||||
|
"private": true,
|
||||||
|
"html_url": "http:\/\/localhost\/test_name\/repo_name",
|
||||||
|
"clone_url": "http:\/\/localhost\/test_name\/repo_name.git",
|
||||||
|
"permissions": {
|
||||||
|
"admin": true,
|
||||||
|
"push": true,
|
||||||
|
"pull": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const repoFilePayload = `{ platform: linux/amd64 }`
|
||||||
|
|
||||||
|
const userRepoPayload = `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"owner": {
|
||||||
|
"username": "test_name",
|
||||||
|
"email": "octocat@github.com",
|
||||||
|
"avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||||
|
},
|
||||||
|
"full_name": "test_name\/repo_name",
|
||||||
|
"private": true,
|
||||||
|
"html_url": "http:\/\/localhost\/test_name\/repo_name",
|
||||||
|
"clone_url": "http:\/\/localhost\/test_name\/repo_name.git",
|
||||||
|
"permissions": {
|
||||||
|
"admin": true,
|
||||||
|
"push": true,
|
||||||
|
"pull": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`
|
|
@ -1,6 +1,6 @@
|
||||||
package testdata
|
package fixtures
|
||||||
|
|
||||||
var PushHook = `
|
var HookPush = `
|
||||||
{
|
{
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"before": "4b2626259b5a97b6b4eab5e6cca66adb986b672b",
|
"before": "4b2626259b5a97b6b4eab5e6cca66adb986b672b",
|
|
@ -12,172 +12,181 @@ import (
|
||||||
"github.com/gogits/go-gogs-client"
|
"github.com/gogits/go-gogs-client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Remote defines a remote implementation that integrates with Gogs, an open
|
// Opts defines configuration options.
|
||||||
// source Git service written in Go. See https://gogs.io/
|
type Opts struct {
|
||||||
type Remote struct {
|
URL string // Gogs server url.
|
||||||
|
Username string // Optional machine account username.
|
||||||
|
Password string // Optional machine account password.
|
||||||
|
PrivateMode bool // Gogs is running in private mode.
|
||||||
|
SkipVerify bool // Skip ssl verification.
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
URL string
|
URL string
|
||||||
Open bool
|
Machine string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
PrivateMode bool
|
PrivateMode bool
|
||||||
SkipVerify bool
|
SkipVerify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a Remote implementation that integrates with Gogs, an open
|
// New returns a Remote implementation that integrates with Gogs, an open
|
||||||
// source Git service written in Go. See https://gogs.io/
|
// source Git service written in Go. See https://gogs.io/
|
||||||
func New(url string, private, skipverify bool) remote.Remote {
|
func New(opts Opts) (remote.Remote, error) {
|
||||||
return &Remote{
|
url, err := url.Parse(opts.URL)
|
||||||
URL: url,
|
if err != nil {
|
||||||
PrivateMode: private,
|
return nil, err
|
||||||
SkipVerify: skipverify,
|
|
||||||
}
|
}
|
||||||
|
host, _, err := net.SplitHostPort(url.Host)
|
||||||
|
if err == nil {
|
||||||
|
url.Host = host
|
||||||
|
}
|
||||||
|
return &client{
|
||||||
|
URL: opts.URL,
|
||||||
|
Machine: url.Host,
|
||||||
|
Username: opts.Username,
|
||||||
|
Password: opts.Password,
|
||||||
|
PrivateMode: opts.PrivateMode,
|
||||||
|
SkipVerify: opts.SkipVerify,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login authenticates the session and returns the authenticated user.
|
// Login authenticates an account with Gogs using basic authenticaiton. The
|
||||||
func (g *Remote) Login(res http.ResponseWriter, req *http.Request) (*model.User, bool, error) {
|
// Gogs account details are returned when the user is successfully authenticated.
|
||||||
|
func (c *client) Login(res http.ResponseWriter, req *http.Request) (*model.User, error) {
|
||||||
var (
|
var (
|
||||||
username = req.FormValue("username")
|
username = req.FormValue("username")
|
||||||
password = req.FormValue("password")
|
password = req.FormValue("password")
|
||||||
)
|
)
|
||||||
|
|
||||||
// if the username or password doesn't exist we re-direct
|
// if the username or password is empty we re-direct to the login screen.
|
||||||
// the user to the login screen.
|
|
||||||
if len(username) == 0 || len(password) == 0 {
|
if len(username) == 0 || len(password) == 0 {
|
||||||
http.Redirect(res, req, "/login/form", http.StatusSeeOther)
|
http.Redirect(res, req, "/login/form", http.StatusSeeOther)
|
||||||
return nil, false, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewGogsClient(g.URL, "", g.SkipVerify)
|
client := c.newClient()
|
||||||
|
|
||||||
// try to fetch drone token if it exists
|
// try to fetch drone token if it exists
|
||||||
var accessToken string
|
var accessToken string
|
||||||
tokens, err := client.ListAccessTokens(username, password)
|
tokens, err := client.ListAccessTokens(username, password)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return nil, false, err
|
for _, token := range tokens {
|
||||||
}
|
if token.Name == "drone" {
|
||||||
for _, token := range tokens {
|
accessToken = token.Sha1
|
||||||
if token.Name == "drone" {
|
break
|
||||||
accessToken = token.Sha1
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if drone token not found, create it
|
// if drone token not found, create it
|
||||||
if accessToken == "" {
|
if accessToken == "" {
|
||||||
token, err := client.CreateAccessToken(username, password, gogs.CreateAccessTokenOption{Name: "drone"})
|
token, terr := client.CreateAccessToken(
|
||||||
if err != nil {
|
username,
|
||||||
return nil, false, err
|
password,
|
||||||
|
gogs.CreateAccessTokenOption{Name: "drone"},
|
||||||
|
)
|
||||||
|
if terr != nil {
|
||||||
|
return nil, terr
|
||||||
}
|
}
|
||||||
accessToken = token.Sha1
|
accessToken = token.Sha1
|
||||||
}
|
}
|
||||||
|
|
||||||
client = NewGogsClient(g.URL, accessToken, g.SkipVerify)
|
client = c.newClientToken(accessToken)
|
||||||
userInfo, err := client.GetUserInfo(username)
|
account, err := client.GetUserInfo(username)
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
user := model.User{}
|
|
||||||
user.Token = accessToken
|
|
||||||
user.Login = userInfo.UserName
|
|
||||||
user.Email = userInfo.Email
|
|
||||||
user.Avatar = expandAvatar(g.URL, userInfo.AvatarUrl)
|
|
||||||
return &user, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auth authenticates the session and returns the remote user
|
|
||||||
// login for the given token and secret
|
|
||||||
func (g *Remote) Auth(token, secret string) (string, error) {
|
|
||||||
return "", fmt.Errorf("Method not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repo fetches the named repository from the remote system.
|
|
||||||
func (g *Remote) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
|
||||||
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
|
||||||
repos_, err := client.ListMyRepos()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fullName := owner + "/" + name
|
return &model.User{
|
||||||
for _, repo := range repos_ {
|
Token: accessToken,
|
||||||
if repo.FullName == fullName {
|
Login: account.UserName,
|
||||||
return toRepo(repo), nil
|
Email: account.Email,
|
||||||
}
|
Avatar: expandAvatar(c.URL, account.AvatarUrl),
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
return nil, fmt.Errorf("Not Found")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repos fetches a list of repos from the remote system.
|
// Auth is not supported by the Gogs driver.
|
||||||
func (g *Remote) Repos(u *model.User) ([]*model.RepoLite, error) {
|
func (c *client) Auth(token, secret string) (string, error) {
|
||||||
|
return "", fmt.Errorf("Not Implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teams is not supported by the Gogs driver.
|
||||||
|
func (c *client) Teams(u *model.User) ([]*model.Team, error) {
|
||||||
|
var empty []*model.Team
|
||||||
|
return empty, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repo returns the named Gogs repository.
|
||||||
|
func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||||
|
client := c.newClientToken(u.Token)
|
||||||
|
repo, err := client.GetRepo(owner, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toRepo(repo), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repos returns a list of all repositories for the Gogs account, including
|
||||||
|
// organization repositories.
|
||||||
|
func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||||
repos := []*model.RepoLite{}
|
repos := []*model.RepoLite{}
|
||||||
|
|
||||||
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
client := c.newClientToken(u.Token)
|
||||||
repos_, err := client.ListMyRepos()
|
all, err := client.ListMyRepos()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repos, err
|
return repos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, repo := range repos_ {
|
for _, repo := range all {
|
||||||
repos = append(repos, toRepoLite(repo))
|
repos = append(repos, toRepoLite(repo))
|
||||||
}
|
}
|
||||||
|
|
||||||
return repos, err
|
return repos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perm fetches the named repository permissions from
|
// Perm returns the user permissions for the named Gogs repository.
|
||||||
// the remote system for the specified user.
|
func (c *client) Perm(u *model.User, owner, name string) (*model.Perm, error) {
|
||||||
func (g *Remote) Perm(u *model.User, owner, name string) (*model.Perm, error) {
|
client := c.newClientToken(u.Token)
|
||||||
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
repo, err := client.GetRepo(owner, name)
|
||||||
repos_, err := client.ListMyRepos()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return toPerm(repo.Permissions), nil
|
||||||
fullName := owner + "/" + name
|
|
||||||
for _, repo := range repos_ {
|
|
||||||
if repo.FullName == fullName {
|
|
||||||
return toPerm(repo.Permissions), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("Not Found")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// File fetches a file from the remote repository and returns in string format.
|
// File fetches the file from the Gogs repository and returns its contents.
|
||||||
func (g *Remote) File(u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
func (c *client) File(u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
||||||
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
client := c.newClientToken(u.Token)
|
||||||
cfg, err := client.GetFile(r.Owner, r.Name, b.Commit, f)
|
cfg, err := client.GetFile(r.Owner, r.Name, b.Commit, f)
|
||||||
return cfg, err
|
return cfg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status sends the commit status to the remote system.
|
// Status is not supported by the Gogs driver.
|
||||||
// An example would be the GitHub pull request status.
|
func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string) error {
|
||||||
func (g *Remote) Status(u *model.User, r *model.Repo, b *model.Build, link string) error {
|
return nil
|
||||||
return fmt.Errorf("Not Implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Netrc returns a .netrc file that can be used to clone
|
// Netrc returns a netrc file capable of authenticating Gogs requests and
|
||||||
// private repositories from a remote system.
|
// cloning Gogs repositories. The netrc will use the global machine account
|
||||||
func (g *Remote) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
// when configured.
|
||||||
url_, err := url.Parse(g.URL)
|
func (c *client) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||||
if err != nil {
|
if c.Password != "" {
|
||||||
return nil, err
|
return &model.Netrc{
|
||||||
}
|
Login: c.Username,
|
||||||
host, _, err := net.SplitHostPort(url_.Host)
|
Password: c.Password,
|
||||||
if err == nil {
|
Machine: c.Machine,
|
||||||
url_.Host = host
|
}, nil
|
||||||
}
|
}
|
||||||
return &model.Netrc{
|
return &model.Netrc{
|
||||||
Login: u.Token,
|
Login: u.Token,
|
||||||
Password: "x-oauth-basic",
|
Password: "x-oauth-basic",
|
||||||
Machine: url_.Host,
|
Machine: c.Machine,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate activates a repository by creating the post-commit hook and
|
// Activate activates the repository by registering post-commit hooks with
|
||||||
// adding the SSH deploy key, if applicable.
|
// the Gogs repository.
|
||||||
func (g *Remote) Activate(u *model.User, r *model.Repo, k *model.Key, link string) error {
|
func (c *client) Activate(u *model.User, r *model.Repo, link string) error {
|
||||||
config := map[string]string{
|
config := map[string]string{
|
||||||
"url": link,
|
"url": link,
|
||||||
"secret": r.Hash,
|
"secret": r.Hash,
|
||||||
|
@ -189,20 +198,19 @@ func (g *Remote) Activate(u *model.User, r *model.Repo, k *model.Key, link strin
|
||||||
Active: true,
|
Active: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
client := c.newClientToken(u.Token)
|
||||||
_, err := client.CreateRepoHook(r.Owner, r.Name, hook)
|
_, err := client.CreateRepoHook(r.Owner, r.Name, hook)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deactivate removes a repository by removing all the post-commit hooks
|
// Deactivate is not supported by the Gogs driver.
|
||||||
// which are equal to link and removing the SSH deploy key.
|
func (c *client) Deactivate(u *model.User, r *model.Repo, link string) error {
|
||||||
func (g *Remote) Deactivate(u *model.User, r *model.Repo, link string) error {
|
return nil
|
||||||
return fmt.Errorf("Not Implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hook parses the post-commit hook from the Request body
|
// Hook parses the incoming Gogs hook and returns the Repository and Build
|
||||||
// and returns the required data in a standard format.
|
// details. If the hook is unsupported nil values are returned.
|
||||||
func (g *Remote) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
func (c *client) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
repo *model.Repo
|
repo *model.Repo
|
||||||
|
@ -211,7 +219,7 @@ func (g *Remote) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
||||||
|
|
||||||
switch r.Header.Get("X-Gogs-Event") {
|
switch r.Header.Get("X-Gogs-Event") {
|
||||||
case "push":
|
case "push":
|
||||||
var push *PushHook
|
var push *pushHook
|
||||||
push, err = parsePush(r.Body)
|
push, err = parsePush(r.Body)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
repo = repoFromPush(push)
|
repo = repoFromPush(push)
|
||||||
|
@ -221,20 +229,20 @@ func (g *Remote) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
||||||
return repo, build, err
|
return repo, build, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient initializes and returns a API client.
|
// helper function to return the Gogs client
|
||||||
func NewGogsClient(url, token string, skipVerify bool) *gogs.Client {
|
func (c *client) newClient() *gogs.Client {
|
||||||
sslClient := &http.Client{}
|
return c.newClientToken("")
|
||||||
c := gogs.NewClient(url, token)
|
}
|
||||||
|
|
||||||
if skipVerify {
|
// helper function to return the Gogs client
|
||||||
sslClient.Transport = &http.Transport{
|
func (c *client) newClientToken(token string) *gogs.Client {
|
||||||
|
client := gogs.NewClient(c.URL, token)
|
||||||
|
if c.SkipVerify {
|
||||||
|
httpClient := &http.Client{}
|
||||||
|
httpClient.Transport = &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
}
|
}
|
||||||
c.SetHTTPClient(sslClient)
|
client.SetHTTPClient(httpClient)
|
||||||
}
|
}
|
||||||
return c
|
return client
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Remote) String() string {
|
|
||||||
return "gogs"
|
|
||||||
}
|
}
|
||||||
|
|
183
remote/gogs/gogs_test.go
Normal file
183
remote/gogs/gogs_test.go
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
package gogs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/drone/drone/model"
|
||||||
|
"github.com/drone/drone/remote/gogs/fixtures"
|
||||||
|
|
||||||
|
"github.com/franela/goblin"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_gogs(t *testing.T) {
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
s := httptest.NewServer(fixtures.Handler())
|
||||||
|
c, _ := New(Opts{
|
||||||
|
URL: s.URL,
|
||||||
|
SkipVerify: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
g := goblin.Goblin(t)
|
||||||
|
g.Describe("Gogs", func() {
|
||||||
|
|
||||||
|
g.After(func() {
|
||||||
|
s.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Describe("Creating a remote", func() {
|
||||||
|
g.It("Should return client with specified options", func() {
|
||||||
|
remote, _ := New(Opts{
|
||||||
|
URL: "http://localhost:8080",
|
||||||
|
Username: "someuser",
|
||||||
|
Password: "password",
|
||||||
|
SkipVerify: true,
|
||||||
|
PrivateMode: true,
|
||||||
|
})
|
||||||
|
g.Assert(remote.(*client).URL).Equal("http://localhost:8080")
|
||||||
|
g.Assert(remote.(*client).Machine).Equal("localhost")
|
||||||
|
g.Assert(remote.(*client).Username).Equal("someuser")
|
||||||
|
g.Assert(remote.(*client).Password).Equal("password")
|
||||||
|
g.Assert(remote.(*client).SkipVerify).Equal(true)
|
||||||
|
g.Assert(remote.(*client).PrivateMode).Equal(true)
|
||||||
|
})
|
||||||
|
g.It("Should handle malformed url", func() {
|
||||||
|
_, err := New(Opts{URL: "%gh&%ij"})
|
||||||
|
g.Assert(err != nil).IsTrue()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Describe("Generating a netrc file", func() {
|
||||||
|
g.It("Should return a netrc with the user token", func() {
|
||||||
|
remote, _ := New(Opts{
|
||||||
|
URL: "http://gogs.com",
|
||||||
|
})
|
||||||
|
netrc, _ := remote.Netrc(fakeUser, nil)
|
||||||
|
g.Assert(netrc.Machine).Equal("gogs.com")
|
||||||
|
g.Assert(netrc.Login).Equal(fakeUser.Token)
|
||||||
|
g.Assert(netrc.Password).Equal("x-oauth-basic")
|
||||||
|
})
|
||||||
|
g.It("Should return a netrc with the machine account", func() {
|
||||||
|
remote, _ := New(Opts{
|
||||||
|
URL: "http://gogs.com",
|
||||||
|
Username: "someuser",
|
||||||
|
Password: "password",
|
||||||
|
})
|
||||||
|
netrc, _ := remote.Netrc(nil, nil)
|
||||||
|
g.Assert(netrc.Machine).Equal("gogs.com")
|
||||||
|
g.Assert(netrc.Login).Equal("someuser")
|
||||||
|
g.Assert(netrc.Password).Equal("password")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Describe("Requesting a repository", func() {
|
||||||
|
g.It("Should return the repository details", func() {
|
||||||
|
repo, err := c.Repo(fakeUser, fakeRepo.Owner, fakeRepo.Name)
|
||||||
|
g.Assert(err == nil).IsTrue()
|
||||||
|
g.Assert(repo.Owner).Equal(fakeRepo.Owner)
|
||||||
|
g.Assert(repo.Name).Equal(fakeRepo.Name)
|
||||||
|
g.Assert(repo.FullName).Equal(fakeRepo.Owner + "/" + fakeRepo.Name)
|
||||||
|
g.Assert(repo.IsPrivate).IsTrue()
|
||||||
|
g.Assert(repo.Clone).Equal("http://localhost/test_name/repo_name.git")
|
||||||
|
g.Assert(repo.Link).Equal("http://localhost/test_name/repo_name")
|
||||||
|
})
|
||||||
|
g.It("Should handle a not found error", func() {
|
||||||
|
_, err := c.Repo(fakeUser, fakeRepoNotFound.Owner, fakeRepoNotFound.Name)
|
||||||
|
g.Assert(err != nil).IsTrue()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Describe("Requesting repository permissions", func() {
|
||||||
|
g.It("Should return the permission details", func() {
|
||||||
|
perm, err := c.Perm(fakeUser, fakeRepo.Owner, fakeRepo.Name)
|
||||||
|
g.Assert(err == nil).IsTrue()
|
||||||
|
g.Assert(perm.Admin).IsTrue()
|
||||||
|
g.Assert(perm.Push).IsTrue()
|
||||||
|
g.Assert(perm.Pull).IsTrue()
|
||||||
|
})
|
||||||
|
g.It("Should handle a not found error", func() {
|
||||||
|
_, err := c.Perm(fakeUser, fakeRepoNotFound.Owner, fakeRepoNotFound.Name)
|
||||||
|
g.Assert(err != nil).IsTrue()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Describe("Requesting a repository list", func() {
|
||||||
|
g.It("Should return the repository list", func() {
|
||||||
|
repos, err := c.Repos(fakeUser)
|
||||||
|
g.Assert(err == nil).IsTrue()
|
||||||
|
g.Assert(repos[0].Owner).Equal(fakeRepo.Owner)
|
||||||
|
g.Assert(repos[0].Name).Equal(fakeRepo.Name)
|
||||||
|
g.Assert(repos[0].FullName).Equal(fakeRepo.Owner + "/" + fakeRepo.Name)
|
||||||
|
})
|
||||||
|
g.It("Should handle a not found error", func() {
|
||||||
|
_, err := c.Repos(fakeUserNoRepos)
|
||||||
|
g.Assert(err != nil).IsTrue()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should register repositroy hooks", func() {
|
||||||
|
err := c.Activate(fakeUser, fakeRepo, "http://localhost")
|
||||||
|
g.Assert(err == nil).IsTrue()
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should return a repository file", func() {
|
||||||
|
raw, err := c.File(fakeUser, fakeRepo, fakeBuild, ".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")
|
||||||
|
g.It("Should handle an access token error")
|
||||||
|
g.It("Should return the authenticated user")
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Describe("Given a repository hook", func() {
|
||||||
|
g.It("Should skip non-push events")
|
||||||
|
g.It("Should return push details")
|
||||||
|
g.It("Should handle a parsing error")
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should return no-op for usupporeted features", func() {
|
||||||
|
_, err1 := c.Auth("octocat", "4vyW6b49Z")
|
||||||
|
_, err2 := c.Teams(nil)
|
||||||
|
err3 := c.Status(nil, nil, nil, "")
|
||||||
|
err4 := c.Deactivate(nil, nil, "")
|
||||||
|
g.Assert(err1 != nil).IsTrue()
|
||||||
|
g.Assert(err2 == nil).IsTrue()
|
||||||
|
g.Assert(err3 == nil).IsTrue()
|
||||||
|
g.Assert(err4 == nil).IsTrue()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
fakeUser = &model.User{
|
||||||
|
Login: "someuser",
|
||||||
|
Token: "cfcd2084",
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeUserNoRepos = &model.User{
|
||||||
|
Login: "someuser",
|
||||||
|
Token: "repos_not_found",
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeRepo = &model.Repo{
|
||||||
|
Owner: "test_name",
|
||||||
|
Name: "repo_name",
|
||||||
|
FullName: "test_name/repo_name",
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeRepoNotFound = &model.Repo{
|
||||||
|
Owner: "test_name",
|
||||||
|
Name: "repo_not_found",
|
||||||
|
FullName: "test_name/repo_not_found",
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeBuild = &model.Build{
|
||||||
|
Commit: "9ecad50",
|
||||||
|
}
|
||||||
|
)
|
|
@ -12,8 +12,7 @@ import (
|
||||||
"github.com/gogits/go-gogs-client"
|
"github.com/gogits/go-gogs-client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// helper function that converts a Gogs repository
|
// helper function that converts a Gogs repository to a Drone repository.
|
||||||
// to a Drone repository.
|
|
||||||
func toRepoLite(from *gogs.Repository) *model.RepoLite {
|
func toRepoLite(from *gogs.Repository) *model.RepoLite {
|
||||||
name := strings.Split(from.FullName, "/")[1]
|
name := strings.Split(from.FullName, "/")[1]
|
||||||
avatar := expandAvatar(
|
avatar := expandAvatar(
|
||||||
|
@ -28,8 +27,7 @@ func toRepoLite(from *gogs.Repository) *model.RepoLite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function that converts a Gogs repository
|
// helper function that converts a Gogs repository to a Drone repository.
|
||||||
// to a Drone repository.
|
|
||||||
func toRepo(from *gogs.Repository) *model.Repo {
|
func toRepo(from *gogs.Repository) *model.Repo {
|
||||||
name := strings.Split(from.FullName, "/")[1]
|
name := strings.Split(from.FullName, "/")[1]
|
||||||
avatar := expandAvatar(
|
avatar := expandAvatar(
|
||||||
|
@ -49,8 +47,7 @@ func toRepo(from *gogs.Repository) *model.Repo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function that converts a Gogs permission
|
// helper function that converts a Gogs permission to a Drone permission.
|
||||||
// to a Drone permission.
|
|
||||||
func toPerm(from gogs.Permission) *model.Perm {
|
func toPerm(from gogs.Permission) *model.Perm {
|
||||||
return &model.Perm{
|
return &model.Perm{
|
||||||
Pull: from.Pull,
|
Pull: from.Pull,
|
||||||
|
@ -59,11 +56,10 @@ func toPerm(from gogs.Permission) *model.Perm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function that extracts the Build data
|
// helper function that extracts the Build data from a Gogs push hook
|
||||||
// from a Gogs push hook
|
func buildFromPush(hook *pushHook) *model.Build {
|
||||||
func buildFromPush(hook *PushHook) *model.Build {
|
|
||||||
avatar := expandAvatar(
|
avatar := expandAvatar(
|
||||||
hook.Repo.Url,
|
hook.Repo.URL,
|
||||||
fixMalformedAvatar(hook.Sender.Avatar),
|
fixMalformedAvatar(hook.Sender.Avatar),
|
||||||
)
|
)
|
||||||
return &model.Build{
|
return &model.Build{
|
||||||
|
@ -79,9 +75,8 @@ func buildFromPush(hook *PushHook) *model.Build {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function that extracts the Repository data
|
// helper function that extracts the Repository data from a Gogs push hook
|
||||||
// from a Gogs push hook
|
func repoFromPush(hook *pushHook) *model.Repo {
|
||||||
func repoFromPush(hook *PushHook) *model.Repo {
|
|
||||||
fullName := fmt.Sprintf(
|
fullName := fmt.Sprintf(
|
||||||
"%s/%s",
|
"%s/%s",
|
||||||
hook.Repo.Owner.Username,
|
hook.Repo.Owner.Username,
|
||||||
|
@ -91,20 +86,19 @@ func repoFromPush(hook *PushHook) *model.Repo {
|
||||||
Name: hook.Repo.Name,
|
Name: hook.Repo.Name,
|
||||||
Owner: hook.Repo.Owner.Username,
|
Owner: hook.Repo.Owner.Username,
|
||||||
FullName: fullName,
|
FullName: fullName,
|
||||||
Link: hook.Repo.Url,
|
Link: hook.Repo.URL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function that parses a push hook from
|
// helper function that parses a push hook from a read closer.
|
||||||
// a read closer.
|
func parsePush(r io.Reader) (*pushHook, error) {
|
||||||
func parsePush(r io.Reader) (*PushHook, error) {
|
push := new(pushHook)
|
||||||
push := new(PushHook)
|
|
||||||
err := json.NewDecoder(r).Decode(push)
|
err := json.NewDecoder(r).Decode(push)
|
||||||
return push, err
|
return push, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// fixMalformedAvatar is a helper function that fixes
|
// fixMalformedAvatar is a helper function that fixes an avatar url if malformed
|
||||||
// an avatar url if malformed (known bug with gogs)
|
// (currently a known bug with gogs)
|
||||||
func fixMalformedAvatar(url string) string {
|
func fixMalformedAvatar(url string) string {
|
||||||
index := strings.Index(url, "///")
|
index := strings.Index(url, "///")
|
||||||
if index != -1 {
|
if index != -1 {
|
||||||
|
@ -117,16 +111,16 @@ func fixMalformedAvatar(url string) string {
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
// expandAvatar is a helper function that converts
|
// expandAvatar is a helper function that converts a relative avatar URL to the
|
||||||
// a relative avatar URL to the abosolute url.
|
// abosolute url.
|
||||||
func expandAvatar(repo, rawurl string) string {
|
func expandAvatar(repo, rawurl string) string {
|
||||||
if !strings.HasPrefix(rawurl, "/avatars/") {
|
if !strings.HasPrefix(rawurl, "/avatars/") {
|
||||||
return rawurl
|
return rawurl
|
||||||
}
|
}
|
||||||
url_, err := url.Parse(repo)
|
url, err := url.Parse(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rawurl
|
return rawurl
|
||||||
}
|
}
|
||||||
url_.Path = rawurl
|
url.Path = rawurl
|
||||||
return url_.String()
|
return url.String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
||||||
"github.com/drone/drone/remote/gogs/testdata"
|
"github.com/drone/drone/remote/gogs/fixtures"
|
||||||
|
|
||||||
"github.com/franela/goblin"
|
"github.com/franela/goblin"
|
||||||
"github.com/gogits/go-gogs-client"
|
"github.com/gogits/go-gogs-client"
|
||||||
|
@ -17,7 +17,7 @@ func Test_parse(t *testing.T) {
|
||||||
g.Describe("Gogs", func() {
|
g.Describe("Gogs", func() {
|
||||||
|
|
||||||
g.It("Should parse push hook payload", func() {
|
g.It("Should parse push hook payload", func() {
|
||||||
buf := bytes.NewBufferString(testdata.PushHook)
|
buf := bytes.NewBufferString(fixtures.HookPush)
|
||||||
hook, err := parsePush(buf)
|
hook, err := parsePush(buf)
|
||||||
g.Assert(err == nil).IsTrue()
|
g.Assert(err == nil).IsTrue()
|
||||||
g.Assert(hook.Ref).Equal("refs/heads/master")
|
g.Assert(hook.Ref).Equal("refs/heads/master")
|
||||||
|
@ -25,7 +25,7 @@ func Test_parse(t *testing.T) {
|
||||||
g.Assert(hook.Before).Equal("4b2626259b5a97b6b4eab5e6cca66adb986b672b")
|
g.Assert(hook.Before).Equal("4b2626259b5a97b6b4eab5e6cca66adb986b672b")
|
||||||
g.Assert(hook.Compare).Equal("http://gogs.golang.org/gordon/hello-world/compare/4b2626259b5a97b6b4eab5e6cca66adb986b672b...ef98532add3b2feb7a137426bba1248724367df5")
|
g.Assert(hook.Compare).Equal("http://gogs.golang.org/gordon/hello-world/compare/4b2626259b5a97b6b4eab5e6cca66adb986b672b...ef98532add3b2feb7a137426bba1248724367df5")
|
||||||
g.Assert(hook.Repo.Name).Equal("hello-world")
|
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.URL).Equal("http://gogs.golang.org/gordon/hello-world")
|
||||||
g.Assert(hook.Repo.Owner.Name).Equal("gordon")
|
g.Assert(hook.Repo.Owner.Name).Equal("gordon")
|
||||||
g.Assert(hook.Repo.Owner.Email).Equal("gordon@golang.org")
|
g.Assert(hook.Repo.Owner.Email).Equal("gordon@golang.org")
|
||||||
g.Assert(hook.Repo.Owner.Username).Equal("gordon")
|
g.Assert(hook.Repo.Owner.Username).Equal("gordon")
|
||||||
|
@ -38,7 +38,7 @@ func Test_parse(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should return a Build struct from a push hook", func() {
|
g.It("Should return a Build struct from a push hook", func() {
|
||||||
buf := bytes.NewBufferString(testdata.PushHook)
|
buf := bytes.NewBufferString(fixtures.HookPush)
|
||||||
hook, _ := parsePush(buf)
|
hook, _ := parsePush(buf)
|
||||||
build := buildFromPush(hook)
|
build := buildFromPush(hook)
|
||||||
g.Assert(build.Event).Equal(model.EventPush)
|
g.Assert(build.Event).Equal(model.EventPush)
|
||||||
|
@ -53,13 +53,13 @@ func Test_parse(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should return a Repo struct from a push hook", func() {
|
g.It("Should return a Repo struct from a push hook", func() {
|
||||||
buf := bytes.NewBufferString(testdata.PushHook)
|
buf := bytes.NewBufferString(fixtures.HookPush)
|
||||||
hook, _ := parsePush(buf)
|
hook, _ := parsePush(buf)
|
||||||
repo := repoFromPush(hook)
|
repo := repoFromPush(hook)
|
||||||
g.Assert(repo.Name).Equal(hook.Repo.Name)
|
g.Assert(repo.Name).Equal(hook.Repo.Name)
|
||||||
g.Assert(repo.Owner).Equal(hook.Repo.Owner.Username)
|
g.Assert(repo.Owner).Equal(hook.Repo.Owner.Username)
|
||||||
g.Assert(repo.FullName).Equal("gordon/hello-world")
|
g.Assert(repo.FullName).Equal("gordon/hello-world")
|
||||||
g.Assert(repo.Link).Equal(hook.Repo.Url)
|
g.Assert(repo.Link).Equal(hook.Repo.URL)
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should return a Perm struct from a Gogs Perm", func() {
|
g.It("Should return a Perm struct from a Gogs Perm", func() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package gogs
|
package gogs
|
||||||
|
|
||||||
type PushHook struct {
|
type pushHook struct {
|
||||||
Ref string `json:"ref"`
|
Ref string `json:"ref"`
|
||||||
Before string `json:"before"`
|
Before string `json:"before"`
|
||||||
After string `json:"after"`
|
After string `json:"after"`
|
||||||
|
@ -15,7 +15,7 @@ type PushHook struct {
|
||||||
Repo struct {
|
Repo struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Url string `json:"url"`
|
URL string `json:"url"`
|
||||||
Private bool `json:"private"`
|
Private bool `json:"private"`
|
||||||
Owner struct {
|
Owner struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -27,7 +27,7 @@ type PushHook struct {
|
||||||
Commits []struct {
|
Commits []struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Url string `json:"url"`
|
URL string `json:"url"`
|
||||||
} `json:"commits"`
|
} `json:"commits"`
|
||||||
|
|
||||||
Sender struct {
|
Sender struct {
|
||||||
|
|
|
@ -134,8 +134,6 @@ func (s *Server) Handler() http.Handler {
|
||||||
repo.Use(session.MustPull)
|
repo.Use(session.MustPull)
|
||||||
|
|
||||||
repo.GET("", api.GetRepo)
|
repo.GET("", api.GetRepo)
|
||||||
repo.GET("/key", api.GetRepoKey)
|
|
||||||
repo.POST("/key", api.PostRepoKey)
|
|
||||||
repo.GET("/builds", api.GetBuilds)
|
repo.GET("/builds", api.GetBuilds)
|
||||||
repo.GET("/builds/:number", api.GetBuild)
|
repo.GET("/builds/:number", api.GetBuild)
|
||||||
repo.GET("/logs/:number/:job", api.GetBuildLogs)
|
repo.GET("/logs/:number/:job", api.GetBuildLogs)
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
package datastore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone/model"
|
|
||||||
"github.com/russross/meddler"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (db *datastore) GetKey(repo *model.Repo) (*model.Key, error) {
|
|
||||||
var key = new(model.Key)
|
|
||||||
var err = meddler.QueryRow(db, key, rebind(keyQuery), repo.ID)
|
|
||||||
return key, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *datastore) CreateKey(key *model.Key) error {
|
|
||||||
return meddler.Save(db, keyTable, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *datastore) UpdateKey(key *model.Key) error {
|
|
||||||
return meddler.Save(db, keyTable, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *datastore) DeleteKey(key *model.Key) error {
|
|
||||||
var _, err = db.Exec(rebind(keyDeleteStmt), key.ID)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyTable = "keys"
|
|
||||||
|
|
||||||
const keyQuery = "SELECT * FROM `keys` WHERE key_repo_id=? LIMIT 1"
|
|
||||||
|
|
||||||
const keyDeleteStmt = "DELETE FROM `keys` WHERE key_id=?"
|
|
|
@ -1,114 +0,0 @@
|
||||||
package datastore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
|
||||||
"github.com/franela/goblin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestKeys(t *testing.T) {
|
|
||||||
db := openTest()
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
s := From(db)
|
|
||||||
g := goblin.Goblin(t)
|
|
||||||
g.Describe("Keys", func() {
|
|
||||||
|
|
||||||
// before each test be sure to purge the package
|
|
||||||
// table data from the database.
|
|
||||||
g.BeforeEach(func() {
|
|
||||||
db.Exec(rebind("DELETE FROM `keys`"))
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should create a key", func() {
|
|
||||||
key := model.Key{
|
|
||||||
RepoID: 1,
|
|
||||||
Public: fakePublicKey,
|
|
||||||
Private: fakePrivateKey,
|
|
||||||
}
|
|
||||||
err := s.CreateKey(&key)
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(key.ID != 0).IsTrue()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should update a key", func() {
|
|
||||||
key := model.Key{
|
|
||||||
RepoID: 1,
|
|
||||||
Public: fakePublicKey,
|
|
||||||
Private: fakePrivateKey,
|
|
||||||
}
|
|
||||||
err := s.CreateKey(&key)
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(key.ID != 0).IsTrue()
|
|
||||||
|
|
||||||
key.Private = ""
|
|
||||||
key.Public = ""
|
|
||||||
|
|
||||||
err1 := s.UpdateKey(&key)
|
|
||||||
getkey, err2 := s.GetKey(&model.Repo{ID: 1})
|
|
||||||
g.Assert(err1 == nil).IsTrue()
|
|
||||||
g.Assert(err2 == nil).IsTrue()
|
|
||||||
g.Assert(key.ID).Equal(getkey.ID)
|
|
||||||
g.Assert(key.Public).Equal(getkey.Public)
|
|
||||||
g.Assert(key.Private).Equal(getkey.Private)
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should get a key", func() {
|
|
||||||
key := model.Key{
|
|
||||||
RepoID: 1,
|
|
||||||
Public: fakePublicKey,
|
|
||||||
Private: fakePrivateKey,
|
|
||||||
}
|
|
||||||
err := s.CreateKey(&key)
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(key.ID != 0).IsTrue()
|
|
||||||
|
|
||||||
getkey, err := s.GetKey(&model.Repo{ID: 1})
|
|
||||||
g.Assert(err == nil).IsTrue()
|
|
||||||
g.Assert(key.ID).Equal(getkey.ID)
|
|
||||||
g.Assert(key.Public).Equal(getkey.Public)
|
|
||||||
g.Assert(key.Private).Equal(getkey.Private)
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should delete a key", func() {
|
|
||||||
key := model.Key{
|
|
||||||
RepoID: 1,
|
|
||||||
Public: fakePublicKey,
|
|
||||||
Private: fakePrivateKey,
|
|
||||||
}
|
|
||||||
err1 := s.CreateKey(&key)
|
|
||||||
err2 := s.DeleteKey(&key)
|
|
||||||
g.Assert(err1 == nil).IsTrue()
|
|
||||||
g.Assert(err2 == nil).IsTrue()
|
|
||||||
|
|
||||||
_, err := s.GetKey(&model.Repo{ID: 1})
|
|
||||||
g.Assert(err == nil).IsFalse()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var fakePublicKey = `
|
|
||||||
-----BEGIN PUBLIC KEY-----
|
|
||||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0
|
|
||||||
FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/
|
|
||||||
3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB
|
|
||||||
-----END PUBLIC KEY-----
|
|
||||||
`
|
|
||||||
|
|
||||||
var fakePrivateKey = `
|
|
||||||
|
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
|
||||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
|
||||||
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
|
|
||||||
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
|
|
||||||
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
|
|
||||||
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
|
|
||||||
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
|
|
||||||
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
|
|
||||||
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
|
||||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
|
||||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
`
|
|
|
@ -54,18 +54,6 @@ type Store interface {
|
||||||
// DeleteRepo deletes a user repository.
|
// DeleteRepo deletes a user repository.
|
||||||
DeleteRepo(*model.Repo) error
|
DeleteRepo(*model.Repo) error
|
||||||
|
|
||||||
// GetKey gets a key by unique repository ID.
|
|
||||||
GetKey(*model.Repo) (*model.Key, error)
|
|
||||||
|
|
||||||
// CreateKey creates a new key.
|
|
||||||
CreateKey(*model.Key) error
|
|
||||||
|
|
||||||
// UpdateKey updates a user key.
|
|
||||||
UpdateKey(*model.Key) error
|
|
||||||
|
|
||||||
// DeleteKey deletes a user key.
|
|
||||||
DeleteKey(*model.Key) error
|
|
||||||
|
|
||||||
// GetSecretList gets a list of repository secrets
|
// GetSecretList gets a list of repository secrets
|
||||||
GetSecretList(*model.Repo) ([]*model.Secret, error)
|
GetSecretList(*model.Repo) ([]*model.Secret, error)
|
||||||
|
|
||||||
|
@ -192,22 +180,6 @@ func DeleteRepo(c context.Context, repo *model.Repo) error {
|
||||||
return FromContext(c).DeleteRepo(repo)
|
return FromContext(c).DeleteRepo(repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetKey(c context.Context, repo *model.Repo) (*model.Key, error) {
|
|
||||||
return FromContext(c).GetKey(repo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateKey(c context.Context, key *model.Key) error {
|
|
||||||
return FromContext(c).CreateKey(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateKey(c context.Context, key *model.Key) error {
|
|
||||||
return FromContext(c).UpdateKey(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteKey(c context.Context, key *model.Key) error {
|
|
||||||
return FromContext(c).DeleteKey(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSecretList(c context.Context, r *model.Repo) ([]*model.Secret, error) {
|
func GetSecretList(c context.Context, r *model.Repo) ([]*model.Secret, error) {
|
||||||
return FromContext(c).GetSecretList(r)
|
return FromContext(c).GetSecretList(r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,10 +65,6 @@ block content
|
||||||
else
|
else
|
||||||
input#trusted[type="checkbox"][hidden="hidden"]
|
input#trusted[type="checkbox"][hidden="hidden"]
|
||||||
label.switch[for="trusted"]
|
label.switch[for="trusted"]
|
||||||
div.row
|
|
||||||
div.col-md-3 Public Key
|
|
||||||
div.col-md-9
|
|
||||||
pre #{Key.Public} #{Repo.Owner}-#{Repo.Name}@drone
|
|
||||||
div.row
|
div.row
|
||||||
div.col-md-12
|
div.col-md-12
|
||||||
div.alert.alert-danger
|
div.alert.alert-danger
|
||||||
|
@ -78,4 +74,4 @@ block content
|
||||||
|
|
||||||
block append scripts
|
block append scripts
|
||||||
script
|
script
|
||||||
var view = new RepoConfigViewModel(#{Repo.FullName});
|
var view = new RepoConfigViewModel(#{Repo.FullName});
|
||||||
|
|
18
web/login.go
18
web/login.go
|
@ -23,7 +23,7 @@ func GetLogin(c *gin.Context) {
|
||||||
// remember why, so need to revisit this line.
|
// remember why, so need to revisit this line.
|
||||||
c.Writer.Header().Del("Content-Type")
|
c.Writer.Header().Del("Content-Type")
|
||||||
|
|
||||||
tmpuser, open, err := remote.Login(c.Writer, c.Request)
|
tmpuser, err := remote.Login(c.Writer, c.Request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("cannot authenticate user. %s", err)
|
log.Errorf("cannot authenticate user. %s", err)
|
||||||
c.Redirect(303, "/login?error=oauth_error")
|
c.Redirect(303, "/login?error=oauth_error")
|
||||||
|
@ -35,20 +35,16 @@ func GetLogin(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var open = false // TODO get this from context
|
||||||
|
|
||||||
// get the user from the database
|
// get the user from the database
|
||||||
u, err := store.GetUserLogin(c, tmpuser.Login)
|
u, err := store.GetUserLogin(c, tmpuser.Login)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
count, err := store.GetUserCount(c)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("cannot register %s. %s", tmpuser.Login, err)
|
|
||||||
c.Redirect(303, "/login?error=internal_error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 !open && count != 0 {
|
if !open {
|
||||||
log.Errorf("cannot register %s. registration closed", tmpuser.Login)
|
log.Errorf("cannot register %s. registration closed", tmpuser.Login)
|
||||||
c.Redirect(303, "/login?error=access_denied")
|
c.Redirect(303, "/login?error=access_denied")
|
||||||
return
|
return
|
||||||
|
@ -69,12 +65,6 @@ func GetLogin(c *gin.Context) {
|
||||||
c.Redirect(303, "/login?error=internal_error")
|
c.Redirect(303, "/login?error=internal_error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is the first user, they
|
|
||||||
// should be an admin.
|
|
||||||
if count == 0 {
|
|
||||||
u.Admin = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the user meta data and authorization
|
// update the user meta data and authorization
|
||||||
|
|
|
@ -116,7 +116,6 @@ func ShowRepoConf(c *gin.Context) {
|
||||||
|
|
||||||
user := session.User(c)
|
user := session.User(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
key, _ := store.GetKey(c, repo)
|
|
||||||
|
|
||||||
token, _ := token.New(
|
token, _ := token.New(
|
||||||
token.CsrfToken,
|
token.CsrfToken,
|
||||||
|
@ -126,7 +125,6 @@ func ShowRepoConf(c *gin.Context) {
|
||||||
c.HTML(200, "repo_config.html", gin.H{
|
c.HTML(200, "repo_config.html", gin.H{
|
||||||
"User": user,
|
"User": user,
|
||||||
"Repo": repo,
|
"Repo": repo,
|
||||||
"Key": key,
|
|
||||||
"Csrf": token,
|
"Csrf": token,
|
||||||
"Link": httputil.GetURL(c.Request),
|
"Link": httputil.GetURL(c.Request),
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue