Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions charts/gha-runner-scale-set-experimental/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ controllerServiceAccount:
# counters:
# gha_started_jobs_total:
# labels:
# ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref", "job_workflow_name", "job_workflow_target"]
# ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref", "job_workflow_name", "job_workflow_repo", "job_workflow_path", "job_workflow_target"]
# gha_completed_jobs_total:
# labels:
# [
Expand All @@ -335,6 +335,8 @@ controllerServiceAccount:
# "job_result",
# "job_workflow_ref",
# "job_workflow_name",
# "job_workflow_repo",
# "job_workflow_path",
# "job_workflow_target",
# ]
# gauges:
Expand All @@ -357,7 +359,7 @@ controllerServiceAccount:
# histograms:
# gha_job_startup_duration_seconds:
# labels:
# ["repository", "organization", "enterprise", "job_name", "event_name","job_workflow_ref", "job_workflow_name", "job_workflow_target"]
# ["repository", "organization", "enterprise", "job_name", "event_name","job_workflow_ref", "job_workflow_name", "job_workflow_repo", "job_workflow_path", "job_workflow_target"]
# buckets:
# [
# 0.01,
Expand Down Expand Up @@ -417,6 +419,8 @@ controllerServiceAccount:
# "job_result",
# "job_workflow_ref",
# "job_workflow_name",
# "job_workflow_repo",
# "job_workflow_path",
# "job_workflow_target"
# ]
# buckets:
Expand Down
8 changes: 6 additions & 2 deletions charts/gha-runner-scale-set/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ githubConfigSecret:
# counters:
# gha_started_jobs_total:
# labels:
# ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref", "job_workflow_name", "job_workflow_target"]
# ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref", "job_workflow_name", "job_workflow_repo", "job_workflow_path", "job_workflow_target"]
# gha_completed_jobs_total:
# labels:
# [
Expand All @@ -169,6 +169,8 @@ githubConfigSecret:
# "job_result",
# "job_workflow_ref",
# "job_workflow_name",
# "job_workflow_repo",
# "job_workflow_path",
# "job_workflow_target",
# ]
# gauges:
Expand All @@ -191,7 +193,7 @@ githubConfigSecret:
# histograms:
# gha_job_startup_duration_seconds:
# labels:
# ["repository", "organization", "enterprise", "job_name", "event_name","job_workflow_ref", "job_workflow_name", "job_workflow_target"]
# ["repository", "organization", "enterprise", "job_name", "event_name","job_workflow_ref", "job_workflow_name", "job_workflow_repo", "job_workflow_path", "job_workflow_target"]
# buckets:
# [
# 0.01,
Expand Down Expand Up @@ -251,6 +253,8 @@ githubConfigSecret:
# "job_result",
# "job_workflow_ref",
# "job_workflow_name",
# "job_workflow_repo",
# "job_workflow_path",
# "job_workflow_target"
# ]
# buckets:
Expand Down
4 changes: 4 additions & 0 deletions cmd/ghalistener/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const (
labelKeyJobName = "job_name"
labelKeyJobWorkflowRef = "job_workflow_ref"
labelKeyJobWorkflowName = "job_workflow_name"
labelKeyJobWorkflowRepo = "job_workflow_repo"
labelKeyJobWorkflowPath = "job_workflow_path"
labelKeyJobWorkflowTarget = "job_workflow_target"
labelKeyEventName = "event_name"
labelKeyJobResult = "job_result"
Expand Down Expand Up @@ -84,6 +86,8 @@ func (e *exporter) jobLabels(jobBase *scaleset.JobMessageBase) prometheus.Labels
labelKeyJobName: jobBase.JobDisplayName,
labelKeyJobWorkflowRef: jobBase.JobWorkflowRef,
labelKeyJobWorkflowName: workflowRefInfo.Name,
labelKeyJobWorkflowRepo: workflowRefInfo.Repo,
labelKeyJobWorkflowPath: workflowRefInfo.FilePath,
labelKeyJobWorkflowTarget: workflowRefInfo.Target,
labelKeyEventName: jobBase.EventName,
}
Expand Down
12 changes: 12 additions & 0 deletions cmd/ghalistener/metrics/metrics_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ func TestMetricsWithWorkflowRefParsing(t *testing.T) {
name string
jobBase scaleset.JobMessageBase
wantName string
wantRepo string
wantPath string
wantTarget string
}{
{
Expand All @@ -36,6 +38,8 @@ func TestMetricsWithWorkflowRefParsing(t *testing.T) {
EventName: "push",
},
wantName: "build",
wantRepo: "actions/runner",
wantPath: ".github/workflows/build.yml",
wantTarget: "heads/main",
},
{
Expand All @@ -48,6 +52,8 @@ func TestMetricsWithWorkflowRefParsing(t *testing.T) {
EventName: "push",
},
wantName: "ci-cd-pipeline",
wantRepo: "myorg/myrepo",
wantPath: ".github/workflows/ci-cd-pipeline.yml",
wantTarget: "heads/feature/new-metrics",
},
{
Expand All @@ -60,6 +66,8 @@ func TestMetricsWithWorkflowRefParsing(t *testing.T) {
EventName: "pull_request",
},
wantName: "pr-checks",
wantRepo: "actions/runner",
wantPath: ".github/workflows/pr-checks.yml",
wantTarget: "pull/123",
},
{
Expand All @@ -72,6 +80,8 @@ func TestMetricsWithWorkflowRefParsing(t *testing.T) {
EventName: "release",
},
wantName: "release",
wantRepo: "actions/runner",
wantPath: ".github/workflows/release.yml",
wantTarget: "tags/v1.2.3",
},
}
Expand All @@ -88,6 +98,8 @@ func TestMetricsWithWorkflowRefParsing(t *testing.T) {
labelKeyJobName: tt.jobBase.JobDisplayName,
labelKeyJobWorkflowRef: tt.jobBase.JobWorkflowRef,
labelKeyJobWorkflowName: tt.wantName,
labelKeyJobWorkflowRepo: tt.wantRepo,
labelKeyJobWorkflowPath: tt.wantPath,
labelKeyJobWorkflowTarget: tt.wantTarget,
labelKeyEventName: tt.jobBase.EventName,
}
Expand Down
19 changes: 18 additions & 1 deletion cmd/ghalistener/metrics/workflow_ref_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import (
type WorkflowRefInfo struct {
// Name is the workflow file name without extension
Name string
// Repo is the {owner}/{repo} hosting the workflow file, which can differ
// from the repository running the job when the workflow is reusable
// Example: myorg/myrepo
Repo string
// FilePath is the workflow file path within the hosting repository
// Example: .github/workflows/blank.yml
FilePath string
// Target is the target ref with type prefix retained for clarity
// Examples:
// - heads/main (branch)
Expand All @@ -18,7 +25,8 @@ type WorkflowRefInfo struct {
Target string
}

// ParseWorkflowRef parses a job_workflow_ref string to extract workflow name and target
// ParseWorkflowRef parses a job_workflow_ref string to extract workflow name,
// hosting repository, file path, and target
// Format: {owner}/{repo}/.github/workflows/{workflow_file}@{ref}
// Example: mygithuborg/myrepo/.github/workflows/blank.yml@refs/heads/main
//
Expand Down Expand Up @@ -48,6 +56,15 @@ func ParseWorkflowRef(workflowRef string) WorkflowRefInfo {
// Remove .yml or .yaml extension
info.Name = strings.TrimSuffix(strings.TrimSuffix(workflowFile, ".yml"), ".yaml")

// Extract the hosting repository ({owner}/{repo}) and the workflow file
// path within it, so that reusable workflows called from another
// repository remain distinguishable
segments := strings.SplitN(workflowPath, "/", 3)
if len(segments) == 3 {
info.Repo = segments[0] + "/" + segments[1]
info.FilePath = segments[2]
}

// Extract target from ref based on type
// Branch refs: refs/heads/{branch}
// Tag refs: refs/tags/{tag}
Expand Down
34 changes: 32 additions & 2 deletions cmd/ghalistener/metrics/workflow_ref_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,88 @@ func TestParseWorkflowRef(t *testing.T) {
name string
workflowRef string
wantName string
wantRepo string
wantPath string
wantTarget string
}{
{
name: "standard branch reference with yml",
workflowRef: "actions-runner-controller-sandbox/mumoshu-orgrunner-test-01/.github/workflows/blank.yml@refs/heads/main",
wantName: "blank",
wantRepo: "actions-runner-controller-sandbox/mumoshu-orgrunner-test-01",
wantPath: ".github/workflows/blank.yml",
wantTarget: "heads/main",
},
{
name: "branch with special characters",
workflowRef: "owner/repo/.github/workflows/ci-cd.yml@refs/heads/feature/new-feature",
wantName: "ci-cd",
wantRepo: "owner/repo",
wantPath: ".github/workflows/ci-cd.yml",
wantTarget: "heads/feature/new-feature",
},
{
name: "yaml extension",
workflowRef: "owner/repo/.github/workflows/deploy.yaml@refs/heads/develop",
wantName: "deploy",
wantRepo: "owner/repo",
wantPath: ".github/workflows/deploy.yaml",
wantTarget: "heads/develop",
},
{
name: "tag reference",
workflowRef: "owner/repo/.github/workflows/release.yml@refs/tags/v1.0.0",
wantName: "release",
wantRepo: "owner/repo",
wantPath: ".github/workflows/release.yml",
wantTarget: "tags/v1.0.0",
},
{
name: "pull request reference",
workflowRef: "owner/repo/.github/workflows/test.yml@refs/pull/123/merge",
wantName: "test",
wantRepo: "owner/repo",
wantPath: ".github/workflows/test.yml",
wantTarget: "pull/123",
},
{
name: "empty workflow ref",
workflowRef: "",
wantName: "",
wantRepo: "",
wantPath: "",
wantTarget: "",
},
{
name: "invalid format - no @ separator",
workflowRef: "owner/repo/.github/workflows/test.yml",
wantName: "",
wantRepo: "",
wantPath: "",
wantTarget: "",
},
{
name: "invalid format - path without repo",
workflowRef: "test.yml@refs/heads/main",
wantName: "test",
wantRepo: "",
wantPath: "",
wantTarget: "heads/main",
},
{
name: "workflow with dots in name",
workflowRef: "owner/repo/.github/workflows/build.test.yml@refs/heads/main",
wantName: "build.test",
wantRepo: "owner/repo",
wantPath: ".github/workflows/build.test.yml",
wantTarget: "heads/main",
},
{
name: "workflow with hyphen and underscore",
workflowRef: "owner/repo/.github/workflows/build-test_deploy.yml@refs/heads/main",
wantName: "build-test_deploy",
wantRepo: "owner/repo",
wantPath: ".github/workflows/build-test_deploy.yml",
wantTarget: "heads/main",
},
}
Expand All @@ -73,8 +101,10 @@ func TestParseWorkflowRef(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
got := ParseWorkflowRef(tt.workflowRef)
expected := WorkflowRefInfo{
Name: tt.wantName,
Target: tt.wantTarget,
Name: tt.wantName,
Repo: tt.wantRepo,
FilePath: tt.wantPath,
Target: tt.wantTarget,
}
assert.Equal(t, expected, got, "ParseWorkflowRef(%q) returned unexpected result", tt.workflowRef)
})
Expand Down