diff --git a/docs/runner-type/runner-type.md b/docs/runner-type/runner-type.md new file mode 100644 index 0000000..0b655d3 --- /dev/null +++ b/docs/runner-type/runner-type.md @@ -0,0 +1,5 @@ +# Runner Types + +Metrics are labelled with the runner type. The logic for determining the runner type is as follows - + +If the runner tag is in the [github_hosted_runner_labels](./gh_actions_exporter/config.py) list the runner type will be `github-hosted` else the runner type will be `self-hosted`. Additional `github-hosted` runner tags can be added via config. diff --git a/gh_actions_exporter/config.py b/gh_actions_exporter/config.py index e0f752c..dd52ac3 100644 --- a/gh_actions_exporter/config.py +++ b/gh_actions_exporter/config.py @@ -47,6 +47,20 @@ class Settings(BaseSettings): github_app_id: Optional[int] github_app_installation_id: Optional[int] github_app_private_key: Optional[SecretStr] + github_hosted_runner_labels: Optional[List[str]] = [ + "ubuntu-latest", + "ubuntu-24.04", + "ubuntu-22.04", + "ubuntu-20.04", + "windows-latest", + "windows-2022", + "windows-2019", + "macos-latest", + "macos-14", + "macos-13", + "macos-12", + "macos-11" + ] class Config: config: ConfigFile = ConfigFile() diff --git a/gh_actions_exporter/metrics.py b/gh_actions_exporter/metrics.py index 2c2117d..2648b81 100644 --- a/gh_actions_exporter/metrics.py +++ b/gh_actions_exporter/metrics.py @@ -25,6 +25,7 @@ def __init__(self, settings: Settings): self.job_labelnames = self.common_labelnames.copy() + [ "job_name", "runner_type", + "runner_labels", ] for relabel in self.settings.job_relabelling: self.job_labelnames.append(relabel.label) @@ -148,11 +149,14 @@ def workflow_labels(self, webhook: WebHook) -> dict: branch=branch, event=webhook.workflow_run.event, ) - + def runner_type(self, webhook: WebHook) -> str: - if "self-hosted" in webhook.workflow_job.labels: - return "self-hosted" - return "github-hosted" + if set(webhook.workflow_job.labels) <= set(self.settings.github_hosted_runner_labels): + return "github-hosted" + return "self-hosted" + + def runner_labels(self, webhook: WebHook) -> str: + return ','.join(webhook.workflow_job.labels) def relabel_job_labels( self, relabel: Relabel, labels: List[str] @@ -180,6 +184,7 @@ def job_labels(self, webhook: WebHook, settings: Settings) -> dict: repository_visibility=webhook.repository.visibility, repository=webhook.repository.full_name, workflow_name=webhook.workflow_job.workflow_name, + runner_labels=self.runner_labels(webhook), ) for relabel in settings.job_relabelling: diff --git a/tests/api/metrics/test_job.py b/tests/api/metrics/test_job.py index ed61599..8c0afa3 100644 --- a/tests/api/metrics/test_job.py +++ b/tests/api/metrics/test_job.py @@ -125,3 +125,20 @@ def test_skipped_job(override_job_config, client, workflow_job, headers): workflow_job["workflow_job"]["completed_at"] = "2021-11-29T14:59:57Z" response = client.post("/webhook", json=workflow_job, headers=headers) assert response.status_code == 202 + +@pytest.mark.parametrize("labels,expected_runner_type", [ + (["warp-ubuntu-latest-x64-2x"], "self-hosted"), + (["self-hosted","linux"], "self-hosted"), + (["ubuntu-latest"], "github-hosted") + ]) +def test_runner_type_and_labels(client, workflow_job, headers, labels, expected_runner_type): + workflow_job["workflow_job"]["labels"] = labels + response = client.post("/webhook", json=workflow_job, headers=headers) + assert response.status_code == 202 + + metrics = client.get("/metrics") + assert metrics.status_code == 200 + + for line in metrics.text.split("\n"): + if "github_actions_job_start_duration_seconds_bucket{" in line: + assert "runner_labels=\"%s\",runner_type=\"%s\"" % (','.join(labels), expected_runner_type) in line