From afc789d89bc36626ec5c74603797807da4d656ee Mon Sep 17 00:00:00 2001 From: Wally Guzman <3623426+WallyGuzman@users.noreply.github.com> Date: Thu, 23 Jul 2026 20:43:31 -0500 Subject: [PATCH] Fix incorrect workflow_id type for workflow_run table - Remove unecessary strconv to match other workflow-related tables - Add optional quals for headSha, actorLogin, and createdAt - Fix minor bug in workflow_job to handle missing CompletedAt fields - Also minor typo fix in docs and new query example with dates --- .../github_actions_repository_workflow_run.md | 43 +++++++++++ ..._github_actions_repository_workflow_job.go | 2 +- ..._github_actions_repository_workflow_run.go | 75 +++++++++++-------- 3 files changed, 88 insertions(+), 32 deletions(-) diff --git a/docs/tables/github_actions_repository_workflow_run.md b/docs/tables/github_actions_repository_workflow_run.md index c2c1036..7c3366c 100644 --- a/docs/tables/github_actions_repository_workflow_run.md +++ b/docs/tables/github_actions_repository_workflow_run.md @@ -43,6 +43,49 @@ where repository_full_name = 'turbot/steampipe'; ``` +### List workflow runs between dates +Identify workflow runs between given dates within the 'turbot/steampipe' repository. This can be useful for tracking workflows over time. + +```sql+postgres +select + id, + event, + workflow_id, + conclusion, + status, + run_number, + workflow_url, + head_commit, + head_branch, + created_at +from + github_actions_repository_workflow_run +where + repository_full_name = 'turbot/steampipe' + and created_at >= '2026-01-01' + and created_at <= '2026-02-01'; +``` + +```sql+sqlite +select + id, + event, + workflow_id, + conclusion, + status, + run_number, + workflow_url, + head_commit, + head_branch, + created_at +from + github_actions_repository_workflow_run +where + repository_full_name = 'turbot/steampipe' + and created_at >= '2026-01-01' + and created_at <= '2026-02-01'; +``` + ### 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. diff --git a/github/table_github_actions_repository_workflow_job.go b/github/table_github_actions_repository_workflow_job.go index c5c787b..1c9f44b 100644 --- a/github/table_github_actions_repository_workflow_job.go +++ b/github/table_github_actions_repository_workflow_job.go @@ -52,7 +52,7 @@ func tableGitHubActionsRepositoryWorkflowJob() *plugin.Table { {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: "completed_at", Type: proto.ColumnType_TIMESTAMP, Transform: transform.FromField("CompletedAt").NullIfZero().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."}, diff --git a/github/table_github_actions_repository_workflow_run.go b/github/table_github_actions_repository_workflow_run.go index a8f9cfd..ab35e29 100644 --- a/github/table_github_actions_repository_workflow_run.go +++ b/github/table_github_actions_repository_workflow_run.go @@ -2,7 +2,8 @@ package github import ( "context" - "strconv" + "strings" + "time" "github.com/google/go-github/v55/github" @@ -24,8 +25,11 @@ func tableGitHubActionsRepositoryWorkflowRun() *plugin.Table { {Name: "workflow_id", Require: plugin.Optional}, {Name: "event", Require: plugin.Optional}, {Name: "head_branch", Require: plugin.Optional}, + {Name: "head_sha", Require: plugin.Optional}, {Name: "status", Require: plugin.Optional}, {Name: "conclusion", Require: plugin.Optional}, + {Name: "actor_login", Require: plugin.Optional}, + {Name: "created_at", Require: plugin.Optional, Operators: []string{">", ">=", "<", "<=", "="}}, }, }, Get: &plugin.GetConfig{ @@ -40,9 +44,9 @@ func tableGitHubActionsRepositoryWorkflowRun() *plugin.Table { 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 run."}, - {Name: "id", Type: proto.ColumnType_INT, Description: "The unque identifier of the workflow run."}, + {Name: "id", Type: proto.ColumnType_INT, Description: "The unique 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 workflow run."}, + {Name: "workflow_id", Type: proto.ColumnType_INT, 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 workflow run."}, @@ -85,29 +89,47 @@ func tableGitHubRepoWorkflowRunList(ctx context.Context, d *plugin.QueryData, h opts := &github.ListWorkflowRunsOptions{ ListOptions: github.ListOptions{PerPage: 100}, } - equalQuals := d.EqualsQuals - if equalQuals["event"] != nil { - if equalQuals["event"].GetStringValue() != "" { - opts.Event = equalQuals["event"].GetStringValue() - } + if event := d.EqualsQualString("event"); event != "" { + opts.Event = event } - if equalQuals["head_branch"] != nil { - if equalQuals["head_branch"].GetStringValue() != "" { - opts.Branch = equalQuals["head_branch"].GetStringValue() - } + if branch := d.EqualsQualString("head_branch"); branch != "" { + opts.Branch = branch } - if equalQuals["status"] != nil { - if equalQuals["status"].GetStringValue() != "" { - opts.Status = equalQuals["status"].GetStringValue() - } + if headSha := d.EqualsQualString("head_sha"); headSha != "" { + opts.HeadSHA = headSha + } + if status := d.EqualsQualString("status"); status != "" { + opts.Status = status + } + if actorLogin := d.EqualsQualString("actor_login"); actorLogin != "" { + opts.Actor = actorLogin } // Status param can take the value from both status and conclusion column - // https://docs.github.com/en/rest/reference/actions#workflow-runs - if equalQuals["conclusion"] != nil { - if opts.Status == "" { - if equalQuals["conclusion"].GetStringValue() != "" { - opts.Status = equalQuals["conclusion"].GetStringValue() + // https://docs.github.com/en/rest/actions/workflow-runs#list-workflow-runs-for-a-repository + if conclusion := d.EqualsQualString("conclusion"); conclusion != "" { + opts.Status = conclusion + } + + // Convert quals into GitHub search syntax + // https://docs.github.com/en/search-github/getting-started-with-searching-on-github/understanding-the-search-syntax#query-for-dates + if createdAt := d.Quals["created_at"]; createdAt != nil { + for _, q := range createdAt.Quals { + givenTime := q.Value.GetTimestampValue().AsTime() + var createdTime string + + op := q.Operator + if op == "=" { + op = "" + createdTime = givenTime.Format(time.DateOnly) + } else { + createdTime = givenTime.Format(time.RFC3339) + } + + if opts.Created == "" { + opts.Created = op + createdTime + } else { + opts.Created = strings.TrimLeft(opts.Created, "<=>") + ".." + createdTime } } } @@ -119,16 +141,7 @@ func tableGitHubRepoWorkflowRunList(ctx context.Context, d *plugin.QueryData, h } } - var workflowId int64 - if equalQuals["workflow_id"] != nil { - if equalQuals["workflow_id"].GetStringValue() != "" { - workflowId_, err := strconv.ParseInt(equalQuals["workflow_id"].GetStringValue(), 10, 64) - if err != nil { - panic(err) - } - workflowId = workflowId_ - } - } + workflowId := d.EqualsQuals["workflow_id"].GetInt64Value() for { var (