Skip to content

Commit 5aa9348

Browse files
committed
add custom properties support
Signed-off-by: Markus Blaschke <[email protected]>
1 parent 6f1eef8 commit 5aa9348

File tree

3 files changed

+102
-33
lines changed

3 files changed

+102
-33
lines changed

Diff for: README.md

+19-17
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,27 @@ Usage:
1414
github-workflow-exporter [OPTIONS]
1515
1616
Application Options:
17-
--log.debug debug mode [$LOG_DEBUG]
18-
--log.devel development mode [$LOG_DEVEL]
19-
--log.json Switch log output to json format [$LOG_JSON]
20-
--github.enterprise.url= GitHub enterprise url (self hosted) [$GITHUB_ENTERPRISE_URL]
21-
--github.organization= GitHub organization name [$GITHUB_ORGANIZATION]
22-
--github.token= GitHub token auth: PAT [$GITHUB_TOKEN]
23-
--github.app.id= GitHub app auth: App ID [$GITHUB_APP_ID]
24-
--github.app.installationid= GitHub app auth: App installation ID [$GITHUB_APP_INSTALLATION_ID]
25-
--github.app.keyfile= GitHub app auth: Private key (path to file) [$GITHUB_APP_PRIVATE_KEY]
26-
--github.workflows.timeframe= GitHub workflow timeframe for fetching (default: 168h) [$GITHUB_WORKFLOWS_TIMEFRAME]
27-
--scrape.time= Scrape time (default: 30m) [$SCRAPE_TIME]
28-
--cache.path= Cache path (to folder, file://path... or azblob://storageaccount.blob.core.windows.net/containername or
29-
k8scm://{namespace}/{configmap}}) [$CACHE_PATH]
30-
--server.bind= Server address (default: :8080) [$SERVER_BIND]
31-
--server.timeout.read= Server read timeout (default: 5s) [$SERVER_TIMEOUT_READ]
32-
--server.timeout.write= Server write timeout (default: 10s) [$SERVER_TIMEOUT_WRITE]
17+
--log.debug debug mode [$LOG_DEBUG]
18+
--log.devel development mode [$LOG_DEVEL]
19+
--log.json Switch log output to json format [$LOG_JSON]
20+
--github.enterprise.url= GitHub enterprise url (self hosted) [$GITHUB_ENTERPRISE_URL]
21+
--github.organization= GitHub organization name [$GITHUB_ORGANIZATION]
22+
--github.token= GitHub token auth: PAT [$GITHUB_TOKEN]
23+
--github.app.id= GitHub app auth: App ID [$GITHUB_APP_ID]
24+
--github.app.installationid= GitHub app auth: App installation ID [$GITHUB_APP_INSTALLATION_ID]
25+
--github.app.keyfile= GitHub app auth: Private key (path to file) [$GITHUB_APP_PRIVATE_KEY]
26+
--github.repository.customprops= GitHub repository custom properties as labels for repos and workflows (space delimiter)
27+
[$GITHUB_REPOSITORY_CUSTOMPROPS]
28+
--github.workflows.timeframe= GitHub workflow timeframe for fetching (default: 168h) [$GITHUB_WORKFLOWS_TIMEFRAME]
29+
--scrape.time= Scrape time (default: 30m) [$SCRAPE_TIME]
30+
--cache.path= Cache path (to folder, file://path... or azblob://storageaccount.blob.core.windows.net/containername or
31+
k8scm://{namespace}/{configmap}}) [$CACHE_PATH]
32+
--server.bind= Server address (default: :8080) [$SERVER_BIND]
33+
--server.timeout.read= Server read timeout (default: 5s) [$SERVER_TIMEOUT_READ]
34+
--server.timeout.write= Server write timeout (default: 10s) [$SERVER_TIMEOUT_WRITE]
3335
3436
Help Options:
35-
-h, --help Show this help message
37+
-h, --help Show this help message
3638
```
3739

3840
### Authentication

Diff for: config/opts.go

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ type (
3030
AppPrivateKeyFile *string `long:"github.app.keyfile" env:"GITHUB_APP_PRIVATE_KEY" description:"GitHub app auth: Private key (path to file)"`
3131
}
3232

33+
Repositories struct {
34+
CustomProperties []string `long:"github.repository.customprops" env:"GITHUB_REPOSITORY_CUSTOMPROPS" description:"GitHub repository custom properties as labels for repos and workflows (space delimiter)" env-delim:" "`
35+
}
36+
3337
Workflows struct {
3438
Timeframe time.Duration `long:"github.workflows.timeframe" env:"GITHUB_WORKFLOWS_TIMEFRAME" description:"GitHub workflow timeframe for fetching" default:"168h"`
3539
}

Diff for: metrics_github_workflows.go

+79-16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"errors"
5+
"fmt"
56
"time"
67

78
"github.com/google/go-github/v61/github"
@@ -10,6 +11,10 @@ import (
1011
"github.com/webdevops/go-common/utils/to"
1112
)
1213

14+
const (
15+
CUSTOMPROP_LABEL_FMT = "prop_%s"
16+
)
17+
1318
type (
1419
MetricsCollectorGithubWorkflows struct {
1520
collector.Processor
@@ -27,16 +32,24 @@ type (
2732
func (m *MetricsCollectorGithubWorkflows) Setup(collector *collector.Collector) {
2833
m.Processor.Setup(collector)
2934

35+
var customPropLabels []string
36+
for _, customProp := range Opts.GitHub.Repositories.CustomProperties {
37+
customPropLabels = append(customPropLabels, fmt.Sprintf(CUSTOMPROP_LABEL_FMT, customProp))
38+
}
39+
3040
m.prometheus.repository = prometheus.NewGaugeVec(
3141
prometheus.GaugeOpts{
3242
Name: "github_repository_info",
3343
Help: "GitHub repository info",
3444
},
35-
[]string{
36-
"org",
37-
"repo",
38-
"defaultBranch",
39-
},
45+
append(
46+
[]string{
47+
"org",
48+
"repo",
49+
"defaultBranch",
50+
},
51+
customPropLabels...,
52+
),
4053
)
4154
m.Collector.RegisterMetricList("repository", m.prometheus.repository, true)
4255

@@ -45,13 +58,16 @@ func (m *MetricsCollectorGithubWorkflows) Setup(collector *collector.Collector)
4558
Name: "github_workflow_info",
4659
Help: "GitHub workflow info",
4760
},
48-
[]string{
49-
"org",
50-
"repo",
51-
"workflow",
52-
"state",
53-
"path",
54-
},
61+
append(
62+
[]string{
63+
"org",
64+
"repo",
65+
"workflow",
66+
"state",
67+
"path",
68+
},
69+
customPropLabels...,
70+
),
5571
)
5672
m.Collector.RegisterMetricList("workflow", m.prometheus.workflow, true)
5773

@@ -133,6 +149,30 @@ func (m *MetricsCollectorGithubWorkflows) getRepoList(org string) ([]*github.Rep
133149
opts.Page = response.NextPage
134150
}
135151

152+
if len(Opts.GitHub.Repositories.CustomProperties) >= 1 {
153+
for _, repository := range repositories {
154+
var err error
155+
var repoCustomProperties []*github.CustomPropertyValue
156+
for {
157+
repoCustomProperties, _, err = githubClient.Repositories.GetAllCustomPropertyValues(m.Context(), org, repository.GetName())
158+
var ghRateLimitError *github.RateLimitError
159+
if ok := errors.As(err, &ghRateLimitError); ok {
160+
m.Logger().Debugf("GetAllCustomPropertyValues ratelimited. Pausing until %s", ghRateLimitError.Rate.Reset.Time.String())
161+
time.Sleep(time.Until(ghRateLimitError.Rate.Reset.Time))
162+
continue
163+
} else if err != nil {
164+
panic(err)
165+
}
166+
break
167+
}
168+
169+
repository.CustomProperties = map[string]string{}
170+
for _, property := range repoCustomProperties {
171+
repository.CustomProperties[property.PropertyName] = property.GetValue()
172+
}
173+
}
174+
}
175+
136176
return repositories, nil
137177
}
138178

@@ -213,11 +253,29 @@ func (m *MetricsCollectorGithubWorkflows) Collect(callback chan<- func()) {
213253
}
214254

215255
for _, repo := range repositories {
216-
repositoryMetric.AddInfo(prometheus.Labels{
256+
// build custom properties
257+
propLabels := prometheus.Labels{}
258+
if len(Opts.GitHub.Repositories.CustomProperties) >= 1 {
259+
for _, customProp := range Opts.GitHub.Repositories.CustomProperties {
260+
labelName := fmt.Sprintf(CUSTOMPROP_LABEL_FMT, customProp)
261+
propLabels[labelName] = ""
262+
263+
if val, exists := repo.CustomProperties[customProp]; exists {
264+
propLabels[labelName] = val
265+
}
266+
}
267+
}
268+
269+
// repo info metric
270+
labels := prometheus.Labels{
217271
"org": org,
218272
"repo": repo.GetName(),
219273
"defaultBranch": to.String(repo.DefaultBranch),
220-
})
274+
}
275+
for labelName, labelValue := range propLabels {
276+
labels[labelName] = labelValue
277+
}
278+
repositoryMetric.AddInfo(labels)
221279

222280
if repo.GetDefaultBranch() == "" {
223281
// repo doesn't have default branch
@@ -229,14 +287,19 @@ func (m *MetricsCollectorGithubWorkflows) Collect(callback chan<- func()) {
229287
panic(err)
230288
}
231289

290+
// workflow info metrics
232291
for _, workflow := range workflows {
233-
workflowMetric.AddInfo(prometheus.Labels{
292+
labels := prometheus.Labels{
234293
"org": org,
235294
"repo": repo.GetName(),
236295
"workflow": workflow.GetName(),
237296
"state": workflow.GetState(),
238297
"path": workflow.GetPath(),
239-
})
298+
}
299+
for labelName, labelValue := range propLabels {
300+
labels[labelName] = labelValue
301+
}
302+
workflowMetric.AddInfo(labels)
240303
}
241304

242305
if len(workflows) >= 1 {

0 commit comments

Comments
 (0)