Skip to content

Commit e7ef5a8

Browse files
committed
refact: generalizes slack handler into reporters, adds some more meat to Makefile
1 parent d0189cd commit e7ef5a8

16 files changed

+170
-94
lines changed

Makefile

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
1+
.DEFAULT_GOAL := build
2+
BIN_FILE=github-judge
3+
14
GO=go
25
GOCOVER=$(GO) tool cover
36
GOTEST=$(GO) test
47

5-
.PHONY: testcov
6-
testcov:
8+
9+
run:
10+
$(GO) run .
11+
12+
build:
13+
$(GO) build -o "dist/${BIN_FILE}"
14+
15+
clean:
16+
$(GO) clean
17+
rm --force cp.out nohup.out
18+
19+
test:
20+
$(GOTEST) ./...
21+
22+
cover:
723
$(GOTEST) -v -coverprofile=coverage.out -coverpkg=./... ./...
824
$(GOCOVER) -func=coverage.out
925
$(GOCOVER) -html=coverage.out -o coverage.html

main.go

+11-74
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,33 @@
11
package main
22

33
import (
4-
"fmt"
54
"log"
65
"os"
7-
"regexp"
86

97
"github.com/schaermu/go-github-judge-bot/config"
10-
"github.com/schaermu/go-github-judge-bot/helpers"
11-
"github.com/schaermu/go-github-judge-bot/scoring"
12-
13-
"github.com/slack-go/slack"
14-
"github.com/slack-go/slack/slackevents"
15-
"github.com/slack-go/slack/socketmode"
8+
"github.com/schaermu/go-github-judge-bot/reporters"
169
)
1710

1811
func main() {
1912
f, err := os.Open("config.yaml")
2013
if err != nil {
21-
panic(err)
14+
log.Panic(err)
2215
}
2316
defer f.Close()
2417

2518
cfg, err := config.New(f)
2619
if err != nil {
27-
fmt.Println("Failed to load config, aborting...")
20+
log.Fatalf("Failed to parse config: %v", err)
2821
return
2922
}
3023

31-
api := slack.New(
32-
cfg.Slack.BotToken,
33-
slack.OptionDebug(cfg.Slack.Debug),
34-
slack.OptionLog(log.New(os.Stdout, "api: ", log.Lshortfile|log.LstdFlags)),
35-
slack.OptionAppLevelToken(cfg.Slack.AppToken),
36-
)
37-
38-
client := socketmode.New(
39-
api,
40-
socketmode.OptionDebug(cfg.Slack.Debug),
41-
socketmode.OptionLog(log.New(os.Stdout, "socketmode: ", log.Lshortfile|log.LstdFlags)),
42-
)
43-
44-
messageMatcher, _ := regexp.Compile("github.com/([^/]+)/([^/<>]+)")
45-
go func() {
46-
for evt := range client.Events {
47-
switch evt.Type {
48-
case socketmode.EventTypeConnecting:
49-
fmt.Println("Connecting to Slack with Socket Mode...")
50-
case socketmode.EventTypeConnectionError:
51-
fmt.Println("Connection failed. Retrying later...")
52-
case socketmode.EventTypeConnected:
53-
fmt.Println("Connected to Slack with Socket Mode.")
54-
case socketmode.EventTypeEventsAPI:
55-
eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent)
56-
if !ok {
57-
fmt.Printf("Ignored %+v\n", evt)
58-
continue
59-
}
60-
61-
fmt.Printf("Event received: %+v\n", eventsAPIEvent)
62-
63-
client.Ack(*evt.Request)
24+
if cfg.Slack.AppToken != "" {
25+
// start handling events coming in from slack
26+
slackReporter := reporters.NewSlackReporter(&cfg)
27+
go slackReporter.HandleMessage("")
28+
slackReporter.Run()
29+
} else {
30+
// assume stdin as source for url, use terminal reporter
6431

65-
switch eventsAPIEvent.Type {
66-
case slackevents.CallbackEvent:
67-
innerEvent := eventsAPIEvent.InnerEvent
68-
switch ev := innerEvent.Data.(type) {
69-
case *slackevents.AppMentionEvent:
70-
match := messageMatcher.Match([]byte(ev.Text))
71-
if match {
72-
gh := helpers.GithubHelper{
73-
Config: cfg.Github,
74-
}
75-
info, err := gh.GetRepositoryData(ev.Text)
76-
77-
if err != nil {
78-
fmt.Printf("Error while fetching github info: %e", err)
79-
}
80-
81-
score, maxScore, penalties := scoring.GetTotalScore(info, cfg.Scorers)
82-
msgBlocks := helpers.BuildSlackResponse(info.OrgName, info.RepositoryName, score, maxScore, penalties)
83-
api.PostMessage(ev.Channel, msgBlocks...)
84-
}
85-
}
86-
default:
87-
client.Debugf("unsupported Events API event received")
88-
}
89-
default:
90-
fmt.Fprintf(os.Stderr, "Unexpected event type received: %s\n", evt.Type)
91-
}
92-
}
93-
}()
94-
95-
client.Run()
32+
}
9633
}

