mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-27 04:11:03 +00:00
Merge pull request #2114 from bradrydzewski/rfc/sync
implement fast repository sync
This commit is contained in:
commit
0f693cb66d
149 changed files with 3092 additions and 22517 deletions
40
cache/cache.go
vendored
40
cache/cache.go
vendored
|
@ -1,40 +0,0 @@
|
|||
package cache
|
||||
|
||||
//go:generate mockery -name Cache -output mock -case=underscore
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/koding/cache"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type Cache interface {
|
||||
Get(string) (interface{}, error)
|
||||
Set(string, interface{}) error
|
||||
Delete(string) error
|
||||
}
|
||||
|
||||
func Get(c context.Context, key string) (interface{}, error) {
|
||||
return FromContext(c).Get(key)
|
||||
}
|
||||
|
||||
func Set(c context.Context, key string, value interface{}) error {
|
||||
return FromContext(c).Set(key, value)
|
||||
}
|
||||
|
||||
func Delete(c context.Context, key string) error {
|
||||
return FromContext(c).Delete(key)
|
||||
}
|
||||
|
||||
// Default creates an in-memory cache with the default
|
||||
// 30 minute expiration period.
|
||||
func Default() Cache {
|
||||
return NewTTL(time.Minute * 30)
|
||||
}
|
||||
|
||||
// NewTTL returns an in-memory cache with the specified
|
||||
// ttl expiration period.
|
||||
func NewTTL(t time.Duration) Cache {
|
||||
return cache.NewMemoryWithTTL(t)
|
||||
}
|
34
cache/cache_test.go
vendored
34
cache/cache_test.go
vendored
|
@ -1,34 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/franela/goblin"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
|
||||
g := goblin.Goblin(t)
|
||||
g.Describe("Cache", func() {
|
||||
|
||||
var c *gin.Context
|
||||
g.BeforeEach(func() {
|
||||
c = new(gin.Context)
|
||||
ToContext(c, Default())
|
||||
})
|
||||
|
||||
g.It("Should set and get an item", func() {
|
||||
Set(c, "foo", "bar")
|
||||
v, e := Get(c, "foo")
|
||||
g.Assert(v).Equal("bar")
|
||||
g.Assert(e == nil).IsTrue()
|
||||
})
|
||||
|
||||
g.It("Should return nil when item not found", func() {
|
||||
v, e := Get(c, "foo")
|
||||
g.Assert(v == nil).IsTrue()
|
||||
g.Assert(e == nil).IsFalse()
|
||||
})
|
||||
})
|
||||
}
|
23
cache/context.go
vendored
23
cache/context.go
vendored
|
@ -1,23 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const key = "cache"
|
||||
|
||||
// Setter defines a context that enables setting values.
|
||||
type Setter interface {
|
||||
Set(string, interface{})
|
||||
}
|
||||
|
||||
// FromContext returns the Cache associated with this context.
|
||||
func FromContext(c context.Context) Cache {
|
||||
return c.Value(key).(Cache)
|
||||
}
|
||||
|
||||
// ToContext adds the Cache to this context if it supports
|
||||
// the Setter interface.
|
||||
func ToContext(c Setter, cache Cache) {
|
||||
c.Set(key, cache)
|
||||
}
|
99
cache/helper.go
vendored
99
cache/helper.go
vendored
|
@ -1,99 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// GetPerms returns the user permissions repositories from the cache
|
||||
// associated with the current repository.
|
||||
func GetPerms(c context.Context, user *model.User, owner, name string) (*model.Perm, error) {
|
||||
key := fmt.Sprintf("perms:%s:%s/%s",
|
||||
user.Login,
|
||||
owner,
|
||||
name,
|
||||
)
|
||||
// if we fetch from the cache we can return immediately
|
||||
val, err := Get(c, key)
|
||||
if err == nil {
|
||||
return val.(*model.Perm), nil
|
||||
}
|
||||
// else we try to grab from the remote system and
|
||||
// populate our cache.
|
||||
perm, err := remote.Perm(c, user, owner, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
Set(c, key, perm)
|
||||
return perm, nil
|
||||
}
|
||||
|
||||
// GetTeamPerms returns the user permissions from the cache
|
||||
// associated with the current organization.
|
||||
func GetTeamPerms(c context.Context, user *model.User, org string) (*model.Perm, error) {
|
||||
key := fmt.Sprintf("perms:%s:%s",
|
||||
user.Login,
|
||||
org,
|
||||
)
|
||||
// if we fetch from the cache we can return immediately
|
||||
val, err := Get(c, key)
|
||||
if err == nil {
|
||||
return val.(*model.Perm), nil
|
||||
}
|
||||
// else we try to grab from the remote system and
|
||||
// populate our cache.
|
||||
perm, err := remote.TeamPerm(c, user, org)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
Set(c, key, perm)
|
||||
return perm, nil
|
||||
}
|
||||
|
||||
// GetRepos returns the list of user repositories from the cache
|
||||
// associated with the current context.
|
||||
func GetRepos(c context.Context, user *model.User) ([]*model.RepoLite, error) {
|
||||
key := fmt.Sprintf("repos:%s",
|
||||
user.Login,
|
||||
)
|
||||
// if we fetch from the cache we can return immediately
|
||||
val, err := Get(c, key)
|
||||
if err == nil {
|
||||
return val.([]*model.RepoLite), nil
|
||||
}
|
||||
// else we try to grab from the remote system and
|
||||
// populate our cache.
|
||||
repos, err := remote.Repos(c, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Set(c, key, repos)
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// GetRepoMap returns the list of user repositories from the cache
|
||||
// associated with the current context in a map structure.
|
||||
func GetRepoMap(c context.Context, user *model.User) (map[string]bool, error) {
|
||||
repos, err := GetRepos(c, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repom := map[string]bool{}
|
||||
for _, repo := range repos {
|
||||
repom[repo.FullName] = true
|
||||
}
|
||||
return repom, nil
|
||||
}
|
||||
|
||||
// DeleteRepos evicts the cached user repositories from the cache associated
|
||||
// with the current context.
|
||||
func DeleteRepos(c context.Context, user *model.User) error {
|
||||
key := fmt.Sprintf("repos:%s",
|
||||
user.Login,
|
||||
)
|
||||
return Delete(c, key)
|
||||
}
|
115
cache/helper_test.go
vendored
115
cache/helper_test.go
vendored
|
@ -1,115 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/remote/mock"
|
||||
"github.com/franela/goblin"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestHelper(t *testing.T) {
|
||||
|
||||
g := goblin.Goblin(t)
|
||||
|
||||
g.Describe("Cache helpers", func() {
|
||||
|
||||
var c *gin.Context
|
||||
var r *mock.Remote
|
||||
|
||||
g.BeforeEach(func() {
|
||||
c = new(gin.Context)
|
||||
ToContext(c, Default())
|
||||
|
||||
r = new(mock.Remote)
|
||||
remote.ToContext(c, r)
|
||||
})
|
||||
|
||||
g.It("Should get permissions from remote", func() {
|
||||
r.On("Perm", fakeUser, fakeRepo.Owner, fakeRepo.Name).Return(fakePerm, nil).Once()
|
||||
p, err := GetPerms(c, fakeUser, fakeRepo.Owner, fakeRepo.Name)
|
||||
g.Assert(p).Equal(fakePerm)
|
||||
g.Assert(err).Equal(nil)
|
||||
|
||||
})
|
||||
|
||||
g.It("Should get permissions from cache", func() {
|
||||
key := fmt.Sprintf("perms:%s:%s/%s",
|
||||
fakeUser.Login,
|
||||
fakeRepo.Owner,
|
||||
fakeRepo.Name,
|
||||
)
|
||||
|
||||
Set(c, key, fakePerm)
|
||||
r.On("Perm", fakeUser, fakeRepo.Owner, fakeRepo.Name).Return(nil, fakeErr).Once()
|
||||
p, err := GetPerms(c, fakeUser, fakeRepo.Owner, fakeRepo.Name)
|
||||
g.Assert(p).Equal(fakePerm)
|
||||
g.Assert(err).Equal(nil)
|
||||
})
|
||||
|
||||
g.It("Should get permissions error", func() {
|
||||
r.On("Perm", fakeUser, fakeRepo.Owner, fakeRepo.Name).Return(nil, fakeErr).Once()
|
||||
p, err := GetPerms(c, fakeUser, fakeRepo.Owner, fakeRepo.Name)
|
||||
g.Assert(p == nil).IsTrue()
|
||||
g.Assert(err).Equal(fakeErr)
|
||||
})
|
||||
|
||||
g.It("Should set and get repos", func() {
|
||||
|
||||
r.On("Repos", fakeUser).Return(fakeRepos, nil).Once()
|
||||
p, err := GetRepos(c, fakeUser)
|
||||
g.Assert(p).Equal(fakeRepos)
|
||||
g.Assert(err).Equal(nil)
|
||||
})
|
||||
|
||||
g.It("Should get repos", func() {
|
||||
key := fmt.Sprintf("repos:%s",
|
||||
fakeUser.Login,
|
||||
)
|
||||
|
||||
Set(c, key, fakeRepos)
|
||||
r.On("Repos", fakeUser).Return(nil, fakeErr).Once()
|
||||
p, err := GetRepos(c, fakeUser)
|
||||
g.Assert(p).Equal(fakeRepos)
|
||||
g.Assert(err).Equal(nil)
|
||||
})
|
||||
|
||||
g.It("Should get repos error", func() {
|
||||
r.On("Repos", fakeUser).Return(nil, fakeErr).Once()
|
||||
p, err := GetRepos(c, fakeUser)
|
||||
g.Assert(p == nil).IsTrue()
|
||||
g.Assert(err).Equal(fakeErr)
|
||||
})
|
||||
|
||||
g.It("Should evict repos", func() {
|
||||
key := fmt.Sprintf("repos:%s",
|
||||
fakeUser.Login,
|
||||
)
|
||||
|
||||
Set(c, key, fakeRepos)
|
||||
repos, err := Get(c, key)
|
||||
g.Assert(repos != nil).IsTrue()
|
||||
g.Assert(err == nil).IsTrue()
|
||||
|
||||
DeleteRepos(c, fakeUser)
|
||||
repos, err = Get(c, key)
|
||||
g.Assert(repos == nil).IsTrue()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
fakeErr = errors.New("Not Found")
|
||||
fakeUser = &model.User{Login: "octocat"}
|
||||
fakePerm = &model.Perm{true, true, true}
|
||||
fakeRepo = &model.RepoLite{Owner: "octocat", Name: "Hello-World"}
|
||||
fakeRepos = []*model.RepoLite{
|
||||
{Owner: "octocat", Name: "Hello-World"},
|
||||
{Owner: "octocat", Name: "hello-world"},
|
||||
{Owner: "octocat", Name: "Spoon-Knife"},
|
||||
}
|
||||
)
|
|
@ -80,12 +80,6 @@ var flags = []cli.Flag{
|
|||
Name: "open",
|
||||
Usage: "open user registration",
|
||||
},
|
||||
cli.DurationFlag{
|
||||
EnvVar: "DRONE_CACHE_TTL",
|
||||
Name: "cache-ttl",
|
||||
Usage: "cache duration",
|
||||
Value: time.Minute * 15,
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
EnvVar: "DRONE_ESCALATE",
|
||||
Name: "escalate",
|
||||
|
@ -415,7 +409,6 @@ func server(c *cli.Context) error {
|
|||
ginrus.Ginrus(logrus.StandardLogger(), time.RFC3339, true),
|
||||
middleware.Version,
|
||||
middleware.Config(c),
|
||||
middleware.Cache(c),
|
||||
middleware.Store(c, store_),
|
||||
middleware.Remote(remote_),
|
||||
)
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
package model
|
||||
|
||||
type Perm struct {
|
||||
Pull bool `json:"pull"`
|
||||
Push bool `json:"push"`
|
||||
Admin bool `json:"admin"`
|
||||
// PermStore persists repository permissions information to storage.
|
||||
type PermStore interface {
|
||||
PermFind(user *User, repo *Repo) (*Perm, error)
|
||||
PermUpsert(perm *Perm) error
|
||||
PermBatch(perms []*Perm) error
|
||||
PermDelete(perm *Perm) error
|
||||
PermFlush(user *User, before int64) error
|
||||
}
|
||||
|
||||
// Perm defines a repository permission for an individual user.
|
||||
type Perm struct {
|
||||
UserID int64 `json:"-" meddler:"perm_user_id"`
|
||||
RepoID int64 `json:"-" meddler:"perm_repo_id"`
|
||||
Repo string `json:"-" meddler:"-"`
|
||||
Pull bool `json:"pull" meddler:"perm_pull"`
|
||||
Push bool `json:"push" meddler:"perm_push"`
|
||||
Admin bool `json:"admin" meddler:"perm_admin"`
|
||||
Synced int64 `json:"synced" meddler:"perm_synced"`
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ type Repo struct {
|
|||
IsTrusted bool `json:"trusted" meddler:"repo_trusted"`
|
||||
IsStarred bool `json:"starred,omitempty" meddler:"-"`
|
||||
IsGated bool `json:"gated" meddler:"repo_gated"`
|
||||
IsActive bool `json:"active,omitempty" meddler:"repo_active"`
|
||||
AllowPull bool `json:"allow_pr" meddler:"repo_allow_pr"`
|
||||
AllowPush bool `json:"allow_push" meddler:"repo_allow_push"`
|
||||
AllowDeploy bool `json:"allow_deploys" meddler:"repo_allow_deploys"`
|
||||
|
@ -34,6 +35,7 @@ type Repo struct {
|
|||
Counter int `json:"last_build" meddler:"repo_counter"`
|
||||
Config string `json:"config_file" meddler:"repo_config_path"`
|
||||
Hash string `json:"-" meddler:"repo_hash"`
|
||||
Perm *Perm `json:"-" meddler:"-"`
|
||||
}
|
||||
|
||||
// RepoPatch represents a repository patch object.
|
||||
|
|
|
@ -34,6 +34,9 @@ type User struct {
|
|||
// Activate indicates the user is active in the system.
|
||||
Active bool `json:"active" meddler:"user_active"`
|
||||
|
||||
// Synced is the timestamp when the user was synced with the remote system.
|
||||
Synced int64 `json:"synced" meddler:"user_synced"`
|
||||
|
||||
// Admin indicates the user is a system administrator.
|
||||
//
|
||||
// NOTE: This is sourced from the DRONE_ADMINS environment variable and is no
|
||||
|
|
|
@ -114,11 +114,6 @@ func (c *config) Teams(u *model.User) ([]*model.Team, error) {
|
|||
return convertTeamList(resp.Values), nil
|
||||
}
|
||||
|
||||
// TeamPerm is not supported by the Bitbucket driver.
|
||||
func (c *config) TeamPerm(u *model.User, org string) (*model.Perm, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Repo returns the named Bitbucket repository.
|
||||
func (c *config) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||
repo, err := c.newClient(u).FindRepo(owner, name)
|
||||
|
@ -130,10 +125,10 @@ func (c *config) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
|||
|
||||
// Repos returns a list of all repositories for Bitbucket account, including
|
||||
// organization repositories.
|
||||
func (c *config) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||
func (c *config) Repos(u *model.User) ([]*model.Repo, error) {
|
||||
client := c.newClient(u)
|
||||
|
||||
var all []*model.RepoLite
|
||||
var all []*model.Repo
|
||||
|
||||
accounts := []string{u.Login}
|
||||
resp, err := client.ListTeams(&internal.ListTeamOpts{
|
||||
|
@ -153,7 +148,7 @@ func (c *config) Repos(u *model.User) ([]*model.RepoLite, error) {
|
|||
return all, err
|
||||
}
|
||||
for _, repo := range repos {
|
||||
all = append(all, convertRepoLite(repo))
|
||||
all = append(all, convertRepo(repo))
|
||||
}
|
||||
}
|
||||
return all, nil
|
||||
|
|
|
@ -110,17 +110,6 @@ func cloneLink(repo *internal.Repo) string {
|
|||
return clone
|
||||
}
|
||||
|
||||
// convertRepoLite is a helper function used to convert a Bitbucket repository
|
||||
// structure to the simplified Drone repository structure.
|
||||
func convertRepoLite(from *internal.Repo) *model.RepoLite {
|
||||
return &model.RepoLite{
|
||||
Owner: strings.Split(from.FullName, "/")[0],
|
||||
Name: strings.Split(from.FullName, "/")[1],
|
||||
FullName: from.FullName,
|
||||
Avatar: from.Owner.Links.Avatar.Href,
|
||||
}
|
||||
}
|
||||
|
||||
// convertUser is a helper function used to convert a Bitbucket user account
|
||||
// structure to the Drone User structure.
|
||||
func convertUser(from *internal.Account, token *oauth2.Token) *model.User {
|
||||
|
|
|
@ -49,18 +49,6 @@ func Test_helper(t *testing.T) {
|
|||
g.Assert(convertDesc(model.StatusError)).Equal(descError)
|
||||
})
|
||||
|
||||
g.It("should convert repository lite", func() {
|
||||
from := &internal.Repo{}
|
||||
from.FullName = "octocat/hello-world"
|
||||
from.Owner.Links.Avatar.Href = "http://..."
|
||||
|
||||
to := convertRepoLite(from)
|
||||
g.Assert(to.Avatar).Equal(from.Owner.Links.Avatar.Href)
|
||||
g.Assert(to.FullName).Equal(from.FullName)
|
||||
g.Assert(to.Owner).Equal("octocat")
|
||||
g.Assert(to.Name).Equal("hello-world")
|
||||
})
|
||||
|
||||
g.It("should convert repository", func() {
|
||||
from := &internal.Repo{
|
||||
FullName: "octocat/hello-world",
|
||||
|
|
|
@ -140,14 +140,14 @@ func (c *Config) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
|||
return convertRepo(repo), nil
|
||||
}
|
||||
|
||||
func (c *Config) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||
func (c *Config) Repos(u *model.User) ([]*model.Repo, error) {
|
||||
repos, err := internal.NewClientWithToken(c.URL, c.Consumer, u.Token).FindRepos()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var all []*model.RepoLite
|
||||
var all []*model.Repo
|
||||
for _, repo := range repos {
|
||||
all = append(all, convertRepoLite(repo))
|
||||
all = append(all, convertRepo(repo))
|
||||
}
|
||||
|
||||
return all, nil
|
||||
|
@ -233,7 +233,7 @@ func CreateConsumer(URL string, ConsumerKey string, PrivateKey *rsa.PrivateKey)
|
|||
consumer.HttpClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
},
|
||||
}
|
||||
return consumer
|
||||
|
|
|
@ -86,19 +86,6 @@ func convertRepo(from *internal.Repo) *model.Repo {
|
|||
|
||||
}
|
||||
|
||||
// convertRepoLite is a helper function used to convert a Bitbucket repository
|
||||
// structure to the simplified Drone repository structure.
|
||||
func convertRepoLite(from *internal.Repo) *model.RepoLite {
|
||||
return &model.RepoLite{
|
||||
Owner: from.Project.Key,
|
||||
Name: from.Slug,
|
||||
FullName: from.Project.Key + "/" + from.Slug,
|
||||
//TODO: find the avatar for the repo
|
||||
//Avatar: might need another ws call?
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// convertPushHook is a helper function used to convert a Bitbucket push
|
||||
// hook to the Drone build struct holding commit information.
|
||||
func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package bitbucketserver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote/bitbucketserver/internal"
|
||||
"github.com/franela/goblin"
|
||||
"github.com/mrjones/oauth"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_helper(t *testing.T) {
|
||||
|
@ -13,17 +14,6 @@ func Test_helper(t *testing.T) {
|
|||
g := goblin.Goblin(t)
|
||||
g.Describe("Bitbucket Server converter", func() {
|
||||
|
||||
g.It("should convert repository lite", func() {
|
||||
from := &internal.Repo{}
|
||||
from.Project.Key = "octocat"
|
||||
from.Slug = "hello-world"
|
||||
|
||||
to := convertRepoLite(from)
|
||||
g.Assert(to.FullName).Equal("octocat/hello-world")
|
||||
g.Assert(to.Owner).Equal("octocat")
|
||||
g.Assert(to.Name).Equal("hello-world")
|
||||
})
|
||||
|
||||
g.It("should convert repository", func() {
|
||||
from := &internal.Repo{
|
||||
Slug: "hello-world",
|
||||
|
|
|
@ -69,18 +69,13 @@ func (c *client) Teams(u *model.User) ([]*model.Team, error) {
|
|||
return empty, nil
|
||||
}
|
||||
|
||||
// TeamPerm is not supported by the Gerrit driver.
|
||||
func (c *client) TeamPerm(u *model.User, org string) (*model.Perm, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Repo is not supported by the Gerrit driver.
|
||||
func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Repos is not supported by the Gerrit driver.
|
||||
func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||
func (c *client) Repos(u *model.User) ([]*model.Repo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -200,8 +200,8 @@ func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
|||
|
||||
// Repos returns a list of all repositories for the Gitea account, including
|
||||
// organization repositories.
|
||||
func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||
repos := []*model.RepoLite{}
|
||||
func (c *client) Repos(u *model.User) ([]*model.Repo, error) {
|
||||
repos := []*model.Repo{}
|
||||
|
||||
client := c.newClientToken(u.Token)
|
||||
all, err := client.ListMyRepos()
|
||||
|
@ -210,7 +210,7 @@ func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) {
|
|||
}
|
||||
|
||||
for _, repo := range all {
|
||||
repos = append(repos, toRepoLite(repo))
|
||||
repos = append(repos, toRepo(repo))
|
||||
}
|
||||
return repos, err
|
||||
}
|
||||
|
|
|
@ -12,21 +12,6 @@ import (
|
|||
"github.com/drone/drone/model"
|
||||
)
|
||||
|
||||
// helper function that converts a Gitea repository to a Drone repository.
|
||||
func toRepoLite(from *gitea.Repository) *model.RepoLite {
|
||||
name := strings.Split(from.FullName, "/")[1]
|
||||
avatar := expandAvatar(
|
||||
from.HTMLURL,
|
||||
from.Owner.AvatarURL,
|
||||
)
|
||||
return &model.RepoLite{
|
||||
Name: name,
|
||||
Owner: from.Owner.UserName,
|
||||
FullName: from.FullName,
|
||||
Avatar: avatar,
|
||||
}
|
||||
}
|
||||
|
||||
// helper function that converts a Gitea repository to a Drone repository.
|
||||
func toRepo(from *gitea.Repository) *model.Repo {
|
||||
name := strings.Split(from.FullName, "/")[1]
|
||||
|
|
|
@ -177,21 +177,6 @@ func Test_parse(t *testing.T) {
|
|||
g.Assert(repo.IsPrivate).Equal(from.Private)
|
||||
})
|
||||
|
||||
g.It("Should return a RepoLite struct from a Gitea Repo", func() {
|
||||
from := gitea.Repository{
|
||||
FullName: "gophers/hello-world",
|
||||
Owner: &gitea.User{
|
||||
UserName: "gordon",
|
||||
AvatarURL: "http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
},
|
||||
}
|
||||
repo := toRepoLite(&from)
|
||||
g.Assert(repo.FullName).Equal(from.FullName)
|
||||
g.Assert(repo.Owner).Equal(from.Owner.UserName)
|
||||
g.Assert(repo.Name).Equal("hello-world")
|
||||
g.Assert(repo.Avatar).Equal(from.Owner.AvatarURL)
|
||||
})
|
||||
|
||||
g.It("Should correct a malformed avatar url", func() {
|
||||
|
||||
var urls = []struct {
|
||||
|
|
|
@ -80,6 +80,7 @@ func convertRepo(from *github.Repository, private bool) *model.Repo {
|
|||
Avatar: *from.Owner.AvatarURL,
|
||||
Kind: model.RepoGit,
|
||||
Branch: defaultBranch,
|
||||
Perm: convertPerm(from),
|
||||
}
|
||||
if from.DefaultBranch != nil {
|
||||
repo.Branch = *from.DefaultBranch
|
||||
|
@ -114,24 +115,24 @@ func convertTeamPerm(from *github.Membership) *model.Perm {
|
|||
|
||||
// convertRepoList is a helper function used to convert a GitHub repository
|
||||
// list to the common Drone repository structure.
|
||||
func convertRepoList(from []github.Repository) []*model.RepoLite {
|
||||
var repos []*model.RepoLite
|
||||
func convertRepoList(from []github.Repository, private bool) []*model.Repo {
|
||||
var repos []*model.Repo
|
||||
for _, repo := range from {
|
||||
repos = append(repos, convertRepoLite(repo))
|
||||
repos = append(repos, convertRepo(&repo, private))
|
||||
}
|
||||
return repos
|
||||
}
|
||||
|
||||
// convertRepoLite is a helper function used to convert a GitHub repository
|
||||
// structure to the common Drone repository structure.
|
||||
func convertRepoLite(from github.Repository) *model.RepoLite {
|
||||
return &model.RepoLite{
|
||||
Owner: *from.Owner.Login,
|
||||
Name: *from.Name,
|
||||
FullName: *from.FullName,
|
||||
Avatar: *from.Owner.AvatarURL,
|
||||
}
|
||||
}
|
||||
// // convertRepoLite is a helper function used to convert a GitHub repository
|
||||
// // structure to the common Drone repository structure.
|
||||
// func convertRepoLite(from github.Repository) *model.RepoLite {
|
||||
// return &model.RepoLite{
|
||||
// Owner: *from.Owner.Login,
|
||||
// Name: *from.Name,
|
||||
// FullName: *from.FullName,
|
||||
// Avatar: *from.Owner.AvatarURL,
|
||||
// }
|
||||
// }
|
||||
|
||||
// convertTeamList is a helper function used to convert a GitHub team list to
|
||||
// the common Drone repository structure.
|
||||
|
|
|
@ -50,36 +50,27 @@ func Test_helper(t *testing.T) {
|
|||
g.Assert(convertDesc(model.StatusError)).Equal(descError)
|
||||
})
|
||||
|
||||
g.It("should convert repository lite", func() {
|
||||
from := github.Repository{
|
||||
FullName: github.String("octocat/hello-world"),
|
||||
Name: github.String("hello-world"),
|
||||
Owner: &github.User{
|
||||
AvatarURL: github.String("http://..."),
|
||||
Login: github.String("octocat"),
|
||||
},
|
||||
}
|
||||
|
||||
to := convertRepoLite(from)
|
||||
g.Assert(to.Avatar).Equal("http://...")
|
||||
g.Assert(to.FullName).Equal("octocat/hello-world")
|
||||
g.Assert(to.Owner).Equal("octocat")
|
||||
g.Assert(to.Name).Equal("hello-world")
|
||||
})
|
||||
|
||||
g.It("should convert repository list", func() {
|
||||
from := []github.Repository{
|
||||
{
|
||||
Private: github.Bool(false),
|
||||
FullName: github.String("octocat/hello-world"),
|
||||
Name: github.String("hello-world"),
|
||||
Owner: &github.User{
|
||||
AvatarURL: github.String("http://..."),
|
||||
Login: github.String("octocat"),
|
||||
},
|
||||
HTMLURL: github.String("https://github.com/octocat/hello-world"),
|
||||
CloneURL: github.String("https://github.com/octocat/hello-world.git"),
|
||||
Permissions: &map[string]bool{
|
||||
"push": true,
|
||||
"pull": true,
|
||||
"admin": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
to := convertRepoList(from)
|
||||
to := convertRepoList(from, false)
|
||||
g.Assert(to[0].Avatar).Equal("http://...")
|
||||
g.Assert(to[0].FullName).Equal("octocat/hello-world")
|
||||
g.Assert(to[0].Owner).Equal("octocat")
|
||||
|
@ -98,6 +89,11 @@ func Test_helper(t *testing.T) {
|
|||
AvatarURL: github.String("http://..."),
|
||||
Login: github.String("octocat"),
|
||||
},
|
||||
Permissions: &map[string]bool{
|
||||
"push": true,
|
||||
"pull": true,
|
||||
"admin": true,
|
||||
},
|
||||
}
|
||||
|
||||
to := convertRepo(&from, false)
|
||||
|
|
|
@ -168,16 +168,6 @@ func (c *client) Teams(u *model.User) ([]*model.Team, error) {
|
|||
return teams, nil
|
||||
}
|
||||
|
||||
// TeamPerm returns the user permissions for the named GitHub organization.
|
||||
func (c *client) TeamPerm(u *model.User, org string) (*model.Perm, error) {
|
||||
client := c.newClientToken(u.Token)
|
||||
membership, _, err := client.Organizations.GetOrgMembership(u.Login, org)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertTeamPerm(membership), nil
|
||||
}
|
||||
|
||||
// Repo returns the named GitHub repository.
|
||||
func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||
client := c.newClientToken(u.Token)
|
||||
|
@ -190,20 +180,20 @@ func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
|||
|
||||
// Repos returns a list of all repositories for GitHub account, including
|
||||
// organization repositories.
|
||||
func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||
func (c *client) Repos(u *model.User) ([]*model.Repo, error) {
|
||||
client := c.newClientToken(u.Token)
|
||||
|
||||
opts := new(github.RepositoryListOptions)
|
||||
opts.PerPage = 100
|
||||
opts.Page = 1
|
||||
|
||||
var repos []*model.RepoLite
|
||||
var repos []*model.Repo
|
||||
for opts.Page > 0 {
|
||||
list, resp, err := client.Repositories.List("", opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repos = append(repos, convertRepoList(list)...)
|
||||
repos = append(repos, convertRepoList(list, c.PrivateMode)...)
|
||||
opts.Page = resp.NextPage
|
||||
}
|
||||
return repos, nil
|
||||
|
|
|
@ -110,23 +110,6 @@ func Test_github(t *testing.T) {
|
|||
})
|
||||
})
|
||||
|
||||
g.Describe("Requesting organization permissions", func() {
|
||||
g.It("Should return the permission details of an admin", func() {
|
||||
perm, err := c.TeamPerm(fakeUser, "octocat")
|
||||
g.Assert(err == nil).IsTrue()
|
||||
g.Assert(perm.Admin).IsTrue()
|
||||
})
|
||||
g.It("Should return the permission details of a member", func() {
|
||||
perm, err := c.TeamPerm(fakeUser, "github")
|
||||
g.Assert(err == nil).IsTrue()
|
||||
g.Assert(perm.Admin).IsFalse()
|
||||
})
|
||||
g.It("Should handle a not found error", func() {
|
||||
_, err := c.TeamPerm(fakeUser, "org_not_found")
|
||||
g.Assert(err != nil).IsTrue()
|
||||
})
|
||||
})
|
||||
|
||||
g.It("Should return a user repository list")
|
||||
|
||||
g.It("Should return a user team list")
|
||||
|
|
|
@ -203,11 +203,6 @@ func (g *Gitlab) Teams(u *model.User) ([]*model.Team, error) {
|
|||
return teams, nil
|
||||
}
|
||||
|
||||
// TeamPerm is not supported by the Gitlab driver.
|
||||
func (g *Gitlab) TeamPerm(u *model.User, org string) (*model.Perm, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Repo fetches the named repository from the remote system.
|
||||
func (g *Gitlab) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
||||
|
@ -248,32 +243,40 @@ func (g *Gitlab) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
|||
}
|
||||
|
||||
// Repos fetches a list of repos from the remote system.
|
||||
func (g *Gitlab) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||
func (g *Gitlab) Repos(u *model.User) ([]*model.Repo, error) {
|
||||
client := NewClient(g.URL, u.Token, g.SkipVerify)
|
||||
|
||||
var repos = []*model.RepoLite{}
|
||||
var repos = []*model.Repo{}
|
||||
|
||||
all, err := client.AllProjects(g.HideArchives)
|
||||
if err != nil {
|
||||
return repos, err
|
||||
}
|
||||
|
||||
for _, repo := range all {
|
||||
var parts = strings.Split(repo.PathWithNamespace, "/")
|
||||
for _, repo_ := range all {
|
||||
var parts = strings.Split(repo_.PathWithNamespace, "/")
|
||||
var owner = parts[0]
|
||||
var name = parts[1]
|
||||
var avatar = repo.AvatarUrl
|
||||
|
||||
if len(avatar) != 0 && !strings.HasPrefix(avatar, "http") {
|
||||
avatar = fmt.Sprintf("%s/%s", g.URL, avatar)
|
||||
repo := &model.Repo{}
|
||||
repo.Owner = owner
|
||||
repo.Name = name
|
||||
repo.FullName = repo_.PathWithNamespace
|
||||
repo.Link = repo_.Url
|
||||
repo.Clone = repo_.HttpRepoUrl
|
||||
repo.Branch = "master"
|
||||
|
||||
if repo_.DefaultBranch != "" {
|
||||
repo.Branch = repo_.DefaultBranch
|
||||
}
|
||||
|
||||
repos = append(repos, &model.RepoLite{
|
||||
Owner: owner,
|
||||
Name: name,
|
||||
FullName: repo.PathWithNamespace,
|
||||
Avatar: avatar,
|
||||
})
|
||||
if g.PrivateMode {
|
||||
repo.IsPrivate = true
|
||||
} else {
|
||||
repo.IsPrivate = !repo_.Public
|
||||
}
|
||||
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
|
||||
return repos, err
|
||||
|
@ -295,7 +298,7 @@ func (g *Gitlab) Perm(u *model.User, owner, name string) (*model.Perm, error) {
|
|||
|
||||
// repo owner is granted full access
|
||||
if repo.Owner != nil && repo.Owner.Username == u.Login {
|
||||
return &model.Perm{true, true, true}, nil
|
||||
return &model.Perm{Push: true, Pull: true, Admin: true}, nil
|
||||
}
|
||||
|
||||
// check permission for current user
|
||||
|
|
|
@ -127,11 +127,6 @@ func (c *client) Teams(u *model.User) ([]*model.Team, error) {
|
|||
return teams, nil
|
||||
}
|
||||
|
||||
// TeamPerm is not supported by the Gogs driver.
|
||||
func (c *client) TeamPerm(u *model.User, org string) (*model.Perm, error) {
|
||||
return nil, 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)
|
||||
|
@ -147,8 +142,8 @@ func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
|||
|
||||
// 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{}
|
||||
func (c *client) Repos(u *model.User) ([]*model.Repo, error) {
|
||||
repos := []*model.Repo{}
|
||||
|
||||
client := c.newClientToken(u.Token)
|
||||
all, err := client.ListMyRepos()
|
||||
|
@ -157,7 +152,7 @@ func (c *client) Repos(u *model.User) ([]*model.RepoLite, error) {
|
|||
}
|
||||
|
||||
for _, repo := range all {
|
||||
repos = append(repos, toRepoLite(repo))
|
||||
repos = append(repos, toRepo(repo))
|
||||
}
|
||||
return repos, err
|
||||
}
|
||||
|
|
|
@ -12,21 +12,6 @@ import (
|
|||
"github.com/gogits/go-gogs-client"
|
||||
)
|
||||
|
||||
// helper function that converts a Gogs repository to a Drone repository.
|
||||
func toRepoLite(from *gogs.Repository) *model.RepoLite {
|
||||
name := strings.Split(from.FullName, "/")[1]
|
||||
avatar := expandAvatar(
|
||||
from.HtmlUrl,
|
||||
from.Owner.AvatarUrl,
|
||||
)
|
||||
return &model.RepoLite{
|
||||
Name: name,
|
||||
Owner: from.Owner.UserName,
|
||||
FullName: from.FullName,
|
||||
Avatar: avatar,
|
||||
}
|
||||
}
|
||||
|
||||
// helper function that converts a Gogs repository to a Drone repository.
|
||||
func toRepo(from *gogs.Repository) *model.Repo {
|
||||
name := strings.Split(from.FullName, "/")[1]
|
||||
|
|
|
@ -176,21 +176,6 @@ func Test_parse(t *testing.T) {
|
|||
g.Assert(repo.IsPrivate).Equal(from.Private)
|
||||
})
|
||||
|
||||
g.It("Should return a RepoLite struct from a Gogs Repo", func() {
|
||||
from := gogs.Repository{
|
||||
FullName: "gophers/hello-world",
|
||||
Owner: gogs.User{
|
||||
UserName: "gordon",
|
||||
AvatarUrl: "http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
},
|
||||
}
|
||||
repo := toRepoLite(&from)
|
||||
g.Assert(repo.FullName).Equal(from.FullName)
|
||||
g.Assert(repo.Owner).Equal(from.Owner.UserName)
|
||||
g.Assert(repo.Name).Equal("hello-world")
|
||||
g.Assert(repo.Avatar).Equal(from.Owner.AvatarUrl)
|
||||
})
|
||||
|
||||
g.It("Should correct a malformed avatar url", func() {
|
||||
|
||||
var urls = []struct {
|
||||
|
|
|
@ -23,15 +23,11 @@ type Remote interface {
|
|||
// Teams fetches a list of team memberships from the remote system.
|
||||
Teams(u *model.User) ([]*model.Team, error)
|
||||
|
||||
// TeamPerm fetches the named organization permissions from
|
||||
// the remote system for the specified user.
|
||||
TeamPerm(u *model.User, org string) (*model.Perm, error)
|
||||
|
||||
// Repo fetches the named repository from the remote system.
|
||||
Repo(u *model.User, owner, repo string) (*model.Repo, error)
|
||||
|
||||
// Repos fetches a list of repos from the remote system.
|
||||
Repos(u *model.User) ([]*model.RepoLite, error)
|
||||
Repos(u *model.User) ([]*model.Repo, error)
|
||||
|
||||
// Perm fetches the named repository permissions from
|
||||
// the remote system for the specified user.
|
||||
|
@ -89,19 +85,13 @@ func Teams(c context.Context, u *model.User) ([]*model.Team, error) {
|
|||
return FromContext(c).Teams(u)
|
||||
}
|
||||
|
||||
// TeamPerm fetches the named organization permissions from
|
||||
// the remote system for the specified user.
|
||||
func TeamPerm(c context.Context, u *model.User, org string) (*model.Perm, error) {
|
||||
return FromContext(c).TeamPerm(u, org)
|
||||
}
|
||||
|
||||
// Repo fetches the named repository from the remote system.
|
||||
func Repo(c context.Context, u *model.User, owner, repo string) (*model.Repo, error) {
|
||||
return FromContext(c).Repo(u, owner, repo)
|
||||
}
|
||||
|
||||
// Repos fetches a list of repos from the remote system.
|
||||
func Repos(c context.Context, u *model.User) ([]*model.RepoLite, error) {
|
||||
func Repos(c context.Context, u *model.User) ([]*model.Repo, error) {
|
||||
return FromContext(c).Repos(u)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/cache"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Cache is a middleware function that initializes the Cache and attaches to
|
||||
// the context of every http.Request.
|
||||
func Cache(cli *cli.Context) gin.HandlerFunc {
|
||||
v := setupCache(cli)
|
||||
return func(c *gin.Context) {
|
||||
cache.ToContext(c, v)
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to create the cache from the CLI context.
|
||||
func setupCache(c *cli.Context) cache.Cache {
|
||||
return cache.NewTTL(
|
||||
c.Duration("cache-ttl"),
|
||||
)
|
||||
}
|
|
@ -2,9 +2,10 @@ package session
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/store"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
@ -92,10 +93,20 @@ func SetPerm() gin.HandlerFunc {
|
|||
|
||||
case user != nil:
|
||||
var err error
|
||||
perm, err = cache.GetPerms(c, user, repo.Owner, repo.Name)
|
||||
perm, err = store.FromContext(c).PermFind(user, repo)
|
||||
if err != nil {
|
||||
log.Errorf("Error fetching permission for %s %s",
|
||||
user.Login, repo.FullName)
|
||||
log.Errorf("Error fetching permission for %s %s. %s",
|
||||
user.Login, repo.FullName, err)
|
||||
}
|
||||
if time.Unix(perm.Synced, 0).Add(time.Hour).Before(time.Now()) {
|
||||
perm, err = remote.FromContext(c).Perm(user, repo.Owner, repo.Name)
|
||||
if err == nil {
|
||||
log.Debugf("Synced user permission for %s %s", user.Login, repo.FullName)
|
||||
perm.Repo = repo.FullName
|
||||
perm.UserID = user.ID
|
||||
perm.Synced = time.Now().Unix()
|
||||
store.FromContext(c).PermUpsert(perm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TeamPerm(c *gin.Context) *model.Perm {
|
||||
user := User(c)
|
||||
team := c.Param("team")
|
||||
perm := &model.Perm{}
|
||||
|
||||
switch {
|
||||
// if the user is not authenticated
|
||||
case user == nil:
|
||||
perm.Admin = false
|
||||
perm.Pull = false
|
||||
perm.Push = false
|
||||
|
||||
// if the user is a DRONE_ADMIN
|
||||
case user.Admin:
|
||||
perm.Admin = true
|
||||
perm.Pull = true
|
||||
perm.Push = true
|
||||
|
||||
// otherwise if the user is authenticated we should
|
||||
// check the remote system to get the users permissiosn.
|
||||
default:
|
||||
log.Debugf("Fetching team permission for %s %s",
|
||||
user.Login, team)
|
||||
|
||||
var err error
|
||||
perm, err = cache.GetTeamPerms(c, user, team)
|
||||
if err != nil {
|
||||
// debug
|
||||
log.Errorf("Error fetching team permission for %s %s",
|
||||
user.Login, team)
|
||||
|
||||
perm.Admin = false
|
||||
perm.Pull = false
|
||||
perm.Push = false
|
||||
}
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
log.Debugf("%s granted %+v team permission to %s",
|
||||
user.Login, perm, team)
|
||||
} else {
|
||||
log.Debugf("Guest granted %+v to %s", perm, team)
|
||||
|
||||
perm.Admin = false
|
||||
perm.Pull = false
|
||||
perm.Push = false
|
||||
}
|
||||
|
||||
return perm
|
||||
}
|
||||
|
||||
func MustTeamAdmin() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
perm := TeamPerm(c)
|
||||
|
||||
if perm.Admin {
|
||||
c.Next()
|
||||
} else {
|
||||
c.String(401, "User not authorized")
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/franela/goblin"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestTeamPerm(t *testing.T) {
|
||||
g := goblin.Goblin(t)
|
||||
|
||||
g.Describe("TeamPerm", func() {
|
||||
|
||||
var c *gin.Context
|
||||
g.BeforeEach(func() {
|
||||
c = new(gin.Context)
|
||||
cache.ToContext(c, cache.Default())
|
||||
})
|
||||
|
||||
g.It("Should set admin to false (user not logged in)", func() {
|
||||
p := TeamPerm(c)
|
||||
g.Assert(p.Admin).IsFalse("admin should be false")
|
||||
})
|
||||
g.It("Should set admin to true (user is DRONE_ADMIN)", func() {
|
||||
// Set DRONE_ADMIN user
|
||||
c.Set("user", fakeUserAdmin)
|
||||
|
||||
p := TeamPerm(c)
|
||||
g.Assert(p.Admin).IsTrue("admin should be false")
|
||||
})
|
||||
g.It("Should set admin to false (user logged in, not owner of org)", func() {
|
||||
// Set fake org
|
||||
params := gin.Params{
|
||||
gin.Param{
|
||||
Key: "team",
|
||||
Value: "test_org",
|
||||
},
|
||||
}
|
||||
c.Params = params
|
||||
|
||||
// Set cache to show user does not Owner/Admin
|
||||
cache.Set(c, "perms:octocat:test_org", fakeTeamPerm)
|
||||
|
||||
// Set User
|
||||
c.Set("user", fakeUser)
|
||||
|
||||
p := TeamPerm(c)
|
||||
g.Assert(p.Admin).IsFalse("admin should be false")
|
||||
})
|
||||
g.It("Should set admin to true (user logged in, owner of org)", func() {
|
||||
// Set fake org
|
||||
params := gin.Params{
|
||||
gin.Param{
|
||||
Key: "team",
|
||||
Value: "test_org",
|
||||
},
|
||||
}
|
||||
c.Params = params
|
||||
|
||||
// Set cache to show user is Owner/Admin
|
||||
cache.Set(c, "perms:octocat:test_org", fakeTeamPermAdmin)
|
||||
|
||||
// Set User
|
||||
c.Set("user", fakeUser)
|
||||
|
||||
p := TeamPerm(c)
|
||||
g.Assert(p.Admin).IsTrue("admin should be true")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
fakeUserAdmin = &model.User{
|
||||
Login: "octocatAdmin",
|
||||
Token: "cfcd2084",
|
||||
Admin: true,
|
||||
}
|
||||
|
||||
fakeUser = &model.User{
|
||||
Login: "octocat",
|
||||
Token: "cfcd2084",
|
||||
Admin: false,
|
||||
}
|
||||
|
||||
fakeTeamPermAdmin = &model.Perm{
|
||||
Admin: true,
|
||||
}
|
||||
|
||||
fakeTeamPerm = &model.Perm{
|
||||
Admin: false,
|
||||
}
|
||||
)
|
|
@ -47,7 +47,6 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
user.GET("", server.GetSelf)
|
||||
user.GET("/feed", server.GetFeed)
|
||||
user.GET("/repos", server.GetRepos)
|
||||
user.GET("/repos/remote", server.GetRemoteRepos)
|
||||
user.POST("/token", server.PostToken)
|
||||
user.DELETE("/token", server.DeleteToken)
|
||||
}
|
||||
|
@ -62,46 +61,42 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
users.DELETE("/:login", server.DeleteUser)
|
||||
}
|
||||
|
||||
repos := e.Group("/api/repos/:owner/:name")
|
||||
repo := e.Group("/api/repos/:owner/:name")
|
||||
{
|
||||
repos.POST("", server.PostRepo)
|
||||
repo.Use(session.SetRepo())
|
||||
repo.Use(session.SetPerm())
|
||||
repo.Use(session.MustPull)
|
||||
|
||||
repo := repos.Group("")
|
||||
{
|
||||
repo.Use(session.SetRepo())
|
||||
repo.Use(session.SetPerm())
|
||||
repo.Use(session.MustPull)
|
||||
repo.POST("", session.MustRepoAdmin(), server.PostRepo)
|
||||
repo.GET("", server.GetRepo)
|
||||
repo.GET("/builds", server.GetBuilds)
|
||||
repo.GET("/builds/:number", server.GetBuild)
|
||||
repo.GET("/logs/:number/:ppid/:proc", server.GetBuildLogs)
|
||||
|
||||
repo.GET("", server.GetRepo)
|
||||
repo.GET("/builds", server.GetBuilds)
|
||||
repo.GET("/builds/:number", server.GetBuild)
|
||||
repo.GET("/logs/:number/:ppid/:proc", server.GetBuildLogs)
|
||||
// requires push permissions
|
||||
repo.GET("/secrets", session.MustPush, server.GetSecretList)
|
||||
repo.POST("/secrets", session.MustPush, server.PostSecret)
|
||||
repo.GET("/secrets/:secret", session.MustPush, server.GetSecret)
|
||||
repo.PATCH("/secrets/:secret", session.MustPush, server.PatchSecret)
|
||||
repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret)
|
||||
|
||||
// requires push permissions
|
||||
repo.GET("/secrets", session.MustPush, server.GetSecretList)
|
||||
repo.POST("/secrets", session.MustPush, server.PostSecret)
|
||||
repo.GET("/secrets/:secret", session.MustPush, server.GetSecret)
|
||||
repo.PATCH("/secrets/:secret", session.MustPush, server.PatchSecret)
|
||||
repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret)
|
||||
// requires push permissions
|
||||
repo.GET("/registry", session.MustPush, server.GetRegistryList)
|
||||
repo.POST("/registry", session.MustPush, server.PostRegistry)
|
||||
repo.GET("/registry/:registry", session.MustPush, server.GetRegistry)
|
||||
repo.PATCH("/registry/:registry", session.MustPush, server.PatchRegistry)
|
||||
repo.DELETE("/registry/:registry", session.MustPush, server.DeleteRegistry)
|
||||
|
||||
// requires push permissions
|
||||
repo.GET("/registry", session.MustPush, server.GetRegistryList)
|
||||
repo.POST("/registry", session.MustPush, server.PostRegistry)
|
||||
repo.GET("/registry/:registry", session.MustPush, server.GetRegistry)
|
||||
repo.PATCH("/registry/:registry", session.MustPush, server.PatchRegistry)
|
||||
repo.DELETE("/registry/:registry", session.MustPush, server.DeleteRegistry)
|
||||
// requires admin permissions
|
||||
repo.PATCH("", session.MustRepoAdmin(), server.PatchRepo)
|
||||
repo.DELETE("", session.MustRepoAdmin(), server.DeleteRepo)
|
||||
repo.POST("/chown", session.MustRepoAdmin(), server.ChownRepo)
|
||||
repo.POST("/repair", session.MustRepoAdmin(), server.RepairRepo)
|
||||
|
||||
// requires push permissions
|
||||
repo.PATCH("", session.MustPush, server.PatchRepo)
|
||||
repo.DELETE("", session.MustRepoAdmin(), server.DeleteRepo)
|
||||
repo.POST("/chown", session.MustRepoAdmin(), server.ChownRepo)
|
||||
repo.POST("/repair", session.MustRepoAdmin(), server.RepairRepo)
|
||||
|
||||
repo.POST("/builds/:number", session.MustPush, server.PostBuild)
|
||||
repo.POST("/builds/:number/approve", session.MustPush, server.PostApproval)
|
||||
repo.POST("/builds/:number/decline", session.MustPush, server.PostDecline)
|
||||
repo.DELETE("/builds/:number/:job", session.MustPush, server.DeleteBuild)
|
||||
}
|
||||
repo.POST("/builds/:number", session.MustPush, server.PostBuild)
|
||||
repo.POST("/builds/:number/approve", session.MustPush, server.PostApproval)
|
||||
repo.POST("/builds/:number/decline", session.MustPush, server.PostDecline)
|
||||
repo.DELETE("/builds/:number/:job", session.MustPush, server.DeleteBuild)
|
||||
}
|
||||
|
||||
badges := e.Group("/api/badges/:owner/:name")
|
||||
|
|
|
@ -84,6 +84,11 @@ func PostHook(c *gin.Context) {
|
|||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
if !repo.IsActive {
|
||||
logrus.Errorf("ignoring hook. %s/%s is inactive.", tmprepo.Owner, tmprepo.Name)
|
||||
c.AbortWithError(204, err)
|
||||
return
|
||||
}
|
||||
|
||||
// get the token and verify the hook is authorized
|
||||
parsed, err := token.ParseRequest(c.Request, func(t *token.Token) (string, error) {
|
||||
|
|
|
@ -4,11 +4,11 @@ import (
|
|||
"encoding/base32"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/securecookie"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
|
@ -20,54 +20,40 @@ import (
|
|||
func PostRepo(c *gin.Context) {
|
||||
remote := remote.FromContext(c)
|
||||
user := session.User(c)
|
||||
owner := c.Param("owner")
|
||||
name := c.Param("name")
|
||||
repo := session.Repo(c)
|
||||
|
||||
if user == nil {
|
||||
c.AbortWithStatus(403)
|
||||
if repo.IsActive {
|
||||
c.String(409, "Repository is already active.")
|
||||
return
|
||||
}
|
||||
|
||||
r, err := remote.Repo(user, owner, name)
|
||||
if err != nil {
|
||||
c.String(404, err.Error())
|
||||
return
|
||||
repo.IsActive = true
|
||||
repo.UserID = user.ID
|
||||
if !repo.AllowPush && !repo.AllowPull && !repo.AllowDeploy && !repo.AllowTag {
|
||||
repo.AllowPush = true
|
||||
repo.AllowPull = true
|
||||
}
|
||||
m, err := cache.GetPerms(c, user, owner, name)
|
||||
if err != nil {
|
||||
c.String(404, err.Error())
|
||||
return
|
||||
if repo.Visibility == "" {
|
||||
repo.Visibility = model.VisibilityPublic
|
||||
if repo.IsPrivate {
|
||||
repo.Visibility = model.VisibilityPrivate
|
||||
}
|
||||
}
|
||||
if !m.Admin {
|
||||
c.String(403, "Administrative access is required.")
|
||||
return
|
||||
if repo.Config == "" {
|
||||
repo.Config = ".drone.yml"
|
||||
}
|
||||
if repo.Timeout == 0 {
|
||||
repo.Timeout = 60 // 1 hour default build time
|
||||
}
|
||||
if repo.Hash == "" {
|
||||
repo.Hash = base32.StdEncoding.EncodeToString(
|
||||
securecookie.GenerateRandomKey(32),
|
||||
)
|
||||
}
|
||||
|
||||
// error if the repository already exists
|
||||
_, err = store.GetRepoOwnerName(c, owner, name)
|
||||
if err == nil {
|
||||
c.String(409, "Repository already exists.")
|
||||
return
|
||||
}
|
||||
|
||||
// set the repository owner to the
|
||||
// currently authenticated user.
|
||||
r.UserID = user.ID
|
||||
r.AllowPush = true
|
||||
r.AllowPull = true
|
||||
r.Visibility = model.VisibilityPublic
|
||||
r.Config = ".drone.yml"
|
||||
r.Timeout = 60 // 1 hour default build time
|
||||
r.Hash = base32.StdEncoding.EncodeToString(
|
||||
securecookie.GenerateRandomKey(32),
|
||||
)
|
||||
if r.IsPrivate {
|
||||
r.Visibility = model.VisibilityPrivate
|
||||
}
|
||||
|
||||
// crates the jwt token used to verify the repository
|
||||
t := token.New(token.HookToken, r.FullName)
|
||||
sig, err := t.Sign(r.Hash)
|
||||
// creates the jwt token used to verify the repository
|
||||
t := token.New(token.HookToken, repo.FullName)
|
||||
sig, err := t.Sign(repo.Hash)
|
||||
if err != nil {
|
||||
c.String(500, err.Error())
|
||||
return
|
||||
|
@ -79,22 +65,19 @@ func PostRepo(c *gin.Context) {
|
|||
sig,
|
||||
)
|
||||
|
||||
// activate the repository before we make any
|
||||
// local changes to the database.
|
||||
err = remote.Activate(user, r, link)
|
||||
err = remote.Activate(user, repo, link)
|
||||
if err != nil {
|
||||
c.String(500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// persist the repository
|
||||
err = store.CreateRepo(c, r)
|
||||
err = store.UpdateRepo(c, repo)
|
||||
if err != nil {
|
||||
c.String(500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, r)
|
||||
c.JSON(200, repo)
|
||||
}
|
||||
|
||||
func PatchRepo(c *gin.Context) {
|
||||
|
@ -173,16 +156,28 @@ func GetRepo(c *gin.Context) {
|
|||
}
|
||||
|
||||
func DeleteRepo(c *gin.Context) {
|
||||
remove, _ := strconv.ParseBool(c.Query("remove"))
|
||||
remote := remote.FromContext(c)
|
||||
repo := session.Repo(c)
|
||||
user := session.User(c)
|
||||
|
||||
err := store.DeleteRepo(c, repo)
|
||||
repo.IsActive = false
|
||||
repo.UserID = 0
|
||||
|
||||
err := store.UpdateRepo(c, repo)
|
||||
if err != nil {
|
||||
c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
if remove {
|
||||
err := store.DeleteRepo(c, repo)
|
||||
if err != nil {
|
||||
c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
remote.Deactivate(user, repo, httputil.GetURL(c.Request))
|
||||
c.Writer.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
"github.com/cncd/logging"
|
||||
"github.com/cncd/pubsub"
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
"github.com/drone/drone/store"
|
||||
|
@ -149,7 +148,10 @@ func EventStream(c *gin.Context) {
|
|||
user := session.User(c)
|
||||
repo := map[string]bool{}
|
||||
if user != nil {
|
||||
repo, _ = cache.GetRepoMap(c, user)
|
||||
repos, _ := store.FromContext(c).RepoList(user)
|
||||
for _, r := range repos {
|
||||
repo[r.FullName] = true
|
||||
}
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(pingPeriod)
|
||||
|
|
66
server/sync.go
Normal file
66
server/sync.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/store"
|
||||
)
|
||||
|
||||
// Syncer synces the user repository and permissions.
|
||||
type Syncer interface {
|
||||
Sync(user *model.User) error
|
||||
}
|
||||
|
||||
type syncer struct {
|
||||
remote remote.Remote
|
||||
store store.Store
|
||||
perms model.PermStore
|
||||
}
|
||||
|
||||
func (s *syncer) Sync(user *model.User) error {
|
||||
unix := time.Now().Unix() - 1 // force immediate expiration
|
||||
repos, err := s.remote.Repos(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var perms []*model.Perm
|
||||
for _, repo := range repos {
|
||||
perm := model.Perm{
|
||||
UserID: user.ID,
|
||||
Repo: repo.FullName,
|
||||
Pull: true,
|
||||
Synced: unix,
|
||||
}
|
||||
if repo.Perm != nil {
|
||||
perm.Push = repo.Perm.Push
|
||||
perm.Admin = repo.Perm.Admin
|
||||
}
|
||||
perms = append(perms, &perm)
|
||||
}
|
||||
|
||||
err = s.store.RepoBatch(repos)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.store.PermBatch(perms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// this is here as a precaution. I want to make sure that if an api
|
||||
// call to the version control system fails and (for some reason) returns
|
||||
// an empty list, we don't wipe out the user repository permissions.
|
||||
//
|
||||
// the side-effect of this code is that a user with 1 repository whose
|
||||
// access is removed will still display in the feed, but they will not
|
||||
// be able to access the actual repository data.
|
||||
if len(repos) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.perms.PermFlush(user, unix)
|
||||
}
|
|
@ -5,6 +5,9 @@
|
|||
<meta name="author" content="bradrydzewski">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
|
||||
|
||||
<link rel="shortcut icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="shortcut icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
|
||||
<title></title>
|
||||
<script>
|
||||
window.ENV = {};
|
||||
|
|
|
@ -94,6 +94,9 @@ var indexpolymer = `<!DOCTYPE html>
|
|||
<meta name="author" content="bradrydzewski">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
|
||||
|
||||
<link rel="shortcut icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="shortcut icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
|
||||
<title></title>
|
||||
<script>
|
||||
window.ENV = {};
|
||||
|
|
18
server/ui.go
18
server/ui.go
|
@ -23,12 +23,13 @@ type website struct {
|
|||
|
||||
// NewWebsite returns a new website loader.
|
||||
func NewWebsite() Website {
|
||||
// TODO change to DRONE_WEB_PATH and add DRONE_WEB_PROXY
|
||||
path := os.Getenv("DRONE_WWW")
|
||||
if path != "" {
|
||||
return NewLocalWebsite(path)
|
||||
}
|
||||
return &website{
|
||||
fs: http.FileServer(dist.AssetFS()),
|
||||
fs: http.FileServer(dist.New()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,14 +39,9 @@ func (w *website) Page(rw http.ResponseWriter, r *http.Request, u *model.User) {
|
|||
|
||||
path := r.URL.Path
|
||||
switch path {
|
||||
case "/login/form":
|
||||
params := map[string]interface{}{}
|
||||
template.T.ExecuteTemplate(rw, "login.html", params)
|
||||
|
||||
case "/login":
|
||||
if err := r.FormValue("error"); err != "" {
|
||||
params := map[string]interface{}{"error": err}
|
||||
template.T.ExecuteTemplate(rw, "error.html", params)
|
||||
// TODO login error
|
||||
} else {
|
||||
http.Redirect(rw, r, "/authorize", 303)
|
||||
}
|
||||
|
@ -62,7 +58,8 @@ func (w *website) Page(rw http.ResponseWriter, r *http.Request, u *model.User) {
|
|||
"user": u,
|
||||
"csrf": csrf,
|
||||
}
|
||||
template.T.ExecuteTemplate(rw, "index.html", params)
|
||||
|
||||
template.T.ExecuteTemplate(rw, "index_polymer.html", params)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +70,9 @@ func (w *website) File(rw http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func (w *website) Routes() []string {
|
||||
return []string{
|
||||
"/static/*filepath",
|
||||
"/favicon-32x32.png",
|
||||
"/favicon-16x16.png",
|
||||
"/src/*filepath",
|
||||
"/bower_components/*filepath",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@ import (
|
|||
"encoding/base32"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/securecookie"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
"github.com/drone/drone/shared/token"
|
||||
"github.com/drone/drone/store"
|
||||
|
@ -21,17 +22,38 @@ func GetSelf(c *gin.Context) {
|
|||
}
|
||||
|
||||
func GetFeed(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
latest, _ := strconv.ParseBool(c.Query("latest"))
|
||||
|
||||
repos, err := cache.GetRepos(c, session.User(c))
|
||||
if err != nil {
|
||||
c.String(500, "Error fetching repository list. %s", err)
|
||||
if time.Unix(user.Synced, 0).Add(time.Hour * 72).Before(time.Now()) {
|
||||
logrus.Debugf("sync begin: %s", user.Login)
|
||||
sync := syncer{
|
||||
remote: remote.FromContext(c),
|
||||
store: store.FromContext(c),
|
||||
perms: store.FromContext(c),
|
||||
}
|
||||
if err := sync.Sync(user); err != nil {
|
||||
logrus.Debugf("sync error: %s: %s", user.Login, err)
|
||||
} else {
|
||||
logrus.Debugf("sync complete: %s", user.Login)
|
||||
user.Synced = time.Now().Unix()
|
||||
store.FromContext(c).UpdateUser(user)
|
||||
}
|
||||
}
|
||||
|
||||
if latest {
|
||||
feed, err := store.FromContext(c).RepoListLatest(user)
|
||||
if err != nil {
|
||||
c.String(500, "Error fetching feed. %s", err)
|
||||
} else {
|
||||
c.JSON(200, feed)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
feed, err := store.GetUserFeed(c, repos, latest)
|
||||
feed, err := store.FromContext(c).UserFeed(user)
|
||||
if err != nil {
|
||||
c.String(500, "Error fetching feed. %s", err)
|
||||
c.String(500, "Error fetching user feed. %s", err)
|
||||
return
|
||||
}
|
||||
c.JSON(200, feed)
|
||||
|
@ -44,58 +66,40 @@ func GetRepos(c *gin.Context) {
|
|||
flush, _ = strconv.ParseBool(c.Query("flush"))
|
||||
)
|
||||
|
||||
if flush {
|
||||
log.Debugf("Evicting repository cache for user %s.", user.Login)
|
||||
cache.DeleteRepos(c, user)
|
||||
if flush || time.Unix(user.Synced, 0).Add(time.Hour*72).Before(time.Now()) {
|
||||
logrus.Debugf("sync begin: %s", user.Login)
|
||||
sync := syncer{
|
||||
remote: remote.FromContext(c),
|
||||
store: store.FromContext(c),
|
||||
perms: store.FromContext(c),
|
||||
}
|
||||
if err := sync.Sync(user); err != nil {
|
||||
logrus.Debugf("sync error: %s: %s", user.Login, err)
|
||||
} else {
|
||||
logrus.Debugf("sync complete: %s", user.Login)
|
||||
user.Synced = time.Now().Unix()
|
||||
store.FromContext(c).UpdateUser(user)
|
||||
}
|
||||
}
|
||||
|
||||
remote, err := cache.GetRepos(c, user)
|
||||
repos, err := store.FromContext(c).RepoList(user)
|
||||
if err != nil {
|
||||
c.String(500, "Error fetching repository list. %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
repos, err := store.GetRepoListOf(c, remote)
|
||||
if err != nil {
|
||||
c.String(500, "Error fetching repository list. %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !all {
|
||||
if all {
|
||||
c.JSON(http.StatusOK, repos)
|
||||
return
|
||||
}
|
||||
|
||||
// below we combine the two lists to include both active and inactive
|
||||
// repositories. This is displayed on the settings screen to enable
|
||||
// toggling on / off repository settings.
|
||||
|
||||
repom := map[string]bool{}
|
||||
active := []*model.Repo{}
|
||||
for _, repo := range repos {
|
||||
repom[repo.FullName] = true
|
||||
}
|
||||
|
||||
for _, repo := range remote {
|
||||
if repom[repo.FullName] {
|
||||
continue
|
||||
if repo.IsActive {
|
||||
active = append(active, repo)
|
||||
}
|
||||
repos = append(repos, &model.Repo{
|
||||
Avatar: repo.Avatar,
|
||||
FullName: repo.FullName,
|
||||
Owner: repo.Owner,
|
||||
Name: repo.Name,
|
||||
})
|
||||
}
|
||||
c.JSON(http.StatusOK, repos)
|
||||
}
|
||||
|
||||
func GetRemoteRepos(c *gin.Context) {
|
||||
repos, err := cache.GetRepos(c, session.User(c))
|
||||
if err != nil {
|
||||
c.String(500, "Error fetching repository list. %s", err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, repos)
|
||||
c.JSON(http.StatusOK, active)
|
||||
}
|
||||
|
||||
func PostToken(c *gin.Context) {
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestBuilds(t *testing.T) {
|
|||
// table data from the database.
|
||||
g.BeforeEach(func() {
|
||||
s.Exec("DELETE FROM builds")
|
||||
s.Exec("DELETE FROM jobs")
|
||||
s.Exec("DELETE FROM procs")
|
||||
})
|
||||
|
||||
g.It("Should Post a Build", func() {
|
||||
|
|
|
@ -108,6 +108,34 @@ var migrations = []struct {
|
|||
name: "update-table-set-repo-seq-default",
|
||||
stmt: updateTableSetRepoSeqDefault,
|
||||
},
|
||||
{
|
||||
name: "alter-table-add-repo-active",
|
||||
stmt: alterTableAddRepoActive,
|
||||
},
|
||||
{
|
||||
name: "update-table-set-repo-active",
|
||||
stmt: updateTableSetRepoActive,
|
||||
},
|
||||
{
|
||||
name: "alter-table-add-user-synced",
|
||||
stmt: alterTableAddUserSynced,
|
||||
},
|
||||
{
|
||||
name: "update-table-set-user-synced",
|
||||
stmt: updateTableSetUserSynced,
|
||||
},
|
||||
{
|
||||
name: "create-table-perms",
|
||||
stmt: createTablePerms,
|
||||
},
|
||||
{
|
||||
name: "create-index-perms-repo",
|
||||
stmt: createIndexPermsRepo,
|
||||
},
|
||||
{
|
||||
name: "create-index-perms-user",
|
||||
stmt: createIndexPermsUser,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate performs the database migration. If the migration fails
|
||||
|
@ -499,3 +527,51 @@ var updateTableSetRepoSeqDefault = `
|
|||
UPDATE repos SET repo_counter = 0
|
||||
WHERE repo_counter IS NULL
|
||||
`
|
||||
|
||||
//
|
||||
// 015_add_column_repo_active.sql
|
||||
//
|
||||
|
||||
var alterTableAddRepoActive = `
|
||||
ALTER TABLE repos ADD COLUMN repo_active BOOLEAN
|
||||
`
|
||||
|
||||
var updateTableSetRepoActive = `
|
||||
UPDATE repos SET repo_active = true
|
||||
`
|
||||
|
||||
//
|
||||
// 016_add_column_user_synced.sql
|
||||
//
|
||||
|
||||
var alterTableAddUserSynced = `
|
||||
ALTER TABLE users ADD COLUMN user_synced INTEGER;
|
||||
`
|
||||
|
||||
var updateTableSetUserSynced = `
|
||||
UPDATE users SET user_synced = 0
|
||||
`
|
||||
|
||||
//
|
||||
// 017_create_table_perms.sql
|
||||
//
|
||||
|
||||
var createTablePerms = `
|
||||
CREATE TABLE IF NOT EXISTS perms (
|
||||
perm_user_id INTEGER NOT NULL
|
||||
,perm_repo_id INTEGER NOT NULL
|
||||
,perm_pull BOOLEAN
|
||||
,perm_push BOOLEAN
|
||||
,perm_admin BOOLEAN
|
||||
,perm_synced INTEGER
|
||||
,UNIQUE(perm_user_id, perm_repo_id)
|
||||
);
|
||||
`
|
||||
|
||||
var createIndexPermsRepo = `
|
||||
CREATE INDEX ix_perms_repo ON perms (perm_repo_id);
|
||||
`
|
||||
|
||||
var createIndexPermsUser = `
|
||||
CREATE INDEX ix_perms_user ON perms (perm_user_id);
|
||||
`
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
-- name: alter-table-add-repo-active
|
||||
|
||||
ALTER TABLE repos ADD COLUMN repo_active BOOLEAN
|
||||
|
||||
-- name: update-table-set-repo-active
|
||||
|
||||
UPDATE repos SET repo_active = true
|
|
@ -0,0 +1,7 @@
|
|||
-- name: alter-table-add-user-synced
|
||||
|
||||
ALTER TABLE users ADD COLUMN user_synced INTEGER;
|
||||
|
||||
-- name: update-table-set-user-synced
|
||||
|
||||
UPDATE users SET user_synced = 0
|
19
store/datastore/ddl/mysql/files/017_create_table_perms.sql
Normal file
19
store/datastore/ddl/mysql/files/017_create_table_perms.sql
Normal file
|
@ -0,0 +1,19 @@
|
|||
-- name: create-table-perms
|
||||
|
||||
CREATE TABLE IF NOT EXISTS perms (
|
||||
perm_user_id INTEGER NOT NULL
|
||||
,perm_repo_id INTEGER NOT NULL
|
||||
,perm_pull BOOLEAN
|
||||
,perm_push BOOLEAN
|
||||
,perm_admin BOOLEAN
|
||||
,perm_synced INTEGER
|
||||
,UNIQUE(perm_user_id, perm_repo_id)
|
||||
);
|
||||
|
||||
-- name: create-index-perms-repo
|
||||
|
||||
CREATE INDEX ix_perms_repo ON perms (perm_repo_id);
|
||||
|
||||
-- name: create-index-perms-user
|
||||
|
||||
CREATE INDEX ix_perms_user ON perms (perm_user_id);
|
|
@ -108,6 +108,34 @@ var migrations = []struct {
|
|||
name: "update-table-set-repo-seq-default",
|
||||
stmt: updateTableSetRepoSeqDefault,
|
||||
},
|
||||
{
|
||||
name: "alter-table-add-repo-active",
|
||||
stmt: alterTableAddRepoActive,
|
||||
},
|
||||
{
|
||||
name: "update-table-set-repo-active",
|
||||
stmt: updateTableSetRepoActive,
|
||||
},
|
||||
{
|
||||
name: "alter-table-add-user-synced",
|
||||
stmt: alterTableAddUserSynced,
|
||||
},
|
||||
{
|
||||
name: "update-table-set-user-synced",
|
||||
stmt: updateTableSetUserSynced,
|
||||
},
|
||||
{
|
||||
name: "create-table-perms",
|
||||
stmt: createTablePerms,
|
||||
},
|
||||
{
|
||||
name: "create-index-perms-repo",
|
||||
stmt: createIndexPermsRepo,
|
||||
},
|
||||
{
|
||||
name: "create-index-perms-user",
|
||||
stmt: createIndexPermsUser,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate performs the database migration. If the migration fails
|
||||
|
@ -499,3 +527,51 @@ var updateTableSetRepoSeqDefault = `
|
|||
UPDATE repos SET repo_counter = 0
|
||||
WHERE repo_counter IS NULL
|
||||
`
|
||||
|
||||
//
|
||||
// 015_add_column_repo_active.sql
|
||||
//
|
||||
|
||||
var alterTableAddRepoActive = `
|
||||
ALTER TABLE repos ADD COLUMN repo_active BOOLEAN
|
||||
`
|
||||
|
||||
var updateTableSetRepoActive = `
|
||||
UPDATE repos SET repo_active = true
|
||||
`
|
||||
|
||||
//
|
||||
// 016_add_column_user_synced.sql
|
||||
//
|
||||
|
||||
var alterTableAddUserSynced = `
|
||||
ALTER TABLE users ADD COLUMN user_synced INTEGER;
|
||||
`
|
||||
|
||||
var updateTableSetUserSynced = `
|
||||
UPDATE users SET user_synced = 0
|
||||
`
|
||||
|
||||
//
|
||||
// 017_create_table_perms.sql
|
||||
//
|
||||
|
||||
var createTablePerms = `
|
||||
CREATE TABLE IF NOT EXISTS perms (
|
||||
perm_user_id INTEGER NOT NULL
|
||||
,perm_repo_id INTEGER NOT NULL
|
||||
,perm_pull BOOLEAN
|
||||
,perm_push BOOLEAN
|
||||
,perm_admin BOOLEAN
|
||||
,perm_synced INTEGER
|
||||
,UNIQUE(perm_user_id, perm_repo_id)
|
||||
);
|
||||
`
|
||||
|
||||
var createIndexPermsRepo = `
|
||||
CREATE INDEX IF NOT EXISTS ix_perms_repo ON perms (perm_repo_id);
|
||||
`
|
||||
|
||||
var createIndexPermsUser = `
|
||||
CREATE INDEX IF NOT EXISTS ix_perms_user ON perms (perm_user_id);
|
||||
`
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
-- name: alter-table-add-repo-active
|
||||
|
||||
ALTER TABLE repos ADD COLUMN repo_active BOOLEAN
|
||||
|
||||
-- name: update-table-set-repo-active
|
||||
|
||||
UPDATE repos SET repo_active = true
|
|
@ -0,0 +1,7 @@
|
|||
-- name: alter-table-add-user-synced
|
||||
|
||||
ALTER TABLE users ADD COLUMN user_synced INTEGER;
|
||||
|
||||
-- name: update-table-set-user-synced
|
||||
|
||||
UPDATE users SET user_synced = 0
|
|
@ -0,0 +1,19 @@
|
|||
-- name: create-table-perms
|
||||
|
||||
CREATE TABLE IF NOT EXISTS perms (
|
||||
perm_user_id INTEGER NOT NULL
|
||||
,perm_repo_id INTEGER NOT NULL
|
||||
,perm_pull BOOLEAN
|
||||
,perm_push BOOLEAN
|
||||
,perm_admin BOOLEAN
|
||||
,perm_synced INTEGER
|
||||
,UNIQUE(perm_user_id, perm_repo_id)
|
||||
);
|
||||
|
||||
-- name: create-index-perms-repo
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_perms_repo ON perms (perm_repo_id);
|
||||
|
||||
-- name: create-index-perms-user
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_perms_user ON perms (perm_user_id);
|
|
@ -112,6 +112,34 @@ var migrations = []struct {
|
|||
name: "update-table-set-repo-seq-default",
|
||||
stmt: updateTableSetRepoSeqDefault,
|
||||
},
|
||||
{
|
||||
name: "alter-table-add-repo-active",
|
||||
stmt: alterTableAddRepoActive,
|
||||
},
|
||||
{
|
||||
name: "update-table-set-repo-active",
|
||||
stmt: updateTableSetRepoActive,
|
||||
},
|
||||
{
|
||||
name: "alter-table-add-user-synced",
|
||||
stmt: alterTableAddUserSynced,
|
||||
},
|
||||
{
|
||||
name: "update-table-set-user-synced",
|
||||
stmt: updateTableSetUserSynced,
|
||||
},
|
||||
{
|
||||
name: "create-table-perms",
|
||||
stmt: createTablePerms,
|
||||
},
|
||||
{
|
||||
name: "create-index-perms-repo",
|
||||
stmt: createIndexPermsRepo,
|
||||
},
|
||||
{
|
||||
name: "create-index-perms-user",
|
||||
stmt: createIndexPermsUser,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate performs the database migration. If the migration fails
|
||||
|
@ -500,3 +528,51 @@ var updateTableSetRepoSeqDefault = `
|
|||
UPDATE repos SET repo_counter = 0
|
||||
WHERE repo_counter IS NULL
|
||||
`
|
||||
|
||||
//
|
||||
// 015_add_column_repo_active.sql
|
||||
//
|
||||
|
||||
var alterTableAddRepoActive = `
|
||||
ALTER TABLE repos ADD COLUMN repo_active BOOLEAN
|
||||
`
|
||||
|
||||
var updateTableSetRepoActive = `
|
||||
UPDATE repos SET repo_active = 1
|
||||
`
|
||||
|
||||
//
|
||||
// 016_add_column_user_synced.sql
|
||||
//
|
||||
|
||||
var alterTableAddUserSynced = `
|
||||
ALTER TABLE users ADD COLUMN user_synced INTEGER;
|
||||
`
|
||||
|
||||
var updateTableSetUserSynced = `
|
||||
UPDATE users SET user_synced = 0
|
||||
`
|
||||
|
||||
//
|
||||
// 017_create_table_perms.sql
|
||||
//
|
||||
|
||||
var createTablePerms = `
|
||||
CREATE TABLE IF NOT EXISTS perms (
|
||||
perm_user_id INTEGER NOT NULL
|
||||
,perm_repo_id INTEGER NOT NULL
|
||||
,perm_pull BOOLEAN
|
||||
,perm_push BOOLEAN
|
||||
,perm_admin BOOLEAN
|
||||
,perm_synced INTEGER
|
||||
,UNIQUE(perm_user_id, perm_repo_id)
|
||||
);
|
||||
`
|
||||
|
||||
var createIndexPermsRepo = `
|
||||
CREATE INDEX IF NOT EXISTS ix_perms_repo ON perms (perm_repo_id);
|
||||
`
|
||||
|
||||
var createIndexPermsUser = `
|
||||
CREATE INDEX IF NOT EXISTS ix_perms_user ON perms (perm_user_id);
|
||||
`
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
-- name: alter-table-add-repo-active
|
||||
|
||||
ALTER TABLE repos ADD COLUMN repo_active BOOLEAN
|
||||
|
||||
-- name: update-table-set-repo-active
|
||||
|
||||
UPDATE repos SET repo_active = 1
|
|
@ -0,0 +1,7 @@
|
|||
-- name: alter-table-add-user-synced
|
||||
|
||||
ALTER TABLE users ADD COLUMN user_synced INTEGER;
|
||||
|
||||
-- name: update-table-set-user-synced
|
||||
|
||||
UPDATE users SET user_synced = 0
|
19
store/datastore/ddl/sqlite/files/017_create_table_perms.sql
Normal file
19
store/datastore/ddl/sqlite/files/017_create_table_perms.sql
Normal file
|
@ -0,0 +1,19 @@
|
|||
-- name: create-table-perms
|
||||
|
||||
CREATE TABLE IF NOT EXISTS perms (
|
||||
perm_user_id INTEGER NOT NULL
|
||||
,perm_repo_id INTEGER NOT NULL
|
||||
,perm_pull BOOLEAN
|
||||
,perm_push BOOLEAN
|
||||
,perm_admin BOOLEAN
|
||||
,perm_synced INTEGER
|
||||
,UNIQUE(perm_user_id, perm_repo_id)
|
||||
);
|
||||
|
||||
-- name: create-index-perms-repo
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_perms_repo ON perms (perm_repo_id);
|
||||
|
||||
-- name: create-index-perms-user
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_perms_user ON perms (perm_user_id);
|
|
@ -1,242 +0,0 @@
|
|||
-- name: create-table-users
|
||||
|
||||
CREATE TABLE users (
|
||||
user_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,user_login TEXT
|
||||
,user_token TEXT
|
||||
,user_secret TEXT
|
||||
,user_expiry INTEGER
|
||||
,user_email TEXT
|
||||
,user_avatar TEXT
|
||||
,user_active BOOLEAN
|
||||
,user_admin BOOLEAN
|
||||
,user_hash TEXT
|
||||
|
||||
,UNIQUE(user_login)
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-repos
|
||||
|
||||
CREATE TABLE repos (
|
||||
repo_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,repo_user_id INTEGER
|
||||
,repo_owner TEXT
|
||||
,repo_name TEXT
|
||||
,repo_full_name TEXT
|
||||
,repo_avatar TEXT
|
||||
,repo_link TEXT
|
||||
,repo_clone TEXT
|
||||
,repo_branch TEXT
|
||||
,repo_timeout INTEGER
|
||||
,repo_private BOOLEAN
|
||||
,repo_trusted BOOLEAN
|
||||
,repo_allow_pr BOOLEAN
|
||||
,repo_allow_push BOOLEAN
|
||||
,repo_allow_deploys BOOLEAN
|
||||
,repo_allow_tags BOOLEAN
|
||||
,repo_hash TEXT
|
||||
,repo_scm TEXT
|
||||
,repo_config_path TEXT
|
||||
,repo_gated BOOLEAN
|
||||
,UNIQUE(repo_full_name)
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-secrets
|
||||
|
||||
CREATE TABLE secrets (
|
||||
secret_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,secret_repo_id INTEGER
|
||||
,secret_name TEXT
|
||||
,secret_value TEXT
|
||||
,secret_images TEXT
|
||||
,secret_events TEXT
|
||||
,secret_skip_verify BOOLEAN
|
||||
,secret_conceal BOOLEAN
|
||||
,UNIQUE(secret_name, secret_repo_id)
|
||||
);
|
||||
|
||||
-- name: create-index-secrets-repo
|
||||
|
||||
CREATE INDEX ix_secrets_repo ON secrets (secret_repo_id);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-registry
|
||||
|
||||
CREATE TABLE registry (
|
||||
registry_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,registry_repo_id INTEGER
|
||||
,registry_addr TEXT
|
||||
,registry_username TEXT
|
||||
,registry_password TEXT
|
||||
,registry_email TEXT
|
||||
,registry_token TEXT
|
||||
|
||||
,UNIQUE(registry_addr, registry_repo_id)
|
||||
);
|
||||
|
||||
-- name: create-index-registry-repo
|
||||
|
||||
CREATE INDEX ix_registry_repo ON registry (registry_repo_id);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-builds
|
||||
|
||||
CREATE TABLE builds (
|
||||
build_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,build_repo_id INTEGER
|
||||
,build_number INTEGER
|
||||
,build_event TEXT
|
||||
,build_status TEXT
|
||||
,build_enqueued INTEGER
|
||||
,build_created INTEGER
|
||||
,build_started INTEGER
|
||||
,build_finished INTEGER
|
||||
,build_commit TEXT
|
||||
,build_branch TEXT
|
||||
,build_ref TEXT
|
||||
,build_refspec TEXT
|
||||
,build_remote TEXT
|
||||
,build_title TEXT
|
||||
,build_message TEXT
|
||||
,build_timestamp INTEGER
|
||||
,build_author TEXT
|
||||
,build_avatar TEXT
|
||||
,build_email TEXT
|
||||
,build_link TEXT
|
||||
,build_deploy TEXT
|
||||
,build_signed BOOLEAN
|
||||
,build_verified BOOLEAN
|
||||
,build_parent INTEGER
|
||||
,build_error TEXT
|
||||
,build_reviewer TEXT
|
||||
,build_reviewed INTEGER
|
||||
,build_sender TEXT
|
||||
,build_config_id INTEGER
|
||||
,UNIQUE(build_number, build_repo_id)
|
||||
);
|
||||
|
||||
-- name: create-index-builds-repo
|
||||
|
||||
CREATE INDEX ix_build_repo ON builds (build_repo_id);
|
||||
|
||||
-- name: create-index-builds-author
|
||||
|
||||
CREATE INDEX ix_build_author ON builds (build_author);
|
||||
|
||||
-- name: create-index-builds-status
|
||||
|
||||
CREATE INDEX ix_build_status_running ON builds (build_status)
|
||||
WHERE build_status IN ('pending', 'running');
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-procs
|
||||
|
||||
CREATE TABLE procs (
|
||||
proc_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,proc_build_id INTEGER
|
||||
,proc_pid INTEGER
|
||||
,proc_ppid INTEGER
|
||||
,proc_pgid INTEGER
|
||||
,proc_name TEXT
|
||||
,proc_state TEXT
|
||||
,proc_error TEXT
|
||||
,proc_exit_code INTEGER
|
||||
,proc_started INTEGER
|
||||
,proc_stopped INTEGER
|
||||
,proc_machine TEXT
|
||||
,proc_platform TEXT
|
||||
,proc_environ TEXT
|
||||
,UNIQUE(proc_build_id, proc_pid)
|
||||
);
|
||||
|
||||
-- name: create-index-procs-build
|
||||
|
||||
CREATE INDEX proc_build_ix ON procs (proc_build_id);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-logs
|
||||
|
||||
CREATE TABLE IF NOT EXISTS logs (
|
||||
log_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,log_job_id INTEGER
|
||||
,log_data BLOB
|
||||
,UNIQUE(log_job_id)
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-files
|
||||
|
||||
CREATE TABLE IF NOT EXISTS files (
|
||||
file_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,file_build_id INTEGER
|
||||
,file_proc_id INTEGER
|
||||
,file_name TEXT
|
||||
,file_mime TEXT
|
||||
,file_size INTEGER
|
||||
,file_time INTEGER
|
||||
,file_data BLOB
|
||||
,UNIQUE(file_proc_id,file_name)
|
||||
,FOREIGN KEY(file_proc_id) REFERENCES procs (proc_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- name: create-index-files-builds
|
||||
|
||||
CREATE INDEX file_build_ix ON files (file_build_id);
|
||||
|
||||
-- name: create-index-files-procs
|
||||
|
||||
CREATE INDEX file_proc_ix ON files (file_proc_id);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-senders
|
||||
|
||||
CREATE TABLE IF NOT EXISTS senders (
|
||||
sender_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,sender_repo_id INTEGER
|
||||
,sender_login BOOLEAN
|
||||
,sender_allow BOOLEAN
|
||||
,sender_block BOOLEAN
|
||||
|
||||
,UNIQUE(sender_repo_id,sender_login)
|
||||
);
|
||||
|
||||
-- name: create-index-sender-repos
|
||||
|
||||
CREATE INDEX sender_repo_ix ON senders (sender_repo_id);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-config
|
||||
|
||||
CREATE TABLE IF NOT EXISTS config (
|
||||
config_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,config_repo_id INTEGER
|
||||
,config_hash TEXT
|
||||
,config_data BLOB
|
||||
|
||||
,UNIQUE(config_hash, config_repo_id)
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-tasks
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
task_id TEXT PRIMARY KEY
|
||||
,task_data BLOB
|
||||
,task_labels BLOB
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- name: create-table-agents
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agents (
|
||||
agent_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,agent_addr TEXT
|
||||
,agent_platform TEXT
|
||||
,agent_capacity INTEGER
|
||||
,agent_created INTEGER
|
||||
,agent_updated INTEGER
|
||||
|
||||
,UNIQUE(agent_addr)
|
||||
);
|
50
store/datastore/perms.go
Normal file
50
store/datastore/perms.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/store/datastore/sql"
|
||||
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
func (db *datastore) PermFind(user *model.User, repo *model.Repo) (*model.Perm, error) {
|
||||
stmt := sql.Lookup(db.driver, "perms-find-user-repo")
|
||||
data := new(model.Perm)
|
||||
err := meddler.QueryRow(db, data, stmt, user.ID, repo.ID)
|
||||
return data, err
|
||||
}
|
||||
|
||||
func (db *datastore) PermUpsert(perm *model.Perm) error {
|
||||
stmt := sql.Lookup(db.driver, "perms-insert-replace-lookup")
|
||||
_, err := db.Exec(stmt,
|
||||
perm.UserID,
|
||||
perm.Repo,
|
||||
perm.Pull,
|
||||
perm.Push,
|
||||
perm.Admin,
|
||||
perm.Synced,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *datastore) PermBatch(perms []*model.Perm) (err error) {
|
||||
for _, perm := range perms {
|
||||
err = db.PermUpsert(perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *datastore) PermDelete(perm *model.Perm) error {
|
||||
stmt := sql.Lookup(db.driver, "perms-delete-user-repo")
|
||||
_, err := db.Exec(stmt, perm.UserID, perm.RepoID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *datastore) PermFlush(user *model.User, before int64) error {
|
||||
stmt := sql.Lookup(db.driver, "perms-delete-user-date")
|
||||
_, err := db.Exec(stmt, user.ID, before)
|
||||
return err
|
||||
}
|
187
store/datastore/perms_test.go
Normal file
187
store/datastore/perms_test.go
Normal file
|
@ -0,0 +1,187 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
)
|
||||
|
||||
func TestPermFind(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
s.Exec("delete from perms")
|
||||
s.Exec("delete from repos")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
user := &model.User{ID: 1}
|
||||
repo := &model.Repo{
|
||||
UserID: 1,
|
||||
FullName: "bradrydzewski/drone",
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
}
|
||||
s.CreateRepo(repo)
|
||||
|
||||
err := s.PermUpsert(
|
||||
&model.Perm{
|
||||
UserID: user.ID,
|
||||
RepoID: repo.ID,
|
||||
Repo: repo.FullName,
|
||||
Pull: true,
|
||||
Push: false,
|
||||
Admin: false,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
perm, err := s.PermFind(user, repo)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if got, want := perm.Pull, true; got != want {
|
||||
t.Errorf("Wanted pull %v, got %v", want, got)
|
||||
}
|
||||
if got, want := perm.Push, false; got != want {
|
||||
t.Errorf("Wanted push %v, got %v", want, got)
|
||||
}
|
||||
if got, want := perm.Admin, false; got != want {
|
||||
t.Errorf("Wanted admin %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermUpsert(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
s.Exec("delete from perms")
|
||||
s.Exec("delete from repos")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
user := &model.User{ID: 1}
|
||||
repo := &model.Repo{
|
||||
UserID: 1,
|
||||
FullName: "bradrydzewski/drone",
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
}
|
||||
s.CreateRepo(repo)
|
||||
|
||||
err := s.PermUpsert(
|
||||
&model.Perm{
|
||||
UserID: user.ID,
|
||||
RepoID: repo.ID,
|
||||
Repo: repo.FullName,
|
||||
Pull: true,
|
||||
Push: false,
|
||||
Admin: false,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
perm, err := s.PermFind(user, repo)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if got, want := perm.Pull, true; got != want {
|
||||
t.Errorf("Wanted pull %v, got %v", want, got)
|
||||
}
|
||||
if got, want := perm.Push, false; got != want {
|
||||
t.Errorf("Wanted push %v, got %v", want, got)
|
||||
}
|
||||
if got, want := perm.Admin, false; got != want {
|
||||
t.Errorf("Wanted admin %v, got %v", want, got)
|
||||
}
|
||||
|
||||
//
|
||||
// this will attempt to replace the existing permissions
|
||||
// using the insert or replace logic.
|
||||
//
|
||||
|
||||
err = s.PermUpsert(
|
||||
&model.Perm{
|
||||
UserID: user.ID,
|
||||
RepoID: repo.ID,
|
||||
Repo: repo.FullName,
|
||||
Pull: true,
|
||||
Push: true,
|
||||
Admin: true,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
perm, err = s.PermFind(user, repo)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if got, want := perm.Pull, true; got != want {
|
||||
t.Errorf("Wanted pull %v, got %v", want, got)
|
||||
}
|
||||
if got, want := perm.Push, true; got != want {
|
||||
t.Errorf("Wanted push %v, got %v", want, got)
|
||||
}
|
||||
if got, want := perm.Admin, true; got != want {
|
||||
t.Errorf("Wanted admin %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermDelete(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
s.Exec("delete from perms")
|
||||
s.Exec("delete from repos")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
user := &model.User{ID: 1}
|
||||
repo := &model.Repo{
|
||||
UserID: 1,
|
||||
FullName: "bradrydzewski/drone",
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
}
|
||||
s.CreateRepo(repo)
|
||||
|
||||
err := s.PermUpsert(
|
||||
&model.Perm{
|
||||
UserID: user.ID,
|
||||
RepoID: repo.ID,
|
||||
Repo: repo.FullName,
|
||||
Pull: true,
|
||||
Push: false,
|
||||
Admin: false,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: insert perm: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
perm, err := s.PermFind(user, repo)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: select perm: %s", err)
|
||||
return
|
||||
}
|
||||
err = s.PermDelete(perm)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: delete perm: %s", err)
|
||||
return
|
||||
}
|
||||
_, err = s.PermFind(user, repo)
|
||||
if err == nil {
|
||||
t.Errorf("Expect error: sql.ErrNoRows")
|
||||
return
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/store/datastore/sql"
|
||||
"github.com/russross/meddler"
|
||||
|
@ -20,25 +18,6 @@ func (db *datastore) GetRepoName(name string) (*model.Repo, error) {
|
|||
return repo, err
|
||||
}
|
||||
|
||||
func (db *datastore) GetRepoListOf(listof []*model.RepoLite) ([]*model.Repo, error) {
|
||||
var (
|
||||
repos []*model.Repo
|
||||
args []interface{}
|
||||
stmt string
|
||||
err error
|
||||
)
|
||||
switch meddler.Default {
|
||||
case meddler.PostgreSQL:
|
||||
stmt, args = toListPostgres(listof)
|
||||
default:
|
||||
stmt, args = toList(listof)
|
||||
}
|
||||
if len(args) > 0 {
|
||||
err = meddler.QueryAll(db, &repos, fmt.Sprintf(repoListOfQuery, stmt), args...)
|
||||
}
|
||||
return repos, err
|
||||
}
|
||||
|
||||
func (db *datastore) GetRepoCount() (count int, err error) {
|
||||
err = db.QueryRow(
|
||||
sql.Lookup(db.driver, "count-repos"),
|
||||
|
@ -55,10 +34,59 @@ func (db *datastore) UpdateRepo(repo *model.Repo) error {
|
|||
}
|
||||
|
||||
func (db *datastore) DeleteRepo(repo *model.Repo) error {
|
||||
var _, err = db.Exec(rebind(repoDeleteStmt), repo.ID)
|
||||
stmt := sql.Lookup(db.driver, "repo-delete")
|
||||
_, err := db.Exec(stmt, repo.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *datastore) RepoList(user *model.User) ([]*model.Repo, error) {
|
||||
stmt := sql.Lookup(db.driver, "repo-find-user")
|
||||
data := []*model.Repo{}
|
||||
err := meddler.QueryAll(db, &data, stmt, user.ID)
|
||||
return data, err
|
||||
}
|
||||
|
||||
func (db *datastore) RepoListLatest(user *model.User) ([]*model.Feed, error) {
|
||||
stmt := sql.Lookup(db.driver, "feed-latest-build")
|
||||
data := []*model.Feed{}
|
||||
err := meddler.QueryAll(db, &data, stmt, user.ID)
|
||||
return data, err
|
||||
}
|
||||
|
||||
func (db *datastore) RepoBatch(repos []*model.Repo) error {
|
||||
stmt := sql.Lookup(db.driver, "repo-insert-ignore")
|
||||
for _, repo := range repos {
|
||||
_, err := db.Exec(stmt,
|
||||
repo.UserID,
|
||||
repo.Owner,
|
||||
repo.Name,
|
||||
repo.FullName,
|
||||
repo.Avatar,
|
||||
repo.Link,
|
||||
repo.Clone,
|
||||
repo.Branch,
|
||||
repo.Timeout,
|
||||
repo.IsPrivate,
|
||||
repo.IsTrusted,
|
||||
repo.IsActive,
|
||||
repo.AllowPull,
|
||||
repo.AllowPush,
|
||||
repo.AllowDeploy,
|
||||
repo.AllowTag,
|
||||
repo.Hash,
|
||||
repo.Kind,
|
||||
repo.Config,
|
||||
repo.IsGated,
|
||||
repo.Visibility,
|
||||
repo.Counter,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const repoTable = "repos"
|
||||
|
||||
const repoNameQuery = `
|
||||
|
@ -68,17 +96,6 @@ WHERE repo_full_name = ?
|
|||
LIMIT 1;
|
||||
`
|
||||
|
||||
const repoListOfQuery = `
|
||||
SELECT *
|
||||
FROM repos
|
||||
WHERE repo_full_name IN (%s)
|
||||
ORDER BY repo_name
|
||||
`
|
||||
|
||||
const repoCountQuery = `
|
||||
SELECT COUNT(*) FROM repos
|
||||
`
|
||||
|
||||
const repoDeleteStmt = `
|
||||
DELETE FROM repos
|
||||
WHERE repo_id = ?
|
||||
|
|
|
@ -84,76 +84,6 @@ func TestRepos(t *testing.T) {
|
|||
g.Assert(repo.Name).Equal(getrepo.Name)
|
||||
})
|
||||
|
||||
g.It("Should Get a Repo List", func() {
|
||||
repo1 := &model.Repo{
|
||||
UserID: 1,
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
FullName: "bradrydzewski/drone",
|
||||
}
|
||||
repo2 := &model.Repo{
|
||||
UserID: 2,
|
||||
Owner: "drone",
|
||||
Name: "drone",
|
||||
FullName: "drone/drone",
|
||||
}
|
||||
repo3 := &model.Repo{
|
||||
UserID: 2,
|
||||
Owner: "octocat",
|
||||
Name: "hello-world",
|
||||
FullName: "octocat/hello-world",
|
||||
}
|
||||
s.CreateRepo(repo1)
|
||||
s.CreateRepo(repo2)
|
||||
s.CreateRepo(repo3)
|
||||
|
||||
repos, err := s.GetRepoListOf([]*model.RepoLite{
|
||||
{FullName: "bradrydzewski/drone"},
|
||||
{FullName: "drone/drone"},
|
||||
})
|
||||
g.Assert(err == nil).IsTrue()
|
||||
g.Assert(len(repos)).Equal(2)
|
||||
g.Assert(repos[0].ID).Equal(repo1.ID)
|
||||
g.Assert(repos[1].ID).Equal(repo2.ID)
|
||||
})
|
||||
|
||||
g.It("Should Get a Repo List", func() {
|
||||
repo1 := &model.Repo{
|
||||
UserID: 1,
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
FullName: "bradrydzewski/drone",
|
||||
}
|
||||
repo2 := &model.Repo{
|
||||
UserID: 2,
|
||||
Owner: "drone",
|
||||
Name: "drone",
|
||||
FullName: "drone/drone",
|
||||
}
|
||||
s.CreateRepo(repo1)
|
||||
s.CreateRepo(repo2)
|
||||
|
||||
count, err := s.GetRepoCount()
|
||||
g.Assert(err == nil).IsTrue()
|
||||
g.Assert(count).Equal(2)
|
||||
})
|
||||
|
||||
g.It("Should Delete a Repo", func() {
|
||||
repo := model.Repo{
|
||||
UserID: 1,
|
||||
FullName: "bradrydzewski/drone",
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
}
|
||||
s.CreateRepo(&repo)
|
||||
_, err1 := s.GetRepo(repo.ID)
|
||||
err2 := s.DeleteRepo(&repo)
|
||||
_, err3 := s.GetRepo(repo.ID)
|
||||
g.Assert(err1 == nil).IsTrue()
|
||||
g.Assert(err2 == nil).IsTrue()
|
||||
g.Assert(err3 == nil).IsFalse()
|
||||
})
|
||||
|
||||
g.It("Should Enforce Unique Repo Name", func() {
|
||||
repo1 := model.Repo{
|
||||
UserID: 1,
|
||||
|
@ -174,3 +104,263 @@ func TestRepos(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestRepoList(t *testing.T) {
|
||||
s := newTest()
|
||||
s.Exec("delete from repos")
|
||||
s.Exec("delete from users")
|
||||
s.Exec("delete from perms")
|
||||
|
||||
defer func() {
|
||||
s.Exec("delete from repos")
|
||||
s.Exec("delete from users")
|
||||
s.Exec("delete from perms")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
user := &model.User{
|
||||
Login: "joe",
|
||||
Email: "foo@bar.com",
|
||||
Token: "e42080dddf012c718e476da161d21ad5",
|
||||
}
|
||||
s.CreateUser(user)
|
||||
|
||||
repo1 := &model.Repo{
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
FullName: "bradrydzewski/drone",
|
||||
}
|
||||
repo2 := &model.Repo{
|
||||
Owner: "drone",
|
||||
Name: "drone",
|
||||
FullName: "drone/drone",
|
||||
}
|
||||
repo3 := &model.Repo{
|
||||
Owner: "octocat",
|
||||
Name: "hello-world",
|
||||
FullName: "octocat/hello-world",
|
||||
}
|
||||
s.CreateRepo(repo1)
|
||||
s.CreateRepo(repo2)
|
||||
s.CreateRepo(repo3)
|
||||
|
||||
s.PermBatch([]*model.Perm{
|
||||
{UserID: user.ID, Repo: repo1.FullName},
|
||||
{UserID: user.ID, Repo: repo2.FullName},
|
||||
})
|
||||
|
||||
repos, err := s.RepoList(user)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if got, want := len(repos), 2; got != want {
|
||||
t.Errorf("Want %d repositories, got %d", want, got)
|
||||
}
|
||||
if got, want := repos[0].ID, repo1.ID; got != want {
|
||||
t.Errorf("Want repository id %d, got %d", want, got)
|
||||
}
|
||||
if got, want := repos[1].ID, repo2.ID; got != want {
|
||||
t.Errorf("Want repository id %d, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoListLatest(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
s.Exec("delete from repos")
|
||||
s.Exec("delete from users")
|
||||
s.Exec("delete from perms")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
user := &model.User{
|
||||
Login: "joe",
|
||||
Email: "foo@bar.com",
|
||||
Token: "e42080dddf012c718e476da161d21ad5",
|
||||
}
|
||||
s.CreateUser(user)
|
||||
|
||||
repo1 := &model.Repo{
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
FullName: "bradrydzewski/drone",
|
||||
IsActive: true,
|
||||
}
|
||||
repo2 := &model.Repo{
|
||||
Owner: "drone",
|
||||
Name: "drone",
|
||||
FullName: "drone/drone",
|
||||
IsActive: true,
|
||||
}
|
||||
repo3 := &model.Repo{
|
||||
Owner: "octocat",
|
||||
Name: "hello-world",
|
||||
FullName: "octocat/hello-world",
|
||||
IsActive: true,
|
||||
}
|
||||
s.CreateRepo(repo1)
|
||||
s.CreateRepo(repo2)
|
||||
s.CreateRepo(repo3)
|
||||
|
||||
s.PermBatch([]*model.Perm{
|
||||
{UserID: user.ID, Repo: repo1.FullName},
|
||||
{UserID: user.ID, Repo: repo2.FullName},
|
||||
})
|
||||
|
||||
build1 := &model.Build{
|
||||
RepoID: repo1.ID,
|
||||
Status: model.StatusFailure,
|
||||
}
|
||||
build2 := &model.Build{
|
||||
RepoID: repo1.ID,
|
||||
Status: model.StatusRunning,
|
||||
}
|
||||
build3 := &model.Build{
|
||||
RepoID: repo2.ID,
|
||||
Status: model.StatusKilled,
|
||||
}
|
||||
build4 := &model.Build{
|
||||
RepoID: repo3.ID,
|
||||
Status: model.StatusError,
|
||||
}
|
||||
s.CreateBuild(build1)
|
||||
s.CreateBuild(build2)
|
||||
s.CreateBuild(build3)
|
||||
s.CreateBuild(build4)
|
||||
|
||||
builds, err := s.RepoListLatest(user)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: repository list with latest build: %s", err)
|
||||
return
|
||||
}
|
||||
if got, want := len(builds), 2; got != want {
|
||||
t.Errorf("Want %d repositories, got %d", want, got)
|
||||
}
|
||||
if got, want := builds[0].Status, model.StatusRunning; want != got {
|
||||
t.Errorf("Want repository status %s, got %s", want, got)
|
||||
}
|
||||
if got, want := builds[0].FullName, repo1.FullName; want != got {
|
||||
t.Errorf("Want repository name %s, got %s", want, got)
|
||||
}
|
||||
if got, want := builds[1].Status, model.StatusKilled; want != got {
|
||||
t.Errorf("Want repository status %s, got %s", want, got)
|
||||
}
|
||||
if got, want := builds[1].FullName, repo2.FullName; want != got {
|
||||
t.Errorf("Want repository name %s, got %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoCount(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
s.Exec("delete from repos")
|
||||
s.Exec("delete from users")
|
||||
s.Exec("delete from perms")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
repo1 := &model.Repo{
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
FullName: "bradrydzewski/drone",
|
||||
}
|
||||
repo2 := &model.Repo{
|
||||
Owner: "drone",
|
||||
Name: "drone",
|
||||
FullName: "drone/drone",
|
||||
}
|
||||
s.CreateRepo(repo1)
|
||||
s.CreateRepo(repo2)
|
||||
|
||||
s.Exec("ANALYZE")
|
||||
count, _ := s.GetRepoCount()
|
||||
if got, want := count, 2; got != want {
|
||||
t.Errorf("Want %d repositories, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoBatch(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
s.Exec("delete from repos")
|
||||
s.Exec("delete from users")
|
||||
s.Exec("delete from perms")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
repo := &model.Repo{
|
||||
UserID: 1,
|
||||
FullName: "foo/bar",
|
||||
Owner: "foo",
|
||||
Name: "bar",
|
||||
}
|
||||
err := s.CreateRepo(repo)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = s.RepoBatch(
|
||||
[]*model.Repo{
|
||||
{
|
||||
UserID: 1,
|
||||
FullName: "foo/bar",
|
||||
Owner: "foo",
|
||||
Name: "bar",
|
||||
},
|
||||
{
|
||||
UserID: 1,
|
||||
FullName: "bar/baz",
|
||||
Owner: "bar",
|
||||
Name: "baz",
|
||||
},
|
||||
{
|
||||
UserID: 1,
|
||||
FullName: "baz/qux",
|
||||
Owner: "baz",
|
||||
Name: "qux",
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
s.Exec("ANALYZE")
|
||||
count, _ := s.GetRepoCount()
|
||||
if got, want := count, 3; got != want {
|
||||
t.Errorf("Want %d repositories, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoCrud(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
s.Exec("delete from repos")
|
||||
s.Exec("delete from users")
|
||||
s.Exec("delete from perms")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
repo := model.Repo{
|
||||
UserID: 1,
|
||||
FullName: "bradrydzewski/drone",
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
}
|
||||
s.CreateRepo(&repo)
|
||||
_, err1 := s.GetRepo(repo.ID)
|
||||
err2 := s.DeleteRepo(&repo)
|
||||
_, err3 := s.GetRepo(repo.ID)
|
||||
if err1 != nil {
|
||||
t.Errorf("Unexpected error: select repository: %s", err1)
|
||||
}
|
||||
if err2 != nil {
|
||||
t.Errorf("Unexpected error: delete repository: %s", err2)
|
||||
}
|
||||
if err3 == nil {
|
||||
t.Errorf("Expected error: sql.ErrNoRows")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ func TestSecretList(t *testing.T) {
|
|||
return
|
||||
}
|
||||
if got, want := len(list), 2; got != want {
|
||||
t.Errorf("Want %d registries, got %d", want, got)
|
||||
t.Errorf("Want %d secrets, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,6 +112,34 @@ func TestSecretUpdate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSecretDelete(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
s.Exec("delete from secrets")
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
secret := &model.Secret{
|
||||
RepoID: 1,
|
||||
Name: "foo",
|
||||
Value: "baz",
|
||||
}
|
||||
if err := s.SecretCreate(secret); err != nil {
|
||||
t.Errorf("Unexpected error: insert secret: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.SecretDelete(secret); err != nil {
|
||||
t.Errorf("Unexpected error: delete secret: %s", err)
|
||||
return
|
||||
}
|
||||
_, err := s.SecretFind(&model.Repo{ID: 1}, "foo")
|
||||
if err == nil {
|
||||
t.Errorf("Expect error: sql.ErrNoRows")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecretIndexes(t *testing.T) {
|
||||
s := newTest()
|
||||
defer func() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/store/datastore/sql/mysql"
|
||||
"github.com/drone/drone/store/datastore/sql/postgres"
|
||||
"github.com/drone/drone/store/datastore/sql/sqlite"
|
||||
)
|
||||
|
@ -18,6 +19,8 @@ func Lookup(driver string, name string) string {
|
|||
switch driver {
|
||||
case DriverPostgres:
|
||||
return postgres.Lookup(name)
|
||||
case DriverMysql:
|
||||
return mysql.Lookup(name)
|
||||
default:
|
||||
return sqlite.Lookup(name)
|
||||
}
|
||||
|
|
28
store/datastore/sql/mysql/files/config.sql
Normal file
28
store/datastore/sql/mysql/files/config.sql
Normal file
|
@ -0,0 +1,28 @@
|
|||
-- name: config-find-id
|
||||
|
||||
SELECT
|
||||
config_id
|
||||
,config_repo_id
|
||||
,config_hash
|
||||
,config_data
|
||||
FROM config
|
||||
WHERE config_id = ?
|
||||
|
||||
-- name: config-find-repo-hash
|
||||
|
||||
SELECT
|
||||
config_id
|
||||
,config_repo_id
|
||||
,config_hash
|
||||
,config_data
|
||||
FROM config
|
||||
WHERE config_repo_id = ?
|
||||
AND config_hash = ?
|
||||
|
||||
-- name: config-find-approved
|
||||
|
||||
SELECT build_id FROM builds
|
||||
WHERE build_repo_id = ?
|
||||
AND build_config_id = ?
|
||||
AND build_status NOT IN ('blocked', 'pending')
|
||||
LIMIT 1
|
14
store/datastore/sql/mysql/files/counts.sql
Normal file
14
store/datastore/sql/mysql/files/counts.sql
Normal file
|
@ -0,0 +1,14 @@
|
|||
-- name: count-users
|
||||
|
||||
SELECT count(1)
|
||||
FROM users
|
||||
|
||||
-- name: count-repos
|
||||
|
||||
SELECT count(1)
|
||||
FROM repos
|
||||
|
||||
-- name: count-builds
|
||||
|
||||
SELECT count(1)
|
||||
FROM builds
|
61
store/datastore/sql/mysql/files/feed.sql
Normal file
61
store/datastore/sql/mysql/files/feed.sql
Normal file
|
@ -0,0 +1,61 @@
|
|||
-- name: feed-latest-build
|
||||
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos LEFT OUTER JOIN builds ON build_id = (
|
||||
SELECT build_id FROM builds
|
||||
WHERE builds.build_repo_id = repos.repo_id
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
AND repos.repo_active = true
|
||||
ORDER BY repo_full_name ASC;
|
||||
|
||||
-- name: feed
|
||||
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
INNER JOIN builds ON builds.build_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 50
|
45
store/datastore/sql/mysql/files/files.sql
Normal file
45
store/datastore/sql/mysql/files/files.sql
Normal file
|
@ -0,0 +1,45 @@
|
|||
-- name: files-find-build
|
||||
|
||||
SELECT
|
||||
file_id
|
||||
,file_build_id
|
||||
,file_proc_id
|
||||
,file_name
|
||||
,file_mime
|
||||
,file_size
|
||||
,file_time
|
||||
FROM files
|
||||
WHERE file_build_id = ?
|
||||
|
||||
-- name: files-find-proc-name
|
||||
|
||||
SELECT
|
||||
file_id
|
||||
,file_build_id
|
||||
,file_proc_id
|
||||
,file_name
|
||||
,file_mime
|
||||
,file_size
|
||||
,file_time
|
||||
FROM files
|
||||
WHERE file_proc_id = ?
|
||||
AND file_name = ?
|
||||
|
||||
-- name: files-find-proc-name-data
|
||||
|
||||
SELECT
|
||||
file_id
|
||||
,file_build_id
|
||||
,file_proc_id
|
||||
,file_name
|
||||
,file_mime
|
||||
,file_size
|
||||
,file_time
|
||||
,file_data
|
||||
FROM files
|
||||
WHERE file_proc_id = ?
|
||||
AND file_name = ?
|
||||
|
||||
-- name: files-delete-build
|
||||
|
||||
DELETE FROM files WHERE file_build_id = ?
|
58
store/datastore/sql/mysql/files/perms.sql
Normal file
58
store/datastore/sql/mysql/files/perms.sql
Normal file
|
@ -0,0 +1,58 @@
|
|||
-- name: perms-find-user
|
||||
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_date
|
||||
FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
|
||||
-- name: perms-find-user-repo
|
||||
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_repo_id = ?
|
||||
|
||||
-- name: perms-insert-replace
|
||||
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES (?,?,?,?,?,?)
|
||||
|
||||
-- name: perms-insert-replace-lookup
|
||||
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES (?,(SELECT repo_id FROM repos WHERE repo_full_name = ?),?,?,?,?)
|
||||
|
||||
-- name: perms-delete-user-repo
|
||||
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_repo_id = ?
|
||||
|
||||
-- name: perms-delete-user-date
|
||||
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_synced < ?
|
87
store/datastore/sql/mysql/files/procs.sql
Normal file
87
store/datastore/sql/mysql/files/procs.sql
Normal file
|
@ -0,0 +1,87 @@
|
|||
-- name: procs-find-id
|
||||
|
||||
SELECT
|
||||
proc_id
|
||||
,proc_build_id
|
||||
,proc_pid
|
||||
,proc_ppid
|
||||
,proc_pgid
|
||||
,proc_name
|
||||
,proc_state
|
||||
,proc_error
|
||||
,proc_exit_code
|
||||
,proc_started
|
||||
,proc_stopped
|
||||
,proc_machine
|
||||
,proc_platform
|
||||
,proc_environ
|
||||
FROM procs
|
||||
WHERE proc_id = ?
|
||||
|
||||
-- name: procs-find-build
|
||||
|
||||
SELECT
|
||||
proc_id
|
||||
,proc_build_id
|
||||
,proc_pid
|
||||
,proc_ppid
|
||||
,proc_pgid
|
||||
,proc_name
|
||||
,proc_state
|
||||
,proc_error
|
||||
,proc_exit_code
|
||||
,proc_started
|
||||
,proc_stopped
|
||||
,proc_machine
|
||||
,proc_platform
|
||||
,proc_environ
|
||||
FROM procs
|
||||
WHERE proc_build_id = ?
|
||||
ORDER BY proc_id ASC
|
||||
|
||||
-- name: procs-find-build-pid
|
||||
|
||||
SELECT
|
||||
proc_id
|
||||
,proc_build_id
|
||||
,proc_pid
|
||||
,proc_ppid
|
||||
,proc_pgid
|
||||
,proc_name
|
||||
,proc_state
|
||||
,proc_error
|
||||
,proc_exit_code
|
||||
,proc_started
|
||||
,proc_stopped
|
||||
,proc_machine
|
||||
,proc_platform
|
||||
,proc_environ
|
||||
FROM procs
|
||||
WHERE proc_build_id = ?
|
||||
AND proc_pid = ?
|
||||
|
||||
-- name: procs-find-build-ppid
|
||||
|
||||
SELECT
|
||||
proc_id
|
||||
,proc_build_id
|
||||
,proc_pid
|
||||
,proc_ppid
|
||||
,proc_pgid
|
||||
,proc_name
|
||||
,proc_state
|
||||
,proc_error
|
||||
,proc_exit_code
|
||||
,proc_started
|
||||
,proc_stopped
|
||||
,proc_machine
|
||||
,proc_platform
|
||||
,proc_environ
|
||||
FROM procs
|
||||
WHERE proc_build_id = ?
|
||||
AND proc_ppid = ?
|
||||
AND proc_name = ?
|
||||
|
||||
-- name: procs-delete-build
|
||||
|
||||
DELETE FROM procs WHERE proc_build_id = ?
|
34
store/datastore/sql/mysql/files/registry.sql
Normal file
34
store/datastore/sql/mysql/files/registry.sql
Normal file
|
@ -0,0 +1,34 @@
|
|||
-- name: registry-find-repo
|
||||
|
||||
SELECT
|
||||
registry_id
|
||||
,registry_repo_id
|
||||
,registry_addr
|
||||
,registry_username
|
||||
,registry_password
|
||||
,registry_email
|
||||
,registry_token
|
||||
FROM registry
|
||||
WHERE registry_repo_id = ?
|
||||
|
||||
-- name: registry-find-repo-addr
|
||||
|
||||
SELECT
|
||||
registry_id
|
||||
,registry_repo_id
|
||||
,registry_addr
|
||||
,registry_username
|
||||
,registry_password
|
||||
,registry_email
|
||||
,registry_token
|
||||
FROM registry
|
||||
WHERE registry_repo_id = ?
|
||||
AND registry_addr = ?
|
||||
|
||||
-- name: registry-delete-repo
|
||||
|
||||
DELETE FROM registry WHERE registry_repo_id = ?
|
||||
|
||||
-- name: registry-delete
|
||||
|
||||
DELETE FROM registry WHERE registry_id = ?
|
67
store/datastore/sql/mysql/files/repos.sql
Normal file
67
store/datastore/sql/mysql/files/repos.sql
Normal file
|
@ -0,0 +1,67 @@
|
|||
-- name: repo-update-counter
|
||||
|
||||
UPDATE repos SET repo_counter = ?
|
||||
WHERE repo_counter = ?
|
||||
AND repo_id = ?
|
||||
|
||||
-- name: repo-find-user
|
||||
|
||||
SELECT
|
||||
repo_id
|
||||
,repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
ORDER BY repo_full_name ASC
|
||||
|
||||
-- name: repo-insert-ignore
|
||||
|
||||
INSERT IGNORE INTO repos (
|
||||
repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
-- name: repo-delete
|
||||
|
||||
DELETE FROM repos WHERE repo_id = ?
|
32
store/datastore/sql/mysql/files/secret.sql
Normal file
32
store/datastore/sql/mysql/files/secret.sql
Normal file
|
@ -0,0 +1,32 @@
|
|||
-- name: secret-find-repo
|
||||
|
||||
SELECT
|
||||
secret_id
|
||||
,secret_repo_id
|
||||
,secret_name
|
||||
,secret_value
|
||||
,secret_images
|
||||
,secret_events
|
||||
,secret_conceal
|
||||
,secret_skip_verify
|
||||
FROM secrets
|
||||
WHERE secret_repo_id = ?
|
||||
|
||||
-- name: secret-find-repo-name
|
||||
|
||||
SELECT
|
||||
secret_id
|
||||
,secret_repo_id
|
||||
,secret_name
|
||||
,secret_value
|
||||
,secret_images
|
||||
,secret_events
|
||||
,secret_conceal
|
||||
,secret_skip_verify
|
||||
FROM secrets
|
||||
WHERE secret_repo_id = ?
|
||||
AND secret_name = ?
|
||||
|
||||
-- name: secret-delete
|
||||
|
||||
DELETE FROM secrets WHERE secret_id = ?
|
30
store/datastore/sql/mysql/files/sender.sql
Normal file
30
store/datastore/sql/mysql/files/sender.sql
Normal file
|
@ -0,0 +1,30 @@
|
|||
-- name: sender-find-repo
|
||||
|
||||
SELECT
|
||||
sender_id
|
||||
,sender_repo_id
|
||||
,sender_login
|
||||
,sender_allow
|
||||
,sender_block
|
||||
FROM senders
|
||||
WHERE sender_repo_id = ?
|
||||
|
||||
-- name: sender-find-repo-login
|
||||
|
||||
SELECT
|
||||
sender_id
|
||||
,sender_repo_id
|
||||
,sender_login
|
||||
,sender_allow
|
||||
,sender_block
|
||||
FROM senders
|
||||
WHERE sender_repo_id = ?
|
||||
AND sender_login = ?
|
||||
|
||||
-- name: sender-delete-repo
|
||||
|
||||
DELETE FROM senders WHERE sender_repo_id = ?
|
||||
|
||||
-- name: sender-delete
|
||||
|
||||
DELETE FROM senders WHERE sender_id = ?
|
11
store/datastore/sql/mysql/files/task.sql
Normal file
11
store/datastore/sql/mysql/files/task.sql
Normal file
|
@ -0,0 +1,11 @@
|
|||
-- name: task-list
|
||||
|
||||
SELECT
|
||||
task_id
|
||||
,task_data
|
||||
,task_labels
|
||||
FROM tasks
|
||||
|
||||
-- name: task-delete
|
||||
|
||||
DELETE FROM tasks WHERE task_id = ?
|
3
store/datastore/sql/mysql/sql.go
Normal file
3
store/datastore/sql/mysql/sql.go
Normal file
|
@ -0,0 +1,3 @@
|
|||
package mysql
|
||||
|
||||
//go:generate togo sql --package=mysql
|
527
store/datastore/sql/mysql/sql_gen.go
Normal file
527
store/datastore/sql/mysql/sql_gen.go
Normal file
|
@ -0,0 +1,527 @@
|
|||
package mysql
|
||||
|
||||
// Lookup returns the named statement.
|
||||
func Lookup(name string) string {
|
||||
return index[name]
|
||||
}
|
||||
|
||||
var index = map[string]string{
|
||||
"config-find-id": configFindId,
|
||||
"config-find-repo-hash": configFindRepoHash,
|
||||
"config-find-approved": configFindApproved,
|
||||
"count-users": countUsers,
|
||||
"count-repos": countRepos,
|
||||
"count-builds": countBuilds,
|
||||
"feed-latest-build": feedLatestBuild,
|
||||
"feed": feed,
|
||||
"files-find-build": filesFindBuild,
|
||||
"files-find-proc-name": filesFindProcName,
|
||||
"files-find-proc-name-data": filesFindProcNameData,
|
||||
"files-delete-build": filesDeleteBuild,
|
||||
"perms-find-user": permsFindUser,
|
||||
"perms-find-user-repo": permsFindUserRepo,
|
||||
"perms-insert-replace": permsInsertReplace,
|
||||
"perms-insert-replace-lookup": permsInsertReplaceLookup,
|
||||
"perms-delete-user-repo": permsDeleteUserRepo,
|
||||
"perms-delete-user-date": permsDeleteUserDate,
|
||||
"procs-find-id": procsFindId,
|
||||
"procs-find-build": procsFindBuild,
|
||||
"procs-find-build-pid": procsFindBuildPid,
|
||||
"procs-find-build-ppid": procsFindBuildPpid,
|
||||
"procs-delete-build": procsDeleteBuild,
|
||||
"registry-find-repo": registryFindRepo,
|
||||
"registry-find-repo-addr": registryFindRepoAddr,
|
||||
"registry-delete-repo": registryDeleteRepo,
|
||||
"registry-delete": registryDelete,
|
||||
"repo-update-counter": repoUpdateCounter,
|
||||
"repo-find-user": repoFindUser,
|
||||
"repo-insert-ignore": repoInsertIgnore,
|
||||
"repo-delete": repoDelete,
|
||||
"secret-find-repo": secretFindRepo,
|
||||
"secret-find-repo-name": secretFindRepoName,
|
||||
"secret-delete": secretDelete,
|
||||
"sender-find-repo": senderFindRepo,
|
||||
"sender-find-repo-login": senderFindRepoLogin,
|
||||
"sender-delete-repo": senderDeleteRepo,
|
||||
"sender-delete": senderDelete,
|
||||
"task-list": taskList,
|
||||
"task-delete": taskDelete,
|
||||
}
|
||||
|
||||
var configFindId = `
|
||||
SELECT
|
||||
config_id
|
||||
,config_repo_id
|
||||
,config_hash
|
||||
,config_data
|
||||
FROM config
|
||||
WHERE config_id = ?
|
||||
`
|
||||
|
||||
var configFindRepoHash = `
|
||||
SELECT
|
||||
config_id
|
||||
,config_repo_id
|
||||
,config_hash
|
||||
,config_data
|
||||
FROM config
|
||||
WHERE config_repo_id = ?
|
||||
AND config_hash = ?
|
||||
`
|
||||
|
||||
var configFindApproved = `
|
||||
SELECT build_id FROM builds
|
||||
WHERE build_repo_id = ?
|
||||
AND build_config_id = ?
|
||||
AND build_status NOT IN ('blocked', 'pending')
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
var countUsers = `
|
||||
SELECT count(1)
|
||||
FROM users
|
||||
`
|
||||
|
||||
var countRepos = `
|
||||
SELECT count(1)
|
||||
FROM repos
|
||||
`
|
||||
|
||||
var countBuilds = `
|
||||
SELECT count(1)
|
||||
FROM builds
|
||||
`
|
||||
|
||||
var feedLatestBuild = `
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos LEFT OUTER JOIN builds ON build_id = (
|
||||
SELECT build_id FROM builds
|
||||
WHERE builds.build_repo_id = repos.repo_id
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
AND repos.repo_active = true
|
||||
ORDER BY repo_full_name ASC;
|
||||
`
|
||||
|
||||
var feed = `
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
INNER JOIN builds ON builds.build_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 50
|
||||
`
|
||||
|
||||
var filesFindBuild = `
|
||||
SELECT
|
||||
file_id
|
||||
,file_build_id
|
||||
,file_proc_id
|
||||
,file_name
|
||||
,file_mime
|
||||
,file_size
|
||||
,file_time
|
||||
FROM files
|
||||
WHERE file_build_id = ?
|
||||
`
|
||||
|
||||
var filesFindProcName = `
|
||||
SELECT
|
||||
file_id
|
||||
,file_build_id
|
||||
,file_proc_id
|
||||
,file_name
|
||||
,file_mime
|
||||
,file_size
|
||||
,file_time
|
||||
FROM files
|
||||
WHERE file_proc_id = ?
|
||||
AND file_name = ?
|
||||
`
|
||||
|
||||
var filesFindProcNameData = `
|
||||
SELECT
|
||||
file_id
|
||||
,file_build_id
|
||||
,file_proc_id
|
||||
,file_name
|
||||
,file_mime
|
||||
,file_size
|
||||
,file_time
|
||||
,file_data
|
||||
FROM files
|
||||
WHERE file_proc_id = ?
|
||||
AND file_name = ?
|
||||
`
|
||||
|
||||
var filesDeleteBuild = `
|
||||
DELETE FROM files WHERE file_build_id = ?
|
||||
`
|
||||
|
||||
var permsFindUser = `
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_date
|
||||
FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
`
|
||||
|
||||
var permsFindUserRepo = `
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_repo_id = ?
|
||||
`
|
||||
|
||||
var permsInsertReplace = `
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES (?,?,?,?,?,?)
|
||||
`
|
||||
|
||||
var permsInsertReplaceLookup = `
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES (?,(SELECT repo_id FROM repos WHERE repo_full_name = ?),?,?,?,?)
|
||||
`
|
||||
|
||||
var permsDeleteUserRepo = `
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_repo_id = ?
|
||||
`
|
||||
|
||||
var permsDeleteUserDate = `
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_synced < ?
|
||||
`
|
||||
|
||||
var procsFindId = `
|
||||
SELECT
|
||||
proc_id
|
||||
,proc_build_id
|
||||
,proc_pid
|
||||
,proc_ppid
|
||||
,proc_pgid
|
||||
,proc_name
|
||||
,proc_state
|
||||
,proc_error
|
||||
,proc_exit_code
|
||||
,proc_started
|
||||
,proc_stopped
|
||||
,proc_machine
|
||||
,proc_platform
|
||||
,proc_environ
|
||||
FROM procs
|
||||
WHERE proc_id = ?
|
||||
`
|
||||
|
||||
var procsFindBuild = `
|
||||
SELECT
|
||||
proc_id
|
||||
,proc_build_id
|
||||
,proc_pid
|
||||
,proc_ppid
|
||||
,proc_pgid
|
||||
,proc_name
|
||||
,proc_state
|
||||
,proc_error
|
||||
,proc_exit_code
|
||||
,proc_started
|
||||
,proc_stopped
|
||||
,proc_machine
|
||||
,proc_platform
|
||||
,proc_environ
|
||||
FROM procs
|
||||
WHERE proc_build_id = ?
|
||||
ORDER BY proc_id ASC
|
||||
`
|
||||
|
||||
var procsFindBuildPid = `
|
||||
SELECT
|
||||
proc_id
|
||||
,proc_build_id
|
||||
,proc_pid
|
||||
,proc_ppid
|
||||
,proc_pgid
|
||||
,proc_name
|
||||
,proc_state
|
||||
,proc_error
|
||||
,proc_exit_code
|
||||
,proc_started
|
||||
,proc_stopped
|
||||
,proc_machine
|
||||
,proc_platform
|
||||
,proc_environ
|
||||
FROM procs
|
||||
WHERE proc_build_id = ?
|
||||
AND proc_pid = ?
|
||||
`
|
||||
|
||||
var procsFindBuildPpid = `
|
||||
SELECT
|
||||
proc_id
|
||||
,proc_build_id
|
||||
,proc_pid
|
||||
,proc_ppid
|
||||
,proc_pgid
|
||||
,proc_name
|
||||
,proc_state
|
||||
,proc_error
|
||||
,proc_exit_code
|
||||
,proc_started
|
||||
,proc_stopped
|
||||
,proc_machine
|
||||
,proc_platform
|
||||
,proc_environ
|
||||
FROM procs
|
||||
WHERE proc_build_id = ?
|
||||
AND proc_ppid = ?
|
||||
AND proc_name = ?
|
||||
`
|
||||
|
||||
var procsDeleteBuild = `
|
||||
DELETE FROM procs WHERE proc_build_id = ?
|
||||
`
|
||||
|
||||
var registryFindRepo = `
|
||||
SELECT
|
||||
registry_id
|
||||
,registry_repo_id
|
||||
,registry_addr
|
||||
,registry_username
|
||||
,registry_password
|
||||
,registry_email
|
||||
,registry_token
|
||||
FROM registry
|
||||
WHERE registry_repo_id = ?
|
||||
`
|
||||
|
||||
var registryFindRepoAddr = `
|
||||
SELECT
|
||||
registry_id
|
||||
,registry_repo_id
|
||||
,registry_addr
|
||||
,registry_username
|
||||
,registry_password
|
||||
,registry_email
|
||||
,registry_token
|
||||
FROM registry
|
||||
WHERE registry_repo_id = ?
|
||||
AND registry_addr = ?
|
||||
`
|
||||
|
||||
var registryDeleteRepo = `
|
||||
DELETE FROM registry WHERE registry_repo_id = ?
|
||||
`
|
||||
|
||||
var registryDelete = `
|
||||
DELETE FROM registry WHERE registry_id = ?
|
||||
`
|
||||
|
||||
var repoUpdateCounter = `
|
||||
UPDATE repos SET repo_counter = ?
|
||||
WHERE repo_counter = ?
|
||||
AND repo_id = ?
|
||||
`
|
||||
|
||||
var repoFindUser = `
|
||||
SELECT
|
||||
repo_id
|
||||
,repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
ORDER BY repo_full_name ASC
|
||||
`
|
||||
|
||||
var repoInsertIgnore = `
|
||||
INSERT IGNORE INTO repos (
|
||||
repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
`
|
||||
|
||||
var repoDelete = `
|
||||
DELETE FROM repos WHERE repo_id = ?
|
||||
`
|
||||
|
||||
var secretFindRepo = `
|
||||
SELECT
|
||||
secret_id
|
||||
,secret_repo_id
|
||||
,secret_name
|
||||
,secret_value
|
||||
,secret_images
|
||||
,secret_events
|
||||
,secret_conceal
|
||||
,secret_skip_verify
|
||||
FROM secrets
|
||||
WHERE secret_repo_id = ?
|
||||
`
|
||||
|
||||
var secretFindRepoName = `
|
||||
SELECT
|
||||
secret_id
|
||||
,secret_repo_id
|
||||
,secret_name
|
||||
,secret_value
|
||||
,secret_images
|
||||
,secret_events
|
||||
,secret_conceal
|
||||
,secret_skip_verify
|
||||
FROM secrets
|
||||
WHERE secret_repo_id = ?
|
||||
AND secret_name = ?
|
||||
`
|
||||
|
||||
var secretDelete = `
|
||||
DELETE FROM secrets WHERE secret_id = ?
|
||||
`
|
||||
|
||||
var senderFindRepo = `
|
||||
SELECT
|
||||
sender_id
|
||||
,sender_repo_id
|
||||
,sender_login
|
||||
,sender_allow
|
||||
,sender_block
|
||||
FROM senders
|
||||
WHERE sender_repo_id = ?
|
||||
`
|
||||
|
||||
var senderFindRepoLogin = `
|
||||
SELECT
|
||||
sender_id
|
||||
,sender_repo_id
|
||||
,sender_login
|
||||
,sender_allow
|
||||
,sender_block
|
||||
FROM senders
|
||||
WHERE sender_repo_id = ?
|
||||
AND sender_login = ?
|
||||
`
|
||||
|
||||
var senderDeleteRepo = `
|
||||
DELETE FROM senders WHERE sender_repo_id = ?
|
||||
`
|
||||
|
||||
var senderDelete = `
|
||||
DELETE FROM senders WHERE sender_id = ?
|
||||
`
|
||||
|
||||
var taskList = `
|
||||
SELECT
|
||||
task_id
|
||||
,task_data
|
||||
,task_labels
|
||||
FROM tasks
|
||||
`
|
||||
|
||||
var taskDelete = `
|
||||
DELETE FROM tasks WHERE task_id = ?
|
||||
`
|
61
store/datastore/sql/postgres/files/feed.sql
Normal file
61
store/datastore/sql/postgres/files/feed.sql
Normal file
|
@ -0,0 +1,61 @@
|
|||
-- name: feed-latest-build
|
||||
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos LEFT OUTER JOIN builds ON build_id = (
|
||||
SELECT build_id FROM builds
|
||||
WHERE builds.build_repo_id = repos.repo_id
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = $1
|
||||
AND repos.repo_active = true
|
||||
ORDER BY repo_full_name ASC;
|
||||
|
||||
-- name: feed
|
||||
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
INNER JOIN builds ON builds.build_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = $1
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 50
|
63
store/datastore/sql/postgres/files/perms.sql
Normal file
63
store/datastore/sql/postgres/files/perms.sql
Normal file
|
@ -0,0 +1,63 @@
|
|||
-- name: perms-find-user
|
||||
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_date
|
||||
FROM perms
|
||||
WHERE perm_user_id = $1
|
||||
|
||||
-- name: perms-find-user-repo
|
||||
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
FROM perms
|
||||
WHERE perm_user_id = $1
|
||||
AND perm_repo_id = $2
|
||||
|
||||
-- name: perms-insert-replace
|
||||
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES ($1,$2,$3,$4,$5,$6)
|
||||
|
||||
-- name: perms-insert-replace-lookup
|
||||
|
||||
INSERT INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES ($1,(SELECT repo_id FROM repos WHERE repo_full_name = $2),$3,$4,$5,$6)
|
||||
ON CONFLICT (perm_user_id, perm_repo_id) DO UPDATE SET
|
||||
perm_pull = EXCLUDED.perm_pull
|
||||
,perm_push = EXCLUDED.perm_push
|
||||
,perm_admin = EXCLUDED.perm_admin
|
||||
,perm_synced = EXCLUDED.perm_synced
|
||||
|
||||
-- name: perms-delete-user-repo
|
||||
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = $1
|
||||
AND perm_repo_id = $2
|
||||
|
||||
-- name: perms-delete-user-date
|
||||
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = $1
|
||||
AND perm_synced < $2
|
|
@ -3,3 +3,67 @@
|
|||
UPDATE repos SET repo_counter = $1
|
||||
WHERE repo_counter = $2
|
||||
AND repo_id = $3
|
||||
|
||||
-- name: repo-find-user
|
||||
|
||||
SELECT
|
||||
repo_id
|
||||
,repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = $1
|
||||
ORDER BY repo_full_name ASC
|
||||
|
||||
-- name: repo-insert-ignore
|
||||
|
||||
INSERT INTO repos (
|
||||
repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22)
|
||||
ON CONFLICT (repo_full_name) DO NOTHING
|
||||
|
||||
-- name: repo-delete
|
||||
|
||||
DELETE FROM repos
|
||||
WHERE repo_id = $1
|
||||
|
|
|
@ -6,35 +6,46 @@ func Lookup(name string) string {
|
|||
}
|
||||
|
||||
var index = map[string]string{
|
||||
"config-find-id": configFindId,
|
||||
"config-find-repo-hash": configFindRepoHash,
|
||||
"config-find-approved": configFindApproved,
|
||||
"count-users": countUsers,
|
||||
"count-repos": countRepos,
|
||||
"count-builds": countBuilds,
|
||||
"files-find-build": filesFindBuild,
|
||||
"files-find-proc-name": filesFindProcName,
|
||||
"files-find-proc-name-data": filesFindProcNameData,
|
||||
"files-delete-build": filesDeleteBuild,
|
||||
"procs-find-id": procsFindId,
|
||||
"procs-find-build": procsFindBuild,
|
||||
"procs-find-build-pid": procsFindBuildPid,
|
||||
"procs-find-build-ppid": procsFindBuildPpid,
|
||||
"procs-delete-build": procsDeleteBuild,
|
||||
"registry-find-repo": registryFindRepo,
|
||||
"registry-find-repo-addr": registryFindRepoAddr,
|
||||
"registry-delete-repo": registryDeleteRepo,
|
||||
"registry-delete": registryDelete,
|
||||
"repo-update-counter": repoUpdateCounter,
|
||||
"secret-find-repo": secretFindRepo,
|
||||
"secret-find-repo-name": secretFindRepoName,
|
||||
"secret-delete": secretDelete,
|
||||
"sender-find-repo": senderFindRepo,
|
||||
"sender-find-repo-login": senderFindRepoLogin,
|
||||
"sender-delete-repo": senderDeleteRepo,
|
||||
"sender-delete": senderDelete,
|
||||
"task-list": taskList,
|
||||
"task-delete": taskDelete,
|
||||
"config-find-id": configFindId,
|
||||
"config-find-repo-hash": configFindRepoHash,
|
||||
"config-find-approved": configFindApproved,
|
||||
"count-users": countUsers,
|
||||
"count-repos": countRepos,
|
||||
"count-builds": countBuilds,
|
||||
"feed-latest-build": feedLatestBuild,
|
||||
"feed": feed,
|
||||
"files-find-build": filesFindBuild,
|
||||
"files-find-proc-name": filesFindProcName,
|
||||
"files-find-proc-name-data": filesFindProcNameData,
|
||||
"files-delete-build": filesDeleteBuild,
|
||||
"perms-find-user": permsFindUser,
|
||||
"perms-find-user-repo": permsFindUserRepo,
|
||||
"perms-insert-replace": permsInsertReplace,
|
||||
"perms-insert-replace-lookup": permsInsertReplaceLookup,
|
||||
"perms-delete-user-repo": permsDeleteUserRepo,
|
||||
"perms-delete-user-date": permsDeleteUserDate,
|
||||
"procs-find-id": procsFindId,
|
||||
"procs-find-build": procsFindBuild,
|
||||
"procs-find-build-pid": procsFindBuildPid,
|
||||
"procs-find-build-ppid": procsFindBuildPpid,
|
||||
"procs-delete-build": procsDeleteBuild,
|
||||
"registry-find-repo": registryFindRepo,
|
||||
"registry-find-repo-addr": registryFindRepoAddr,
|
||||
"registry-delete-repo": registryDeleteRepo,
|
||||
"registry-delete": registryDelete,
|
||||
"repo-update-counter": repoUpdateCounter,
|
||||
"repo-find-user": repoFindUser,
|
||||
"repo-insert-ignore": repoInsertIgnore,
|
||||
"repo-delete": repoDelete,
|
||||
"secret-find-repo": secretFindRepo,
|
||||
"secret-find-repo-name": secretFindRepoName,
|
||||
"secret-delete": secretDelete,
|
||||
"sender-find-repo": senderFindRepo,
|
||||
"sender-find-repo-login": senderFindRepoLogin,
|
||||
"sender-delete-repo": senderDeleteRepo,
|
||||
"sender-delete": senderDelete,
|
||||
"task-list": taskList,
|
||||
"task-delete": taskDelete,
|
||||
}
|
||||
|
||||
var configFindId = `
|
||||
|
@ -81,6 +92,68 @@ SELECT reltuples
|
|||
FROM pg_class WHERE relname = 'builds';
|
||||
`
|
||||
|
||||
var feedLatestBuild = `
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos LEFT OUTER JOIN builds ON build_id = (
|
||||
SELECT build_id FROM builds
|
||||
WHERE builds.build_repo_id = repos.repo_id
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = $1
|
||||
AND repos.repo_active = true
|
||||
ORDER BY repo_full_name ASC;
|
||||
`
|
||||
|
||||
var feed = `
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
INNER JOIN builds ON builds.build_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = $1
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 50
|
||||
`
|
||||
|
||||
var filesFindBuild = `
|
||||
SELECT
|
||||
file_id
|
||||
|
@ -127,6 +200,70 @@ var filesDeleteBuild = `
|
|||
DELETE FROM files WHERE file_build_id = $1
|
||||
`
|
||||
|
||||
var permsFindUser = `
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_date
|
||||
FROM perms
|
||||
WHERE perm_user_id = $1
|
||||
`
|
||||
|
||||
var permsFindUserRepo = `
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
FROM perms
|
||||
WHERE perm_user_id = $1
|
||||
AND perm_repo_id = $2
|
||||
`
|
||||
|
||||
var permsInsertReplace = `
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES ($1,$2,$3,$4,$5,$6)
|
||||
`
|
||||
|
||||
var permsInsertReplaceLookup = `
|
||||
INSERT INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES ($1,(SELECT repo_id FROM repos WHERE repo_full_name = $2),$3,$4,$5,$6)
|
||||
ON CONFLICT (perm_user_id, perm_repo_id) DO UPDATE SET
|
||||
perm_pull = EXCLUDED.perm_pull
|
||||
,perm_push = EXCLUDED.perm_push
|
||||
,perm_admin = EXCLUDED.perm_admin
|
||||
,perm_synced = EXCLUDED.perm_synced
|
||||
`
|
||||
|
||||
var permsDeleteUserRepo = `
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = $1
|
||||
AND perm_repo_id = $2
|
||||
`
|
||||
|
||||
var permsDeleteUserDate = `
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = $1
|
||||
AND perm_synced < $2
|
||||
`
|
||||
|
||||
var procsFindId = `
|
||||
SELECT
|
||||
proc_id
|
||||
|
@ -256,6 +393,70 @@ WHERE repo_counter = $2
|
|||
AND repo_id = $3
|
||||
`
|
||||
|
||||
var repoFindUser = `
|
||||
SELECT
|
||||
repo_id
|
||||
,repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = $1
|
||||
ORDER BY repo_full_name ASC
|
||||
`
|
||||
|
||||
var repoInsertIgnore = `
|
||||
INSERT INTO repos (
|
||||
repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22)
|
||||
ON CONFLICT (repo_full_name) DO NOTHING
|
||||
`
|
||||
|
||||
var repoDelete = `
|
||||
DELETE FROM repos
|
||||
WHERE repo_id = $1
|
||||
`
|
||||
|
||||
var secretFindRepo = `
|
||||
SELECT
|
||||
secret_id
|
||||
|
|
61
store/datastore/sql/sqlite/files/feed.sql
Normal file
61
store/datastore/sql/sqlite/files/feed.sql
Normal file
|
@ -0,0 +1,61 @@
|
|||
-- name: feed-latest-build
|
||||
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos LEFT OUTER JOIN builds ON build_id = (
|
||||
SELECT build_id FROM builds
|
||||
WHERE builds.build_repo_id = repos.repo_id
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
AND repos.repo_active = 1
|
||||
ORDER BY repo_full_name ASC;
|
||||
|
||||
-- name: feed
|
||||
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
INNER JOIN builds ON builds.build_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 50
|
58
store/datastore/sql/sqlite/files/perms.sql
Normal file
58
store/datastore/sql/sqlite/files/perms.sql
Normal file
|
@ -0,0 +1,58 @@
|
|||
-- name: perms-find-user
|
||||
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_date
|
||||
FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
|
||||
-- name: perms-find-user-repo
|
||||
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_repo_id = ?
|
||||
|
||||
-- name: perms-insert-replace
|
||||
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES (?,?,?,?,?,?)
|
||||
|
||||
-- name: perms-insert-replace-lookup
|
||||
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES (?,(SELECT repo_id FROM repos WHERE repo_full_name = ?),?,?,?,?)
|
||||
|
||||
-- name: perms-delete-user-repo
|
||||
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_repo_id = ?
|
||||
|
||||
-- name: perms-delete-user-date
|
||||
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_synced < ?
|
|
@ -3,3 +3,65 @@
|
|||
UPDATE repos SET repo_counter = ?
|
||||
WHERE repo_counter = ?
|
||||
AND repo_id = ?
|
||||
|
||||
-- name: repo-find-user
|
||||
|
||||
SELECT
|
||||
repo_id
|
||||
,repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
ORDER BY repo_full_name ASC
|
||||
|
||||
-- name: repo-insert-ignore
|
||||
|
||||
INSERT OR IGNORE INTO repos (
|
||||
repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
-- name: repo-delete
|
||||
|
||||
DELETE FROM repos WHERE repo_id = ?
|
||||
|
|
|
@ -6,35 +6,46 @@ func Lookup(name string) string {
|
|||
}
|
||||
|
||||
var index = map[string]string{
|
||||
"config-find-id": configFindId,
|
||||
"config-find-repo-hash": configFindRepoHash,
|
||||
"config-find-approved": configFindApproved,
|
||||
"count-users": countUsers,
|
||||
"count-repos": countRepos,
|
||||
"count-builds": countBuilds,
|
||||
"files-find-build": filesFindBuild,
|
||||
"files-find-proc-name": filesFindProcName,
|
||||
"files-find-proc-name-data": filesFindProcNameData,
|
||||
"files-delete-build": filesDeleteBuild,
|
||||
"procs-find-id": procsFindId,
|
||||
"procs-find-build": procsFindBuild,
|
||||
"procs-find-build-pid": procsFindBuildPid,
|
||||
"procs-find-build-ppid": procsFindBuildPpid,
|
||||
"procs-delete-build": procsDeleteBuild,
|
||||
"registry-find-repo": registryFindRepo,
|
||||
"registry-find-repo-addr": registryFindRepoAddr,
|
||||
"registry-delete-repo": registryDeleteRepo,
|
||||
"registry-delete": registryDelete,
|
||||
"repo-update-counter": repoUpdateCounter,
|
||||
"secret-find-repo": secretFindRepo,
|
||||
"secret-find-repo-name": secretFindRepoName,
|
||||
"secret-delete": secretDelete,
|
||||
"sender-find-repo": senderFindRepo,
|
||||
"sender-find-repo-login": senderFindRepoLogin,
|
||||
"sender-delete-repo": senderDeleteRepo,
|
||||
"sender-delete": senderDelete,
|
||||
"task-list": taskList,
|
||||
"task-delete": taskDelete,
|
||||
"config-find-id": configFindId,
|
||||
"config-find-repo-hash": configFindRepoHash,
|
||||
"config-find-approved": configFindApproved,
|
||||
"count-users": countUsers,
|
||||
"count-repos": countRepos,
|
||||
"count-builds": countBuilds,
|
||||
"feed-latest-build": feedLatestBuild,
|
||||
"feed": feed,
|
||||
"files-find-build": filesFindBuild,
|
||||
"files-find-proc-name": filesFindProcName,
|
||||
"files-find-proc-name-data": filesFindProcNameData,
|
||||
"files-delete-build": filesDeleteBuild,
|
||||
"perms-find-user": permsFindUser,
|
||||
"perms-find-user-repo": permsFindUserRepo,
|
||||
"perms-insert-replace": permsInsertReplace,
|
||||
"perms-insert-replace-lookup": permsInsertReplaceLookup,
|
||||
"perms-delete-user-repo": permsDeleteUserRepo,
|
||||
"perms-delete-user-date": permsDeleteUserDate,
|
||||
"procs-find-id": procsFindId,
|
||||
"procs-find-build": procsFindBuild,
|
||||
"procs-find-build-pid": procsFindBuildPid,
|
||||
"procs-find-build-ppid": procsFindBuildPpid,
|
||||
"procs-delete-build": procsDeleteBuild,
|
||||
"registry-find-repo": registryFindRepo,
|
||||
"registry-find-repo-addr": registryFindRepoAddr,
|
||||
"registry-delete-repo": registryDeleteRepo,
|
||||
"registry-delete": registryDelete,
|
||||
"repo-update-counter": repoUpdateCounter,
|
||||
"repo-find-user": repoFindUser,
|
||||
"repo-insert-ignore": repoInsertIgnore,
|
||||
"repo-delete": repoDelete,
|
||||
"secret-find-repo": secretFindRepo,
|
||||
"secret-find-repo-name": secretFindRepoName,
|
||||
"secret-delete": secretDelete,
|
||||
"sender-find-repo": senderFindRepo,
|
||||
"sender-find-repo-login": senderFindRepoLogin,
|
||||
"sender-delete-repo": senderDeleteRepo,
|
||||
"sender-delete": senderDelete,
|
||||
"task-list": taskList,
|
||||
"task-delete": taskDelete,
|
||||
}
|
||||
|
||||
var configFindId = `
|
||||
|
@ -81,6 +92,68 @@ SELECT count(1)
|
|||
FROM builds
|
||||
`
|
||||
|
||||
var feedLatestBuild = `
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos LEFT OUTER JOIN builds ON build_id = (
|
||||
SELECT build_id FROM builds
|
||||
WHERE builds.build_repo_id = repos.repo_id
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
AND repos.repo_active = 1
|
||||
ORDER BY repo_full_name ASC;
|
||||
`
|
||||
|
||||
var feed = `
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
INNER JOIN builds ON builds.build_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 50
|
||||
`
|
||||
|
||||
var filesFindBuild = `
|
||||
SELECT
|
||||
file_id
|
||||
|
@ -127,6 +200,65 @@ var filesDeleteBuild = `
|
|||
DELETE FROM files WHERE file_build_id = ?
|
||||
`
|
||||
|
||||
var permsFindUser = `
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_date
|
||||
FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
`
|
||||
|
||||
var permsFindUserRepo = `
|
||||
SELECT
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_repo_id = ?
|
||||
`
|
||||
|
||||
var permsInsertReplace = `
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES (?,?,?,?,?,?)
|
||||
`
|
||||
|
||||
var permsInsertReplaceLookup = `
|
||||
REPLACE INTO perms (
|
||||
perm_user_id
|
||||
,perm_repo_id
|
||||
,perm_pull
|
||||
,perm_push
|
||||
,perm_admin
|
||||
,perm_synced
|
||||
) VALUES (?,(SELECT repo_id FROM repos WHERE repo_full_name = ?),?,?,?,?)
|
||||
`
|
||||
|
||||
var permsDeleteUserRepo = `
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_repo_id = ?
|
||||
`
|
||||
|
||||
var permsDeleteUserDate = `
|
||||
DELETE FROM perms
|
||||
WHERE perm_user_id = ?
|
||||
AND perm_synced < ?
|
||||
`
|
||||
|
||||
var procsFindId = `
|
||||
SELECT
|
||||
proc_id
|
||||
|
@ -256,6 +388,68 @@ WHERE repo_counter = ?
|
|||
AND repo_id = ?
|
||||
`
|
||||
|
||||
var repoFindUser = `
|
||||
SELECT
|
||||
repo_id
|
||||
,repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
ORDER BY repo_full_name ASC
|
||||
`
|
||||
|
||||
var repoInsertIgnore = `
|
||||
INSERT OR IGNORE INTO repos (
|
||||
repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
`
|
||||
|
||||
var repoDelete = `
|
||||
DELETE FROM repos WHERE repo_id = ?
|
||||
`
|
||||
|
||||
var secretFindRepo = `
|
||||
SELECT
|
||||
secret_id
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/store/datastore/sql"
|
||||
"github.com/russross/meddler"
|
||||
|
@ -26,46 +24,6 @@ func (db *datastore) GetUserList() ([]*model.User, error) {
|
|||
return users, err
|
||||
}
|
||||
|
||||
func (db *datastore) GetUserFeed(listof []*model.RepoLite) ([]*model.Feed, error) {
|
||||
var (
|
||||
args []interface{}
|
||||
stmt string
|
||||
err error
|
||||
|
||||
feed = []*model.Feed{}
|
||||
)
|
||||
switch meddler.Default {
|
||||
case meddler.PostgreSQL:
|
||||
stmt, args = toListPostgres(listof)
|
||||
default:
|
||||
stmt, args = toList(listof)
|
||||
}
|
||||
if len(args) > 0 {
|
||||
err = meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedQuery, stmt), args...)
|
||||
}
|
||||
return feed, err
|
||||
}
|
||||
|
||||
func (db *datastore) GetUserFeedLatest(listof []*model.RepoLite) ([]*model.Feed, error) {
|
||||
var (
|
||||
args []interface{}
|
||||
stmt string
|
||||
err error
|
||||
|
||||
feed = []*model.Feed{}
|
||||
)
|
||||
switch meddler.Default {
|
||||
case meddler.PostgreSQL:
|
||||
stmt, args = toListPostgres(listof)
|
||||
default:
|
||||
stmt, args = toList(listof)
|
||||
}
|
||||
if len(args) > 0 {
|
||||
err = meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedLatest, stmt), args...)
|
||||
}
|
||||
return feed, err
|
||||
}
|
||||
|
||||
func (db *datastore) GetUserCount() (count int, err error) {
|
||||
err = db.QueryRow(
|
||||
sql.Lookup(db.driver, "count-users"),
|
||||
|
@ -86,6 +44,13 @@ func (db *datastore) DeleteUser(user *model.User) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (db *datastore) UserFeed(user *model.User) ([]*model.Feed, error) {
|
||||
stmt := sql.Lookup(db.driver, "feed")
|
||||
data := []*model.Feed{}
|
||||
err := meddler.QueryAll(db, &data, stmt, user.ID)
|
||||
return data, err
|
||||
}
|
||||
|
||||
const userTable = "users"
|
||||
|
||||
const userLoginQuery = `
|
||||
|
@ -101,75 +66,7 @@ FROM users
|
|||
ORDER BY user_login ASC
|
||||
`
|
||||
|
||||
const userCountQuery = `
|
||||
SELECT count(1)
|
||||
FROM users
|
||||
`
|
||||
|
||||
const userDeleteStmt = `
|
||||
DELETE FROM users
|
||||
WHERE user_id=?
|
||||
`
|
||||
|
||||
const userFeedQuery = `
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM
|
||||
builds b
|
||||
,repos r
|
||||
WHERE b.build_repo_id = r.repo_id
|
||||
AND r.repo_full_name IN (%s)
|
||||
ORDER BY b.build_id DESC
|
||||
LIMIT 50
|
||||
`
|
||||
|
||||
// thanks to this article for helping me find a sane sql query
|
||||
// https://www.periscopedata.com/blog/4-ways-to-join-only-the-first-row-in-sql.html
|
||||
|
||||
const userFeedLatest = `
|
||||
SELECT
|
||||
repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,build_number
|
||||
,build_event
|
||||
,build_status
|
||||
,build_created
|
||||
,build_started
|
||||
,build_finished
|
||||
,build_commit
|
||||
,build_branch
|
||||
,build_ref
|
||||
,build_refspec
|
||||
,build_remote
|
||||
,build_title
|
||||
,build_message
|
||||
,build_author
|
||||
,build_email
|
||||
,build_avatar
|
||||
FROM repos LEFT OUTER JOIN builds ON build_id = (
|
||||
SELECT build_id FROM builds
|
||||
WHERE builds.build_repo_id = repos.repo_id
|
||||
ORDER BY build_id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE repo_full_name IN (%s)
|
||||
`
|
||||
|
|
|
@ -20,7 +20,7 @@ func TestUsers(t *testing.T) {
|
|||
s.Exec("DELETE FROM users")
|
||||
s.Exec("DELETE FROM repos")
|
||||
s.Exec("DELETE FROM builds")
|
||||
s.Exec("DELETE FROM jobs")
|
||||
s.Exec("DELETE FROM procs")
|
||||
})
|
||||
|
||||
g.It("Should Update a User", func() {
|
||||
|
@ -166,28 +166,40 @@ func TestUsers(t *testing.T) {
|
|||
})
|
||||
|
||||
g.It("Should get the Build feed for a User", func() {
|
||||
user := &model.User{
|
||||
Login: "joe",
|
||||
Email: "foo@bar.com",
|
||||
Token: "e42080dddf012c718e476da161d21ad5",
|
||||
}
|
||||
s.CreateUser(user)
|
||||
|
||||
repo1 := &model.Repo{
|
||||
UserID: 1,
|
||||
Owner: "bradrydzewski",
|
||||
Name: "drone",
|
||||
FullName: "bradrydzewski/drone",
|
||||
IsActive: true,
|
||||
}
|
||||
repo2 := &model.Repo{
|
||||
UserID: 2,
|
||||
Owner: "drone",
|
||||
Name: "drone",
|
||||
FullName: "drone/drone",
|
||||
IsActive: true,
|
||||
}
|
||||
repo3 := &model.Repo{
|
||||
UserID: 2,
|
||||
Owner: "octocat",
|
||||
Name: "hello-world",
|
||||
FullName: "octocat/hello-world",
|
||||
IsActive: true,
|
||||
}
|
||||
s.CreateRepo(repo1)
|
||||
s.CreateRepo(repo2)
|
||||
s.CreateRepo(repo3)
|
||||
|
||||
s.PermBatch([]*model.Perm{
|
||||
{UserID: user.ID, Repo: repo1.FullName},
|
||||
{UserID: user.ID, Repo: repo2.FullName},
|
||||
})
|
||||
|
||||
build1 := &model.Build{
|
||||
RepoID: repo1.ID,
|
||||
Status: model.StatusFailure,
|
||||
|
@ -209,10 +221,7 @@ func TestUsers(t *testing.T) {
|
|||
s.CreateBuild(build3)
|
||||
s.CreateBuild(build4)
|
||||
|
||||
builds, err := s.GetUserFeed([]*model.RepoLite{
|
||||
{FullName: "bradrydzewski/drone"},
|
||||
{FullName: "drone/drone"},
|
||||
})
|
||||
builds, err := s.UserFeed(user)
|
||||
g.Assert(err == nil).IsTrue()
|
||||
g.Assert(len(builds)).Equal(3)
|
||||
g.Assert(builds[0].FullName).Equal(repo2.FullName)
|
||||
|
|
|
@ -2,9 +2,7 @@ package datastore
|
|||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
|
@ -35,41 +33,3 @@ func rebind(query string) string {
|
|||
}
|
||||
return string(rqb)
|
||||
}
|
||||
|
||||
// helper function that converts a simple repsitory list
|
||||
// to a sql IN statment.
|
||||
func toList(listof []*model.RepoLite) (string, []interface{}) {
|
||||
var size = len(listof)
|
||||
switch {
|
||||
case meddler.Default == meddler.SQLite && size > 999:
|
||||
size = 999
|
||||
listof = listof[:999]
|
||||
case size > 15000:
|
||||
size = 15000
|
||||
listof = listof[:15000]
|
||||
}
|
||||
var qs = make([]string, size, size)
|
||||
var in = make([]interface{}, size, size)
|
||||
for i, repo := range listof {
|
||||
qs[i] = "?"
|
||||
in[i] = repo.FullName
|
||||
}
|
||||
return strings.Join(qs, ","), in
|
||||
}
|
||||
|
||||
// helper function that converts a simple repository list
|
||||
// to a sql IN statement compatible with postgres.
|
||||
func toListPostgres(listof []*model.RepoLite) (string, []interface{}) {
|
||||
var size = len(listof)
|
||||
if size > 15000 {
|
||||
size = 15000
|
||||
listof = listof[:15000]
|
||||
}
|
||||
var qs = make([]string, size, size)
|
||||
var in = make([]interface{}, size, size)
|
||||
for i, repo := range listof {
|
||||
qs[i] = "$" + strconv.Itoa(i+1)
|
||||
in[i] = repo.FullName
|
||||
}
|
||||
return strings.Join(qs, ","), in
|
||||
}
|
||||
|
|
|
@ -18,13 +18,6 @@ type Store interface {
|
|||
// GetUserList gets a list of all users in the system.
|
||||
GetUserList() ([]*model.User, error)
|
||||
|
||||
// GetUserFeed gets a user activity feed.
|
||||
GetUserFeed([]*model.RepoLite) ([]*model.Feed, error)
|
||||
|
||||
// GetUserFeedLatest gets a user activity feed for all repositories including
|
||||
// only the latest build for each repository.
|
||||
GetUserFeedLatest(listof []*model.RepoLite) ([]*model.Feed, error)
|
||||
|
||||
// GetUserCount gets a count of all users in the system.
|
||||
GetUserCount() (int, error)
|
||||
|
||||
|
@ -43,9 +36,6 @@ type Store interface {
|
|||
// GetRepoName gets a repo by its full name.
|
||||
GetRepoName(string) (*model.Repo, error)
|
||||
|
||||
// GetRepoListOf gets the list of enumerated repos in the system.
|
||||
GetRepoListOf([]*model.RepoLite) ([]*model.Repo, error)
|
||||
|
||||
// GetRepoCount gets a count of all repositories in the system.
|
||||
GetRepoCount() (int, error)
|
||||
|
||||
|
@ -92,6 +82,18 @@ type Store interface {
|
|||
// new functions
|
||||
//
|
||||
|
||||
UserFeed(*model.User) ([]*model.Feed, error)
|
||||
|
||||
RepoList(*model.User) ([]*model.Repo, error)
|
||||
RepoListLatest(*model.User) ([]*model.Feed, error)
|
||||
RepoBatch([]*model.Repo) error
|
||||
|
||||
PermFind(user *model.User, repo *model.Repo) (*model.Perm, error)
|
||||
PermUpsert(perm *model.Perm) error
|
||||
PermBatch(perms []*model.Perm) error
|
||||
PermDelete(perm *model.Perm) error
|
||||
PermFlush(user *model.User, before int64) error
|
||||
|
||||
ConfigLoad(int64) (*model.Config, error)
|
||||
ConfigFind(*model.Repo, string) (*model.Config, error)
|
||||
ConfigFindApproved(*model.Config) (bool, error)
|
||||
|
@ -151,14 +153,6 @@ func GetUserList(c context.Context) ([]*model.User, error) {
|
|||
return FromContext(c).GetUserList()
|
||||
}
|
||||
|
||||
// GetUserFeed gets a user activity feed.
|
||||
func GetUserFeed(c context.Context, listof []*model.RepoLite, latest bool) ([]*model.Feed, error) {
|
||||
if latest {
|
||||
return FromContext(c).GetUserFeedLatest(listof)
|
||||
}
|
||||
return FromContext(c).GetUserFeed(listof)
|
||||
}
|
||||
|
||||
// GetUserCount gets a count of all users in the system.
|
||||
func GetUserCount(c context.Context) (int, error) {
|
||||
return FromContext(c).GetUserCount()
|
||||
|
@ -188,10 +182,6 @@ func GetRepoOwnerName(c context.Context, owner, name string) (*model.Repo, error
|
|||
return FromContext(c).GetRepoName(owner + "/" + name)
|
||||
}
|
||||
|
||||
func GetRepoListOf(c context.Context, listof []*model.RepoLite) ([]*model.Repo, error) {
|
||||
return FromContext(c).GetRepoListOf(listof)
|
||||
}
|
||||
|
||||
func CreateRepo(c context.Context, repo *model.Repo) error {
|
||||
return FromContext(c).CreateRepo(repo)
|
||||
}
|
||||
|
|
27
vendor/github.com/ianschenck/envflag/LICENSE
generated
vendored
27
vendor/github.com/ianschenck/envflag/LICENSE
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
Copyright (c) 2013, Ian Schenck
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the name of Ian Schenck nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
vendor/github.com/ianschenck/envflag/README.md
generated
vendored
37
vendor/github.com/ianschenck/envflag/README.md
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
envflag
|
||||
=======
|
||||
|
||||
Golang flags, but bolted onto the environment rather than the command-line.
|
||||
|
||||
Read the [godocs](http://godoc.org/github.com/ianschenck/envflag).
|
||||
|
||||
Motivation
|
||||
==========
|
||||
|
||||
Some like the distinction that command-line flags control behavior
|
||||
while environment variables configure. Also
|
||||
[12-factor](http://12factor.net/) recommends the use of environment
|
||||
variables for configuration. The interface of the golang flag package
|
||||
is well designed and easy to use, and allows for other lists
|
||||
(os.Environ() vs os.Args) to be parsed as flags. It makes sense then
|
||||
to use the same interface, the same types, and the same parsing
|
||||
(caveat: there is some ugly string hacking to make environment
|
||||
variables look like flags) to the same ends.
|
||||
|
||||
Differences
|
||||
===========
|
||||
|
||||
Calling `flag.Parse()` will not parse environment flags. Calling
|
||||
`envflag.Parse()` will not parse command-line flags. There is no good
|
||||
reason to combine these two when the net savings is a single line in a
|
||||
`func main()`. Furthermore, doing so would require users to accept a
|
||||
precedence order of my choosing.
|
||||
|
||||
The presence of an environment variable named `h` or `help` will
|
||||
probably cause problems (print Usage and os.Exit(0)). Work around this
|
||||
by defining those flags somewhere (and ignoring them).
|
||||
|
||||
Before calling `Flagset.Parse` on `EnvironmentFlags`, the environment
|
||||
variables being passed to `Parse` are trimmed down using
|
||||
`Lookup`. This behavior is different from `flag.Parse` in that extra
|
||||
environment variables are ignored (and won't crash `envflag.Parse`).
|
192
vendor/github.com/ianschenck/envflag/envflag.go
generated
vendored
192
vendor/github.com/ianschenck/envflag/envflag.go
generated
vendored
|
@ -1,192 +0,0 @@
|
|||
// Copyright 2013 Ian Schenck. Use of this source code is governed by
|
||||
// a license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package envflag adds environment variable flags to the flag package.
|
||||
|
||||
Usage:
|
||||
|
||||
Define flags using envflag.String(), Bool(), Int(), etc. This package
|
||||
works nearly the same as the stdlib flag package. Parsing the
|
||||
Environment flags is done by calling envflag.Parse()
|
||||
|
||||
It will *not* attempt to parse any normally-defined command-line
|
||||
flags. Command-line flags are explicitly left alone and separate.
|
||||
*/
|
||||
package envflag
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// VisitAll visits the environment flags in lexicographical order,
|
||||
// calling fn for each. It visits all flags, even those not set.
|
||||
func VisitAll(fn func(*flag.Flag)) {
|
||||
EnvironmentFlags.VisitAll(fn)
|
||||
}
|
||||
|
||||
// Visit visits the environment flags in lexicographical order,
|
||||
// calling fn for each. It visits only those flags that have been
|
||||
// set.
|
||||
func Visit(fn func(*flag.Flag)) {
|
||||
EnvironmentFlags.Visit(fn)
|
||||
}
|
||||
|
||||
// Lookup returns the Flag structure of the named environment flag,
|
||||
// returning nil if none exists.
|
||||
func Lookup(name string) *flag.Flag {
|
||||
return EnvironmentFlags.Lookup(name)
|
||||
}
|
||||
|
||||
// Set sets the value of the named environment flag.
|
||||
func Set(name, value string) error {
|
||||
return EnvironmentFlags.Set(name, value)
|
||||
}
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and
|
||||
// usage string. The argument p points to a bool variable in which to
|
||||
// store the value of the flag.
|
||||
func BoolVar(p *bool, name string, value bool, usage string) {
|
||||
EnvironmentFlags.BoolVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and
|
||||
// usage string. The return value is the address of a bool variable
|
||||
// that stores the value of the flag.
|
||||
func Bool(name string, value bool, usage string) *bool {
|
||||
return EnvironmentFlags.Bool(name, value, usage)
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and
|
||||
// usage string. The argument p points to an int variable in which to
|
||||
// store the value of the flag.
|
||||
func IntVar(p *int, name string, value int, usage string) {
|
||||
EnvironmentFlags.IntVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and
|
||||
// usage string. The return value is the address of an int variable
|
||||
// that stores the value of the flag.
|
||||
func Int(name string, value int, usage string) *int {
|
||||
return EnvironmentFlags.Int(name, value, usage)
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value,
|
||||
// and usage string. The argument p points to an int64 variable in
|
||||
// which to store the value of the flag.
|
||||
func Int64Var(p *int64, name string, value int64, usage string) {
|
||||
EnvironmentFlags.Int64Var(p, name, value, usage)
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and
|
||||
// usage string. The return value is the address of an int64 variable
|
||||
// that stores the value of the flag.
|
||||
func Int64(name string, value int64, usage string) *int64 {
|
||||
return EnvironmentFlags.Int64(name, value, usage)
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and
|
||||
// usage string. The argument p points to a uint variable in which to
|
||||
// store the value of the flag.
|
||||
func UintVar(p *uint, name string, value uint, usage string) {
|
||||
EnvironmentFlags.UintVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and
|
||||
// usage string. The return value is the address of a uint variable
|
||||
// that stores the value of the flag.
|
||||
func Uint(name string, value uint, usage string) *uint {
|
||||
return EnvironmentFlags.Uint(name, value, usage)
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value,
|
||||
// and usage string. The argument p points to a uint64 variable in
|
||||
// which to store the value of the flag.
|
||||
func Uint64Var(p *uint64, name string, value uint64, usage string) {
|
||||
EnvironmentFlags.Uint64Var(p, name, value, usage)
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value,
|
||||
// and usage string. The return value is the address of a uint64
|
||||
// variable that stores the value of the flag.
|
||||
func Uint64(name string, value uint64, usage string) *uint64 {
|
||||
return EnvironmentFlags.Uint64(name, value, usage)
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value,
|
||||
// and usage string. The argument p points to a string variable in
|
||||
// which to store the value of the flag.
|
||||
func StringVar(p *string, name string, value string, usage string) {
|
||||
EnvironmentFlags.StringVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value,
|
||||
// and usage string. The return value is the address of a string
|
||||
// variable that stores the value of the flag.
|
||||
func String(name string, value string, usage string) *string {
|
||||
return EnvironmentFlags.String(name, value, usage)
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default
|
||||
// value, and usage string. The argument p points to a float64
|
||||
// variable in which to store the value of the flag.
|
||||
func Float64Var(p *float64, name string, value float64, usage string) {
|
||||
EnvironmentFlags.Float64Var(p, name, value, usage)
|
||||
}
|
||||
|
||||
// Float64 defines a float64 flag with specified name, default value,
|
||||
// and usage string. The return value is the address of a float64
|
||||
// variable that stores the value of the flag.
|
||||
func Float64(name string, value float64, usage string) *float64 {
|
||||
return EnvironmentFlags.Float64(name, value, usage)
|
||||
}
|
||||
|
||||
// DurationVar defines a time.Duration flag with specified name,
|
||||
// default value, and usage string. The argument p points to a
|
||||
// time.Duration variable in which to store the value of the flag.
|
||||
func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
||||
EnvironmentFlags.DurationVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
// Duration defines a time.Duration flag with specified name, default
|
||||
// value, and usage string. The return value is the address of a
|
||||
// time.Duration variable that stores the value of the flag.
|
||||
func Duration(name string, value time.Duration, usage string) *time.Duration {
|
||||
return EnvironmentFlags.Duration(name, value, usage)
|
||||
}
|
||||
|
||||
// PrintDefaults prints to standard error the default values of all
|
||||
// defined environment flags.
|
||||
func PrintDefaults() {
|
||||
EnvironmentFlags.PrintDefaults()
|
||||
}
|
||||
|
||||
// Parse parses the environment flags from os.Environ. Must be called
|
||||
// after all flags are defined and before flags are accessed by the
|
||||
// program.
|
||||
func Parse() {
|
||||
env := os.Environ()
|
||||
// Clean up and "fake" some flag k/v pairs.
|
||||
args := make([]string, 0, len(env))
|
||||
for _, value := range env {
|
||||
if Lookup(value[:strings.Index(value, "=")]) == nil {
|
||||
continue
|
||||
}
|
||||
args = append(args, fmt.Sprintf("-%s", value))
|
||||
}
|
||||
EnvironmentFlags.Parse(args)
|
||||
}
|
||||
|
||||
// Parsed returns true if the environment flags have been parsed.
|
||||
func Parsed() bool {
|
||||
return EnvironmentFlags.Parsed()
|
||||
}
|
||||
|
||||
// EnvironmentFlags is the default set of environment flags, parsed
|
||||
// from os.Environ(). The top-level functions such as BoolVar, Arg,
|
||||
// and on are wrappers for the methods of EnvironmentFlags.
|
||||
var EnvironmentFlags = flag.NewFlagSet("environment", flag.ExitOnError)
|
201
vendor/github.com/jackspirou/syscerts/LICENSE
generated
vendored
201
vendor/github.com/jackspirou/syscerts/LICENSE
generated
vendored
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
42
vendor/github.com/jackspirou/syscerts/README.md
generated
vendored
42
vendor/github.com/jackspirou/syscerts/README.md
generated
vendored
|
@ -1,42 +0,0 @@
|
|||
# syscerts
|
||||
Gather local system certificates in Go via a public `SystemRootsPool` method.
|
||||
|
||||
#### What does this do?
|
||||
Provide a way to gather local system certificates
|
||||
on different OS platforms.
|
||||
|
||||
#### How does it do it?
|
||||
It uses the `crypto/x509` package and provides a single public method called
|
||||
`SystemRootsPool()` to return a `*x509.CertPool` object.
|
||||
|
||||
#### How do you use it?
|
||||
```Go
|
||||
// gather CA certs
|
||||
certpool := syscerts.SystemRootsPool()
|
||||
|
||||
// place them in an HTTP client for trusted SSL/TLS connections
|
||||
tlsConfig := &tls.Config{RootCAs: certpool}
|
||||
transport := &http.Transport{TLSClientConfig: tlsConfig}
|
||||
client := &http.Client{Transport: transport}
|
||||
|
||||
// make a request
|
||||
resp, err := client.Do(req)
|
||||
```
|
||||
|
||||
#### Why even do it?
|
||||
The `crypto/x509` package already has a `systemRootsPool` method.
|
||||
The `crypto/x509.systemRootsPool` method is almost the same as
|
||||
`github.com/jackspirou/syscerts.SystemRootsPool`.
|
||||
The difference? The `crypto/x509.systemRootsPool` method is private so you
|
||||
cannot access it. :(
|
||||
|
||||
There are plans for the `crypto/x509.systemRootsPool` method to become public
|
||||
in Go 1.7. When this happens you might no longer need `github.com/jackspirou/syscerts.SystemRootsPool`.
|
||||
|
||||
The only reason you may still use this package after the Go 1.7 release might
|
||||
be for the Mac OSX System Keychain certs which are not included in the
|
||||
`crypto/x509` package. Relevant lines below:
|
||||
|
||||
* https://github.com/jackspirou/syscerts/blob/master/root_darwin.go#L24-L32
|
||||
|
||||
Find more about this Go issue here: https://github.com/golang/go/issues/13335
|
22
vendor/github.com/jackspirou/syscerts/root.go
generated
vendored
22
vendor/github.com/jackspirou/syscerts/root.go
generated
vendored
|
@ -1,22 +0,0 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
systemRoots *x509.CertPool
|
||||
)
|
||||
|
||||
// SystemRootsPool attempts to find and return a pool of all all installed
|
||||
// system certificates.
|
||||
func SystemRootsPool() *x509.CertPool {
|
||||
once.Do(initSystemRoots)
|
||||
return systemRoots
|
||||
}
|
14
vendor/github.com/jackspirou/syscerts/root_bsd.go
generated
vendored
14
vendor/github.com/jackspirou/syscerts/root_bsd.go
generated
vendored
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build dragonfly freebsd netbsd openbsd
|
||||
|
||||
package syscerts
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
|
||||
"/etc/ssl/cert.pem", // OpenBSD
|
||||
"/etc/openssl/certs/ca-certificates.crt", // NetBSD
|
||||
}
|
85
vendor/github.com/jackspirou/syscerts/root_cgo_darwin.go
generated
vendored
85
vendor/github.com/jackspirou/syscerts/root_cgo_darwin.go
generated
vendored
|
@ -1,85 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build cgo,darwin,!arm,!arm64,!ios
|
||||
|
||||
package syscerts
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
|
||||
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
// FetchPEMRootsC fetches the system's list of trusted X.509 root certificates.
|
||||
//
|
||||
// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
|
||||
// certificates of the system. On failure, the function returns -1.
|
||||
//
|
||||
// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
|
||||
// we've consumed its content.
|
||||
int FetchPEMRootsC(CFDataRef *pemRoots) {
|
||||
if (pemRoots == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CFArrayRef certs = NULL;
|
||||
OSStatus err = SecTrustCopyAnchorCertificates(&certs);
|
||||
if (err != noErr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||
int i, ncerts = CFArrayGetCount(certs);
|
||||
for (i = 0; i < ncerts; i++) {
|
||||
CFDataRef data = NULL;
|
||||
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
|
||||
if (cert == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
|
||||
// Once we support weak imports via cgo we should prefer that, and fall back to this
|
||||
// for older systems.
|
||||
err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
|
||||
if (err != noErr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
|
||||
CFRelease(data);
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(certs);
|
||||
|
||||
*pemRoots = combinedData;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
import "C"
|
||||
import (
|
||||
"crypto/x509"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func initSystemRoots() {
|
||||
roots := x509.NewCertPool()
|
||||
|
||||
var data C.CFDataRef = nil
|
||||
err := C.FetchPEMRootsC(&data)
|
||||
if err == -1 {
|
||||
return
|
||||
}
|
||||
|
||||
defer C.CFRelease(C.CFTypeRef(data))
|
||||
buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
|
||||
roots.AppendCertsFromPEM(buf)
|
||||
systemRoots = roots
|
||||
}
|
||||
*/
|
39
vendor/github.com/jackspirou/syscerts/root_darwin.go
generated
vendored
39
vendor/github.com/jackspirou/syscerts/root_darwin.go
generated
vendored
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go
|
||||
|
||||
package syscerts
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func execSecurityRoots() (*x509.CertPool, error) {
|
||||
roots := x509.NewCertPool()
|
||||
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roots.AppendCertsFromPEM(data)
|
||||
|
||||
// if available add the Mac OSX System Keychain
|
||||
if _, err := os.Stat("/Library/Keychains/System.keychain"); err == nil {
|
||||
cmd = exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/Library/Keychains/System.keychain")
|
||||
data, err = cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roots.AppendCertsFromPEM(data)
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
func initSystemRoots() {
|
||||
systemRoots, _ = execSecurityRoots()
|
||||
}
|
4909
vendor/github.com/jackspirou/syscerts/root_darwin_armx.go
generated
vendored
4909
vendor/github.com/jackspirou/syscerts/root_darwin_armx.go
generated
vendored
File diff suppressed because it is too large
Load diff
13
vendor/github.com/jackspirou/syscerts/root_linux.go
generated
vendored
13
vendor/github.com/jackspirou/syscerts/root_linux.go
generated
vendored
|
@ -1,13 +0,0 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
||||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL
|
||||
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
||||
"/etc/pki/tls/cacert.pem", // OpenELEC
|
||||
}
|
8
vendor/github.com/jackspirou/syscerts/root_nacl.go
generated
vendored
8
vendor/github.com/jackspirou/syscerts/root_nacl.go
generated
vendored
|
@ -1,8 +0,0 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{}
|
32
vendor/github.com/jackspirou/syscerts/root_plan9.go
generated
vendored
32
vendor/github.com/jackspirou/syscerts/root_plan9.go
generated
vendored
|
@ -1,32 +0,0 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build plan9
|
||||
|
||||
package syscerts
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/sys/lib/tls/ca.pem",
|
||||
}
|
||||
|
||||
func initSystemRoots() {
|
||||
roots := x509.NewCertPool()
|
||||
for _, file := range certFiles {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err == nil {
|
||||
roots.AppendCertsFromPEM(data)
|
||||
systemRoots = roots
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// All of the files failed to load. systemRoots will be nil which will
|
||||
// trigger a specific error at verification time.
|
||||
}
|
12
vendor/github.com/jackspirou/syscerts/root_solaris.go
generated
vendored
12
vendor/github.com/jackspirou/syscerts/root_solaris.go
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package syscerts
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/etc/certs/ca-certificates.crt", // Solaris 11.2+
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS
|
||||
"/etc/ssl/cacert.pem", // OmniOS
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue