Skip to content

Resolve remote workflow names for logs targets - #59454

Merged
pelikhan merged 1 commit into
mainfrom
copilot/update-logs-command-target-resolution
Sep 8, 2026
Merged

pelikhan merged 1 commit into
mainfrom
copilot/update-logs-command-target-resolution

Conversation

Copilot AI commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Remote logs targets used the agentic workflow ID directly with gh run list, which fails when the GitHub Actions workflow has a different display name.

  • Remote resolution

    • Fetch workflow metadata once per target repository.
    • Match IDs and display names against remote workflow paths.
    • Pass the resolved display name to run listing.
  • Multi-target handling

    • Reuse repository metadata across targets.
    • Skip unresolved targets while preserving successful targets.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI requested a review from pelikhan September 8, 2026 12:28
@pelikhan
pelikhan marked this pull request as ready for review September 8, 2026 12:33
Copilot AI balanced review requested due to automatic review settings September 8, 2026 12:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Three moderate workflow-resolution and reporting issues remain unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Resolves remote workflow IDs to GitHub Actions display names before listing runs.

Changes:

  • Caches remote workflow metadata per repository.
  • Preserves successful targets when other resolutions fail.
  • Adds basic display-name resolution coverage.
File summaries
File Review
pkg/cli/logs_command.go Moderate: repository-qualified local targets bypass resolution; remote fetch counts use local files; cross-repository workflow paths fail ID fallback.
pkg/cli/logs_command_test.go Nit: add multi-target coverage for caching, unresolved targets, and preserved successes.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment thread pkg/cli/logs_command.go
Comment on lines +322 to +325
if target.workflowName == "" || target.repoOverride == "" || repoIsLocal(target.repoOverride) {
resolvedTargets = append(resolvedTargets, *target)
continue
}
Comment thread pkg/cli/logs_command.go
continue
}
var err error
githubWorkflows, err = fetchWorkflows(ctx, target.repoOverride, verbose)
Comment thread pkg/cli/logs_command.go
Comment on lines +343 to +344
resolvedName := matchRemoteWorkflowName(target.workflowName, githubWorkflows)
if resolvedName == "" {
Comment on lines +437 to +456
targets := []logsWorkflowTarget{
{repoOverride: "githubnext/gh-aw-cao", workflowName: "uk-ai-advisory"},
}
fetchWorkflows := func(context.Context, string, bool) (map[string]*GitHubWorkflow, error) {
return map[string]*GitHubWorkflow{
"uk-ai-advisory": {
Name: "UK AI Advisory",
Path: ".github/workflows/uk-ai-advisory.lock.yml",
},
}, nil
}

resolved, targetErrors := resolveRemoteLogsWorkflowTargetsWithFetcher(
context.Background(), targets, false, fetchWorkflows,
)

require.Empty(t, targetErrors)
require.Len(t, resolved, 1)
assert.Equal(t, "UK AI Advisory", resolved[0].workflowName)
assert.Equal(t, "githubnext/gh-aw-cao", resolved[0].repoOverride)
@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ Ponytail Reviewer completed successfully!

Lean already. Ship.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Ponytail Reviewer for #59454

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR Code Quality Reviewer completed the code quality review.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-09-08T12:48:18Z
review_event: REQUEST_CHANGES
top_themes:
  - missing regression coverage for multi-target remote resolution
files_reviewed:
  - pkg/cli/logs_command.go
  - pkg/cli/logs_command_test.go
comment_count: 1

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 25.2 AIC · ⌖ 7.41 AIC · ⊞ 23.5K · ◷
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes

The remote workflow-name resolution logic is reasonable, but the new test coverage is too narrow for the failure modes this code adds.

Blocking theme

The implementation now caches remote workflow metadata per repository and intentionally keeps successful targets when a sibling target in the same batch cannot be resolved. That is exactly the kind of control flow that breaks later if we only test a single happy-path target. Right now there is no regression test proving that same-repo targets share one fetch or that an unresolved target does not poison the rest of the batch.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 25.2 AIC · ⌖ 7.41 AIC · ⊞ 23.5K
Comment /review to run again

require.Empty(t, targetErrors)
require.Len(t, resolved, 1)
assert.Equal(t, "UK AI Advisory", resolved[0].workflowName)
assert.Equal(t, "githubnext/gh-aw-cao", resolved[0].repoOverride)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new test only exercises a single happy-path target, so the repository-level cache and partial-failure behavior added in resolveRemoteLogsWorkflowTargetsWithFetcher can regress unnoticed. A second target in the same repo and an unresolved target in the same batch are the cases that prove this logic actually preserves successful targets while reusing the cached workflow list.

💡 Add a batch test that covers the new control flow

The new code introduces two behaviors that are easy to break independently:

targets := []logsWorkflowTarget{
    {repoOverride: "githubnext/gh-aw-cao", workflowName: "uk-ai-advisory"},
    {repoOverride: "githubnext/gh-aw-cao", workflowName: "missing-workflow"},
}

var fetchCalls int
fetchWorkflows := func(context.Context, string, bool) (map[string]*GitHubWorkflow, error) {
    fetchCalls++
    return map[string]*GitHubWorkflow{
        "uk-ai-advisory": {Name: "UK AI Advisory", Path: ".github/workflows/uk-ai-advisory.lock.yml"},
    }, nil
}

resolved, errs := resolveRemoteLogsWorkflowTargetsWithFetcher(context.Background(), targets, false, fetchWorkflows)
require.Len(t, resolved, 1)
require.Len(t, errs, 1)
assert.Equal(t, 1, fetchCalls)

Without a test like this, a future refactor can accidentally re-fetch per target or drop all results after the first unresolved workflow, and this PR would still pass.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd. The fix correctly resolves the display-name mismatch for remote logs targets and reuses per-repo workflow metadata, but it reintroduces a regression for extension-suffixed workflow targets, and the new test doesn't cover the multi-target caching/skip behavior the PR describes.

📋 Key Findings

Confirmed Bug

  • matchRemoteWorkflowName matches against the file-derived key (extension stripped), but cross-repo file-path targets (e.g. owner/repo/.github/workflows/daily-report.yml) retain their .yml suffix in workflowName. I reproduced this with a standalone test — resolution now fails with workflow not found for such targets, which worked prior to this PR since no remote lookup was previously performed on the raw name.

Test Coverage Gap

  • The only new test (TestResolveRemoteLogsWorkflowTargets) covers a single successful target. The PR body advertises repository-metadata reuse across multiple targets and skip-unresolved-while-preserving-successful behavior — neither is exercised, so both could regress silently.

Positive Highlights

  • ✅ Per-repo caching of both successful (workflowsByRepo) and failed (errorsByRepo) fetches avoids redundant API calls across targets.
  • ✅ Correctly short-circuits for local repos and empty names, avoiding unnecessary remote calls.

Note: this overlaps with and confirms one of the automated Copilot review comments already on this PR (extension/file-path target mismatch); I've added a concrete repro and a fix suggestion, plus a distinct test-coverage recommendation.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 88.1 AIC · ⌖ 14.9 AIC · ⊞ 10.3K
Comment /matt to run again

Comment thread pkg/cli/logs_command.go
}