reporters/reporters.go

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package reporters
2+
3+
import (
4+
"regexp"
5+
6+
"github.com/schaermu/go-github-judge-bot/config"
7+
"github.com/schaermu/go-github-judge-bot/data"
8+
"github.com/schaermu/go-github-judge-bot/helpers"
9+
"github.com/schaermu/go-github-judge-bot/scoring"
10+
)
11+
12+
var GITHUB_URL_MATCHER = regexp.MustCompile("github.com/([^/]+)/([^/<>]+)")
13+
14+
type Reporter interface {
15+
HandleMessage(message string)
16+
Run()
17+
}
18+
19+
type BaseReporter struct {
20+
cfg config.Config
21+
}
22+
23+
func (r *BaseReporter) GetScoreForText(text string) (success bool, score float64, maxScore float64, penalties []scoring.ScoringPenalty, info *data.GithubRepoInfo) {
24+
match := GITHUB_URL_MATCHER.MatchString(text)
25+
if match {
26+
gh := helpers.GithubHelper{
27+
Config: r.cfg.Github,
28+
}
29+
ghInfo, _ := gh.GetRepositoryData(text)
30+
31+
info = &ghInfo
32+
score, maxScore, penalties = scoring.GetTotalScore(info, r.cfg.Scorers)
33+
success = true
34+
return
35+
} else {
36+
return false, -1, -1, nil, nil
37+
}
38+
}

reporters/slack.go

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package reporters
2+
3+
import (
4+
"log"
5+
"os"
6+
7+
"github.com/schaermu/go-github-judge-bot/config"
8+
"github.com/schaermu/go-github-judge-bot/helpers"
9+
"github.com/slack-go/slack"
10+
"github.com/slack-go/slack/slackevents"
11+
"github.com/slack-go/slack/socketmode"
12+
)
13+
14+
type SlackReporter struct {
15+
Reporter
16+
BaseReporter
17+
client *socketmode.Client
18+
api *slack.Client
19+
}
20+
21+
func NewSlackReporter(cfg *config.Config) SlackReporter {
22+
api := slack.New(
23+
cfg.Slack.BotToken,
24+
slack.OptionDebug(cfg.Slack.Debug),
25+
slack.OptionLog(log.New(os.Stdout, "api: ", log.Lshortfile|log.LstdFlags)),
26+
slack.OptionAppLevelToken(cfg.Slack.AppToken),
27+
)
28+
29+
client := socketmode.New(
30+
api,
31+
socketmode.OptionDebug(cfg.Slack.Debug),
32+
socketmode.OptionLog(log.New(os.Stdout, "socketmode: ", log.Lshortfile|log.LstdFlags)),
33+
)
34+
35+
return SlackReporter{
36+
BaseReporter: BaseReporter{cfg: *cfg},
37+
client: client,
38+
api: api,
39+
}
40+
}
41+
42+
func (sr *SlackReporter) Run() {
43+
sr.client.Run()
44+
}
45+
46+
func (sr *SlackReporter) HandleMessage(message string) {
47+
for evt := range sr.client.Events {
48+
switch evt.Type {
49+
case socketmode.EventTypeConnecting:
50+
log.Println("Connecting to Slack with Socket Mode...")
51+
case socketmode.EventTypeConnectionError:
52+
log.Println("Connection failed. Retrying later...")
53+
case socketmode.EventTypeConnected:
54+
log.Println("Connected to Slack with Socket Mode.")
55+
case socketmode.EventTypeHello:
56+
log.Println("Slack sent back hello, handshake complete.")
57+
case socketmode.EventTypeEventsAPI:
58+
eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent)
59+
if !ok {
60+
log.Printf("Ignored %+v\n", evt)
61+
continue
62+
}
63+
64+
log.Printf("Event received: %+v\n", eventsAPIEvent)
65+
66+
sr.client.Ack(*evt.Request)
67+
68+
switch eventsAPIEvent.Type {
69+
case slackevents.CallbackEvent:
70+
innerEvent := eventsAPIEvent.InnerEvent
71+
switch ev := innerEvent.Data.(type) {
72+
case *slackevents.AppMentionEvent:
73+
if isScored, score, maxScore, penalties, info := sr.GetScoreForText(ev.Text); isScored {
74+
msgBlocks := helpers.BuildSlackResponse(info.OrgName, info.RepositoryName, score, maxScore, penalties)
75+
sr.api.PostMessage(ev.Channel, msgBlocks...)
76+
}
77+
}
78+
default:
79+
sr.client.Debugf("unsupported Events API event received")
80+
}
81+
default:
82+
log.Printf("Unexpected event type received: %s\n", evt.Type)
83+
}
84+
}
85+
}

scoring/commit_activity_scorer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
type CommitActivityScorer struct {
12-
data data.GithubRepoInfo
12+
data *data.GithubRepoInfo
1313
config config.ScorerConfig
1414
}
1515

scoring/commit_activity_scorer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func getTestCommitActivityData(inactiveWeekCount int) []*github.WeeklyCommitActi
2929

