2015-10-22 23:36:43 +00:00
|
|
|
package gogs
|
|
|
|
|
|
|
|
import (
|
2016-03-22 10:34:33 +00:00
|
|
|
"crypto/tls"
|
2015-10-22 23:36:43 +00:00
|
|
|
"fmt"
|
2015-12-24 15:09:18 +00:00
|
|
|
"net"
|
2015-10-22 23:36:43 +00:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/drone/drone/model"
|
|
|
|
"github.com/drone/drone/shared/envconfig"
|
|
|
|
"github.com/gogits/go-gogs-client"
|
|
|
|
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Gogs struct {
|
|
|
|
URL string
|
|
|
|
Open bool
|
|
|
|
PrivateMode bool
|
|
|
|
SkipVerify bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func Load(env envconfig.Env) *Gogs {
|
|
|
|
config := env.String("REMOTE_CONFIG", "")
|
|
|
|
|
|
|
|
// parse the remote DSN configuration string
|
|
|
|
url_, err := url.Parse(config)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("unable to parse remote dsn. %s", err)
|
|
|
|
}
|
|
|
|
params := url_.Query()
|
|
|
|
url_.RawQuery = ""
|
|
|
|
|
|
|
|
// create the Githbub remote using parameters from
|
|
|
|
// the parsed DSN configuration string.
|
|
|
|
gogs := Gogs{}
|
|
|
|
gogs.URL = url_.String()
|
|
|
|
gogs.PrivateMode, _ = strconv.ParseBool(params.Get("private_mode"))
|
|
|
|
gogs.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify"))
|
|
|
|
gogs.Open, _ = strconv.ParseBool(params.Get("open"))
|
|
|
|
|
|
|
|
return &gogs
|
|
|
|
}
|
|
|
|
|
|
|
|
// Login authenticates the session and returns the
|
|
|
|
// remote user details.
|
|
|
|
func (g *Gogs) Login(res http.ResponseWriter, req *http.Request) (*model.User, bool, error) {
|
|
|
|
var (
|
|
|
|
username = req.FormValue("username")
|
|
|
|
password = req.FormValue("password")
|
|
|
|
)
|
|
|
|
|
|
|
|
// if the username or password doesn't exist we re-direct
|
|
|
|
// the user to the login screen.
|
|
|
|
if len(username) == 0 || len(password) == 0 {
|
|
|
|
http.Redirect(res, req, "/login/form", http.StatusSeeOther)
|
|
|
|
return nil, false, nil
|
|
|
|
}
|
|
|
|
|
2016-03-22 10:34:33 +00:00
|
|
|
client := NewGogsClient(g.URL, "", g.SkipVerify)
|
2015-10-22 23:36:43 +00:00
|
|
|
|
|
|
|
// try to fetch drone token if it exists
|
|
|
|
var accessToken string
|
|
|
|
tokens, err := client.ListAccessTokens(username, password)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
for _, token := range tokens {
|
|
|
|
if token.Name == "drone" {
|
|
|
|
accessToken = token.Sha1
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if drone token not found, create it
|
|
|
|
if accessToken == "" {
|
|
|
|
token, err := client.CreateAccessToken(username, password, gogs.CreateAccessTokenOption{Name: "drone"})
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
accessToken = token.Sha1
|
|
|
|
}
|
|
|
|
|
2016-03-22 10:34:33 +00:00
|
|
|
client = NewGogsClient(g.URL, accessToken, g.SkipVerify)
|
2015-10-22 23:36:43 +00:00
|
|
|
userInfo, 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
|
2015-10-27 17:58:58 +00:00
|
|
|
user.Avatar = expandAvatar(g.URL, userInfo.AvatarUrl)
|
2015-10-22 23:36:43 +00:00
|
|
|
return &user, g.Open, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Auth authenticates the session and returns the remote user
|
|
|
|
// login for the given token and secret
|
|
|
|
func (g *Gogs) Auth(token, secret string) (string, error) {
|
|
|
|
return "", fmt.Errorf("Method not supported")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Repo fetches the named repository from the remote system.
|
|
|
|
func (g *Gogs) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
2016-01-21 16:50:15 +00:00
|
|
|
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
2015-10-22 23:36:43 +00:00
|
|
|
repos_, err := client.ListMyRepos()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
fullName := owner + "/" + name
|
|
|
|
for _, repo := range repos_ {
|
|
|
|
if repo.FullName == fullName {
|
|
|
|
return toRepo(repo), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("Not Found")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Repos fetches a list of repos from the remote system.
|
|
|
|
func (g *Gogs) Repos(u *model.User) ([]*model.RepoLite, error) {
|
|
|
|
repos := []*model.RepoLite{}
|
|
|
|
|
2016-01-21 16:50:15 +00:00
|
|
|
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
2015-10-22 23:36:43 +00:00
|
|
|
repos_, err := client.ListMyRepos()
|
|
|
|
if err != nil {
|
|
|
|
return repos, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, repo := range repos_ {
|
|
|
|
repos = append(repos, toRepoLite(repo))
|
|
|
|
}
|
|
|
|
|
|
|
|
return repos, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perm fetches the named repository permissions from
|
|
|
|
// the remote system for the specified user.
|
|
|
|
func (g *Gogs) Perm(u *model.User, owner, name string) (*model.Perm, error) {
|
2016-01-21 16:50:15 +00:00
|
|
|
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
2015-10-22 23:36:43 +00:00
|
|
|
repos_, err := client.ListMyRepos()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
fullName := owner + "/" + name
|
|
|
|
for _, repo := range repos_ {
|
|
|
|
if repo.FullName == fullName {
|
|
|
|
return toPerm(repo.Permissions), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("Not Found")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-03-22 10:34:33 +00:00
|
|
|
// File fetches a file from the remote repository and returns in string format.
|
|
|
|
func (g *Gogs) File(u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
2016-01-21 16:50:15 +00:00
|
|
|
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
2016-03-22 10:34:33 +00:00
|
|
|
cfg, err := client.GetFile(r.Owner, r.Name, b.Commit, f)
|
|
|
|
return cfg, err
|
2015-10-22 23:36:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Status sends the commit status to the remote system.
|
|
|
|
// An example would be the GitHub pull request status.
|
|
|
|
func (g *Gogs) Status(u *model.User, r *model.Repo, b *model.Build, link string) error {
|
|
|
|
return fmt.Errorf("Not Implemented")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Netrc returns a .netrc file that can be used to clone
|
|
|
|
// private repositories from a remote system.
|
|
|
|
func (g *Gogs) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
|
|
|
url_, err := url.Parse(g.URL)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-12-24 15:09:18 +00:00
|
|
|
host, _, err := net.SplitHostPort(url_.Host)
|
|
|
|
if err == nil {
|
2016-03-22 10:34:33 +00:00
|
|
|
url_.Host = host
|
2015-12-24 15:09:18 +00:00
|
|
|
}
|
2015-10-22 23:36:43 +00:00
|
|
|
return &model.Netrc{
|
|
|
|
Login: u.Token,
|
|
|
|
Password: "x-oauth-basic",
|
|
|
|
Machine: url_.Host,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Activate activates a repository by creating the post-commit hook and
|
|
|
|
// adding the SSH deploy key, if applicable.
|
|
|
|
func (g *Gogs) Activate(u *model.User, r *model.Repo, k *model.Key, link string) error {
|
|
|
|
config := map[string]string{
|
|
|
|
"url": link,
|
|
|
|
"secret": r.Hash,
|
|
|
|
"content_type": "json",
|
|
|
|
}
|
|
|
|
hook := gogs.CreateHookOption{
|
|
|
|
Type: "gogs",
|
|
|
|
Config: config,
|
|
|
|
Active: true,
|
|
|
|
}
|
|
|
|
|
2016-01-21 16:50:15 +00:00
|
|
|
client := NewGogsClient(g.URL, u.Token, g.SkipVerify)
|
2015-10-22 23:36:43 +00:00
|
|
|
_, err := client.CreateRepoHook(r.Owner, r.Name, hook)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deactivate removes a repository by removing all the post-commit hooks
|
|
|
|
// which are equal to link and removing the SSH deploy key.
|
|
|
|
func (g *Gogs) Deactivate(u *model.User, r *model.Repo, link string) error {
|
|
|
|
return fmt.Errorf("Not Implemented")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hook parses the post-commit hook from the Request body
|
|
|
|
// and returns the required data in a standard format.
|
|
|
|
func (g *Gogs) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
|
|
|
var (
|
|
|
|
err error
|
|
|
|
repo *model.Repo
|
|
|
|
build *model.Build
|
|
|
|
)
|
|
|
|
|
|
|
|
switch r.Header.Get("X-Gogs-Event") {
|
|
|
|
case "push":
|
|
|
|
var push *PushHook
|
|
|
|
push, err = parsePush(r.Body)
|
|
|
|
if err == nil {
|
|
|
|
repo = repoFromPush(push)
|
|
|
|
build = buildFromPush(push)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return repo, build, err
|
|
|
|
}
|
2015-10-27 23:48:05 +00:00
|
|
|
|
2016-01-21 16:50:15 +00:00
|
|
|
// NewClient initializes and returns a API client.
|
|
|
|
func NewGogsClient(url, token string, skipVerify bool) *gogs.Client {
|
2016-03-22 10:34:33 +00:00
|
|
|
sslClient := &http.Client{}
|
|
|
|
c := gogs.NewClient(url, token)
|
|
|
|
|
|
|
|
if skipVerify {
|
|
|
|
sslClient.Transport = &http.Transport{
|
|
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
|
|
}
|
|
|
|
c.SetHTTPClient(sslClient)
|
|
|
|
}
|
|
|
|
return c
|
2016-01-21 16:50:15 +00:00
|
|
|
}
|
|
|
|
|
2015-10-27 23:48:05 +00:00
|
|
|
func (g *Gogs) String() string {
|
|
|
|
return "gogs"
|
|
|
|
}
|