1+ import base64
2+ import binascii
13from dataclasses import dataclass , field
24from datetime import datetime
35from typing import Any , Iterator
46
7+ import dlt
58from dlt .sources .helpers import requests
69from dlt .sources .helpers .rest_client .client import RESTClient
710from dlt .sources .helpers .rest_client .paginators import (
6164 TeamRole ,
6265 User ,
6366 Workflow ,
67+ WorkflowJob ,
68+ WorkflowStep ,
6469)
6570from openhound_github .models .repo_role_assignment import TEAM_PERMISSION_MAP
6671from openhound_github .models .repository_role import DEFAULT_REPO_ROLES
@@ -388,7 +393,6 @@ def teams(ctx: SourceContext):
388393 "query" : TEAMS_QUERY ,
389394 "variables" : {"login" : org_name , "count" : 100 , "after" : None },
390395 }
391-
392396 for page_data in client .paginate (
393397 "/graphql" ,
394398 method = "POST" ,
@@ -452,6 +456,10 @@ def team_members(team: Team, ctx: SourceContext):
452456 )
453457
454458 if team .members .page_info .has_next_page :
459+ if not team .members .page_info .end_cursor :
460+ raise RuntimeError (
461+ f"GitHub team { team .org_login } /{ team .slug } has more members but no endCursor"
462+ )
455463 client = _client_for_org (ctx , team .org_login )
456464 data = {
457465 "query" : TEAM_MEMBERS_OVERFLOW_QUERY ,
@@ -846,19 +854,52 @@ def workflows(repo: Repository, ctx: SourceContext):
846854 Yields:
847855 Workflow (Workflow): An active workflow record.
848856 """
857+
858+ @dlt .defer
859+ def _workflow_file_contents (
860+ client : RESTClient , repo : Repository , workflow : dict [str , Any ]
861+ ) -> dict | None :
862+ path = workflow .get ("path" )
863+ if not path :
864+ return None
865+
866+ params = {"ref" : repo .default_branch } if repo .default_branch else None
867+ response = client .get (
868+ f"/repos/{ repo .full_name } /contents/{ path } " , params = params
869+ ).json ()
870+
871+ content = response .get ("content" )
872+ if not content :
873+ return None
874+
875+ return {
876+ ** workflow ,
877+ "contents" : content ,
878+ "branch" : repo .default_branch ,
879+ "repository_name" : repo .name ,
880+ "repository_node_id" : repo .node_id ,
881+ "org_login" : repo .org_login ,
882+ }
883+
849884 client = _client_for_org (ctx , repo .org_login )
850885 for page in client .paginate (
851886 f"/repos/{ repo .full_name } /actions/workflows" , params = {"per_page" : 100 }
852887 ):
853888 for workflow in page :
854- # TODO: Check if we should only store active workflows
855889 if workflow .get ("state" ) == "active" :
856- yield {
857- ** workflow ,
858- "repository_name" : repo .name ,
859- "repository_node_id" : repo .node_id ,
860- "org_login" : repo .org_login ,
861- }
890+ yield _workflow_file_contents (client , repo , workflow )
891+
892+
893+ @app .transformer (name = "workflow_jobs" , columns = WorkflowJob , parallelized = True )
894+ def workflow_jobs (workflow : Workflow ):
895+ for row in workflow .workflow_job_rows ():
896+ yield row
897+
898+
899+ @app .transformer (name = "workflow_steps" , columns = WorkflowStep , parallelized = True )
900+ def workflow_steps (workflow : Workflow ):
901+ for row in workflow .workflow_step_rows ():
902+ yield row
862903
863904
864905@app .transformer (name = "environments" , columns = Environment , parallelized = True )
@@ -1451,6 +1492,7 @@ def external_identities(ctx: SourceContext):
14511492 cursor_variable = "after" ,
14521493 cursor_field = "endCursor" ,
14531494 has_next_field = "hasNextPage" ,
1495+ allow_missing_page_info = True ,
14541496 )
14551497 data = {
14561498 "query" : SAML_IDENTITIES_QUERY ,
@@ -1511,6 +1553,7 @@ def organization_resources(ctx: SourceContext):
15111553 roles_resource = org_roles (ctx )
15121554 repo_roles_base = list (repository_roles_base (ctx ))
15131555 repos_resource = repositories (ctx )
1556+ workflows_resource = repos_resource | workflows (ctx )
15141557 environments_resource = repos_resource | environments (ctx )
15151558 personal_access_tokens_resource = personal_access_tokens (ctx )
15161559
@@ -1535,7 +1578,9 @@ def organization_resources(ctx: SourceContext):
15351578 actions_permissions (ctx ),
15361579 repos_resource ,
15371580 repos_resource | repository_roles (repo_roles_base ),
1538- repos_resource | workflows (ctx ),
1581+ workflows_resource ,
1582+ workflows_resource | workflow_jobs (),
1583+ workflows_resource | workflow_steps (),
15391584 repos_resource | repo_runners (ctx ),
15401585 repos_resource | repository_secrets (ctx ),
15411586 repos_resource | repository_variables (ctx ),
0 commit comments