Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend Logging & Report to WebHook Caller back if pulls are disabled #369

Merged
merged 1 commit into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ import (
func loop(c *cli.Context) error {

// debug level if requested by user
// TODO: format output & options to switch to json aka. option to add channels to send logs to
if c.Bool("debug") {
logrus.SetReportCaller(true)
logrus.SetLevel(logrus.DebugLevel)
} else {
logrus.SetLevel(logrus.WarnLevel)
Expand Down
26 changes: 18 additions & 8 deletions server/api/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func BlockTilQueueHasRunningItem(c *gin.Context) {
func PostHook(c *gin.Context) {
remote_ := remote.FromContext(c)

tmprepo, build, err := remote_.Hook(c.Request)
tmpRepo, build, err := remote_.Hook(c.Request)
if err != nil {
logrus.Errorf("failure to parse hook. %s", err)
c.AbortWithError(400, err)
Expand All @@ -89,7 +89,7 @@ func PostHook(c *gin.Context) {
c.Writer.WriteHeader(200)
return
}
if tmprepo == nil {
if tmpRepo == nil {
logrus.Errorf("failure to ascertain repo from hook.")
c.Writer.WriteHeader(400)
return
Expand All @@ -104,14 +104,14 @@ func PostHook(c *gin.Context) {
return
}

repo, err := store.GetRepoOwnerName(c, tmprepo.Owner, tmprepo.Name)
repo, err := store.GetRepoOwnerName(c, tmpRepo.Owner, tmpRepo.Name)
if err != nil {
logrus.Errorf("failure to find repo %s/%s from hook. %s", tmprepo.Owner, tmprepo.Name, err)
logrus.Errorf("failure to find repo %s/%s from hook. %s", tmpRepo.Owner, tmpRepo.Name, err)
c.AbortWithError(404, err)
return
}
if !repo.IsActive {
logrus.Errorf("ignoring hook. %s/%s is inactive.", tmprepo.Owner, tmprepo.Name)
logrus.Errorf("ignoring hook. %s/%s is inactive.", tmpRepo.Owner, tmpRepo.Name)
c.AbortWithError(204, err)
return
}
Expand Down Expand Up @@ -139,6 +139,7 @@ func PostHook(c *gin.Context) {

if build.Event == model.EventPull && !repo.AllowPull {
logrus.Infof("ignoring hook. repo %s is disabled for pull requests.", repo.FullName)
c.Writer.Write([]byte("pulls are disabled on woodpecker for this repo"))
6543 marked this conversation as resolved.
Show resolved Hide resolved
c.Writer.WriteHeader(204)
return
}
Expand All @@ -154,9 +155,14 @@ func PostHook(c *gin.Context) {
// may be stale. Therefore, we should refresh prior to dispatching
// the build.
if refresher, ok := remote_.(remote.Refresher); ok {
ok, _ := refresher.Refresh(user)
if ok {
store.UpdateUser(c, user)
ok, err := refresher.Refresh(user)
if err != nil {
logrus.Errorf("failed to refresh oauth2 token: %s", err)
} else if ok {
if err := store.UpdateUser(c, user); err != nil {
logrus.Errorf("error while updating user: %s", err)
// move forward
}
}
}

Expand Down Expand Up @@ -286,12 +292,16 @@ func PostHook(c *gin.Context) {
queueBuild(build, repo, buildItems)
}

// TODO: parse yaml once and not for each filter function
func branchFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) (bool, error) {
logrus.Tracef("hook.branchFiltered(): build branch: '%s' build event: '%s' config count: %d", build.Branch, build.Event, len(remoteYamlConfigs))
for _, remoteYamlConfig := range remoteYamlConfigs {
parsedPipelineConfig, err := yaml.ParseString(string(remoteYamlConfig.Data))
if err != nil {
logrus.Tracef("parse config '%s': %s", remoteYamlConfig.Name, err)
return false, err
}
logrus.Tracef("config '%s': %#v", remoteYamlConfig.Name, parsedPipelineConfig)

if !parsedPipelineConfig.Branches.Match(build.Branch) && build.Event != model.EventTag && build.Event != model.EventDeploy {
} else {
Expand Down
3 changes: 2 additions & 1 deletion server/api/z.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
package api

import (
"github.com/gin-gonic/gin"
"github.com/woodpecker-ci/woodpecker/server/store"
"github.com/woodpecker-ci/woodpecker/version"

"github.com/gin-gonic/gin"
)

// Health endpoint returns a 500 if the server state is unhealthy.
Expand Down
2 changes: 2 additions & 0 deletions server/model/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const (
EventDeploy = "deployment"
)

// TODO: type StatusValue string

const (
StatusSkipped = "skipped"
StatusPending = "pending"
Expand Down
7 changes: 0 additions & 7 deletions server/model/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ import (
"strings"
)

type RepoLite struct {
Owner string `json:"owner"`
Name string `json:"name"`
FullName string `json:"full_name"`
Avatar string `json:"avatar_url"`
}

// Repo represents a repository.
//
// swagger:model repo
Expand Down
9 changes: 0 additions & 9 deletions server/remote/coding/coding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,6 @@ var (
Name: "not_found_project",
}

fakeRepos = []*model.RepoLite{
&model.RepoLite{
Owner: "demo1",
Name: "test1",
FullName: "demo1/test1",
Avatar: "/static/project_icon/scenery-5.png",
},
}

fakeBuild = &model.Build{
Commit: "4504a072cc",
}
Expand Down
4 changes: 4 additions & 0 deletions server/remote/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import (
"golang.org/x/net/context"
)

// TODO: use pagination
// TODO: use context
// TODO: add Driver() who return source forge back

type Remote interface {
// Login authenticates the session and returns the
// remote user details.
Expand Down
13 changes: 0 additions & 13 deletions server/router/middleware/session/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,6 @@ func Repo(c *gin.Context) *model.Repo {
return r
}

func Repos(c *gin.Context) []*model.RepoLite {
v, ok := c.Get("repos")
if !ok {
return nil
}
r, ok := v.([]*model.RepoLite)
if !ok {
return nil
}
return r
}

func SetRepo() gin.HandlerFunc {
return func(c *gin.Context) {
var (
Expand Down Expand Up @@ -93,7 +81,6 @@ func Perm(c *gin.Context) *model.Perm {
}

func SetPerm() gin.HandlerFunc {

return func(c *gin.Context) {
user := User(c)
repo := Repo(c)
Expand Down
12 changes: 0 additions & 12 deletions server/router/middleware/session/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,6 @@ func User(c *gin.Context) *model.User {
return u
}

func Token(c *gin.Context) *token.Token {
v, ok := c.Get("token")
if !ok {
return nil
}
u, ok := v.(*token.Token)
if !ok {
return nil
}
return u
}

func SetUser() gin.HandlerFunc {
return func(c *gin.Context) {
var user *model.User
Expand Down
10 changes: 8 additions & 2 deletions server/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ package router
import (
"net/http"

"github.com/gin-gonic/gin"

"github.com/woodpecker-ci/woodpecker/server/api"
"github.com/woodpecker-ci/woodpecker/server/api/debug"
"github.com/woodpecker-ci/woodpecker/server/api/metrics"
"github.com/woodpecker-ci/woodpecker/server/router/middleware/header"
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
"github.com/woodpecker-ci/woodpecker/server/router/middleware/token"
"github.com/woodpecker-ci/woodpecker/server/web"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)

// Load loads the router
Expand All @@ -34,6 +35,11 @@ func Load(serveHTTP func(w http.ResponseWriter, r *http.Request), middleware ...
e := gin.New()
e.Use(gin.Recovery())

e.Use(func(c *gin.Context) {
6543 marked this conversation as resolved.
Show resolved Hide resolved
logrus.Tracef("[%s] %s", c.Request.Method, c.Request.URL.String())
c.Next()
})

e.Use(header.NoCache)
e.Use(header.Options)
e.Use(header.Secure)
Expand Down
21 changes: 18 additions & 3 deletions server/shared/configFetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (

"github.com/woodpecker-ci/woodpecker/server/model"
"github.com/woodpecker-ci/woodpecker/server/remote"

"github.com/sirupsen/logrus"
)

type configFetcher struct {
Expand All @@ -25,10 +27,14 @@ func NewConfigFetcher(remote remote.Remote, user *model.User, repo *model.Repo,
}
}

// Fetch
// TODO: dedupe code
func (cf *configFetcher) Fetch() (files []*remote.FileMeta, err error) {
var file []byte
config := strings.TrimSpace(cf.repo.Config)

logrus.Tracef("Start Fetching config for '%s'", cf.repo.FullName)

for i := 0; i < 5; i++ {
select {
case <-time.After(time.Second * time.Duration(i)):
Expand All @@ -37,6 +43,7 @@ func (cf *configFetcher) Fetch() (files []*remote.FileMeta, err error) {
if !strings.HasSuffix(config, "/") {
file, err = cf.remote_.File(cf.user, cf.repo, cf.build, config)
if err == nil && len(file) != 0 {
logrus.Tracef("ConfigFetch[%s]: found file '%s'", cf.repo.FullName, config)
return []*remote.FileMeta{{
Name: config,
Data: file,
Expand All @@ -47,29 +54,37 @@ func (cf *configFetcher) Fetch() (files []*remote.FileMeta, err error) {
// or a folder
files, err = cf.remote_.Dir(cf.user, cf.repo, cf.build, strings.TrimSuffix(config, "/"))
if err == nil {
logrus.Tracef("ConfigFetch[%s]: found %d files in '%s'", cf.repo.FullName, len(files), config)
return filterPipelineFiles(files), nil
}
} else {
logrus.Tracef("ConfigFetch[%s]: user did not defined own config follow default procedure", cf.repo.FullName)
// no user defined config so try .woodpecker/*.yml -> .woodpecker.yml -> .drone.yml

// test .woodpecker/ folder
// if folder is not supported we will get a "Not implemented" error and continue
files, err = cf.remote_.Dir(cf.user, cf.repo, cf.build, ".woodpecker")
config = ".woodpecker"
files, err = cf.remote_.Dir(cf.user, cf.repo, cf.build, config)
logrus.Tracef("ConfigFetch[%s]: found %d files in '%s'", cf.repo.FullName, len(files), config)
files = filterPipelineFiles(files)
if err == nil && len(files) != 0 {
return files, nil
}

file, err = cf.remote_.File(cf.user, cf.repo, cf.build, ".woodpecker.yml")
config = ".woodpecker.yml"
file, err = cf.remote_.File(cf.user, cf.repo, cf.build, config)
if err == nil && len(file) != 0 {
logrus.Tracef("ConfigFetch[%s]: found file '%s'", cf.repo.FullName, config)
return []*remote.FileMeta{{
Name: ".woodpecker.yml",
Data: file,
}}, nil
}

file, err = cf.remote_.File(cf.user, cf.repo, cf.build, ".drone.yml")
config = ".drone.yml"
file, err = cf.remote_.File(cf.user, cf.repo, cf.build, config)
if err == nil && len(file) != 0 {
logrus.Tracef("ConfigFetch[%s]: found file '%s'", cf.repo.FullName, config)
return []*remote.FileMeta{{
Name: ".drone.yml",
Data: file,
Expand Down
22 changes: 13 additions & 9 deletions shared/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"net/http"

"github.com/golang-jwt/jwt"
"github.com/sirupsen/logrus"
)

type SecretFunc func(*Token) (string, error)
Expand All @@ -31,15 +32,15 @@ const (
AgentToken = "agent"
)

// Default algorithm used to sign JWT tokens.
// SignerAlgo id default algorithm used to sign JWT tokens.
const SignerAlgo = "HS256"

type Token struct {
Kind string
Text string
}

func Parse(raw string, fn SecretFunc) (*Token, error) {
func parse(raw string, fn SecretFunc) (*Token, error) {
token := &Token{}
parsed, err := jwt.Parse(raw, keyFunc(token, fn))
if err != nil {
Expand All @@ -51,21 +52,24 @@ func Parse(raw string, fn SecretFunc) (*Token, error) {
}

func ParseRequest(r *http.Request, fn SecretFunc) (*Token, error) {
var token = r.Header.Get("Authorization")
token := r.Header.Get("Authorization")

// first we attempt to get the token from the
// authorization header.
if len(token) != 0 {
token = r.Header.Get("Authorization")
fmt.Sscanf(token, "Bearer %s", &token)
return Parse(token, fn)
logrus.Tracef("token.ParseRequest: found token in header: %s", token)
bearer := token
if _, err := fmt.Sscanf(token, "Bearer %s", &bearer); err != nil {
return nil, err
}
return parse(bearer, fn)
}

// then we attempt to get the token from the
// access_token url query parameter
token = r.FormValue("access_token")
if len(token) != 0 {
return Parse(token, fn)
return parse(token, fn)
}

// and finally we attempt to get the token from
Expand All @@ -74,7 +78,7 @@ func ParseRequest(r *http.Request, fn SecretFunc) (*Token, error) {
if err != nil {
return nil, err
}
return Parse(cookie.Value, fn)
return parse(cookie.Value, fn)
}

func CheckCsrf(r *http.Request, fn SecretFunc) error {
Expand All @@ -88,7 +92,7 @@ func CheckCsrf(r *http.Request, fn SecretFunc) error {

// parse the raw CSRF token value and validate
raw := r.Header.Get("X-CSRF-TOKEN")
_, err := Parse(raw, fn)
_, err := parse(raw, fn)
return err
}

Expand Down