Skip to content

Commit

Permalink
Add support for workflow runs data
Browse files Browse the repository at this point in the history
  • Loading branch information
lehmanju committed Jan 22, 2025
1 parent b603a8b commit b150ab9
Show file tree
Hide file tree
Showing 17 changed files with 463 additions and 3 deletions.
28 changes: 26 additions & 2 deletions pkg/github/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func (client *Client) GetWorkflowUsage(ctx context.Context, owner, repo, workflo
}
var workflowRuns []*googlegithub.WorkflowRun
var err error
workflowRuns, page, err = client.getWorkflowRuns(ctx, owner, repo, workflow, timeRange, page)
workflowRuns, page, err = client.getWorkflowRuns(ctx, owner, repo, workflow, "", timeRange, page)
if err != nil {
return models.WorkflowUsage{}, fmt.Errorf("fetching workflow runs: %w", err)
}
Expand Down Expand Up @@ -280,7 +280,29 @@ func (client *Client) getWorkflowUsage(ctx context.Context, owner, repo string,
return client.restClient.Actions.GetWorkflowUsageByFileName(ctx, owner, repo, workflow)
}

func (client *Client) getWorkflowRuns(ctx context.Context, owner, repo, workflow string, timeRange backend.TimeRange, page int) ([]*googlegithub.WorkflowRun, int, error) {
func (client *Client) GetWorkflowRuns(ctx context.Context, owner, repo, workflow string, branch string, timeRange backend.TimeRange) ([]*googlegithub.WorkflowRun, error) {
workflowRuns := []*googlegithub.WorkflowRun{}

page := 1
for {
if page == 0 {
break
}

workflowRunsPage, nextPage, err := client.getWorkflowRuns(ctx, owner, repo, workflow, branch, timeRange, page)
if err != nil {
return nil, fmt.Errorf("fetching workflow runs: %w", err)
}

workflowRuns = append(workflowRuns, workflowRunsPage...)

page = nextPage
}

return workflowRuns, nil
}

func (client *Client) getWorkflowRuns(ctx context.Context, owner, repo, workflow string, branch string, timeRange backend.TimeRange, page int) ([]*googlegithub.WorkflowRun, int, error) {
workflowID, _ := strconv.ParseInt(workflow, 10, 64)

workflowRuns := []*googlegithub.WorkflowRun{}
Expand All @@ -298,11 +320,13 @@ func (client *Client) getWorkflowRuns(ctx context.Context, owner, repo, workflow
runs, response, err = client.restClient.Actions.ListWorkflowRunsByID(ctx, owner, repo, workflowID, &googlegithub.ListWorkflowRunsOptions{
Created: created,
ListOptions: googlegithub.ListOptions{Page: page, PerPage: 100},
Branch: branch,
})
} else {
runs, response, err = client.restClient.Actions.ListWorkflowRunsByFileName(ctx, owner, repo, workflow, &googlegithub.ListWorkflowRunsOptions{
Created: created,
ListOptions: googlegithub.ListOptions{Page: page, PerPage: 100},
Branch: branch,
})
}

Expand Down
12 changes: 12 additions & 0 deletions pkg/github/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ func (d *Datasource) HandleWorkflowUsageQuery(ctx context.Context, query *models
return GetWorkflowUsage(ctx, d.client, opt, req.TimeRange)
}

// HandleWorkflowRunsQuery is the query handler for listing workflow runs of a GitHub repository
func (d *Datasource) HandleWorkflowRunsQuery(ctx context.Context, query *models.WorkflowRunsQuery, req backend.DataQuery) (dfutil.Framer, error) {
opt := models.WorkflowRunsOptions{
Repository: query.Repository,
Owner: query.Owner,
Workflow: query.Options.Workflow,
Branch: query.Options.Branch,
}

return GetWorkflowRuns(ctx, d.client, opt, req.TimeRange)
}

// CheckHealth is the health check for GitHub
func (d *Datasource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
_, err := GetAllRepositories(ctx, d.client, models.ListRepositoriesOptions{
Expand Down
1 change: 1 addition & 0 deletions pkg/github/query_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func GetQueryHandlers(s *QueryHandler) *datasource.QueryTypeMux {
mux.HandleFunc(models.QueryTypeStargazers, s.HandleStargazers)
mux.HandleFunc(models.QueryTypeWorkflows, s.HandleWorkflows)
mux.HandleFunc(models.QueryTypeWorkflowUsage, s.HandleWorkflowUsage)
mux.HandleFunc(models.QueryTypeWorkflowRuns, s.HandleWorkflowRuns)

return mux
}
200 changes: 200 additions & 0 deletions pkg/github/testdata/workflowRuns.golden.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// 🌟 This was machine generated. Do not edit. 🌟
//
// Frame[0] {
// "typeVersion": [
// 0,
// 0
// ],
// "preferredVisualisationType": "table"
// }
// Name: workflow_run
// Dimensions: 13 Fields by 2 Rows
// +----------------+-----------------+-------------------+-----------------+-------------------------------+-------------------------------+-----------------+-----------------+-----------------+------------------+-----------------+-------------------+------------------+
// | Name: id | Name: name | Name: head_branch | Name: head_sha | Name: created_at | Name: updated_at | Name: html_url | Name: url | Name: status | Name: conclusion | Name: event | Name: workflow_id | Name: run_number |
// | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: | Labels: |
// | Type: []*int64 | Type: []*string | Type: []*string | Type: []*string | Type: []*time.Time | Type: []*time.Time | Type: []*string | Type: []*string | Type: []*string | Type: []*string | Type: []*string | Type: []*int64 | Type: []int64 |
// +----------------+-----------------+-------------------+-----------------+-------------------------------+-------------------------------+-----------------+-----------------+-----------------+------------------+-----------------+-------------------+------------------+
// | 2 | name_2 | head_branch_2 | head_sha_2 | 2013-02-03 00:00:00 +0000 UTC | 2013-02-04 00:00:00 +0000 UTC | html_url_2 | url_2 | status_2 | conclusion_2 | event_2 | 2 | 2 |
// | 1 | name_1 | head_branch_1 | head_sha_1 | 2013-02-01 00:00:00 +0000 UTC | 2013-02-02 00:00:00 +0000 UTC | html_url_1 | url_1 | status_1 | conclusion_1 | event_1 | 1 | 1 |
// +----------------+-----------------+-------------------+-----------------+-------------------------------+-------------------------------+-----------------+-----------------+-----------------+------------------+-----------------+-------------------+------------------+
//
//
// 🌟 This was machine generated. Do not edit. 🌟
{
"status": 200,
"frames": [
{
"schema": {
"name": "workflow_run",
"meta": {
"typeVersion": [
0,
0
],
"preferredVisualisationType": "table"
},
"fields": [
{
"name": "id",
"type": "number",
"typeInfo": {
"frame": "int64",
"nullable": true
}
},
{
"name": "name",
"type": "string",
"typeInfo": {
"frame": "string",
"nullable": true
}
},
{
"name": "head_branch",
"type": "string",
"typeInfo": {
"frame": "string",
"nullable": true
}
},
{
"name": "head_sha",
"type": "string",
"typeInfo": {
"frame": "string",
"nullable": true
}
},
{
"name": "created_at",
"type": "time",
"typeInfo": {
"frame": "time.Time",
"nullable": true
}
},
{
"name": "updated_at",
"type": "time",
"typeInfo": {
"frame": "time.Time",
"nullable": true
}
},
{
"name": "html_url",
"type": "string",
"typeInfo": {
"frame": "string",
"nullable": true
}
},
{
"name": "url",
"type": "string",
"typeInfo": {
"frame": "string",
"nullable": true
}
},
{
"name": "status",
"type": "string",
"typeInfo": {
"frame": "string",
"nullable": true
}
},
{
"name": "conclusion",
"type": "string",
"typeInfo": {
"frame": "string",
"nullable": true
}
},
{
"name": "event",
"type": "string",
"typeInfo": {
"frame": "string",
"nullable": true
}
},
{
"name": "workflow_id",
"type": "number",
"typeInfo": {
"frame": "int64",
"nullable": true
}
},
{
"name": "run_number",
"type": "number",
"typeInfo": {
"frame": "int64"
}
}
]
},
"data": {
"values": [
[
2,
1
],
[
"name_2",
"name_1"
],
[
"head_branch_2",
"head_branch_1"
],
[
"head_sha_2",
"head_sha_1"
],
[
1359849600000,
1359676800000
],
[
1359936000000,
1359763200000
],
[
"html_url_2",
"html_url_1"
],
[
"url_2",
"url_1"
],
[
"status_2",
"status_1"
],
[
"conclusion_2",
"conclusion_1"
],
[
"event_2",
"event_1"
],
[
2,
1
],
[
2,
1
]
]
}
}
]
}
59 changes: 59 additions & 0 deletions pkg/github/workflows.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,62 @@ func GetWorkflowUsage(ctx context.Context, client models.Client, opts models.Wor

return WorkflowUsageWrapper(data), nil
}

// WorkflowRunsWrapper is a list of GitHub workflow runs
type WorkflowRunsWrapper []*googlegithub.WorkflowRun

// Frames converts the list of workflow runs to a Grafana DataFrame
func (workflowRuns WorkflowRunsWrapper) Frames() data.Frames {
frame := data.NewFrame(
"workflow_run",
data.NewField("id", nil, []*int64{}),
data.NewField("name", nil, []*string{}),
data.NewField("head_branch", nil, []*string{}),
data.NewField("head_sha", nil, []*string{}),
data.NewField("created_at", nil, []*time.Time{}),
data.NewField("updated_at", nil, []*time.Time{}),
data.NewField("html_url", nil, []*string{}),
data.NewField("url", nil, []*string{}),
data.NewField("status", nil, []*string{}),
data.NewField("conclusion", nil, []*string{}),
data.NewField("event", nil, []*string{}),
data.NewField("workflow_id", nil, []*int64{}),
data.NewField("run_number", nil, []int64{}),
)

for _, workflowRun := range workflowRuns {
frame.InsertRow(
0,
workflowRun.ID,
workflowRun.Name,
workflowRun.HeadBranch,
workflowRun.HeadSHA,
workflowRun.CreatedAt.GetTime(),
workflowRun.UpdatedAt.GetTime(),
workflowRun.HTMLURL,
workflowRun.URL,
workflowRun.Status,
workflowRun.Conclusion,
workflowRun.Event,
workflowRun.WorkflowID,
int64(*workflowRun.RunNumber),
)
}

frame.Meta = &data.FrameMeta{PreferredVisualization: data.VisTypeTable}
return data.Frames{frame}
}

// GetWorkflowRuns gets all workflows runs for a GitHub repository and workflow
func GetWorkflowRuns(ctx context.Context, client models.Client, opts models.WorkflowRunsOptions, timeRange backend.TimeRange) (WorkflowRunsWrapper, error) {
if opts.Owner == "" || opts.Repository == "" {
return nil, nil
}

workflowRuns, err := client.GetWorkflowRuns(ctx, opts.Owner, opts.Repository, opts.Workflow, opts.Branch, timeRange)
if err != nil {
return nil, fmt.Errorf("listing workflows: opts=%+v %w", opts, err)
}

return WorkflowRunsWrapper(workflowRuns), nil
}
16 changes: 16 additions & 0 deletions pkg/github/workflows_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,19 @@ func (s *QueryHandler) HandleWorkflowUsage(ctx context.Context, req *backend.Que
Responses: processQueries(ctx, req, s.handleWorkflowUsageQuery),
}, nil
}

func (s *QueryHandler) handleWorkflowRunsQuery(ctx context.Context, q backend.DataQuery) backend.DataResponse {
query := &models.WorkflowRunsQuery{}
if err := UnmarshalQuery(q.JSON, query); err != nil {
return *err
}

return dfutil.FrameResponseWithError(s.Datasource.HandleWorkflowRunsQuery(ctx, query, q))
}

// HandleWorkflowRuns handles the plugin query for GitHub workflows
func (s *QueryHandler) HandleWorkflowRuns(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
return &backend.QueryDataResponse{
Responses: processQueries(ctx, req, s.handleWorkflowRunsQuery),
}, nil
}
Loading

0 comments on commit b150ab9

Please sign in to comment.