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

Read config #55

Merged
merged 4 commits into from
Jul 25, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
read local config and send to analyzers
Signed-off-by: Maxim Sukharev <[email protected]>
  • Loading branch information
smacker committed Jul 24, 2018
commit 97f723019142cd9fcc2f3158471b522f1b9d1440
6 changes: 4 additions & 2 deletions cmd/lookout/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ func (c *PushCommand) Execute(args []string) error {
return err
}

srv := lookout.NewServer(nil, &LogPoster{log.DefaultLogger}, nil, map[string]lookout.AnalyzerClient{
"test-analyzes": client,
srv := lookout.NewServer(nil, &LogPoster{log.DefaultLogger}, dataSrv.FileGetter, map[string]lookout.Analyzer{
"test-analyzes": lookout.Analyzer{
Client: client,
},
})

log, err := c.repo.Log(&gogit.LogOptions{From: plumbing.NewHash(toRef.Hash)})
Expand Down
6 changes: 4 additions & 2 deletions cmd/lookout/review.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ func (c *ReviewCommand) Execute(args []string) error {
return err
}

srv := lookout.NewServer(nil, &LogPoster{log.DefaultLogger}, nil, map[string]lookout.AnalyzerClient{
"test-analyzes": client,
srv := lookout.NewServer(nil, &LogPoster{log.DefaultLogger}, dataSrv.FileGetter, map[string]lookout.Analyzer{
"test-analyzes": lookout.Analyzer{
Client: client,
},
})

err = srv.HandleReview(context.TODO(), &lookout.ReviewEvent{
Expand Down
24 changes: 8 additions & 16 deletions cmd/lookout/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,6 @@ func init() {
}
}

// AnalyzerConfig is a configuration of analyzer
type AnalyzerConfig struct {
Name string
Addr string
}

// Config is a server configuration
type Config struct {
Analyzers []AnalyzerConfig
}

type ServeCommand struct {
ConfigFile string `long:"config" short:"c" default:"config.yml" env:"LOOKOUT_CONFIG_FILE" description:"path to configuration file"`
GithubUser string `long:"github-user" env:"GITHUB_USER" description:"user for the GitHub API"`
Expand All @@ -51,7 +40,7 @@ type ServeCommand struct {
}

func (c *ServeCommand) Execute(args []string) error {
var conf Config
var conf lookout.Config
configData, err := ioutil.ReadFile(c.ConfigFile)
if err != nil {
return fmt.Errorf("Can't open configuration file: %s", err)
Expand All @@ -71,13 +60,16 @@ func (c *ServeCommand) Execute(args []string) error {
return err
}

analyzers := make(map[string]lookout.AnalyzerClient, len(conf.Analyzers))
analyzers := make(map[string]lookout.Analyzer, len(conf.Analyzers))
for _, aConf := range conf.Analyzers {
a, err := c.startAnalyzer(aConf)
client, err := c.startAnalyzer(aConf)
if err != nil {
return err
}
analyzers[aConf.Name] = a
analyzers[aConf.Name] = lookout.Analyzer{
Client: client,
Config: aConf,
}
}

poster, err := c.initPoster()
Expand Down Expand Up @@ -113,7 +105,7 @@ func (c *ServeCommand) initPoster() (lookout.Poster, error) {
}), nil
}

func (c *ServeCommand) startAnalyzer(conf AnalyzerConfig) (lookout.AnalyzerClient, error) {
func (c *ServeCommand) startAnalyzer(conf lookout.AnalyzerConfig) (lookout.AnalyzerClient, error) {
addr, err := lookout.ToGoGrpcAddress(conf.Addr)
if err != nil {
return nil, err
Expand Down
113 changes: 100 additions & 13 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,47 @@ package lookout

import (
"context"
"fmt"
"sync"

"github.com/src-d/lookout/pb"
log "gopkg.in/src-d/go-log.v1"
yaml "gopkg.in/yaml.v2"
)

type reqSent func(AnalyzerClient) ([]*Comment, error)
// AnalyzerConfig is a configuration of analyzer
type AnalyzerConfig struct {
Name string
// Addr is gRPC URL.
// can be defined only in global config, repository-scoped configuration is ignored
Addr string
// Settings any configuration for an analyzer
Settings map[string]interface{}
}

// Config is a server configuration
type Config struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a name like ServerConfig may be could help avoid the confusion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed

Analyzers []AnalyzerConfig
}

// Analyzer is a struct of analyzer client and config
type Analyzer struct {
Client AnalyzerClient
Config AnalyzerConfig
}

type reqSent func(client AnalyzerClient, settings map[string]interface{}) ([]*Comment, error)

// Server implements glue between providers / data-server / analyzers
type Server struct {
watcher Watcher
poster Poster
fileGetter FileGetter
analyzers map[string]AnalyzerClient
analyzers map[string]Analyzer
}

// NewServer creates new Server
func NewServer(w Watcher, p Poster, fileGetter FileGetter, analyzers map[string]AnalyzerClient) *Server {
func NewServer(w Watcher, p Poster, fileGetter FileGetter, analyzers map[string]Analyzer) *Server {
return &Server{w, p, fileGetter, analyzers}
}

Expand Down Expand Up @@ -51,16 +75,25 @@ func (s *Server) HandleReview(ctx context.Context, e *ReviewEvent) error {
})
logger.Infof("processing pull request")

send := func(a AnalyzerClient) ([]*Comment, error) {
conf, err := s.getConfig(ctx, logger, e)
if err != nil {
return err
}

send := func(a AnalyzerClient, settings map[string]interface{}) ([]*Comment, error) {
st := pb.ToStruct(settings)
if st != nil {
e.Configuration = *st
}
resp, err := a.NotifyReviewEvent(ctx, e)
if err != nil {
return nil, err
}
return resp.Comments, nil
}
comments := s.concurrentRequest(ctx, logger, send)
comments := s.concurrentRequest(ctx, logger, conf, send)

s.post(ctx, logger, e, comments.Get())
s.post(ctx, logger, e, comments)
return nil
}

Expand All @@ -73,21 +106,75 @@ func (s *Server) HandlePush(ctx context.Context, e *PushEvent) error {
})
logger.Infof("processing push")

send := func(a AnalyzerClient) ([]*Comment, error) {
conf, err := s.getConfig(ctx, logger, e)
if err != nil {
return err
}

send := func(a AnalyzerClient, settings map[string]interface{}) ([]*Comment, error) {
st := pb.ToStruct(settings)
if st != nil {
e.Configuration = *st
}
resp, err := a.NotifyPushEvent(ctx, e)
if err != nil {
return nil, err
}
return resp.Comments, nil
}
comments := s.concurrentRequest(ctx, logger, send)
comments := s.concurrentRequest(ctx, logger, conf, send)

s.post(ctx, logger, e, comments.Get())
s.post(ctx, logger, e, comments)
return nil
}

// FIXME(max): it's better to hold logger inside context
func (s *Server) concurrentRequest(ctx context.Context, logger log.Logger, send reqSent) commentsList {
func (s *Server) getConfig(ctx context.Context, logger log.Logger, e Event) (map[string]AnalyzerConfig, error) {
rev := e.Revision()
scanner, err := s.fileGetter.GetFiles(ctx, &FilesRequest{
Revision: &rev.Head,
IncludePattern: `^\.lookout\.yml$`,
WantContents: true,
})
if err != nil {
return nil, err
}
var configContent []byte
if scanner.Next() {
configContent = scanner.File().Content
}
scanner.Close()
if err := scanner.Err(); err != nil {
return nil, err
}

if len(configContent) == 0 {
logger.Infof("repository config is not found")
return nil, nil
}

var conf Config
if err := yaml.Unmarshal(configContent, &conf); err != nil {
return nil, fmt.Errorf("Can't parse configuration file: %s", err)
}

res := make(map[string]AnalyzerConfig, len(s.analyzers))
for name, a := range s.analyzers {
res[name] = a.Config
}
for _, aConf := range conf.Analyzers {
if _, ok := s.analyzers[aConf.Name]; !ok {
logger.Warningf("analyzer '%s' required by local config isn't enabled on server", aConf.Name)
continue
}
res[aConf.Name] = aConf
}

return res, nil
}

// FIXME(max): it's better to hold logger inside context
func (s *Server) concurrentRequest(ctx context.Context, logger log.Logger, conf map[string]AnalyzerConfig, send reqSent) []*Comment {
var comments commentsList

var wg sync.WaitGroup
Expand All @@ -100,7 +187,7 @@ func (s *Server) concurrentRequest(ctx context.Context, logger log.Logger, send
"analyzer": name,
})

cs, err := send(a)
cs, err := send(a, conf[name].Settings)
if err != nil {
aLogger.Errorf(err, "analysis failed")
return
Expand All @@ -111,11 +198,11 @@ func (s *Server) concurrentRequest(ctx context.Context, logger log.Logger, send
}

comments.Add(cs...)
}(name, a)
}(name, a.Client)
}
wg.Wait()

return comments
return comments.Get()
}

func (s *Server) post(ctx context.Context, logger log.Logger, e Event, comments []*Comment) {
Expand Down