Skip to content

Commit

Permalink
Refactor configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
ragurney committed Jan 31, 2019
1 parent 235c39e commit d135324
Show file tree
Hide file tree
Showing 15 changed files with 222 additions and 103 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/

# Secrets directory for development
secrets/

vendor
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ FROM alpine AS term-check
RUN apk add ca-certificates

COPY --from=server_builder /go/bin/term-check /bin/term-check
ENTRYPOINT ["/bin/term-check"]
COPY --from=server_builder /go/src/github.com/ragurney/term-check/config.yaml .

ENTRYPOINT ["/bin/term-check", "--config", "config.yaml"]
6 changes: 0 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,3 @@ clean:
rm -f $(BINARY_UNIX)
run: build
./$(BINARY_NAME)

# Cross compilation
# build-linux:
# CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BINARY_UNIX) -v
# docker-build:
# docker run --rm -it -v "$(GOPATH)":/go -w /go/src/bitbucket.org/rsohlich/makepost golang:latest go build -o "$(BINARY_UNIX)" -v
41 changes: 10 additions & 31 deletions cmd/term-check/main.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,23 @@
// Package main provides the entry point for the GitHub application
package main

import (
"strconv"

"github.com/ragurney/term-check/internal/bot"
"github.com/ragurney/term-check/pkg/config"

"flag"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"

"github.com/ragurney/term-check/internal/bot"
"github.com/ragurney/term-check/internal/config"
)

var filepath = flag.String("config", "config.yaml", "Location of the configuration file.")

