Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions docs/tables/github_actions_repository_workflow_run.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion github/table_github_actions_repository_workflow_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -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."},
Expand Down
75 changes: 44 additions & 31 deletions github/table_github_actions_repository_workflow_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package github

import (
"context"
"strconv"
"strings"
"time"

"github.com/google/go-github/v55/github"

Expand All @@ -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{
Expand All @@ -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."},
Expand Down Expand Up @@ -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
}
}
}
Expand All @@ -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 (
Expand Down