From c7aa4f8bd417e8ab7aa3f691133ca2941a034b3d Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 11:41:58 +0200 Subject: [PATCH 01/16] Fix type for WorkFLowJob runs_on field --- src/openhound_github/models/workflow_job.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/openhound_github/models/workflow_job.py b/src/openhound_github/models/workflow_job.py index 803e917..73b715c 100644 --- a/src/openhound_github/models/workflow_job.py +++ b/src/openhound_github/models/workflow_job.py @@ -49,7 +49,7 @@ class GHWorkflowJobProperties(GHNodeProperties): """ job_key: str | None = None - runs_on: Any = None + runs_on: str = None is_self_hosted: bool = False container: str | None = None environment: str | None = None @@ -153,7 +153,7 @@ class WorkflowJob(BaseAsset): repository_name: str repository_node_id: str org_login: str - runs_on: Any = None + runs_on: str | list[str] | dict[str, str] = None is_self_hosted: bool = False container: str | None = None environment: str | None = None @@ -163,6 +163,20 @@ class WorkflowJob(BaseAsset): secret_references: list[WorkflowReference] = Field(default_factory=list) variable_references: list[WorkflowReference] = Field(default_factory=list) + @property + def normalize_runs_on(self) -> str: + if isinstance(self.runs_on, str): + return self.runs_on + + elif isinstance(self.runs_on, list): + return ",".join(self.runs_on) + + elif isinstance(self.runs_on, dict): + return ",".join([f"{key}:{value}" for key, value in self.runs_on.items()]) + + else: + return str(self.runs_on) + @property def org_node_id(self) -> str | None: return self._lookup.org_id_for_login(self.org_login) @@ -189,7 +203,7 @@ def as_node(self) -> GHNode: displayname=self.job_key, node_id=self.node_id, job_key=self.job_key, - runs_on=self.runs_on, + runs_on=self.normalize_runs_on, is_self_hosted=self.is_self_hosted, container=self.container, environment=self.environment, From 36ed53d47444e3459a41e9516c876c7a9ac79b08 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 11:46:24 +0200 Subject: [PATCH 02/16] Fix type for WorkFLowJob runs_on field --- src/openhound_github/models/workflow_job.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/openhound_github/models/workflow_job.py b/src/openhound_github/models/workflow_job.py index 73b715c..8393bdd 100644 --- a/src/openhound_github/models/workflow_job.py +++ b/src/openhound_github/models/workflow_job.py @@ -49,7 +49,7 @@ class GHWorkflowJobProperties(GHNodeProperties): """ job_key: str | None = None - runs_on: str = None + runs_on: str | None = None is_self_hosted: bool = False container: str | None = None environment: str | None = None @@ -153,7 +153,7 @@ class WorkflowJob(BaseAsset): repository_name: str repository_node_id: str org_login: str - runs_on: str | list[str] | dict[str, str] = None + runs_on: str | list[str] | dict[str, str] | None = None is_self_hosted: bool = False container: str | None = None environment: str | None = None @@ -164,18 +164,20 @@ class WorkflowJob(BaseAsset): variable_references: list[WorkflowReference] = Field(default_factory=list) @property - def normalize_runs_on(self) -> str: + def normalize_runs_on(self) -> str | None: + if self.runs_on is None: + return None + if isinstance(self.runs_on, str): return self.runs_on - elif isinstance(self.runs_on, list): + if isinstance(self.runs_on, list): return ",".join(self.runs_on) - elif isinstance(self.runs_on, dict): + if isinstance(self.runs_on, dict): return ",".join([f"{key}:{value}" for key, value in self.runs_on.items()]) - else: - return str(self.runs_on) + return str(self.runs_on) @property def org_node_id(self) -> str | None: From ddd04eb6ec407e3550392bc4b0f494cca3513ac4 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 12:03:05 +0200 Subject: [PATCH 03/16] Replace "Any" field types with fixed types for Workflow model fields --- src/openhound_github/models/workflow.py | 27 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index 97ce207..d660702 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -51,8 +51,8 @@ class WorkflowStepDefinition(BaseModel): name: str | None = None uses: str | None = None run: str | None = None - with_: dict[str, Any] = Field(default_factory=dict, alias="with") - env: dict[str, Any] = Field(default_factory=dict) + with_: dict[str, str] = Field(default_factory=dict, alias="with") + env: dict[str, str] = Field(default_factory=dict) @field_validator("with_", "env", mode="before") @classmethod @@ -79,17 +79,24 @@ def type(self) -> str: return "unknown" +class Container(BaseModel): + image: str + credentials: dict[str, str] | None = None + env: dict[str, str] | None = None + ports: list[int] | None = None + + class WorkflowJobDefinition(BaseModel): model_config = ConfigDict(extra="allow", populate_by_name=True) - runs_on: Any = Field(default=None, alias="runs-on") - needs: Any = None - environment: Any = None - permissions: Any = None + runs_on: str | list[str] | dict[str, str] = Field(default=None, alias="runs-on") + needs: str | list[str] = None + environment: str | dict[str, str] = None + permissions: str | dict[str, str] = None uses: str | None = None - container: Any = None - env: dict[str, Any] = Field(default_factory=dict) - secrets: dict[str, Any] | str | None = None + container: Container = None + env: dict[str, str] = Field(default_factory=dict) + secrets: dict[str, str] | str | None = None steps: list[WorkflowStepDefinition] = Field(default_factory=list) @field_validator("env", mode="before") @@ -143,7 +150,7 @@ def container_value(self) -> str | None: class WorkflowDocument(BaseModel): model_config = ConfigDict(extra="allow") - permissions: Any = None + permissions: str | dict[str, str] = None jobs: dict[str, WorkflowJobDefinition] = Field(default_factory=dict) @field_validator("jobs", mode="before") From ed087ee4c16cfd69e04dfef9977d83344895c940 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 14:05:17 +0200 Subject: [PATCH 04/16] Create a list of runs_on instead of single-value string. --- src/openhound_github/models/workflow_job.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/openhound_github/models/workflow_job.py b/src/openhound_github/models/workflow_job.py index 8393bdd..0f30053 100644 --- a/src/openhound_github/models/workflow_job.py +++ b/src/openhound_github/models/workflow_job.py @@ -49,7 +49,7 @@ class GHWorkflowJobProperties(GHNodeProperties): """ job_key: str | None = None - runs_on: str | None = None + runs_on: list[str] | None = None is_self_hosted: bool = False container: str | None = None environment: str | None = None @@ -164,20 +164,20 @@ class WorkflowJob(BaseAsset): variable_references: list[WorkflowReference] = Field(default_factory=list) @property - def normalize_runs_on(self) -> str | None: + def normalize_runs_on(self) -> list[str] | None: if self.runs_on is None: return None if isinstance(self.runs_on, str): - return self.runs_on + return [self.runs_on] if isinstance(self.runs_on, list): - return ",".join(self.runs_on) + return self.runs_on if isinstance(self.runs_on, dict): - return ",".join([f"{key}:{value}" for key, value in self.runs_on.items()]) + return [f"{key}:{value}" for key, value in self.runs_on.items()] - return str(self.runs_on) + return [str(self.runs_on)] @property def org_node_id(self) -> str | None: @@ -188,12 +188,16 @@ def org_node_id(self) -> str | None: def normalize_permissions(cls, value: Any) -> list[str] | None: if value is None: return None + if isinstance(value, dict): return [f"{key}:{permission}" for key, permission in value.items()] + if isinstance(value, str): return [value] + if isinstance(value, list): return [str(item) for item in value] + return [str(value)] @property From 75f1a7f7aca0affc1965b958ce37874d70c54c3e Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 14:10:16 +0200 Subject: [PATCH 05/16] Make WorkflowJobDefinition fields optional --- src/openhound_github/models/workflow.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index d660702..ee0bd20 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -89,10 +89,12 @@ class Container(BaseModel): class WorkflowJobDefinition(BaseModel): model_config = ConfigDict(extra="allow", populate_by_name=True) - runs_on: str | list[str] | dict[str, str] = Field(default=None, alias="runs-on") - needs: str | list[str] = None - environment: str | dict[str, str] = None - permissions: str | dict[str, str] = None + runs_on: str | list[str] | dict[str, str] | None = Field( + default=None, alias="runs-on" + ) + needs: str | list[str] | None = None + environment: str | dict[str, str] | None = None + permissions: str | dict[str, str] | None = None uses: str | None = None container: Container = None env: dict[str, str] = Field(default_factory=dict) From 89259d3d941fab8082db22c645dfee5c0f665804 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 14:11:05 +0200 Subject: [PATCH 06/16] Container can be a single-value string as well --- src/openhound_github/models/workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index ee0bd20..9575ea0 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -96,7 +96,7 @@ class WorkflowJobDefinition(BaseModel): environment: str | dict[str, str] | None = None permissions: str | dict[str, str] | None = None uses: str | None = None - container: Container = None + container: str | Container | None = None env: dict[str, str] = Field(default_factory=dict) secrets: dict[str, str] | str | None = None steps: list[WorkflowStepDefinition] = Field(default_factory=list) From 4185d2be415dce48ab17b9008da2471c0709c4e0 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 14:13:34 +0200 Subject: [PATCH 07/16] Simplify returning container image name --- src/openhound_github/models/workflow.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index 9575ea0..07fd1e2 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -85,6 +85,9 @@ class Container(BaseModel): env: dict[str, str] | None = None ports: list[int] | None = None + def __str__(self) -> str: + return self.image + class WorkflowJobDefinition(BaseModel): model_config = ConfigDict(extra="allow", populate_by_name=True) @@ -142,11 +145,7 @@ def is_self_hosted(self) -> bool: @property def container_value(self) -> str | None: - if self.container is None: - return None - if isinstance(self.container, str): - return self.container - return str(self.container) + return str(self.container) if self.container else None class WorkflowDocument(BaseModel): From 83acacaf8001d879c2e9b7a54f60611482662a89 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 14:21:03 +0200 Subject: [PATCH 08/16] Add None as allowed value for permissions in WorkflowDocument --- src/openhound_github/models/workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index 07fd1e2..cf13657 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -151,7 +151,7 @@ def container_value(self) -> str | None: class WorkflowDocument(BaseModel): model_config = ConfigDict(extra="allow") - permissions: str | dict[str, str] = None + permissions: str | dict[str, str] | None = None jobs: dict[str, WorkflowJobDefinition] = Field(default_factory=dict) @field_validator("jobs", mode="before") From 5bcc84cfb87216c73c95b15d78846aead762b323 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 14:46:33 +0200 Subject: [PATCH 09/16] Also normalize the secrets map when loading the model --- src/openhound_github/models/workflow.py | 30 +++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index cf13657..e0a6940 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -101,13 +101,30 @@ class WorkflowJobDefinition(BaseModel): uses: str | None = None container: str | Container | None = None env: dict[str, str] = Field(default_factory=dict) - secrets: dict[str, str] | str | None = None + secrets: dict[str, str] = Field(default_factory=dict) steps: list[WorkflowStepDefinition] = Field(default_factory=list) + # This may seem strange, but the GitHub yaml format accepts empty values for keys + # additionally, to prevent other yaml parsing issues, make sure we always convert the key/value to string first + # for both env and secrets + @field_validator("env", mode="before") @classmethod - def dict_or_empty(cls, value: Any) -> dict[str, Any]: - return value if isinstance(value, dict) else {} + def dict_or_empty(cls, value: Any) -> dict[str, str]: + return ( + {f"{str(key)}": f"{str(value)}" for key, value in value.items()} + if isinstance(value, dict) + else {} + ) + + @field_validator("secrets", mode="before") + @classmethod + def secrets_or_empty(cls, value: Any) -> dict[str, str]: + return ( + {f"{str(key)}": f"{str(value)}" for key, value in value.items()} + if isinstance(value, dict) + else {} + ) @field_validator("steps", mode="before") @classmethod @@ -498,10 +515,9 @@ def workflow_job_rows(self) -> list[dict[str, Any]]: for job_key, job in document.jobs.items(): secret_refs = [] variable_refs = [] - if isinstance(job.secrets, dict): - secret_refs.extend( - mapping_references(SECRET_REFERENCE_RE, job.secrets, "secrets") - ) + secret_refs.extend( + mapping_references(SECRET_REFERENCE_RE, job.secrets, "secrets") + ) secret_refs.extend(mapping_references(SECRET_REFERENCE_RE, job.env, "env")) variable_refs.extend( mapping_references(VARIABLE_REFERENCE_RE, job.env, "env") From 39568bad4b2fda7f9a5dc1167fec0b6ff0c4186a Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 14:56:10 +0200 Subject: [PATCH 10/16] Combine secret/env normalization in single validator --- src/openhound_github/models/workflow.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index e0a6940..5561d8d 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -108,7 +108,7 @@ class WorkflowJobDefinition(BaseModel): # additionally, to prevent other yaml parsing issues, make sure we always convert the key/value to string first # for both env and secrets - @field_validator("env", mode="before") + @field_validator("env", "secrets", mode="before") @classmethod def dict_or_empty(cls, value: Any) -> dict[str, str]: return ( @@ -117,15 +117,6 @@ def dict_or_empty(cls, value: Any) -> dict[str, str]: else {} ) - @field_validator("secrets", mode="before") - @classmethod - def secrets_or_empty(cls, value: Any) -> dict[str, str]: - return ( - {f"{str(key)}": f"{str(value)}" for key, value in value.items()} - if isinstance(value, dict) - else {} - ) - @field_validator("steps", mode="before") @classmethod def valid_step_dicts(cls, value: Any) -> list[dict[str, Any]]: From c6dbfda28888f77549a2d0b4bfb0b719a9688bbf Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 14:57:48 +0200 Subject: [PATCH 11/16] Combine runs_on/permissions normalization in single validator --- src/openhound_github/models/workflow_job.py | 30 +++++---------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/src/openhound_github/models/workflow_job.py b/src/openhound_github/models/workflow_job.py index 0f30053..d330787 100644 --- a/src/openhound_github/models/workflow_job.py +++ b/src/openhound_github/models/workflow_job.py @@ -153,7 +153,7 @@ class WorkflowJob(BaseAsset): repository_name: str repository_node_id: str org_login: str - runs_on: str | list[str] | dict[str, str] | None = None + runs_on: list[str] | None = None is_self_hosted: bool = False container: str | None = None environment: str | None = None @@ -163,41 +163,25 @@ class WorkflowJob(BaseAsset): secret_references: list[WorkflowReference] = Field(default_factory=list) variable_references: list[WorkflowReference] = Field(default_factory=list) - @property - def normalize_runs_on(self) -> list[str] | None: - if self.runs_on is None: - return None - - if isinstance(self.runs_on, str): - return [self.runs_on] - - if isinstance(self.runs_on, list): - return self.runs_on - - if isinstance(self.runs_on, dict): - return [f"{key}:{value}" for key, value in self.runs_on.items()] - - return [str(self.runs_on)] - @property def org_node_id(self) -> str | None: return self._lookup.org_id_for_login(self.org_login) - @field_validator("permissions", mode="before") + @field_validator("runs_on", "permissions", mode="before") @classmethod - def normalize_permissions(cls, value: Any) -> list[str] | None: + def normalize_mapping(cls, value: Any) -> list[str] | None: if value is None: return None - if isinstance(value, dict): - return [f"{key}:{permission}" for key, permission in value.items()] - if isinstance(value, str): return [value] if isinstance(value, list): return [str(item) for item in value] + if isinstance(value, dict): + return [f"{str(key)}:{str(value)}" for key, value in value.items()] + return [str(value)] @property @@ -209,7 +193,7 @@ def as_node(self) -> GHNode: displayname=self.job_key, node_id=self.node_id, job_key=self.job_key, - runs_on=self.normalize_runs_on, + runs_on=self.runs_on, is_self_hosted=self.is_self_hosted, container=self.container, environment=self.environment, From ef304a63d1d21d77e77d273647ad0c16def61054 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 15:34:21 +0200 Subject: [PATCH 12/16] Add additional types for runs_on --- src/openhound_github/models/workflow.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index 5561d8d..deb86e4 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -89,12 +89,15 @@ def __str__(self) -> str: return self.image +class RunsOn(BaseModel): + group: str | None = None + labels: list[str] | str | None = None + + class WorkflowJobDefinition(BaseModel): model_config = ConfigDict(extra="allow", populate_by_name=True) - runs_on: str | list[str] | dict[str, str] | None = Field( - default=None, alias="runs-on" - ) + runs_on: str | list[str] | RunsOn | None = Field(default=None, alias="runs-on") needs: str | list[str] | None = None environment: str | dict[str, str] | None = None permissions: str | dict[str, str] | None = None @@ -107,7 +110,6 @@ class WorkflowJobDefinition(BaseModel): # This may seem strange, but the GitHub yaml format accepts empty values for keys # additionally, to prevent other yaml parsing issues, make sure we always convert the key/value to string first # for both env and secrets - @field_validator("env", "secrets", mode="before") @classmethod def dict_or_empty(cls, value: Any) -> dict[str, str]: From da4e3185c64724c18a873acf7f92808df3ccc6e7 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 15:38:18 +0200 Subject: [PATCH 13/16] Split runs_on normalizer due to more complex field types --- src/openhound_github/models/workflow_job.py | 31 +++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/openhound_github/models/workflow_job.py b/src/openhound_github/models/workflow_job.py index d330787..3032882 100644 --- a/src/openhound_github/models/workflow_job.py +++ b/src/openhound_github/models/workflow_job.py @@ -167,9 +167,9 @@ class WorkflowJob(BaseAsset): def org_node_id(self) -> str | None: return self._lookup.org_id_for_login(self.org_login) - @field_validator("runs_on", "permissions", mode="before") + @field_validator("permissions", mode="before") @classmethod - def normalize_mapping(cls, value: Any) -> list[str] | None: + def normalize_permissions(cls, value: Any) -> list[str] | None: if value is None: return None @@ -184,6 +184,33 @@ def normalize_mapping(cls, value: Any) -> list[str] | None: return [str(value)] + @field_validator("runs_on", mode="before") + @classmethod + def normalize_runs_on(cls, value: Any) -> list[str] | None: + if value is None: + return None + + if isinstance(value, str): + return [value] + + if isinstance(value, list): + return [str(item) for item in value] + + if isinstance(value, dict): + labels = value.get("labels") + if labels is None: + return None + + if isinstance(labels, str): + return [labels] + + if isinstance(labels, list): + return [str(item) for item in labels] + + return [str(labels)] + + return [str(value)] + @property def as_node(self) -> GHNode: return GHNode( From c961e314ddfa0e3162856e598d2b202ab5806c62 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 16:07:48 +0200 Subject: [PATCH 14/16] Remove is_self_hosted from top Workflow model --- src/openhound_github/models/workflow.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/openhound_github/models/workflow.py b/src/openhound_github/models/workflow.py index deb86e4..403301d 100644 --- a/src/openhound_github/models/workflow.py +++ b/src/openhound_github/models/workflow.py @@ -145,14 +145,6 @@ def environment_name(self) -> str | None: return str(self.environment["name"]) return None - @property - def is_self_hosted(self) -> bool: - if isinstance(self.runs_on, str): - return self.runs_on == "self-hosted" - if isinstance(self.runs_on, list): - return "self-hosted" in [str(item) for item in self.runs_on] - return False - @property def container_value(self) -> str | None: return str(self.container) if self.container else None @@ -522,7 +514,6 @@ def workflow_job_rows(self) -> list[dict[str, Any]]: "name": f"{self.repository_name}\\{job_key}", "job_key": job_key, "runs_on": job.runs_on, - "is_self_hosted": job.is_self_hosted, "container": job.container_value, "environment": job.environment_name, "permissions": job.permissions From 93c84bf511dc350e2744e061093dbf555f2a03ee Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 16:08:28 +0200 Subject: [PATCH 15/16] Add is_self_hosted to sub WorkflowJob model + added safety to check if RunsOn is a RunsOn model or dict --- src/openhound_github/models/workflow_job.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/openhound_github/models/workflow_job.py b/src/openhound_github/models/workflow_job.py index 3032882..6e58420 100644 --- a/src/openhound_github/models/workflow_job.py +++ b/src/openhound_github/models/workflow_job.py @@ -21,6 +21,7 @@ from openhound_github.kinds import edges as ek from openhound_github.kinds import nodes as nk from openhound_github.main import app +from openhound_github.models.workflow import RunsOn TEMPLATE_RE = re.compile(r"\$\{\{\s*[^}]+?\s*\}\}") @@ -154,7 +155,6 @@ class WorkflowJob(BaseAsset): repository_node_id: str org_login: str runs_on: list[str] | None = None - is_self_hosted: bool = False container: str | None = None environment: str | None = None permissions: list[str] | None = None @@ -196,6 +196,9 @@ def normalize_runs_on(cls, value: Any) -> list[str] | None: if isinstance(value, list): return [str(item) for item in value] + if isinstance(value, RunsOn): + value = value.model_dump() + if isinstance(value, dict): labels = value.get("labels") if labels is None: @@ -211,6 +214,10 @@ def normalize_runs_on(cls, value: Any) -> list[str] | None: return [str(value)] + @property + def is_self_hosted(self): + return "self-hosted" in (self.runs_on or []) + @property def as_node(self) -> GHNode: return GHNode( From 2318a02502aa76f5ef18336c95455ccc62b92841 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 16:29:35 +0200 Subject: [PATCH 16/16] Add typehint --- src/openhound_github/models/workflow_job.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openhound_github/models/workflow_job.py b/src/openhound_github/models/workflow_job.py index 6e58420..9dad1f4 100644 --- a/src/openhound_github/models/workflow_job.py +++ b/src/openhound_github/models/workflow_job.py @@ -215,7 +215,7 @@ def normalize_runs_on(cls, value: Any) -> list[str] | None: return [str(value)] @property - def is_self_hosted(self): + def is_self_hosted(self) -> bool: return "self-hosted" in (self.runs_on or []) @property