func main() {
zerolog.TimeFieldFormat = ""
flag.Parse()

c := config.New()

id, err := strconv.Atoi(c.Env("APP_ID", ""))
if err != nil {
log.Panic().Err(err)
}

pk := c.Env("PRIVATE_KEY_PATH", "")

secrets, err := config.Secrets()

if err != nil {
log.Panic().Err(err)
}

ws, ok := secrets["WEBHOOK_SECRET_KEY"]

if ok != true {
log.Panic().Msg("Could not read PRIVATE_KEY_PATH from secrets.")
}
c := config.New(*filepath)

log.Info().Msg("Starting service...")

bot.New(
bot.WithAppID(id),
bot.WithPrivateKeyPath(pk),
bot.WithWebhookSecretKey(ws),
).Start()
bot.New(c.ForBot, c.ForClient, c.ForServer).Start()
}
19 changes: 19 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
shared:
appID: &appID 18238
botConfig:
appID: *appID
termList:
- master
- slave
- whitelist
- blacklist
checkName: Term Check
checkSuccessSummary: ✅ No flagged terms found.
checkFailureSummary: ⚠️ Flagged terms found.
checkDetails: Placeholder text
annotationTitle: Term Notice
annotationBody: >
Please consider changing the following terms on this line: %s
clientConfig:
appID: *appID
privateKeyPath: /secrets/PRIVATE_KEY
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ require (
github.com/waigani/diffparser v0.0.0-20180518143736-8ef6bf958d9e
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect
gopkg.in/yaml.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.2.2
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
77 changes: 44 additions & 33 deletions internal/bot/bot.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Package bot contains all of the main logic for handling GitHub events, including creating CheckRuns for each
// Pull Request
package bot

import (
Expand All @@ -10,6 +12,7 @@ import (
"time"

"github.com/google/go-github/v18/github"
"github.com/ragurney/term-check/internal/config"
gh "github.com/ragurney/term-check/pkg/github"
"github.com/ragurney/term-check/pkg/lib"
"github.com/rs/zerolog"
Expand All @@ -18,7 +21,6 @@ import (
)

const (
checkName = "Term Check"
checkSuccessConclusion = "success"
checkFailureConclusion = "neutral"
checkRunAnnotationLevel = "warning"
Expand All @@ -37,38 +39,46 @@ var (
"opened": {},
"reopened": {},
}
flaggedTerms = []string{
"master",
"slave",
}
)

// Bot is a type containing config for the GitHub bot logic
type Bot struct {
client *gh.Client
server *gh.Server
privateKeyPath string
webhookSecretKey string
appID int
client *gh.Client
server *gh.Server
privateKeyPath string
webhookSecretKey string
appID int
termList []string
checkName string
checkSuccessSummary string
checkFailureSummary string
checkDetails string
annotationTitle string
annotationBody string
}

// New creates a new instance of Bot, taking in BotOptions
func New(options ...Option) *Bot {
func New(botConfig *config.BotConfig, clientConfig *config.ClientConfig, serverConfig *config.ServerConfig) *Bot {
zerolog.TimeFieldFormat = ""

b := Bot{}

for _, option := range options {
option(&b)
b := Bot{
appID: botConfig.AppID,
termList: botConfig.TermList,
checkName: botConfig.CheckName,
checkSuccessSummary: botConfig.CheckSuccessSummary,
checkFailureSummary: botConfig.CheckFailureSummary,
checkDetails: botConfig.CheckDetails,
annotationTitle: botConfig.AnnotationTitle,
annotationBody: botConfig.AnnotationBody,
}

b.client = gh.NewClient(
gh.WithPrivateKeyPath(b.privateKeyPath),
gh.WithAppID(b.appID),
gh.WithPrivateKeyPath(clientConfig.PrivateKeyPath),
gh.WithAppID(clientConfig.AppID),
)

b.server = gh.NewServer(
gh.WithWebhookSecretKey(b.webhookSecretKey),
gh.WithWebhookSecretKey(serverConfig.WebhookSecretKey),
gh.WithEventHandler(&b),
)

Expand All @@ -83,7 +93,7 @@ func (b *Bot) Start() {
}

// HandleEvent interface implementation for Server to pass incoming GitHub events to
func (b *Bot) HandleEvent(event interface{}) { //TODO DRY
func (b *Bot) HandleEvent(event interface{}) {
switch event := event.(type) {
case *github.CheckSuiteEvent:
log.Info().Msg("CheckSuiteEvent received")
Expand All @@ -92,7 +102,7 @@ func (b *Bot) HandleEvent(event interface{}) { //TODO DRY
cs := event.GetCheckSuite()

if id := cs.GetApp().GetID(); id != int64(b.appID) {
log.Error().Msgf("Event App ID of %d does not match Bot's App ID", id)
log.Error().Msgf("Event App ID of %d does not match Bot's App ID of %d", id, b.appID)
return
}
if action := event.GetAction(); !lib.Contains(checkSuiteRelevantActions, action) {
Expand All @@ -114,7 +124,7 @@ func (b *Bot) HandleEvent(event interface{}) { //TODO DRY
cr := event.GetCheckRun()

if id := cr.GetApp().GetID(); id != int64(b.appID) {
log.Error().Msgf("Event App ID of %d does not match Bot's App ID", id)
log.Error().Msgf("Event App ID of %d does not match Bot's App ID of %d", id, b.appID)
return
}
if action := event.GetAction(); !lib.Contains(checkRunRelevantActions, action) {
Expand Down Expand Up @@ -154,32 +164,32 @@ func (b *Bot) createCheckRun(ctx context.Context, pr *github.PullRequest, r *git
headSHA := pr.GetHead().GetSHA()

log.Debug().Msgf("Creating CheckRun for SHA %s...", headSHA)
annotations, err := createAnnotations(ctx, pr, r, ghc)
annotations, err := b.createAnnotations(ctx, pr, r, ghc)
if err != nil {
log.Error().Err(err).Msgf("Failed to create annotations for SHA %s", headSHA)
return
}

cro := github.CreateCheckRunOptions{
Name: checkName,
Name: b.checkName,
HeadBranch: pr.GetHead().GetRef(),
HeadSHA: headSHA,
Status: github.String("completed"),
CompletedAt: &github.Timestamp{time.Now()},
Output: &github.CheckRunOutput{
Title: github.String("Term Check"),
Text: github.String("Placeholder text"),
Title: github.String(b.checkName),
Text: github.String(b.checkDetails),
AnnotationsCount: github.Int(len(annotations)),
Annotations: annotations,
},
}
// presence of annotations signals there is usage of flagged terms
if len(annotations) > 0 {
cro.Conclusion = github.String(checkFailureConclusion)
cro.Output.Summary = github.String("⚠️ Flagged terms found.")
cro.Output.Summary = github.String(b.checkFailureSummary)
} else {
cro.Conclusion = github.String(checkSuccessConclusion)
cro.Output.Summary = github.String("✅ No flagged terms found.")
cro.Output.Summary = github.String(b.checkSuccessSummary)
}

_, resp, err := ghc.Checks.CreateCheckRun(ctx, r.GetOwner().GetLogin(), r.GetName(), cro)
Expand All @@ -190,7 +200,7 @@ func (b *Bot) createCheckRun(ctx context.Context, pr *github.PullRequest, r *git
}
}

func createAnnotations(ctx context.Context, pr *github.PullRequest, r *github.Repository, ghc *github.Client) ([]*github.CheckRunAnnotation, error) {
func (b *Bot) createAnnotations(ctx context.Context, pr *github.PullRequest, r *github.Repository, ghc *github.Client) ([]*github.CheckRunAnnotation, error) {
headSHA := pr.GetHead().GetSHA()
diff, resp, err := ghc.PullRequests.GetRaw( // TODO: refactor to move methods making requests to Client?
ctx,
Expand All @@ -210,15 +220,15 @@ func createAnnotations(ctx context.Context, pr *github.PullRequest, r *github.Re
return []*github.CheckRunAnnotation{}, e
}

re, _ := regexp.Compile(strings.Join(flaggedTerms, "|"))
re, _ := regexp.Compile(strings.Join(b.termList, "|"))
var annotations = []*github.CheckRunAnnotation{}

for _, f := range parsedDiff.Files {
for _, h := range f.Hunks {
adds := h.NewRange
for _, l := range adds.Lines {
if matches := lib.Unique(re.FindAllString(l.Content, -1)); len(matches) > 0 {
annotations = append(annotations, createAnnotation(f, l, matches))
annotations = append(annotations, b.createAnnotation(f, l, matches))
}
}
}
Expand All @@ -227,15 +237,16 @@ func createAnnotations(ctx context.Context, pr *github.PullRequest, r *github.Re
return annotations, nil
}

func createAnnotation(f *diffparser.DiffFile, l *diffparser.DiffLine, m []string) (a *github.CheckRunAnnotation) {
msg := fmt.Sprintf("Please consider changing the following terms on this line: `%s`", strings.Join(m, ", "))
func (b *Bot) createAnnotation(f *diffparser.DiffFile, l *diffparser.DiffLine, m []string) (a *github.CheckRunAnnotation) {
msg := fmt.Sprintf(b.annotationBody, strings.Join(m, ", ")) // Expects %s format string in body
msg = strings.Split(msg, "%!")[0] // Remove formatting error if user doesn't provide format string in body

return &github.CheckRunAnnotation{
Path: github.String(f.NewName),
StartLine: github.Int(l.Number),
EndLine: github.Int(l.Number),
AnnotationLevel: github.String(checkRunAnnotationLevel),
Message: github.String(msg),
Title: github.String("Term Notice"),
Title: github.String(b.annotationTitle),
}
}
25 changes: 0 additions & 25 deletions internal/bot/bot.options.go

This file was deleted.

Loading

0 comments on commit d135324

Please sign in to comment.