-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
122 lines (104 loc) · 3.48 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package main
import (
"errors"
"flag"
"fmt"
"os"
"runtime/debug"
"time"
"log/slog"
"github.com/chelmertz/elly/internal/github"
"github.com/chelmertz/elly/internal/server"
"github.com/chelmertz/elly/internal/storage"
"github.com/chelmertz/elly/internal/types"
)
var timeoutMinutes = flag.Int("timeout", 5, "refresh PRs every N minutes")
var url = flag.String("url", "localhost:9876", "URL for web GUI")
var golden = flag.Bool("golden", false, "provide a button for turning a PR into a test. do NOT use outside of development")
var demo = flag.Bool("demo", false, "mock the PRs so you can take a proper screenshot of the GUI")
var versionFlag = flag.Bool("version", false, "show version")
var verboseFlag = flag.Bool("verbose", false, "verbose logging")
var logLevel = &slog.LevelVar{}
var logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: true, Level: logLevel}))
func main() {
flag.Parse()
var version string
if bi, ok := debug.ReadBuildInfo(); ok {
version = bi.Main.Version
}
if version == "" {
version = "unknown"
}
if *versionFlag {
fmt.Println(version)
os.Exit(0)
}
// TODO try out with bad github pat and make sure it fails gracefully (and is shown in GUI)
token := os.Getenv("GITHUB_PAT")
if token == "" {
logger.Error("missing GITHUB_PAT env var")
os.Exit(1)
}
os.Unsetenv("GITHUB_PAT")
var store storage.Storage = storage.NewStorage(logger)
username, err := github.UsernameFromPat(token, logger)
if err != nil {
logger.Error("could not get username from PAT", "error", err)
os.Exit(1)
}
if *verboseFlag {
logLevel.Set(slog.LevelDebug)
} else {
logLevel.Set(slog.LevelInfo)
}
logger.Info("starting elly", "version", version, "timeout_minutes", *timeoutMinutes, "github_user", username, "golden_testing_enabled", *golden, "demo", *demo, "log_level", logLevel)
if *demo {
store = storage.NewStorageDemo()
}
refreshChannel := make(chan types.RefreshAction, 1)
go startRefreshLoop(token, username, store, refreshChannel)
refreshChannel <- types.RefreshUpstart
server.ServeWeb(*url, username, *golden, store, refreshChannel, *timeoutMinutes, version, logger)
}
func startRefreshLoop(token, username string, store storage.Storage, refresh chan types.RefreshAction) {
refreshTimer := time.NewTicker(time.Duration(*timeoutMinutes) * time.Minute)
retriesLeft := 5
for {
select {
case action := <-refresh:
logger.Debug("refresh loop", "action", action)
switch action {
case types.RefreshStop:
refreshTimer.Stop()
return
}
if time.Since(store.Prs().LastFetched) < time.Duration(1)*time.Minute {
// querying github once a minute should be fine,
// especially as long as we do the passive, loopy thing more seldom
continue
}
prs, err := github.QueryGithub(token, username, logger)
if err != nil {
if errors.Is(err, github.ErrClient) {
refreshTimer.Stop()
logger.Error("client error when querying github, giving up", slog.Any("error", err))
return
} else if errors.Is(err, github.ErrGithubServer) {
retriesLeft--
if retriesLeft <= 0 {
refreshTimer.Stop()
logger.Error("too many failed github requests, giving up")
return
}
logger.Warn("error refreshing PRs", slog.Any("error", err), slog.Int("retries_left", retriesLeft))
return
}
} else if err := store.StoreRepoPrs(prs); err != nil {
logger.Error("could not store prs", slog.Any("error", err))
return
}
case <-refreshTimer.C:
refresh <- types.RefreshTick
}
}
}