-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.go
170 lines (142 loc) · 3.71 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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package main
import (
"encoding/json"
"flag"
"fmt"
"net/http"
"os"
"time"
"github.com/canonical/matter-snap-info/config"
"github.com/canonical/matter-snap-info/logger"
"github.com/jedib0t/go-pretty/v6/table"
)
const (
configURL = "https://raw.githubusercontent.com/canonical/edgex-snap-info/main/config.json"
)
func main() {
confFile := flag.String("conf", configURL, "URL or local path to config file")
snapName := flag.String("snap", "", "Get info for a single snap only")
flag.Parse()
conf, err := config.Load(*confFile)
if err != nil {
logger.Fatalf("Error loading config file: %s", err)
}
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.SetStyle(table.StyleColoredBright)
t.AppendHeader(table.Row{"Name", "Channel", "Version", "Arch", "Rev", "Date", "Build", "Test"})
t.SetColumnConfigs([]table.ColumnConfig{
{Number: 1, AutoMerge: true},
{Number: 2, AutoMerge: true},
{Number: 3, AutoMerge: true},
})
for k, v := range conf.Snaps {
// filter by snap name
if *snapName != "" && k != *snapName {
continue
}
logger.Infof("⏬ %s", k)
// snap store
info, err := querySnapStore(k)
if err != nil {
logger.Fatalf("Error querying snap store: %s", err)
}
// github
runs, err := queryGithub(v.GithubRepo)
if err != nil {
logger.Fatalf("Error querying launchpad: %s", err)
}
build := computeWorkflowRunStats(runs, "Snap Builder")
test := computeWorkflowRunStats(runs, "Snap Testing")
// fill the table
for _, cm := range info.ChannelMap {
t.AppendRow(table.Row{
k,
cm.Channel.Track + "/" + cm.Channel.Risk,
cm.Version,
cm.Channel.Architecture,
cm.Revision,
cm.Channel.ReleasedAt.Format(time.Stamp),
fmt.Sprintf("%d/%d", build.success, build.total),
fmt.Sprintf("%d/%d", test.success, test.total),
}, table.RowConfig{AutoMerge: true})
}
t.AppendSeparator()
}
t.Render()
}
type workflowRunStats struct {
total, success uint
}
func computeWorkflowRunStats(run *workflowRuns, runName string) (s workflowRunStats) {
for _, r := range run.WorkflowRuns {
if r.Name != runName {
continue
}
s.total++
if r.Conclusion == "success" {
s.success++
// logger.Successf("🟢 %s (%s)", r.DisplayTitle, r.HTMLURL)
} else {
logger.Errorf("🔴 %s (%s)", r.DisplayTitle, r.HTMLURL)
}
}
return s
}
type snapInfo struct {
ChannelMap []struct {
Channel struct {
Architecture string
Track, Risk string
ReleasedAt time.Time `json:"released-at"`
}
Revision uint
Version string
} `json:"channel-map"`
}
func querySnapStore(snapName string) (*snapInfo, error) {
logger.Infoln("Querying Snap Store info for:", snapName)
req, err := http.NewRequest(http.MethodGet, "https://api.snapcraft.io/v2/snaps/info/"+snapName, nil)
if err != nil {
return nil, err
}
req.Header = http.Header{
"Snap-Device-Series": {"16"},
}
client := http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, err
}
var info snapInfo
err = json.NewDecoder(res.Body).Decode(&info)
if err != nil {
return nil, err
}
return &info, nil
}
type workflowRuns struct {
WorkflowRuns []struct {
Name string
Conclusion string
DisplayTitle string `json:"display_title"`
HTMLURL string `json:"html_url"`
} `json:"workflow_runs"`
Message string
}
func queryGithub(project string) (*workflowRuns, error) {
logger.Infoln("Querying Github workflow runs for:", project)
res, err := http.Get(fmt.Sprintf("https://api.github.com/repos/%s/actions/runs?per_page=10&event=pull_request", project))
if err != nil {
return nil, err
}
var r workflowRuns
err = json.NewDecoder(res.Body).Decode(&r)
if err != nil {
return nil, err
}
if r.Message != "" {
logger.Warnf("🟠 %s", r.Message)
}
return &r, err
}