harness-drone/plugin/remote/gitlab/gitlab.go
Matt Bostock 307aed12bc Move open registration setting into remote plugins
...so that it's possible to enable or disable open registration on a
per-remote basis.

For example, the `DRONE_REGISTRATION_OPEN` environment variable now
becomes `DRONE_GITHUB_OPEN` when using GitHub as a remote.

The default for open registration in this commit is `false` (disabled),
which matches the existing behaviour.

This is useful if you need to support both public and private remotes,
e.g. GitHub.com and GitHub Enterprise, where you trust all of the
private users and want to allow open registration for those but would
not want all GitHub.com users to run builds on your server.

Tested with GitHub and GitLab.
2015-01-16 22:04:24 +00:00

199 lines
4.9 KiB
Go

package gitlab
import (
"io/ioutil"
"net/http"
"net/url"
"strconv"
"github.com/Bugagazavr/go-gitlab-client"
"github.com/drone/drone/shared/model"
)
type Gitlab struct {
url string
SkipVerify bool
Open bool
}
func New(url string, skipVerify, open bool) *Gitlab {
return &Gitlab{
url: url,
SkipVerify: skipVerify,
Open: open,
}
}
// Authorize handles authentication with thrid party remote systems,
// such as github or bitbucket, and returns user data.
func (r *Gitlab) Authorize(res http.ResponseWriter, req *http.Request) (*model.Login, error) {
var username = req.FormValue("username")
var password = req.FormValue("password")
var client = NewClient(r.url, "", r.SkipVerify)
var session, err = client.GetSession(username, password)
if err != nil {
return nil, err
}
var login = new(model.Login)
login.ID = int64(session.Id)
login.Access = session.PrivateToken
login.Login = session.UserName
login.Name = session.Name
login.Email = session.Email
return login, nil
}
// GetKind returns the identifier of this remote GitHub instane.
func (r *Gitlab) GetKind() string {
return model.RemoteGitlab
}
// GetHost returns the hostname of this remote GitHub instance.
func (r *Gitlab) GetHost() string {
uri, _ := url.Parse(r.url)
return uri.Host
}
// GetRepos fetches all repositories that the specified
// user has access to in the remote system.
func (r *Gitlab) GetRepos(user *model.User) ([]*model.Repo, error) {
var repos []*model.Repo
var client = NewClient(r.url, user.Access, r.SkipVerify)
var list, err = client.AllProjects()
if err != nil {
return nil, err
}
var remote = r.GetKind()
var hostname = r.GetHost()
for _, item := range list {
var repo = model.Repo{
UserID: user.ID,
Remote: remote,
Host: hostname,
Owner: item.Namespace.Path,
Name: item.Path,
Private: !item.Public,
CloneURL: item.HttpRepoUrl,
GitURL: item.HttpRepoUrl,
SSHURL: item.SshRepoUrl,
URL: item.Url,
Role: &model.Perm{},
}
if repo.Private {
repo.CloneURL = repo.SSHURL
}
// if the user is the owner we can assume full access,
// otherwise check for the permission items.
if repo.Owner == user.Login {
repo.Role = new(model.Perm)
repo.Role.Admin = true
repo.Role.Write = true
repo.Role.Read = true
} else {
// Fetch current project
project, err := client.Project(strconv.Itoa(item.Id))
if err != nil || project.Permissions == nil {
continue
}
repo.Role.Admin = IsAdmin(project)
repo.Role.Write = IsWrite(project)
repo.Role.Read = IsRead(project)
}
repos = append(repos, &repo)
}
return repos, err
}
// GetScript fetches the build script (.drone.yml) from the remote
// repository and returns in string format.
func (r *Gitlab) GetScript(user *model.User, repo *model.Repo, hook *model.Hook) ([]byte, error) {
var client = NewClient(r.url, user.Access, r.SkipVerify)
var path = ns(repo.Owner, repo.Name)
return client.RepoRawFile(path, hook.Sha, ".drone.yml")
}
// Activate activates a repository by adding a Post-commit hook and
// a Public Deploy key, if applicable.
func (r *Gitlab) Activate(user *model.User, repo *model.Repo, link string) error {
var client = NewClient(r.url, user.Access, r.SkipVerify)
var path = ns(repo.Owner, repo.Name)
var title, err = GetKeyTitle(link)
if err != nil {
return err
}
// if the repository is private we'll need
// to upload a github key to the repository
if repo.Private {
var err = client.AddProjectDeployKey(path, title, repo.PublicKey)
if err != nil {
return err
}
}
// append the repo owner / name to the hook url since gitlab
// doesn't send this detail in the post-commit hook
link += "?owner=" + repo.Owner + "&name=" + repo.Name
// add the hook
return client.AddProjectHook(path, link, true, false, true)
}
// ParseHook parses the post-commit hook from the Request body
// and returns the required data in a standard format.
func (r *Gitlab) ParseHook(req *http.Request) (*model.Hook, error) {
defer req.Body.Close()
var payload, _ = ioutil.ReadAll(req.Body)
var parsed, err = gogitlab.ParseHook(payload)
if err != nil {
return nil, err
}
if len(parsed.After) == 0 || parsed.TotalCommitsCount == 0 {
return nil, nil
}
if parsed.ObjectKind == "merge_request" {
// TODO (bradrydzewski) figure out how to handle merge requests
return nil, nil
}
if len(parsed.After) == 0 {
return nil, nil
}
var hook = new(model.Hook)
hook.Owner = req.FormValue("owner")
hook.Repo = req.FormValue("name")
hook.Sha = parsed.After
hook.Branch = parsed.Branch()
var head = parsed.Head()
hook.Message = head.Message
hook.Timestamp = head.Timestamp
// extracts the commit author (ideally email)
// from the post-commit hook
switch {
case head.Author != nil:
hook.Author = head.Author.Email
case head.Author == nil:
hook.Author = parsed.UserName
}
return hook, nil
}
func (r *Gitlab) OpenRegistration() bool {
return r.Open
}