resolvedName := matchRemoteWorkflowName(target.workflowName, githubWorkflows)
if resolvedName == "" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/diagnosing-bugs] Confirmed regression: matchRemoteWorkflowName matches on the file-derived key (no extension), but splitCrossRepoWorkflowTarget/resolveLogsWorkflowTarget leave file targets like owner/repo/.github/workflows/daily-report.yml with the .yml suffix intact, so this new resolution step now fails cross-repo file targets that worked before this PR.

💡 Repro + fix

I reproduced this with a standalone test:

targets := []logsWorkflowTarget{{repoOverride:"o/r", workflowName:"daily-report.yml"}}
fetch := func(context.Context,string,bool)(map[string]*GitHubWorkflow,error){
  return map[string]*GitHubWorkflow{"daily-report": {Name:"Daily Report", Path:".github/workflows/daily-report.lock.yml"}}, nil
}
resolved, errs := resolveRemoteLogsWorkflowTargetsWithFetcher(context.Background(), targets, false, fetch)
// errs = ["o/r/daily-report.yml: workflow not found"]

The root cause (mismatched display name) is fixed, but a second pre-existing normalization gap (extension not stripped for file-path targets before matching) is now newly exercised by this code path. Normalize target.workflowName (e.g. via normalizeWorkflowID) before calling matchRemoteWorkflowName, and add a regression test for a .yml/.md-suffixed file target.

