mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2026-04-15 01:41:56 +00:00
refactoring input and configuration
This commit is contained in:
@@ -11,22 +11,18 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/shared/httputil"
|
||||
"github.com/drone/drone/shared/oauth2"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/google/go-github/github"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultURL = "https://github.com"
|
||||
DefaultAPI = "https://api.github.com"
|
||||
DefaultScope = "repo,repo:status,user:email"
|
||||
DefaultMergeRef = "merge"
|
||||
DefaultURL = "https://github.com" // Default GitHub URL
|
||||
DefaultAPI = "https://api.github.com" // Default GitHub API URL
|
||||
)
|
||||
|
||||
var githubDeployRegex = regexp.MustCompile(".+/deployments/(\\d+)")
|
||||
|
||||
type Github struct {
|
||||
URL string
|
||||
API string
|
||||
@@ -34,58 +30,35 @@ type Github struct {
|
||||
Secret string
|
||||
Scope string
|
||||
MergeRef string
|
||||
Orgs []string
|
||||
Open bool
|
||||
PrivateMode bool
|
||||
SkipVerify bool
|
||||
GitSSH bool
|
||||
}
|
||||
|
||||
func Load(config string) *Github {
|
||||
|
||||
// parse the remote DSN configuration string
|
||||
url_, err := url.Parse(config)
|
||||
if err != nil {
|
||||
log.Fatalln("unable to parse remote dsn. %s", err)
|
||||
func New(url, client, secret string, scope []string, private, skipverify, mergeref bool) (remote.Remote, error) {
|
||||
remote := &Github{
|
||||
URL: strings.TrimSuffix(url, "/"),
|
||||
Client: client,
|
||||
Secret: secret,
|
||||
Scope: strings.Join(scope, ","),
|
||||
PrivateMode: private,
|
||||
SkipVerify: skipverify,
|
||||
MergeRef: "head",
|
||||
}
|
||||
params := url_.Query()
|
||||
url_.Path = ""
|
||||
url_.RawQuery = ""
|
||||
|
||||
// create the Githbub remote using parameters from
|
||||
// the parsed DSN configuration string.
|
||||
github := Github{}
|
||||
github.URL = url_.String()
|
||||
github.Client = params.Get("client_id")
|
||||
github.Secret = params.Get("client_secret")
|
||||
github.Scope = params.Get("scope")
|
||||
github.Orgs = params["orgs"]
|
||||
github.PrivateMode, _ = strconv.ParseBool(params.Get("private_mode"))
|
||||
github.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify"))
|
||||
github.Open, _ = strconv.ParseBool(params.Get("open"))
|
||||
github.GitSSH, _ = strconv.ParseBool(params.Get("ssh"))
|
||||
github.MergeRef = params.Get("merge_ref")
|
||||
|
||||
if github.URL == DefaultURL {
|
||||
github.API = DefaultAPI
|
||||
if remote.URL == DefaultURL {
|
||||
remote.API = DefaultAPI
|
||||
} else {
|
||||
github.API = github.URL + "/api/v3/"
|
||||
remote.API = remote.URL + "/api/v3/"
|
||||
}
|
||||
if mergeref {
|
||||
remote.MergeRef = "merge"
|
||||
}
|
||||
|
||||
if github.Scope == "" {
|
||||
github.Scope = DefaultScope
|
||||
}
|
||||
|
||||
if github.MergeRef == "" {
|
||||
github.MergeRef = DefaultMergeRef
|
||||
}
|
||||
|
||||
return &github
|
||||
return remote, nil
|
||||
}
|
||||
|
||||
// Login authenticates the session and returns the
|
||||
// remote user details.
|
||||
func (g *Github) Login(res http.ResponseWriter, req *http.Request) (*model.User, bool, error) {
|
||||
// Login authenticates the session and returns the remote user details.
|
||||
func (g *Github) Login(res http.ResponseWriter, req *http.Request) (*model.User, error) {
|
||||
|
||||
var config = &oauth2.Config{
|
||||
ClientId: g.Client,
|
||||
@@ -101,7 +74,7 @@ func (g *Github) Login(res http.ResponseWriter, req *http.Request) (*model.User,
|
||||
if len(code) == 0 {
|
||||
var random = GetRandom()
|
||||
http.Redirect(res, req, config.AuthCodeURL(random), http.StatusSeeOther)
|
||||
return nil, false, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var trans = &oauth2.Transport{
|
||||
@@ -117,23 +90,13 @@ func (g *Github) Login(res http.ResponseWriter, req *http.Request) (*model.User,
|
||||
}
|
||||
var token, err = trans.Exchange(code)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Error exchanging token. %s", err)
|
||||
return nil, fmt.Errorf("Error exchanging token. %s", err)
|
||||
}
|
||||
|
||||
var client = NewClient(g.API, token.AccessToken, g.SkipVerify)
|
||||
var useremail, errr = GetUserEmail(client)
|
||||
if errr != nil {
|
||||
return nil, false, fmt.Errorf("Error retrieving user or verified email. %s", errr)
|
||||
}
|
||||
|
||||
if len(g.Orgs) > 0 {
|
||||
allowedOrg, err := UserBelongsToOrg(client, g.Orgs)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Could not check org membership. %s", err)
|
||||
}
|
||||
if !allowedOrg {
|
||||
return nil, false, fmt.Errorf("User does not belong to correct org. Must belong to %v", g.Orgs)
|
||||
}
|
||||
return nil, fmt.Errorf("Error retrieving user or verified email. %s", errr)
|
||||
}
|
||||
|
||||
user := model.User{}
|
||||
@@ -141,7 +104,7 @@ func (g *Github) Login(res http.ResponseWriter, req *http.Request) (*model.User,
|
||||
user.Email = *useremail.Email
|
||||
user.Token = token.AccessToken
|
||||
user.Avatar = *useremail.AvatarURL
|
||||
return &user, g.Open, nil
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// Auth authenticates the session and returns the remote user
|
||||
@@ -155,37 +118,52 @@ func (g *Github) Auth(token, secret string) (string, error) {
|
||||
return *user.Login, nil
|
||||
}
|
||||
|
||||
// Repo fetches the named repository from the remote system.
|
||||
func (g *Github) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||
func (g *Github) Teams(u *model.User) ([]*model.Team, error) {
|
||||
client := NewClient(g.API, u.Token, g.SkipVerify)
|
||||
repo_, err := GetRepo(client, owner, name)
|
||||
orgs, err := GetOrgs(client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo := &model.Repo{}
|
||||
repo.Owner = owner
|
||||
repo.Name = name
|
||||
repo.FullName = *repo_.FullName
|
||||
repo.Link = *repo_.HTMLURL
|
||||
repo.IsPrivate = *repo_.Private
|
||||
repo.Clone = *repo_.CloneURL
|
||||
repo.Branch = "master"
|
||||
repo.Avatar = *repo_.Owner.AvatarURL
|
||||
repo.Kind = model.RepoGit
|
||||
var teams []*model.Team
|
||||
for _, org := range orgs {
|
||||
teams = append(teams, &model.Team{
|
||||
Login: *org.Login,
|
||||
Avatar: *org.AvatarURL,
|
||||
})
|
||||
}
|
||||
return teams, nil
|
||||
}
|
||||
|
||||
if repo_.DefaultBranch != nil {
|
||||
repo.Branch = *repo_.DefaultBranch
|
||||
// Repo fetches the named repository from the remote system.
|
||||
func (g *Github) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||
client := NewClient(g.API, u.Token, g.SkipVerify)
|
||||
r, err := GetRepo(client, owner, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo := &model.Repo{
|
||||
Owner: owner,
|
||||
Name: name,
|
||||
FullName: *r.FullName,
|
||||
Link: *r.HTMLURL,
|
||||
IsPrivate: *r.Private,
|
||||
Clone: *r.CloneURL,
|
||||
Avatar: *r.Owner.AvatarURL,
|
||||
Kind: model.RepoGit,
|
||||
}
|
||||
|
||||
if r.DefaultBranch != nil {
|
||||
repo.Branch = *r.DefaultBranch
|
||||
} else {
|
||||
repo.Branch = "master"
|
||||
}
|
||||
|
||||
if g.PrivateMode {
|
||||
repo.IsPrivate = true
|
||||
}
|
||||
|
||||
if g.GitSSH && repo.IsPrivate {
|
||||
repo.Clone = *repo_.SSHURL
|
||||
}
|
||||
|
||||
return repo, err
|
||||
}
|
||||
|
||||
@@ -257,8 +235,10 @@ func repoStatus(client *github.Client, r *model.Repo, b *model.Build, link strin
|
||||
return err
|
||||
}
|
||||
|
||||
var reDeploy = regexp.MustCompile(".+/deployments/(\\d+)")
|
||||
|
||||
func deploymentStatus(client *github.Client, r *model.Repo, b *model.Build, link string) error {
|
||||
matches := githubDeployRegex.FindStringSubmatch(b.Link)
|
||||
matches := reDeploy.FindStringSubmatch(b.Link)
|
||||
// if the deployment was not triggered from github, don't send a deployment status
|
||||
if len(matches) != 2 {
|
||||
return nil
|
||||
@@ -294,21 +274,7 @@ func (g *Github) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||
// adding the SSH deploy key, if applicable.
|
||||
func (g *Github) Activate(u *model.User, r *model.Repo, k *model.Key, link string) error {
|
||||
client := NewClient(g.API, u.Token, g.SkipVerify)
|
||||
title, err := GetKeyTitle(link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if the CloneURL is using the SSHURL then we know that
|
||||
// we need to add an SSH key to GitHub.
|
||||
if r.IsPrivate || g.PrivateMode {
|
||||
_, err = CreateUpdateKey(client, r.Owner, r.Name, title, k.Public)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = CreateUpdateHook(client, r.Owner, r.Name, link)
|
||||
_, err := CreateUpdateHook(client, r.Owner, r.Name, link)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -316,18 +282,6 @@ func (g *Github) Activate(u *model.User, r *model.Repo, k *model.Key, link strin
|
||||
// which are equal to link and removing the SSH deploy key.
|
||||
func (g *Github) Deactivate(u *model.User, r *model.Repo, link string) error {
|
||||
client := NewClient(g.API, u.Token, g.SkipVerify)
|
||||
title, err := GetKeyTitle(link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// remove the deploy-key if it is installed remote.
|
||||
if r.IsPrivate || g.PrivateMode {
|
||||
if err := DeleteKey(client, r.Owner, r.Name, title); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return DeleteHook(client, r.Owner, r.Name, link)
|
||||
}
|
||||
|
||||
|
||||
@@ -46,31 +46,32 @@ func TestHook(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoad(t *testing.T) {
|
||||
conf := "https://github.com?client_id=client&client_secret=secret&scope=scope1,scope2"
|
||||
|
||||
g := Load(conf)
|
||||
if g.URL != "https://github.com" {
|
||||
t.Errorf("g.URL = %q; want https://github.com", g.URL)
|
||||
}
|
||||
if g.Client != "client" {
|
||||
t.Errorf("g.Client = %q; want client", g.Client)
|
||||
}
|
||||
if g.Secret != "secret" {
|
||||
t.Errorf("g.Secret = %q; want secret", g.Secret)
|
||||
}
|
||||
if g.Scope != "scope1,scope2" {
|
||||
t.Errorf("g.Scope = %q; want scope1,scope2", g.Scope)
|
||||
}
|
||||
if g.API != DefaultAPI {
|
||||
t.Errorf("g.API = %q; want %q", g.API, DefaultAPI)
|
||||
}
|
||||
if g.MergeRef != DefaultMergeRef {
|
||||
t.Errorf("g.MergeRef = %q; want %q", g.MergeRef, DefaultMergeRef)
|
||||
}
|
||||
|
||||
g = Load("")
|
||||
if g.Scope != DefaultScope {
|
||||
t.Errorf("g.Scope = %q; want %q", g.Scope, DefaultScope)
|
||||
}
|
||||
}
|
||||
//
|
||||
// func TestLoad(t *testing.T) {
|
||||
// conf := "https://github.com?client_id=client&client_secret=secret&scope=scope1,scope2"
|
||||
//
|
||||
// g := Load(conf)
|
||||
// if g.URL != "https://github.com" {
|
||||
// t.Errorf("g.URL = %q; want https://github.com", g.URL)
|
||||
// }
|
||||
// if g.Client != "client" {
|
||||
// t.Errorf("g.Client = %q; want client", g.Client)
|
||||
// }
|
||||
// if g.Secret != "secret" {
|
||||
// t.Errorf("g.Secret = %q; want secret", g.Secret)
|
||||
// }
|
||||
// if g.Scope != "scope1,scope2" {
|
||||
// t.Errorf("g.Scope = %q; want scope1,scope2", g.Scope)
|
||||
// }
|
||||
// if g.API != DefaultAPI {
|
||||
// t.Errorf("g.API = %q; want %q", g.API, DefaultAPI)
|
||||
// }
|
||||
// if g.MergeRef != DefaultMergeRef {
|
||||
// t.Errorf("g.MergeRef = %q; want %q", g.MergeRef, DefaultMergeRef)
|
||||
// }
|
||||
//
|
||||
// g = Load("")
|
||||
// if g.Scope != DefaultScope {
|
||||
// t.Errorf("g.Scope = %q; want %q", g.Scope, DefaultScope)
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -72,53 +72,6 @@ func GetRepo(client *github.Client, owner, repo string) (*github.Repository, err
|
||||
return r, err
|
||||
}
|
||||
|
||||
// GetAllRepos is a helper function that returns an aggregated list
|
||||
// of all user and organization repositories.
|
||||
func GetAllRepos(client *github.Client) ([]github.Repository, error) {
|
||||
orgs, err := GetOrgs(client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repos, err := GetUserRepos(client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, org := range orgs {
|
||||
list, err := GetOrgRepos(client, *org.Login)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repos = append(repos, list...)
|
||||
}
|
||||
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// GetSubscriptions is a helper function that returns an aggregated list
|
||||
// of all user and organization repositories.
|
||||
// func GetSubscriptions(client *github.Client) ([]github.Repository, error) {
|
||||
// var repos []github.Repository
|
||||
// var opts = github.ListOptions{}
|
||||
// opts.PerPage = 100
|
||||
// opts.Page = 1
|
||||
|
||||
// // loop through user repository list
|
||||
// for opts.Page > 0 {
|
||||
// list, resp, err := client.Activity.ListWatched(""), &opts)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// repos = append(repos, list...)
|
||||
|
||||
// // increment the next page to retrieve
|
||||
// opts.Page = resp.NextPage
|
||||
// }
|
||||
|
||||
// return repos, nil
|
||||
// }
|
||||
|
||||
// GetUserRepos is a helper function that returns a list of
|
||||
// all user repositories. Paginated results are aggregated into
|
||||
// a single list.
|
||||
@@ -143,30 +96,6 @@ func GetUserRepos(client *github.Client) ([]github.Repository, error) {
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// GetOrgRepos is a helper function that returns a list of
|
||||
// all org repositories. Paginated results are aggregated into
|
||||
// a single list.
|
||||
func GetOrgRepos(client *github.Client, org string) ([]github.Repository, error) {
|
||||
var repos []github.Repository
|
||||
var opts = github.RepositoryListByOrgOptions{}
|
||||
opts.PerPage = 100
|
||||
opts.Page = 1
|
||||
|
||||
// loop through user repository list
|
||||
for opts.Page > 0 {
|
||||
list, resp, err := client.Repositories.ListByOrg(org, &opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repos = append(repos, list...)
|
||||
|
||||
// increment the next page to retrieve
|
||||
opts.Page = resp.NextPage
|
||||
}
|
||||
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// GetOrgs is a helper function that returns a list of
|
||||
// all orgs that a user belongs to.
|
||||
func GetOrgs(client *github.Client) ([]github.Organization, error) {
|
||||
@@ -250,70 +179,6 @@ func CreateUpdateHook(client *github.Client, owner, name, url string) (*github.H
|
||||
return CreateHook(client, owner, name, url)
|
||||
}
|
||||
|
||||
// GetKey is a heper function that retrieves a public Key by
|
||||
// title. To do this, it will retrieve a list of all keys
|
||||
// and iterate through the list.
|
||||
func GetKey(client *github.Client, owner, name, title string) (*github.Key, error) {
|
||||
keys, _, err := client.Repositories.ListKeys(owner, name, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, key := range keys {
|
||||
if *key.Title == title {
|
||||
return &key, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetKeyTitle is a helper function that generates a title for the
|
||||
// RSA public key based on the username and domain name.
|
||||
func GetKeyTitle(rawurl string) (string, error) {
|
||||
var uri, err = url.Parse(rawurl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("drone@%s", uri.Host), nil
|
||||
}
|
||||
|
||||
// DeleteKey is a helper function that deletes a deploy key
|
||||
// for the specified repository.
|
||||
func DeleteKey(client *github.Client, owner, name, title string) error {
|
||||
var k, err = GetKey(client, owner, name, title)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if k == nil {
|
||||
return nil
|
||||
}
|
||||
_, err = client.Repositories.DeleteKey(owner, name, *k.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateKey is a helper function that creates a deploy key
|
||||
// for the specified repository.
|
||||
func CreateKey(client *github.Client, owner, name, title, key string) (*github.Key, error) {
|
||||
var k = new(github.Key)
|
||||
k.Title = github.String(title)
|
||||
k.Key = github.String(key)
|
||||
created, _, err := client.Repositories.CreateKey(owner, name, k)
|
||||
return created, err
|
||||
}
|
||||
|
||||
// CreateUpdateKey is a helper function that creates a deployment key
|
||||
// for the specified repository if it does not already exist, otherwise
|
||||
// it updates the existing key
|
||||
func CreateUpdateKey(client *github.Client, owner, name, title, key string) (*github.Key, error) {
|
||||
var k, _ = GetKey(client, owner, name, title)
|
||||
if k != nil {
|
||||
k.Title = github.String(title)
|
||||
k.Key = github.String(key)
|
||||
client.Repositories.DeleteKey(owner, name, *k.ID)
|
||||
}
|
||||
|
||||
return CreateKey(client, owner, name, title, key)
|
||||
}
|
||||
|
||||
// GetFile is a heper function that retrieves a file from
|
||||
// GitHub and returns its contents in byte array format.
|
||||
func GetFile(client *github.Client, owner, name, path, ref string) ([]byte, error) {
|
||||
@@ -344,25 +209,3 @@ func GetPayload(req *http.Request) []byte {
|
||||
}
|
||||
return []byte(payload)
|
||||
}
|
||||
|
||||
// UserBelongsToOrg returns true if the currently authenticated user is a
|
||||
// member of any of the organizations provided.
|
||||
func UserBelongsToOrg(client *github.Client, permittedOrgs []string) (bool, error) {
|
||||
userOrgs, err := GetOrgs(client)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
userOrgSet := make(map[string]struct{}, len(userOrgs))
|
||||
for _, org := range userOrgs {
|
||||
userOrgSet[*org.Login] = struct{}{}
|
||||
}
|
||||
|
||||
for _, org := range permittedOrgs {
|
||||
if _, ok := userOrgSet[org]; ok {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user