mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-22 16:36:30 +00:00
improve and simplify repository caching
This commit is contained in:
parent
6769eed65d
commit
3dd0260b69
15 changed files with 444 additions and 364 deletions
10
cache/cache.go
vendored
10
cache/cache.go
vendored
|
@ -1,5 +1,7 @@
|
|||
package cache
|
||||
|
||||
//go:generate mockery -name Cache -output mock -case=underscore
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
|
@ -23,7 +25,7 @@ func Set(c context.Context, key string, value interface{}) error {
|
|||
// Default creates an in-memory cache with the default
|
||||
// 30 minute expiration period.
|
||||
func Default() Cache {
|
||||
return cache.NewMemoryWithTTL(time.Minute * 30)
|
||||
return NewTTL(time.Minute * 30)
|
||||
}
|
||||
|
||||
// NewTTL returns an in-memory cache with the specified
|
||||
|
@ -31,9 +33,3 @@ func Default() Cache {
|
|||
func NewTTL(t time.Duration) Cache {
|
||||
return cache.NewMemoryWithTTL(t)
|
||||
}
|
||||
|
||||
// NewTTL returns an in-memory cache with the specified
|
||||
// ttl expiration period.
|
||||
func NewLRU(size int) Cache {
|
||||
return cache.NewLRU(size)
|
||||
}
|
||||
|
|
79
cache/helper.go
vendored
79
cache/helper.go
vendored
|
@ -4,72 +4,51 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// GetRepos returns the user permissions to the named repository
|
||||
// from the cache associated with the current context.
|
||||
func GetPerms(c context.Context, user *model.User, owner, name string) *model.Perm {
|
||||
// GetPerm 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,
|
||||
)
|
||||
val, err := FromContext(c).Get(key)
|
||||
if err != nil {
|
||||
return nil
|
||||
// if we fetch from the cache we can return immediately
|
||||
val, err := Get(c, key)
|
||||
if err == nil {
|
||||
return val.(*model.Perm), nil
|
||||
}
|
||||
return val.(*model.Perm)
|
||||
}
|
||||
|
||||
// SetRepos adds the listof user permissions to the named repsotiory
|
||||
// to the cache assocaited with the current context.
|
||||
func SetPerms(c context.Context, user *model.User, perm *model.Perm, owner, name string) {
|
||||
key := fmt.Sprintf("perms:%s:%s/%s",
|
||||
user.Login,
|
||||
owner,
|
||||
name,
|
||||
)
|
||||
FromContext(c).Set(key, perm)
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
func GetRepos(c context.Context, user *model.User) ([]*model.RepoLite, error) {
|
||||
key := fmt.Sprintf("repos:%s",
|
||||
user.Login,
|
||||
)
|
||||
val, err := FromContext(c).Get(key)
|
||||
if err != nil {
|
||||
return nil
|
||||
// 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
|
||||
}
|
||||
return val.([]*model.RepoLite)
|
||||
}
|
||||
|
||||
// SetRepos adds the listof user repositories to the cache assocaited
|
||||
// with the current context.
|
||||
func SetRepos(c context.Context, user *model.User, repos []*model.RepoLite) {
|
||||
key := fmt.Sprintf("repos:%s",
|
||||
user.Login,
|
||||
)
|
||||
FromContext(c).Set(key, repos)
|
||||
Set(c, key, repos)
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// GetSetRepos is a helper function that attempts to get the
|
||||
// repository list from the cache first. If no data is in the
|
||||
// cache or it is expired, it will remotely fetch the list of
|
||||
// repositories and populate the cache.
|
||||
// func GetSetRepos(c context.Context, user *model.User) ([]*model.RepoLite, error) {
|
||||
// cache := FromContext(c).Repos()
|
||||
// repos := FromContext(c).Repos().Get(user)
|
||||
// if repos != nil {
|
||||
// return repos, nil
|
||||
// }
|
||||
// var err error
|
||||
// repos, err = remote.FromContext(c).Repos(user)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// cache.Set(user, repos)
|
||||
// return repos, nil
|
||||
// }
|
||||
|
|
74
cache/helper_test.go
vendored
74
cache/helper_test.go
vendored
|
@ -1,9 +1,13 @@
|
|||
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"
|
||||
)
|
||||
|
@ -11,43 +15,83 @@ import (
|
|||
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 set and get permissions", func() {
|
||||
SetPerms(c, fakeUser, fakePerm, "octocat", "Spoon-Knife")
|
||||
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)
|
||||
|
||||
v := GetPerms(c, fakeUser, "octocat", "Spoon-Knife")
|
||||
g.Assert(v).Equal(fakePerm)
|
||||
})
|
||||
|
||||
g.It("Should return nil if permissions if not found", func() {
|
||||
v := GetPerms(c, fakeUser, "octocat", "Spoon-Knife")
|
||||
g.Assert(v == nil).IsTrue()
|
||||
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 set and get repositories", func() {
|
||||
SetRepos(c, fakeUser, fakeRepos)
|
||||
|
||||
v := GetRepos(c, fakeUser)
|
||||
g.Assert(v).Equal(fakeRepos)
|
||||
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 return nil if repositories not found", func() {
|
||||
v := GetRepos(c, fakeUser)
|
||||
g.Assert(v == nil).IsTrue()
|
||||
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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
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"},
|
||||
|
|
|
@ -5,11 +5,10 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"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/httputil"
|
||||
"github.com/drone/drone/shared/token"
|
||||
|
@ -17,38 +16,19 @@ import (
|
|||
)
|
||||
|
||||
func ShowIndex(c *gin.Context) {
|
||||
remote := remote.FromContext(c)
|
||||
user := session.User(c)
|
||||
if user == nil {
|
||||
c.Redirect(http.StatusSeeOther, "/login")
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
var repos []*model.RepoLite
|
||||
|
||||
// get the repository list from the cache
|
||||
reposv, ok := c.Get("repos")
|
||||
if ok {
|
||||
repos = reposv.([]*model.RepoLite)
|
||||
} else {
|
||||
repos, err = remote.Repos(user)
|
||||
if err != nil {
|
||||
log.Errorf("Failure to get remote repositories for %s. %s.",
|
||||
user.Login, err)
|
||||
} else {
|
||||
c.Set("repos", repos)
|
||||
}
|
||||
repos, err := cache.GetRepos(c, user)
|
||||
if err != nil {
|
||||
c.String(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// for each repository in the remote system we get
|
||||
// the intersection of those repostiories in Drone
|
||||
// repos_, err := store.GetRepoListOf(c, repos)
|
||||
// if err != nil {
|
||||
// log.Errorf("Failure to get repository list for %s. %s.",
|
||||
// user.Login, err)
|
||||
// }
|
||||
|
||||
c.HTML(200, "repos.html", gin.H{
|
||||
"User": user,
|
||||
"Repos": repos,
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
|
@ -34,7 +35,7 @@ func PostRepo(c *gin.Context) {
|
|||
c.String(404, err.Error())
|
||||
return
|
||||
}
|
||||
m, err := remote.Perm(user, owner, name)
|
||||
m, err := cache.GetPerms(c, user, owner, name)
|
||||
if err != nil {
|
||||
c.String(404, err.Error())
|
||||
return
|
||||
|
@ -176,7 +177,7 @@ func PostRepoKey(c *gin.Context) {
|
|||
body, err := ioutil.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
c.String(500, "Error reading private key from body. %s", err)
|
||||
return
|
||||
return
|
||||
}
|
||||
pkey := crypto.UnmarshalPrivateKey(body)
|
||||
if pkey == nil {
|
||||
|
|
|
@ -5,8 +5,7 @@ import (
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
"github.com/drone/drone/shared/token"
|
||||
"github.com/drone/drone/store"
|
||||
|
@ -18,20 +17,12 @@ func GetSelf(c *gin.Context) {
|
|||
|
||||
func GetFeed(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
remote := remote.FromContext(c)
|
||||
var repos []*model.RepoLite
|
||||
|
||||
// get the repository list from the cache
|
||||
reposv, ok := c.Get("repos")
|
||||
if ok {
|
||||
repos = reposv.([]*model.RepoLite)
|
||||
} else {
|
||||
var err error
|
||||
repos, err = remote.Repos(user)
|
||||
if err != nil {
|
||||
c.String(400, err.Error())
|
||||
return
|
||||
}
|
||||
repos, err := cache.GetRepos(c, user)
|
||||
if err != nil {
|
||||
c.String(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
feed, err := store.GetUserFeed(c, repos)
|
||||
|
@ -44,20 +35,11 @@ func GetFeed(c *gin.Context) {
|
|||
|
||||
func GetRepos(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
remote := remote.FromContext(c)
|
||||
var repos []*model.RepoLite
|
||||
|
||||
// get the repository list from the cache
|
||||
reposv, ok := c.Get("repos")
|
||||
if ok {
|
||||
repos = reposv.([]*model.RepoLite)
|
||||
} else {
|
||||
var err error
|
||||
repos, err = remote.Repos(user)
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
repos, err := cache.GetRepos(c, user)
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// for each repository in the remote system we get
|
||||
|
@ -68,27 +50,18 @@ func GetRepos(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
c.Set("repos", repos)
|
||||
c.IndentedJSON(http.StatusOK, repos_)
|
||||
}
|
||||
|
||||
func GetRemoteRepos(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
remote := remote.FromContext(c)
|
||||
|
||||
reposv, ok := c.Get("repos")
|
||||
if ok {
|
||||
c.IndentedJSON(http.StatusOK, reposv)
|
||||
return
|
||||
}
|
||||
|
||||
repos, err := remote.Repos(user)
|
||||
repos, err := cache.GetRepos(c, user)
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("repos", repos)
|
||||
c.IndentedJSON(http.StatusOK, repos)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,10 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
DefaultURL = "https://github.com"
|
||||
DefaultAPI = "https://api.github.com"
|
||||
DefaultScope = "repo,repo:status,user:email"
|
||||
DefaultURL = "https://github.com"
|
||||
DefaultAPI = "https://api.github.com"
|
||||
DefaultScope = "repo,repo:status,user:email"
|
||||
DefaultMergeRef = "merge"
|
||||
)
|
||||
|
||||
type Github struct {
|
||||
|
@ -29,6 +30,7 @@ type Github struct {
|
|||
API string
|
||||
Client string
|
||||
Secret string
|
||||
MergeRef string
|
||||
Orgs []string
|
||||
Open bool
|
||||
PrivateMode bool
|
||||
|
@ -59,6 +61,7 @@ func Load(env envconfig.Env) *Github {
|
|||
github.SkipVerify, _ = strconv.ParseBool(params.Get("skip_verify"))
|
||||
github.Open, _ = strconv.ParseBool(params.Get("open"))
|
||||
github.GitSSH, _ = strconv.ParseBool(params.Get("ssh"))
|
||||
github.MergeRef = params.Get("merge_ref")
|
||||
|
||||
if github.URL == DefaultURL {
|
||||
github.API = DefaultAPI
|
||||
|
@ -66,6 +69,10 @@ func Load(env envconfig.Env) *Github {
|
|||
github.API = github.URL + "/api/v3/"
|
||||
}
|
||||
|
||||
if github.MergeRef == "" {
|
||||
github.MergeRef = DefaultMergeRef
|
||||
}
|
||||
|
||||
return &github
|
||||
}
|
||||
|
||||
|
@ -402,7 +409,7 @@ func (g *Github) pullRequest(r *http.Request) (*model.Repo, *model.Build, error)
|
|||
build := &model.Build{}
|
||||
build.Event = model.EventPull
|
||||
build.Commit = *hook.PullRequest.Head.SHA
|
||||
build.Ref = fmt.Sprintf("refs/pull/%d/merge", *hook.PullRequest.Number)
|
||||
build.Ref = fmt.Sprintf("refs/pull/%d/%s", *hook.PullRequest.Number, g.MergeRef)
|
||||
build.Link = *hook.PullRequest.HTMLURL
|
||||
build.Branch = *hook.PullRequest.Head.Ref
|
||||
build.Message = *hook.PullRequest.Title
|
||||
|
|
238
remote/mock/remote.go
Normal file
238
remote/mock/remote.go
Normal file
|
@ -0,0 +1,238 @@
|
|||
package mock
|
||||
|
||||
import "github.com/stretchr/testify/mock"
|
||||
|
||||
import "net/http"
|
||||
import "github.com/drone/drone/model"
|
||||
|
||||
type Remote struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (_m *Remote) Login(w http.ResponseWriter, r *http.Request) (*model.User, bool, error) {
|
||||
ret := _m.Called(w, r)
|
||||
|
||||
var r0 *model.User
|
||||
if rf, ok := ret.Get(0).(func(http.ResponseWriter, *http.Request) *model.User); ok {
|
||||
r0 = rf(w, r)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.User)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 bool
|
||||
if rf, ok := ret.Get(1).(func(http.ResponseWriter, *http.Request) bool); ok {
|
||||
r1 = rf(w, r)
|
||||
} else {
|
||||
r1 = ret.Get(1).(bool)
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(http.ResponseWriter, *http.Request) error); ok {
|
||||
r2 = rf(w, r)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
func (_m *Remote) Auth(token string, secret string) (string, error) {
|
||||
ret := _m.Called(token, secret)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(string, string) string); ok {
|
||||
r0 = rf(token, secret)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||
r1 = rf(token, secret)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
func (_m *Remote) Repo(u *model.User, owner string, repo string) (*model.Repo, error) {
|
||||
ret := _m.Called(u, owner, repo)
|
||||
|
||||
var r0 *model.Repo
|
||||
if rf, ok := ret.Get(0).(func(*model.User, string, string) *model.Repo); ok {
|
||||
r0 = rf(u, owner, repo)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Repo)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*model.User, string, string) error); ok {
|
||||
r1 = rf(u, owner, repo)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
func (_m *Remote) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||
ret := _m.Called(u)
|
||||
|
||||
var r0 []*model.RepoLite
|
||||
if rf, ok := ret.Get(0).(func(*model.User) []*model.RepoLite); ok {
|
||||
r0 = rf(u)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.RepoLite)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*model.User) error); ok {
|
||||
r1 = rf(u)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
func (_m *Remote) Perm(u *model.User, owner string, repo string) (*model.Perm, error) {
|
||||
ret := _m.Called(u, owner, repo)
|
||||
|
||||
var r0 *model.Perm
|
||||
if rf, ok := ret.Get(0).(func(*model.User, string, string) *model.Perm); ok {
|
||||
r0 = rf(u, owner, repo)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Perm)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*model.User, string, string) error); ok {
|
||||
r1 = rf(u, owner, repo)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
func (_m *Remote) Script(u *model.User, r *model.Repo, b *model.Build) ([]byte, []byte, error) {
|
||||
ret := _m.Called(u, r, b)
|
||||
|
||||
var r0 []byte
|
||||
if rf, ok := ret.Get(0).(func(*model.User, *model.Repo, *model.Build) []byte); ok {
|
||||
r0 = rf(u, r, b)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 []byte
|
||||
if rf, ok := ret.Get(1).(func(*model.User, *model.Repo, *model.Build) []byte); ok {
|
||||
r1 = rf(u, r, b)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(*model.User, *model.Repo, *model.Build) error); ok {
|
||||
r2 = rf(u, r, b)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
func (_m *Remote) Status(u *model.User, r *model.Repo, b *model.Build, link string) error {
|
||||
ret := _m.Called(u, r, b, link)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*model.User, *model.Repo, *model.Build, string) error); ok {
|
||||
r0 = rf(u, r, b, link)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
func (_m *Remote) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||
ret := _m.Called(u, r)
|
||||
|
||||
var r0 *model.Netrc
|
||||
if rf, ok := ret.Get(0).(func(*model.User, *model.Repo) *model.Netrc); ok {
|
||||
r0 = rf(u, r)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Netrc)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*model.User, *model.Repo) error); ok {
|
||||
r1 = rf(u, r)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
func (_m *Remote) Activate(u *model.User, r *model.Repo, k *model.Key, link string) error {
|
||||
ret := _m.Called(u, r, k, link)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*model.User, *model.Repo, *model.Key, string) error); ok {
|
||||
r0 = rf(u, r, k, link)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
func (_m *Remote) Deactivate(u *model.User, r *model.Repo, link string) error {
|
||||
ret := _m.Called(u, r, link)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*model.User, *model.Repo, string) error); ok {
|
||||
r0 = rf(u, r, link)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
func (_m *Remote) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
||||
ret := _m.Called(r)
|
||||
|
||||
var r0 *model.Repo
|
||||
if rf, ok := ret.Get(0).(func(*http.Request) *model.Repo); ok {
|
||||
r0 = rf(r)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Repo)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *model.Build
|
||||
if rf, ok := ret.Get(1).(func(*http.Request) *model.Build); ok {
|
||||
r1 = rf(r)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*model.Build)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(*http.Request) error); ok {
|
||||
r2 = rf(r)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package remote
|
||||
|
||||
//go:generate mockery -name Remote -output mock -case=underscore
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
|
@ -10,7 +12,8 @@ import (
|
|||
"github.com/drone/drone/remote/gogs"
|
||||
"github.com/drone/drone/shared/envconfig"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func Load(env envconfig.Env) Remote {
|
||||
|
@ -27,7 +30,7 @@ func Load(env envconfig.Env) Remote {
|
|||
return gogs.Load(env)
|
||||
|
||||
default:
|
||||
log.Fatalf("unknown remote driver %s", driver)
|
||||
logrus.Fatalf("unknown remote driver %s", driver)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -83,3 +86,79 @@ type Refresher interface {
|
|||
// token was not refreshed, and error if it failed to refersh.
|
||||
Refresh(*model.User) (bool, error)
|
||||
}
|
||||
|
||||
// Login authenticates the session and returns the
|
||||
// remote user details.
|
||||
func Login(c context.Context, w http.ResponseWriter, r *http.Request) (*model.User, bool, error) {
|
||||
return FromContext(c).Login(w, r)
|
||||
}
|
||||
|
||||
// Auth authenticates the session and returns the remote user
|
||||
// login for the given token and secret
|
||||
func Auth(c context.Context, token, secret string) (string, error) {
|
||||
return FromContext(c).Auth(token, secret)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return FromContext(c).Repos(u)
|
||||
}
|
||||
|
||||
// Perm fetches the named repository permissions from
|
||||
// the remote system for the specified user.
|
||||
func Perm(c context.Context, u *model.User, owner, repo string) (*model.Perm, error) {
|
||||
return FromContext(c).Perm(u, owner, repo)
|
||||
}
|
||||
|
||||
// Script fetches the build script (.drone.yml) from the remote
|
||||
// repository and returns in string format.
|
||||
func Script(c context.Context, u *model.User, r *model.Repo, b *model.Build) ([]byte, []byte, error) {
|
||||
return FromContext(c).Script(u, r, b)
|
||||
}
|
||||
|
||||
// Status sends the commit status to the remote system.
|
||||
// An example would be the GitHub pull request status.
|
||||
func Status(c context.Context, u *model.User, r *model.Repo, b *model.Build, link string) error {
|
||||
return FromContext(c).Status(u, r, b, link)
|
||||
}
|
||||
|
||||
// Netrc returns a .netrc file that can be used to clone
|
||||
// private repositories from a remote system.
|
||||
func Netrc(c context.Context, u *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||
return FromContext(c).Netrc(u, r)
|
||||
}
|
||||
|
||||
// Activate activates a repository by creating the post-commit hook and
|
||||
// adding the SSH deploy key, if applicable.
|
||||
func Activate(c context.Context, u *model.User, r *model.Repo, k *model.Key, link string) error {
|
||||
return FromContext(c).Activate(u, r, k, link)
|
||||
}
|
||||
|
||||
// Deactivate removes a repository by removing all the post-commit hooks
|
||||
// which are equal to link and removing the SSH deploy key.
|
||||
func Deactivate(c context.Context, u *model.User, r *model.Repo, link string) error {
|
||||
return FromContext(c).Deactivate(u, r, link)
|
||||
}
|
||||
|
||||
// Hook parses the post-commit hook from the Request body
|
||||
// and returns the required data in a standard format.
|
||||
func Hook(c context.Context, r *http.Request) (*model.Repo, *model.Build, error) {
|
||||
return FromContext(c).Hook(r)
|
||||
}
|
||||
|
||||
// Refresh refreshes an oauth token and expiration for the given
|
||||
// user. It returns true if the token was refreshed, false if the
|
||||
// token was not refreshed, and error if it failed to refersh.
|
||||
func Refresh(c context.Context, u *model.User) (bool, error) {
|
||||
remote := FromContext(c)
|
||||
refresher, ok := remote.(Refresher)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
return refresher.Refresh(u)
|
||||
}
|
||||
|
|
54
router/middleware/cache/perms.go
vendored
54
router/middleware/cache/perms.go
vendored
|
@ -1,54 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const permKey = "perm"
|
||||
|
||||
// Perms is a middleware function that attempts to cache the
|
||||
// user's remote repository permissions (ie in GitHub) to minimize
|
||||
// remote calls that might be expensive, slow or rate-limited.
|
||||
func Perms(c *gin.Context) {
|
||||
var (
|
||||
owner = c.Param("owner")
|
||||
name = c.Param("name")
|
||||
user, _ = c.Get("user")
|
||||
)
|
||||
|
||||
if user == nil {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// if the item already exists in the cache
|
||||
// we can continue the middleware chain and
|
||||
// exit afterwards.
|
||||
v := cache.GetPerms(c,
|
||||
user.(*model.User),
|
||||
owner,
|
||||
name,
|
||||
)
|
||||
if v != nil {
|
||||
c.Set("perm", v)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, if the item isn't cached we execute
|
||||
// the middleware chain and then cache the permissions
|
||||
// after the request is processed.
|
||||
c.Next()
|
||||
|
||||
perm, ok := c.Get("perm")
|
||||
if ok {
|
||||
cache.SetPerms(c,
|
||||
user.(*model.User),
|
||||
perm.(*model.Perm),
|
||||
owner,
|
||||
name,
|
||||
)
|
||||
}
|
||||
}
|
61
router/middleware/cache/perms_test.go
vendored
61
router/middleware/cache/perms_test.go
vendored
|
@ -1,61 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/franela/goblin"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestPermCache(t *testing.T) {
|
||||
|
||||
g := goblin.Goblin(t)
|
||||
g.Describe("Perm Cache", func() {
|
||||
|
||||
var c *gin.Context
|
||||
g.BeforeEach(func() {
|
||||
c = new(gin.Context)
|
||||
cache.ToContext(c, cache.Default())
|
||||
})
|
||||
|
||||
g.It("should skip when no user session", func() {
|
||||
c.Params = gin.Params{
|
||||
gin.Param{Key: "owner", Value: "octocat"},
|
||||
gin.Param{Key: "name", Value: "hello-world"},
|
||||
}
|
||||
|
||||
Perms(c)
|
||||
|
||||
_, ok := c.Get("perm")
|
||||
g.Assert(ok).IsFalse()
|
||||
})
|
||||
|
||||
g.It("should get perms from cache", func() {
|
||||
c.Params = gin.Params{
|
||||
gin.Param{Key: "owner", Value: "octocat"},
|
||||
gin.Param{Key: "name", Value: "hello-world"},
|
||||
}
|
||||
c.Set("user", fakeUser)
|
||||
cache.SetPerms(c, fakeUser, fakePerm, "octocat", "hello-world")
|
||||
|
||||
Perms(c)
|
||||
|
||||
perm, ok := c.Get("perm")
|
||||
g.Assert(ok).IsTrue()
|
||||
g.Assert(perm).Equal(fakePerm)
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
var fakePerm = &model.Perm{
|
||||
Pull: true,
|
||||
Push: true,
|
||||
Admin: true,
|
||||
}
|
||||
|
||||
var fakeUser = &model.User{
|
||||
Login: "octocat",
|
||||
}
|
42
router/middleware/cache/repos.go
vendored
42
router/middleware/cache/repos.go
vendored
|
@ -1,42 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Repos is a middleware function that attempts to cache the
|
||||
// user's list of remote repositories (ie in GitHub) to minimize
|
||||
// remote calls that might be expensive, slow or rate-limited.
|
||||
func Repos(c *gin.Context) {
|
||||
var user, _ = c.Get("user")
|
||||
|
||||
if user == nil {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// if the item already exists in the cache
|
||||
// we can continue the middleware chain and
|
||||
// exit afterwards.
|
||||
v := cache.GetRepos(c, user.(*model.User))
|
||||
if v != nil {
|
||||
c.Set("repos", v)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, if the item isn't cached we execute
|
||||
// the middleware chain and then cache the permissions
|
||||
// after the request is processed.
|
||||
c.Next()
|
||||
|
||||
repos, ok := c.Get("repos")
|
||||
if ok {
|
||||
cache.SetRepos(c,
|
||||
user.(*model.User),
|
||||
repos.([]*model.RepoLite),
|
||||
)
|
||||
}
|
||||
}
|
46
router/middleware/cache/repos_test.go
vendored
46
router/middleware/cache/repos_test.go
vendored
|
@ -1,46 +0,0 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/franela/goblin"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestReposCache(t *testing.T) {
|
||||
|
||||
g := goblin.Goblin(t)
|
||||
g.Describe("Repo List Cache", func() {
|
||||
|
||||
var c *gin.Context
|
||||
g.BeforeEach(func() {
|
||||
c = new(gin.Context)
|
||||
cache.ToContext(c, cache.Default())
|
||||
})
|
||||
|
||||
g.It("should skip when no user session", func() {
|
||||
Perms(c)
|
||||
|
||||
_, ok := c.Get("perm")
|
||||
g.Assert(ok).IsFalse()
|
||||
})
|
||||
|
||||
g.It("should get repos from cache", func() {
|
||||
c.Set("user", fakeUser)
|
||||
cache.SetRepos(c, fakeUser, fakeRepos)
|
||||
|
||||
Repos(c)
|
||||
|
||||
repos, ok := c.Get("repos")
|
||||
g.Assert(ok).IsTrue()
|
||||
g.Assert(repos).Equal(fakeRepos)
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
var fakeRepos = []*model.RepoLite{
|
||||
{Owner: "octocat", Name: "hello-world"},
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/shared/token"
|
||||
|
@ -112,19 +113,6 @@ func SetPerm() gin.HandlerFunc {
|
|||
repo := Repo(c)
|
||||
perm := &model.Perm{}
|
||||
|
||||
if user != nil {
|
||||
// attempt to get the permissions from a local cache
|
||||
// just to avoid excess API calls to GitHub
|
||||
val, ok := c.Get("perm")
|
||||
if ok {
|
||||
c.Next()
|
||||
|
||||
log.Debugf("%s using cached %+v permission to %s",
|
||||
user.Login, val, repo.FullName)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
// if the user is not authenticated, and the
|
||||
// repository is private, the user has NO permission
|
||||
|
@ -150,7 +138,7 @@ func SetPerm() gin.HandlerFunc {
|
|||
// check the remote system to get the users permissiosn.
|
||||
default:
|
||||
var err error
|
||||
perm, err = remote.FromContext(c).Perm(user, repo.Owner, repo.Name)
|
||||
perm, err = cache.GetPerms(c, user, repo.Owner, repo.Name)
|
||||
if err != nil {
|
||||
perm.Pull = false
|
||||
perm.Push = false
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/drone/drone/controller"
|
||||
"github.com/drone/drone/router/middleware/cache"
|
||||
"github.com/drone/drone/router/middleware/header"
|
||||
"github.com/drone/drone/router/middleware/location"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
|
@ -27,10 +26,9 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
e.Use(header.Secure)
|
||||
e.Use(middleware...)
|
||||
e.Use(session.SetUser())
|
||||
e.Use(cache.Perms)
|
||||
e.Use(token.Refresh)
|
||||
|
||||
e.GET("/", cache.Repos, controller.ShowIndex)
|
||||
e.GET("/", controller.ShowIndex)
|
||||
e.GET("/login", controller.ShowLogin)
|
||||
e.GET("/login/form", controller.ShowLoginForm)
|
||||
e.GET("/logout", controller.GetLogout)
|
||||
|
@ -64,8 +62,8 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
user.Use(session.MustUser())
|
||||
user.GET("", controller.GetSelf)
|
||||
user.GET("/feed", controller.GetFeed)
|
||||
user.GET("/repos", cache.Repos, controller.GetRepos)
|
||||
user.GET("/repos/remote", cache.Repos, controller.GetRemoteRepos)
|
||||
user.GET("/repos", controller.GetRepos)
|
||||
user.GET("/repos/remote", controller.GetRemoteRepos)
|
||||
user.POST("/token", controller.PostToken)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue