From 3fd913ed4810a263d8ef7d1e66c7a8089f155f4c Mon Sep 17 00:00:00 2001 From: Wally Guzman <3623426+WallyGuzman@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:38:11 -0500 Subject: [PATCH] Add table github_actions_repository_workflow_job - Follow documentation and logic from github_actions_repository_workflow_run - Return all jobs by default in ListWorkflowJob call --- .../github_actions_repository_workflow_job.md | 87 +++++++++++ .../github_actions_repository_workflow_run.md | 14 +- github/plugin.go | 1 + ..._github_actions_repository_workflow_job.go | 141 ++++++++++++++++++ ..._github_actions_repository_workflow_run.go | 6 +- 5 files changed, 241 insertions(+), 8 deletions(-) create mode 100644 docs/tables/github_actions_repository_workflow_job.md create mode 100644 github/table_github_actions_repository_workflow_job.go diff --git a/docs/tables/github_actions_repository_workflow_job.md b/docs/tables/github_actions_repository_workflow_job.md new file mode 100644 index 0000000..f8a250e --- /dev/null +++ b/docs/tables/github_actions_repository_workflow_job.md @@ -0,0 +1,87 @@ +--- +title: "Steampipe Table: github_actions_repository_workflow_job - Query GitHub Actions Repository Workflow Jobs using SQL" +description: "Allows users to query GitHub Actions Repository Workflow Jobs, specifically the details of each workflow job in a repository, providing insights into the status, conclusion, and other metadata of the jobs." +folder: "Actions" +--- + +# Table: github_actions_repository_workflow_job - Query GitHub Actions Repository Workflow Jobs using SQL + +GitHub Actions is a CI/CD solution that allows you to automate how you build, test, and deploy your projects on any platform, including Linux, macOS, and Windows. It lets you run a series of commands in response to events on GitHub. With GitHub Actions, you can build end-to-end continuous integration (CI) and continuous deployment (CD) capabilities directly in your repository. + +## Table Usage Guide + +The `github_actions_repository_workflow_job` table provides insights into GitHub Actions Repository Workflow Jobs. As a software developer or DevOps engineer, explore details of each workflow job in a repository through this table, including its status, conclusion, and other metadata. Utilize it to monitor and analyze the performance and results of your CI/CD workflows, ensuring your software development process is efficient and effective. + +To query this table using a [fine-grained access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token), the following permissions are required: + - Repository permissions: + - Actions (Read-only): Required to access all columns. + - Metadata (Read-only): Required to access general repository metadata. + +**Important Notes** +- You must specify the `repository_full_name` column, along with either the `run_id` or the `id` column, in the `where` or `join` clause to query the table. + +## Examples + +### List workflow jobs +Analyze the settings to understand the operations and status of the workflow jobs in a specific GitHub repository. This can be beneficial in assessing the efficiency and effectiveness of workflows, identifying potential issues, and making informed decisions on workflow optimization. + +```sql+postgres +select + * +from + github_actions_repository_workflow_job +where + repository_full_name = 'turbot/steampipe' + and run_id = 26404053809; +``` + +```sql+sqlite +select + * +from + github_actions_repository_workflow_job +where + repository_full_name = 'turbot/steampipe' + and run_id = 26404053809; +``` + +### List failed workflow jobs +Identify instances where workflow jobs have failed within the 'turbot/steampipe' repository. This can be useful for debugging and identifying problematic jobs. + +```sql+postgres +select + id, + steps, + runner_id, + conclusion, + status, + run_attempt, + run_url, + head_sha, + head_branch +from + github_actions_repository_workflow_job +where + repository_full_name = 'turbot/steampipe' + and run_id = 26404053809 + and conclusion = 'failure'; +``` + +```sql+sqlite +select + id, + steps, + runner_id, + conclusion, + status, + run_attempt, + run_url, + head_sha, + head_branch +from + github_actions_repository_workflow_job +where + repository_full_name = 'turbot/steampipe' + and run_id = 26404053809 + and conclusion = 'failure'; +``` \ No newline at end of file diff --git a/docs/tables/github_actions_repository_workflow_run.md b/docs/tables/github_actions_repository_workflow_run.md index 9846fc2..c2c1036 100644 --- a/docs/tables/github_actions_repository_workflow_run.md +++ b/docs/tables/github_actions_repository_workflow_run.md @@ -43,7 +43,7 @@ where repository_full_name = 'turbot/steampipe'; ``` -### List failure workflow runs +### List failed workflow runs Identify instances where workflow runs have failed within the 'turbot/steampipe' repository. This can be useful for debugging and identifying problematic workflows. ```sql+postgres @@ -60,7 +60,8 @@ select from github_actions_repository_workflow_run where - repository_full_name = 'turbot/steampipe' and conclusion = 'failure'; + repository_full_name = 'turbot/steampipe' + and conclusion = 'failure'; ``` ```sql+sqlite @@ -77,7 +78,8 @@ select from github_actions_repository_workflow_run where - repository_full_name = 'turbot/steampipe' and conclusion = 'failure'; + repository_full_name = 'turbot/steampipe' + and conclusion = 'failure'; ``` ### List manual workflow runs @@ -99,7 +101,8 @@ select from github_actions_repository_workflow_run where - repository_full_name = 'turbot/steampipe' and event = 'workflow_dispatch'; + repository_full_name = 'turbot/steampipe' + and event = 'workflow_dispatch'; ``` ```sql+sqlite @@ -118,5 +121,6 @@ select from github_actions_repository_workflow_run where - repository_full_name = 'turbot/steampipe' and event = 'workflow_dispatch'; + repository_full_name = 'turbot/steampipe' + and event = 'workflow_dispatch'; ``` \ No newline at end of file diff --git a/github/plugin.go b/github/plugin.go index 7915a0d..4b10271 100644 --- a/github/plugin.go +++ b/github/plugin.go @@ -29,6 +29,7 @@ func Plugin(ctx context.Context) *plugin.Plugin { "github_actions_repository_runner": tableGitHubActionsRepositoryRunner(), "github_actions_repository_secret": tableGitHubActionsRepositorySecret(), "github_actions_repository_variable": tableGitHubActionsRepositoryVariable(), + "github_actions_repository_workflow_job": tableGitHubActionsRepositoryWorkflowJob(), "github_actions_repository_workflow_run": tableGitHubActionsRepositoryWorkflowRun(), "github_audit_log": tableGitHubAuditLog(), "github_blob": tableGitHubBlob(), diff --git a/github/table_github_actions_repository_workflow_job.go b/github/table_github_actions_repository_workflow_job.go new file mode 100644 index 0000000..3d9bace --- /dev/null +++ b/github/table_github_actions_repository_workflow_job.go @@ -0,0 +1,141 @@ +package github + +import ( + "context" + + "github.com/google/go-github/v55/github" + + "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" + "github.com/turbot/steampipe-plugin-sdk/v5/plugin" + "github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform" +) + +func tableGitHubActionsRepositoryWorkflowJob() *plugin.Table { + return &plugin.Table{ + Name: "github_actions_repository_workflow_job", + Description: "WorkflowJob represents a repository action workflow job", + List: &plugin.ListConfig{ + KeyColumns: []*plugin.KeyColumn{ + {Name: "repository_full_name", Require: plugin.Required}, + {Name: "run_id", Require: plugin.Required}, + }, + ShouldIgnoreError: isNotFoundError([]string{"404"}), + Hydrate: tableGitHubRepoWorkflowJobList, + }, + Get: &plugin.GetConfig{ + KeyColumns: []*plugin.KeyColumn{ + {Name: "repository_full_name", Require: plugin.Required, Operators: []string{"="}}, + {Name: "id", Require: plugin.Required, Operators: []string{"="}}, + }, + ShouldIgnoreError: isNotFoundError([]string{"404"}), + Hydrate: tableGitHubRepoWorkflowJobGet, + }, + Columns: commonColumns([]*plugin.Column{ + // Top columns + {Name: "repository_full_name", Type: proto.ColumnType_STRING, Transform: transform.FromQual("repository_full_name"), Description: "Full name of the repository that specifies the workflow job."}, + {Name: "run_id", Type: proto.ColumnType_INT, Description: "The unique identifier of the workflow run."}, + {Name: "id", Type: proto.ColumnType_INT, Description: "The unique identifier of the workflow job."}, + {Name: "name", Type: proto.ColumnType_STRING, Description: "The name of the workflow job."}, + {Name: "workflow_name", Type: proto.ColumnType_STRING, Description: "The workflow name of the workflow job."}, + {Name: "node_id", Type: proto.ColumnType_STRING, Description: "The node id of the workflow job."}, + {Name: "conclusion", Type: proto.ColumnType_STRING, Description: "The conclusion for workflow job."}, + {Name: "status", Type: proto.ColumnType_STRING, Description: "The status of the workflow job."}, + {Name: "run_url", Type: proto.ColumnType_STRING, Description: "The API address of the workflow run the job belongs to."}, + {Name: "check_run_url", Type: proto.ColumnType_STRING, Description: "The API address of the check run associated with the workflow job."}, + {Name: "head_branch", Type: proto.ColumnType_STRING, Description: "The head branch of the workflow job."}, + {Name: "head_sha", Type: proto.ColumnType_STRING, Description: "The head sha of the workflow job.", Transform: transform.FromField("HeadSHA")}, + {Name: "html_url", Type: proto.ColumnType_STRING, Description: "The address for the workflow job's GitHub web page.", Transform: transform.FromField("HTMLURL")}, + {Name: "url", Type: proto.ColumnType_STRING, Description: "The address for the workflow job GitHub web page.", Transform: transform.FromField("URL")}, + + // Other columns + {Name: "steps", Type: proto.ColumnType_JSON, Description: "The list of step details for the workflow job."}, + {Name: "labels", Type: proto.ColumnType_JSON, Description: "The list of labels for the workflow job."}, + {Name: "created_at", Type: proto.ColumnType_TIMESTAMP, Transform: transform.FromField("CreatedAt").Transform(convertTimestamp), Description: "Time when the workflow job was created."}, + {Name: "started_at", Type: proto.ColumnType_TIMESTAMP, Transform: transform.FromField("StartedAt").Transform(convertTimestamp), Description: "Time when the workflow job was started."}, + {Name: "completed_at", Type: proto.ColumnType_TIMESTAMP, Transform: transform.FromField("CompletedAt").Transform(convertTimestamp), Description: "Time when the workflow job was completed."}, + {Name: "run_attempt", Type: proto.ColumnType_INT, Description: "The attempt number of the workflow run."}, + {Name: "runner_id", Type: proto.ColumnType_INT, Description: "The unique identifier of the workflow job runner."}, + {Name: "runner_name", Type: proto.ColumnType_STRING, Description: "The name of the workflow job runner."}, + {Name: "runner_group_id", Type: proto.ColumnType_INT, Description: "The unique identifier of the job runner group."}, + {Name: "runner_group_name", Type: proto.ColumnType_STRING, Description: "The name of the workflow job runner group."}, + }), + } +} + +func tableGitHubRepoWorkflowJobList(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + client := connect(ctx, d) + + runId := d.EqualsQuals["run_id"].GetInt64Value() + orgName := d.EqualsQuals["repository_full_name"].GetStringValue() + owner, repo := parseRepoFullName(orgName) + opts := &github.ListWorkflowJobsOptions{ + // The API defaults to "latest", which only returns jobs from the most recent + // run attempt. "all" includes jobs from previous attempts. + Filter: "all", + ListOptions: github.ListOptions{PerPage: 100}, + } + + limit := d.QueryContext.Limit + if limit != nil { + if *limit < int64(opts.PerPage) { + opts.PerPage = int(*limit) + } + } + + for { + var ( + workflowJobs *github.Jobs + resp *github.Response + err error + ) + workflowJobs, resp, err = client.Actions.ListWorkflowJobs(ctx, owner, repo, runId, opts) + if err != nil { + return nil, err + } + + for _, i := range workflowJobs.Jobs { + if i != nil { + d.StreamListItem(ctx, i) + } + + // Context can be cancelled due to manual cancellation or the limit has been hit + if d.RowsRemaining(ctx) == 0 { + return nil, nil + } + } + + if resp.NextPage == 0 { + break + } + + opts.Page = resp.NextPage + } + + return nil, nil +} + +func tableGitHubRepoWorkflowJobGet(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + jobId := d.EqualsQuals["id"].GetInt64Value() + orgName := d.EqualsQuals["repository_full_name"].GetStringValue() + + // Empty check for the parameters + if jobId == 0 || orgName == "" { + return nil, nil + } + + owner, repo := parseRepoFullName(orgName) + plugin.Logger(ctx).Trace("tableGitHubRepoWorkflowJobGet", "owner", owner, "repo", repo, "jobId", jobId) + + client := connect(ctx, d) + + var ( + workflowJob *github.WorkflowJob + err error + ) + workflowJob, _, err = client.Actions.GetWorkflowJobByID(ctx, owner, repo, jobId) + if err != nil { + return nil, err + } + + return workflowJob, nil +} diff --git a/github/table_github_actions_repository_workflow_run.go b/github/table_github_actions_repository_workflow_run.go index 68cd5d0..bb1c1cb 100644 --- a/github/table_github_actions_repository_workflow_run.go +++ b/github/table_github_actions_repository_workflow_run.go @@ -42,10 +42,10 @@ func tableGitHubActionsRepositoryWorkflowRun() *plugin.Table { {Name: "repository_full_name", Type: proto.ColumnType_STRING, Transform: transform.FromQual("repository_full_name"), Description: "Full name of the repository that specifies the workflow run."}, {Name: "id", Type: proto.ColumnType_INT, Description: "The unque identifier of the workflow run."}, {Name: "event", Type: proto.ColumnType_STRING, Description: "The event for which workflow triggered off."}, - {Name: "workflow_id", Type: proto.ColumnType_STRING, Description: "The workflow id of the worflow run."}, - {Name: "node_id", Type: proto.ColumnType_STRING, Description: "The node id of the worflow run."}, + {Name: "workflow_id", Type: proto.ColumnType_STRING, Description: "The workflow id of the workflow run."}, + {Name: "node_id", Type: proto.ColumnType_STRING, Description: "The node id of the workflow run."}, {Name: "conclusion", Type: proto.ColumnType_STRING, Description: "The conclusion for workflow run."}, - {Name: "status", Type: proto.ColumnType_STRING, Description: "The status of the worflow run."}, + {Name: "status", Type: proto.ColumnType_STRING, Description: "The status of the workflow run."}, {Name: "run_number", Type: proto.ColumnType_INT, Description: "The number of time workflow has run."}, {Name: "artifacts_url", Type: proto.ColumnType_STRING, Description: "The address for artifact GitHub web page."}, {Name: "cancel_url", Type: proto.ColumnType_STRING, Description: "The address for workflow run cancel GitHub web page."},