3030
func getTestCommitActivityScorer(inactiveWeekCount int, penaltyPerWeek float64) CommitActivityScorer {
3131
return CommitActivityScorer{
32-
data: data.GithubRepoInfo{
32+
data: &data.GithubRepoInfo{
3333
CommitActivity: getTestCommitActivityData(inactiveWeekCount),
3434
},
3535
config: config.ScorerConfig{

scoring/contributors_scorer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010

1111
type ContributorsScorer struct {
1212
Scorer
13-
data data.GithubRepoInfo
13+
data *data.GithubRepoInfo
1414
config config.ScorerConfig
1515
}
1616

scoring/contributors_scorer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func getTestContributorData(contributorCount int) []*github.ContributorStats {
2323

2424
func getTestContributorScorer(contributorCount int, minContributors int) ContributorsScorer {
2525
return ContributorsScorer{
26-
data: data.GithubRepoInfo{
26+
data: &data.GithubRepoInfo{
2727
Contributors: getTestContributorData(contributorCount),
2828
},
2929
config: config.ScorerConfig{

scoring/issue_scorer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func getTestIssueData(closedOpenRatio float64, closedIssueCount int, openIssueCo
2525

2626
func getTestIssueScorer(closedOpenRatio float64, closedIssueCount int, openIssueCount int) IssuesScorer {
2727
return IssuesScorer{
28-
data: data.GithubRepoInfo{
28+
data: &data.GithubRepoInfo{
2929
Issues: getTestIssueData(closedOpenRatio, closedIssueCount, openIssueCount),
3030
},
3131
config: config.ScorerConfig{

scoring/issues_scorer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
type IssuesScorer struct {
12-
data data.GithubRepoInfo
12+
data *data.GithubRepoInfo
1313
config config.ScorerConfig
1414
}
1515

scoring/license_scorer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
type LicenseScorer struct {
12-
data data.GithubRepoInfo
12+
data *data.GithubRepoInfo
1313
config config.ScorerConfig
1414
}
1515

scoring/license_scorer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
func getTestLicenseScorer(license string, validLicenses []string) LicenseScorer {
1313
return LicenseScorer{
14-
data: data.GithubRepoInfo{
14+
data: &data.GithubRepoInfo{
1515
License: license,
1616
LicenseId: license,
1717
},

scoring/scoring.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Scorer interface {
1414
GetScore(currentScore float64, penalties []ScoringPenalty) (float64, []ScoringPenalty)
1515
}
1616

17-
func CreateScorer(data data.GithubRepoInfo, config config.ScorerConfig) Scorer {
17+
func CreateScorer(data *data.GithubRepoInfo, config config.ScorerConfig) Scorer {
1818
switch config.Name {
1919
case "stars":
2020
return StarsScorer{data: data, config: config}
@@ -31,7 +31,7 @@ func CreateScorer(data data.GithubRepoInfo, config config.ScorerConfig) Scorer {
3131
}
3232
}
3333

34-
func CreateScorerMap(data data.GithubRepoInfo, configs []config.ScorerConfig) (scorers map[string]Scorer, score float64) {
34+
func CreateScorerMap(data *data.GithubRepoInfo, configs []config.ScorerConfig) (scorers map[string]Scorer, score float64) {
3535
// create map of all scorers and initialize score to maximum possible
3636
scorers = map[string]Scorer{}
3737
for _, config := range configs {
@@ -41,7 +41,7 @@ func CreateScorerMap(data data.GithubRepoInfo, configs []config.ScorerConfig) (s
4141
return
4242
}
4343

44-
func GetTotalScore(data data.GithubRepoInfo, scorers []config.ScorerConfig) (score float64, maxScore float64, penalties []ScoringPenalty) {
44+
func GetTotalScore(data *data.GithubRepoInfo, scorers []config.ScorerConfig) (score float64, maxScore float64, penalties []ScoringPenalty) {
4545
scorerMap, maxScore := CreateScorerMap(data, scorers)
4646
score = maxScore
4747
// execute scorers

scoring/scoring_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import (
1111
"github.com/stretchr/testify/assert"
1212
)
1313

14-
func getGithubTestData() data.GithubRepoInfo {
15-
return data.GithubRepoInfo{
14+
func getGithubTestData() *data.GithubRepoInfo {
15+
return &data.GithubRepoInfo{
1616
License: "Not existing dummy license",
1717
LicenseId: "NOT_EXISTING",
1818
Stars: 1,
@@ -36,9 +36,9 @@ func TestCreateScorer(t *testing.T) {
3636
panic(err)
3737
}
3838

39-
for _, config := range config.Scorers {
40-
scorer := CreateScorer(testData, config)
41-
assert.Equal(t, strcase.ToCamel(config.Name+"Scorer"), reflect.TypeOf(scorer).Name())
39+
for _, sc := range config.Scorers {
40+
scorer := CreateScorer(testData, sc)
41+
assert.Equal(t, strcase.ToCamel(sc.Name+"Scorer"), reflect.TypeOf(scorer).Name())
4242
}
4343
}
4444

scoring/stars_scorer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
)
99

1010
type StarsScorer struct {
11-
data data.GithubRepoInfo
11+
data *data.GithubRepoInfo
1212
config config.ScorerConfig
1313
}
1414

0 commit comments

Comments
 (0)