Skip to content

Commit 81e2556

Browse files
authored
fix: missing json:path from health cmd (#20221)
1 parent e1f4359 commit 81e2556

2 files changed

Lines changed: 121 additions & 3 deletions

File tree

pkg/cli/logs_github_api.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ type ListWorkflowRunsOptions struct {
154154
// The processedCount and targetCount parameters are used to display progress in the spinner message.
155155
func listWorkflowRunsWithPagination(opts ListWorkflowRunsOptions) ([]WorkflowRun, int, error) {
156156
logsGitHubAPILog.Printf("Listing workflow runs: workflow=%s, limit=%d, startDate=%s, endDate=%s, ref=%s", opts.WorkflowName, opts.Limit, opts.StartDate, opts.EndDate, opts.Ref)
157-
args := []string{"run", "list", "--json", "databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle"}
157+
args := []string{"run", "list", "--json", "databaseId,number,url,status,conclusion,workflowName,path,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle"}
158158

159159
// Add filters
160160
if opts.WorkflowName != "" {
@@ -246,15 +246,27 @@ func listWorkflowRunsWithPagination(opts ListWorkflowRunsOptions) ([]WorkflowRun
246246
return nil, 0, fmt.Errorf("failed to list workflow runs (exit code %d): %w", exitCode, err)
247247
}
248248

249-
var runs []WorkflowRun
250-
if err := json.Unmarshal(output, &runs); err != nil {
249+
// gh run list outputs "path" for the workflow file path, but WorkflowRun uses "workflowPath".
250+
// Unmarshal via a helper struct so both fields are captured correctly.
251+
var rawRuns []struct {
252+
WorkflowRun
253+
Path string `json:"path"`
254+
}
255+
if err := json.Unmarshal(output, &rawRuns); err != nil {
251256
// Stop spinner on parse error
252257
if !opts.Verbose {
253258
spinner.Stop()
254259
}
255260
return nil, 0, fmt.Errorf("failed to parse workflow runs: %w", err)
256261
}
257262

263+
runs := make([]WorkflowRun, len(rawRuns))
264+
for i, raw := range rawRuns {
265+
run := raw.WorkflowRun
266+
run.WorkflowPath = raw.Path
267+
runs[i] = run
268+
}
269+
258270
// Stop spinner silently - don't show per-iteration messages
259271
if !opts.Verbose {
260272
spinner.Stop()

pkg/cli/logs_github_api_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//go:build !integration
2+
3+
package cli
4+
5+
import (
6+
"encoding/json"
7+
"strings"
8+
"testing"
9+
"time"
10+
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
// TestWorkflowRunPathFieldUnmarshal verifies that the "path" key returned by
16+
// "gh run list --json" is correctly bridged to WorkflowRun.WorkflowPath during
17+
// unmarshaling. The gh CLI uses "path" but WorkflowRun serialises the field as
18+
// "workflowPath" for backward compatibility, so a helper struct is used at the
19+
// unmarshal site.
20+
//
21+
// Regression: commit 61cc2d7ac (Jan 4 2026) silently dropped "path" from the
22+
// gh run list --json field list, causing WorkflowPath to always be "" and the
23+
// .lock.yml filter in fetchWorkflowRuns to discard every run.
24+
func TestWorkflowRunPathFieldUnmarshal(t *testing.T) {
25+
// Simulate a single row of "gh run list --json path,workflowName,..."
26+
rawJSON := `[
27+
{
28+
"databaseId": 42,
29+
"workflowName": "My Workflow",
30+
"path": ".github/workflows/my-workflow.lock.yml",
31+
"status": "completed",
32+
"conclusion": "success",
33+
"createdAt": "2026-01-01T00:00:00Z",
34+
"startedAt": "2026-01-01T00:00:01Z",
35+
"updatedAt": "2026-01-01T00:01:00Z"
36+
}
37+
]`
38+
39+
var rawRuns []struct {
40+
WorkflowRun
41+
Path string `json:"path"`
42+
}
43+
require.NoError(t, json.Unmarshal([]byte(rawJSON), &rawRuns), "unmarshal should succeed")
44+
require.Len(t, rawRuns, 1)
45+
46+
run := rawRuns[0].WorkflowRun
47+
run.WorkflowPath = rawRuns[0].Path
48+
49+
assert.Equal(t, ".github/workflows/my-workflow.lock.yml", run.WorkflowPath,
50+
"WorkflowPath should be populated from the 'path' JSON key")
51+
assert.Equal(t, int64(42), run.DatabaseID)
52+
assert.Equal(t, "My Workflow", run.WorkflowName)
53+
}
54+
55+
// TestFetchWorkflowRunsLockYMLFilter verifies the .lock.yml suffix filter used
56+
// in fetchWorkflowRuns. Only runs whose WorkflowPath ends in ".lock.yml" must
57+
// be retained; runs with a plain ".yml" path (regular Actions workflows) must
58+
// be excluded.
59+
func TestFetchWorkflowRunsLockYMLFilter(t *testing.T) {
60+
runs := []WorkflowRun{
61+
{
62+
DatabaseID: 1,
63+
WorkflowName: "Agentic Workflow",
64+
WorkflowPath: ".github/workflows/agentic-workflow.lock.yml",
65+
StartedAt: time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC),
66+
UpdatedAt: time.Date(2026, 1, 1, 0, 5, 0, 0, time.UTC),
67+
},
68+
{
69+
DatabaseID: 2,
70+
WorkflowName: "Regular CI",
71+
WorkflowPath: ".github/workflows/ci.yml",
72+
},
73+
{
74+
DatabaseID: 3,
75+
WorkflowName: "Another Agentic",
76+
WorkflowPath: ".github/workflows/another.lock.yml",
77+
StartedAt: time.Date(2026, 1, 2, 0, 0, 0, 0, time.UTC),
78+
UpdatedAt: time.Date(2026, 1, 2, 0, 3, 0, 0, time.UTC),
79+
},
80+
{
81+
// Run with empty WorkflowPath — must be excluded (mimics the pre-fix state
82+
// where "path" was absent from the JSON query).
83+
DatabaseID: 4,
84+
WorkflowName: "Agentic But No Path",
85+
WorkflowPath: "",
86+
},
87+
}
88+
89+
var filtered []WorkflowRun
90+
for _, run := range runs {
91+
if strings.HasSuffix(run.WorkflowPath, ".lock.yml") {
92+
if run.Duration == 0 && !run.StartedAt.IsZero() && !run.UpdatedAt.IsZero() {
93+
run.Duration = run.UpdatedAt.Sub(run.StartedAt)
94+
}
95+
filtered = append(filtered, run)
96+
}
97+
}
98+
99+
require.Len(t, filtered, 2, "only .lock.yml runs should pass the filter")
100+
101+
assert.Equal(t, int64(1), filtered[0].DatabaseID)
102+
assert.Equal(t, 5*time.Minute, filtered[0].Duration, "duration should be calculated from StartedAt/UpdatedAt")
103+
104+
assert.Equal(t, int64(3), filtered[1].DatabaseID)
105+
assert.Equal(t, 3*time.Minute, filtered[1].Duration)
106+
}

0 commit comments

Comments
 (0)