183 lines
4.4 KiB
Go
183 lines
4.4 KiB
Go
package gogs
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/drone/drone/shared/model"
|
|
"github.com/gogits/go-gogs-client"
|
|
)
|
|
|
|
type Gogs struct {
|
|
URL string
|
|
Secret string
|
|
}
|
|
|
|
func New(url string, secret string) *Gogs {
|
|
return &Gogs{URL: url, Secret: secret}
|
|
}
|
|
|
|
// Authorize handles Gogs authorization
|
|
func (r *Gogs) Authorize(res http.ResponseWriter, req *http.Request) (*model.Login, error) {
|
|
var username = req.FormValue("username")
|
|
var password = req.FormValue("password")
|
|
var client = gogs.NewClient(r.URL, "")
|
|
|
|
// try to fetch drone token if it exists
|
|
var accessToken = ""
|
|
tokens, err := client.ListAccessTokens(username, password)
|
|
if err != nil {
|
|
return nil, 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, err
|
|
}
|
|
accessToken = token.Sha1
|
|
}
|
|
|
|
// update client
|
|
client = gogs.NewClient(r.URL, accessToken)
|
|
|
|
// fetch user information
|
|
user, err := client.GetUserInfo(username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var login = new(model.Login)
|
|
login.Name = user.FullName
|
|
login.Email = user.Email
|
|
login.Access = accessToken
|
|
login.Login = username
|
|
return login, nil
|
|
}
|
|
|
|
// GetKind returns the internal identifier of this remote Gogs instance
|
|
func (r *Gogs) GetKind() string {
|
|
return model.RemoteGogs
|
|
}
|
|
|
|
// GetHost returns the hostname of this remote Gogs instance
|
|
func (r *Gogs) 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 *Gogs) GetRepos(user *model.User) ([]*model.Repo, error) {
|
|
var repos []*model.Repo
|
|
|
|
var remote = r.GetKind()
|
|
var hostname = r.GetHost()
|
|
var client = gogs.NewClient(r.URL, user.Access)
|
|
|
|
gogsRepos, err := client.ListMyRepos()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, repo := range gogsRepos {
|
|
var repoName = strings.Split(repo.FullName, "/")
|
|
if len(repoName) < 2 {
|
|
log.Println("invalid repo full_name", repo.FullName)
|
|
continue
|
|
}
|
|
var owner = repoName[0]
|
|
var name = repoName[1]
|
|
|
|
var repo = model.Repo{
|
|
UserID: user.ID,
|
|
Remote: remote,
|
|
Host: hostname,
|
|
Owner: owner,
|
|
Name: name,
|
|
Private: repo.Private,
|
|
CloneURL: repo.CloneUrl,
|
|
GitURL: repo.CloneUrl,
|
|
SSHURL: repo.SshUrl,
|
|
URL: repo.HtmlUrl,
|
|
Role: &model.Perm{
|
|
Admin: repo.Permissions.Admin,
|
|
Write: repo.Permissions.Push,
|
|
Read: repo.Permissions.Pull,
|
|
},
|
|
}
|
|
|
|
repos = append(repos, &repo)
|
|
}
|
|
|
|
return repos, err
|
|
}
|
|
|
|
// GetScript fetches the build script (.drone.yml) from the remote
|
|
// repository and returns a byte array
|
|
func (r *Gogs) GetScript(user *model.User, repo *model.Repo, hook *model.Hook) ([]byte, error) {
|
|
var client = gogs.NewClient(r.URL, user.Access)
|
|
return client.GetFile(repo.Owner, repo.Name, hook.Sha, ".drone.yml")
|
|
}
|
|
|
|
// Activate activates a repository
|
|
func (r *Gogs) Activate(user *model.User, repo *model.Repo, link string) error {
|
|
var client = gogs.NewClient(r.URL, user.Access)
|
|
|
|
var config = map[string]string{
|
|
"url": link,
|
|
"secret": r.Secret,
|
|
"content_type": "json",
|
|
}
|
|
var hook = gogs.CreateHookOption{
|
|
Type: "gogs",
|
|
Config: config,
|
|
Active: true,
|
|
}
|
|
|
|
_, err := client.CreateRepoHook(repo.Owner, repo.Name, hook)
|
|
return err
|
|
}
|
|
|
|
// ParseHook parses the post-commit hook from the Request body
|
|
// and returns the required data in a standard format.
|
|
func (r *Gogs) ParseHook(req *http.Request) (*model.Hook, error) {
|
|
defer req.Body.Close()
|
|
var payloadbytes, _ = ioutil.ReadAll(req.Body)
|
|
var payload, err = gogs.ParseHook(payloadbytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// verify the payload has the minimum amount of required data.
|
|
if payload.Repo == nil || payload.Commits == nil || len(payload.Commits) == 0 {
|
|
return nil, fmt.Errorf("Invalid Gogs post-commit Hook. Missing Repo or Commit data.")
|
|
}
|
|
|
|
if payload.Secret != r.Secret {
|
|
return nil, fmt.Errorf("Payload secret does not match stored secret")
|
|
}
|
|
|
|
return &model.Hook{
|
|
Owner: payload.Repo.Owner.UserName,
|
|
Repo: payload.Repo.Name,
|
|
Sha: payload.Commits[0].Id,
|
|
Branch: payload.Branch(),
|
|
Author: payload.Commits[0].Author.UserName,
|
|
Timestamp: time.Now().UTC().String(),
|
|
Message: payload.Commits[0].Message,
|
|
}, nil
|
|
}
|