@copilot please address this.

Comment thread pkg/cli/logs_command.go
}
logsCommandLog.Printf("Resolved remote workflow name: %s -> %s", target.displayName(), resolvedName)
target.workflowName = resolvedName
resolvedTargets = append(resolvedTargets, *target)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] resolveRemoteLogsWorkflowTargetsWithFetcher has no test for the multi-target/repo-cache behavior it advertises (single fetch per repo, skip-on-error preserving other targets, per-repo error reuse). Only a single successful target is exercised.

💡 Suggested test cases
  • Two targets, same repoOverride, assert fetchWorkflows is called exactly once (e.g. via a call counter closure).
  • One resolvable + one unresolvable workflow name in the same repo: assert the resolvable target is still returned and only the unresolvable one produces an error (workflow not found).
  • fetchWorkflows returning an error for a repo with two targets: assert both targets get failed to resolve workflow name errors and the fetch is attempted only once (errorsByRepo cache hit).
  • A target whose workflowName still carries a .yml/.md suffix (file-path target), to catch the normalization gap noted in the other comment.

Without these, the repository-cache and skip-unresolved logic described in the PR body can silently regress.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is a backend Go change (workflow-name resolution logic for logs targets), not a UI change, so Impeccable UI modes (audit/critique/harden/etc.) don't apply. Performed a standard correctness/security review instead.

I independently verified the existing unresolved Copilot review comments on this PR are all valid, high-confidence, and still unaddressed in the current diff:

  • logs_command.go:344 — confirmed bug: normalizeWorkflowID("daily-report.yml") only strips .lock.yml/.md suffixes, so a cross-repo file target like owner/repo/.github/workflows/daily-report.yml keeps target.workflowName = "daily-report.yml". Meanwhile fetchGitHubWorkflows/extractWorkflowNameFromPath builds the remote map keyed by the extension-stripped name ("daily-report"). matchRemoteWorkflowName's case-insensitive key comparison will therefore never match, and resolution silently falls through to "workflow not found" for exactly the documented cross-repo file-path use case.
  • logs_command.go:325 and logs_command.go:334 — as previously flagged, the local-checkout skip and the local-.md-file-based success counting in fetchGitHubWorkflows don't generalize correctly to purely remote repos.
  • logs_command_test.go:456 — test coverage gap: only a single successful target is exercised; the advertised per-repo caching (workflowsByRepo/errorsByRepo) and skip-on-unresolved-target behavior have no test coverage and could regress silently.

These are blocking correctness issues in the core new logic (resolveRemoteLogsWorkflowTargetsWithFetcher) and should be fixed before merge. I'm not re-posting duplicate inline comments since the threads are already open; please address the existing comment threads.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet50 · 89.8 AIC · ⌖ 13.3 AIC · ⊞ 8.3K

@pelikhan
pelikhan merged commit 6eb5fd8 into main Sep 8, 2026
120 checks passed
@pelikhan
pelikhan deleted the copilot/update-logs-command-target-resolution branch September 8, 2026 13:09
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.88.7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants