@@ -7,13 +7,16 @@ import (
7
7
"github.com/google/go-github/v61/github"
8
8
"github.com/prometheus/client_golang/prometheus"
9
9
"github.com/webdevops/go-common/prometheus/collector"
10
+ "github.com/webdevops/go-common/utils/to"
10
11
)
11
12
12
13
type (
13
14
MetricsCollectorGithubWorkflows struct {
14
15
collector.Processor
15
16
16
17
prometheus struct {
18
+ repository * prometheus.GaugeVec
19
+ workflow * prometheus.GaugeVec
17
20
workflowLatestRun * prometheus.GaugeVec
18
21
workflowLatestRunTimestamp * prometheus.GaugeVec
19
22
workflowConsecutiveFailures * prometheus.GaugeVec
@@ -24,6 +27,34 @@ type (
24
27
func (m * MetricsCollectorGithubWorkflows ) Setup (collector * collector.Collector ) {
25
28
m .Processor .Setup (collector )
26
29
30
+ m .prometheus .repository = prometheus .NewGaugeVec (
31
+ prometheus.GaugeOpts {
32
+ Name : "github_repository_info" ,
33
+ Help : "GitHub repository info" ,
34
+ },
35
+ []string {
36
+ "org" ,
37
+ "repo" ,
38
+ "defaultBranch" ,
39
+ },
40
+ )
41
+ m .Collector .RegisterMetricList ("repository" , m .prometheus .repository , true )
42
+
43
+ m .prometheus .workflow = prometheus .NewGaugeVec (
44
+ prometheus.GaugeOpts {
45
+ Name : "github_workflow_info" ,
46
+ Help : "GitHub workflow info" ,
47
+ },
48
+ []string {
49
+ "org" ,
50
+ "repo" ,
51
+ "workflow" ,
52
+ "state" ,
53
+ "path" ,
54
+ },
55
+ )
56
+ m .Collector .RegisterMetricList ("workflow" , m .prometheus .workflow , true )
57
+
27
58
m .prometheus .workflowLatestRun = prometheus .NewGaugeVec (
28
59
prometheus.GaugeOpts {
29
60
Name : "github_workflow_latest_run" ,
@@ -32,7 +63,7 @@ func (m *MetricsCollectorGithubWorkflows) Setup(collector *collector.Collector)
32
63
[]string {
33
64
"org" ,
34
65
"repo" ,
35
- "workflowName " ,
66
+ "workflow " ,
36
67
"event" ,
37
68
"branch" ,
38
69
"conclusion" ,
@@ -48,7 +79,7 @@ func (m *MetricsCollectorGithubWorkflows) Setup(collector *collector.Collector)
48
79
[]string {
49
80
"org" ,
50
81
"repo" ,
51
- "workflowName " ,
82
+ "workflow " ,
52
83
"event" ,
53
84
"branch" ,
54
85
"conclusion" ,
@@ -64,7 +95,7 @@ func (m *MetricsCollectorGithubWorkflows) Setup(collector *collector.Collector)
64
95
[]string {
65
96
"org" ,
66
97
"repo" ,
67
- "workflowName " ,
98
+ "workflow " ,
68
99
"branch" ,
69
100
},
70
101
)
@@ -76,12 +107,12 @@ func (m *MetricsCollectorGithubWorkflows) Reset() {}
76
107
func (m * MetricsCollectorGithubWorkflows ) getRepoList (org string ) ([]* github.Repository , error ) {
77
108
var repositories []* github.Repository
78
109
79
- repoOpts := & github.RepositoryListByOrgOptions {
110
+ opts := github.RepositoryListByOrgOptions {
80
111
ListOptions : github.ListOptions {PerPage : 100 , Page : 1 },
81
112
}
82
113
83
114
for {
84
- result , response , err := githubClient .Repositories .ListByOrg (m .Context (), org , repoOpts )
115
+ result , response , err := githubClient .Repositories .ListByOrg (m .Context (), org , & opts )
85
116
var ghRateLimitError * github.RateLimitError
86
117
if ok := errors .As (err , & ghRateLimitError ); ok {
87
118
m .Logger ().Debugf ("ListByOrg ratelimited. Pausing until %s" , ghRateLimitError .Rate .Reset .Time .String ())
@@ -97,26 +128,54 @@ func (m *MetricsCollectorGithubWorkflows) getRepoList(org string) ([]*github.Rep
97
128
if response .NextPage == 0 {
98
129
break
99
130
}
100
- repoOpts .Page = response .NextPage
131
+ opts .Page = response .NextPage
101
132
}
102
133
103
134
return repositories , nil
104
135
}
105
136
106
- func (m * MetricsCollectorGithubWorkflows ) getRepoWorkflows (repo * github.Repository ) ([]* github.WorkflowRun , error ) {
137
+ func (m * MetricsCollectorGithubWorkflows ) getRepoWorkflows (org , repo string ) ([]* github.Workflow , error ) {
138
+ var workflows []* github.Workflow
139
+
140
+ opts := github.ListOptions {PerPage : 100 , Page : 1 }
141
+
142
+ for {
143
+ result , response , err := githubClient .Actions .ListWorkflows (m .Context (), org , repo , & opts )
144
+ var ghRateLimitError * github.RateLimitError
145
+ if ok := errors .As (err , & ghRateLimitError ); ok {
146
+ m .Logger ().Debugf ("ListWorkflows ratelimited. Pausing until %s" , ghRateLimitError .Rate .Reset .Time .String ())
147
+ time .Sleep (time .Until (ghRateLimitError .Rate .Reset .Time ))
148
+ continue
149
+ } else if err != nil {
150
+ return workflows , err
151
+ }
152
+
153
+ workflows = append (workflows , result .Workflows ... )
154
+
155
+ // calc next page
156
+ if response .NextPage == 0 {
157
+ break
158
+ }
159
+ opts .Page = response .NextPage
160
+ }
161
+
162
+ return workflows , nil
163
+ }
164
+
165
+ func (m * MetricsCollectorGithubWorkflows ) getRepoWorkflowRuns (repo * github.Repository ) ([]* github.WorkflowRun , error ) {
107
166
var workflowRuns []* github.WorkflowRun
108
167
109
- workflowRunOpts := & github.ListWorkflowRunsOptions {
168
+ opts := github.ListWorkflowRunsOptions {
110
169
Branch : repo .GetDefaultBranch (),
111
170
ExcludePullRequests : true ,
112
171
ListOptions : github.ListOptions {PerPage : 100 , Page : 1 },
113
172
Created : ">=" + time .Now ().Add (- Opts .GitHub .Workflows .Timeframe ).Format (time .RFC3339 ),
114
173
}
115
174
116
175
for {
117
- m .Logger ().Debugf (`fetching list of workflow runs for repo "%s" with page "%d"` , repo .GetName (), workflowRunOpts .Page )
176
+ m .Logger ().Debugf (`fetching list of workflow runs for repo "%s" with page "%d"` , repo .GetName (), opts .Page )
118
177
119
- result , response , err := githubClient .Actions .ListRepositoryWorkflowRuns (m .Context (), Opts .GitHub .Organization , * repo .Name , workflowRunOpts )
178
+ result , response , err := githubClient .Actions .ListRepositoryWorkflowRuns (m .Context (), Opts .GitHub .Organization , * repo .Name , & opts )
120
179
var ghRateLimitError * github.RateLimitError
121
180
if ok := errors .As (err , & ghRateLimitError ); ok {
122
181
m .Logger ().Debugf ("ListRepositoryWorkflowRuns ratelimited. Pausing until %s" , ghRateLimitError .Rate .Reset .Time .String ())
@@ -132,34 +191,62 @@ func (m *MetricsCollectorGithubWorkflows) getRepoWorkflows(repo *github.Reposito
132
191
if response .NextPage == 0 {
133
192
break
134
193
}
135
- workflowRunOpts .Page = response .NextPage
194
+ opts .Page = response .NextPage
136
195
}
137
196
138
197
return workflowRuns , nil
139
198
}
140
199
141
200
func (m * MetricsCollectorGithubWorkflows ) Collect (callback chan <- func ()) {
142
- repositories , err := m .getRepoList (Opts .GitHub .Organization )
201
+ repositoryMetric := m .Collector .GetMetricList ("repository" )
202
+ workflowMetric := m .Collector .GetMetricList ("workflow" )
203
+
204
+ org := Opts .GitHub .Organization
205
+
206
+ repositories , err := m .getRepoList (org )
143
207
if err != nil {
144
208
panic (err )
145
209
}
146
210
147
211
for _ , repo := range repositories {
148
212
var workflowRuns []* github.WorkflowRun
149
213
214
+ repositoryMetric .AddInfo (prometheus.Labels {
215
+ "org" : org ,
216
+ "repo" : repo .GetName (),
217
+ "defaultBranch" : to .String (repo .DefaultBranch ),
218
+ })
219
+
150
220
if repo .GetDefaultBranch () == "" {
151
221
// repo doesn't have default branch
152
222
continue
153
223
}
154
224
155
- workflowRuns , err := m .getRepoWorkflows (repo )
225
+ workflows , err := m .getRepoWorkflows (org , repo . GetName () )
156
226
if err != nil {
157
227
panic (err )
158
228
}
159
229
230
+ for _ , workflow := range workflows {
231
+ workflowMetric .AddInfo (prometheus.Labels {
232
+ "org" : org ,
233
+ "repo" : repo .GetName (),
234
+ "workflow" : workflow .GetName (),
235
+ "state" : workflow .GetState (),
236
+ "path" : workflow .GetPath (),
237
+ })
238
+ }
239
+
160
240
if len (workflowRuns ) >= 1 {
161
- m .collectLatestRun (Opts .GitHub .Organization , repo , workflowRuns , callback )
162
- m .collectConsecutiveFailures (Opts .GitHub .Organization , repo , workflowRuns , callback )
241
+ workflowRuns , err := m .getRepoWorkflowRuns (repo )
242
+ if err != nil {
243
+ panic (err )
244
+ }
245
+
246
+ if len (workflowRuns ) >= 1 {
247
+ m .collectLatestRun (Opts .GitHub .Organization , repo , workflowRuns , callback )
248
+ m .collectConsecutiveFailures (Opts .GitHub .Organization , repo , workflowRuns , callback )
249
+ }
163
250
}
164
251
}
165
252
}
@@ -201,12 +288,12 @@ func (m *MetricsCollectorGithubWorkflows) collectLatestRun(org string, repo *git
201
288
202
289
for _ , workflowRun := range latestJobs {
203
290
labels := prometheus.Labels {
204
- "org" : org ,
205
- "repo" : repo .GetName (),
206
- "workflowName" : workflowRun .GetName (),
207
- "event" : workflowRun .GetEvent (),
208
- "branch" : workflowRun .GetHeadBranch (),
209
- "conclusion" : workflowRun .GetConclusion (),
291
+ "org" : org ,
292
+ "repo" : repo .GetName (),
293
+ "workflow" : workflowRun .GetName (),
294
+ "event" : workflowRun .GetEvent (),
295
+ "branch" : workflowRun .GetHeadBranch (),
296
+ "conclusion" : workflowRun .GetConclusion (),
210
297
}
211
298
212
299
runMetric .AddInfo (labels )
@@ -258,10 +345,10 @@ func (m *MetricsCollectorGithubWorkflows) collectConsecutiveFailures(org string,
258
345
}
259
346
260
347
labels := prometheus.Labels {
261
- "org" : org ,
262
- "repo" : repo .GetName (),
263
- "workflowName " : workflowRun .GetName (),
264
- "branch" : workflowRun .GetHeadBranch (),
348
+ "org" : org ,
349
+ "repo" : repo .GetName (),
350
+ "workflow " : workflowRun .GetName (),
351
+ "branch" : workflowRun .GetHeadBranch (),
265
352
}
266
353
consecutiveFailuresMetric .Add (labels , float64 (consecutiveFailMap [workflowId ]))
267
354
}
0 commit comments