Skip to content

feat: add --exclude flag to logs command and MCP tool to skip specified workflows#28477

Closed
Copilot wants to merge 4 commits intomainfrom
copilot/recreate-changes-from-28452
Closed

feat: add --exclude flag to logs command and MCP tool to skip specified workflows#28477
Copilot wants to merge 4 commits intomainfrom
copilot/recreate-changes-from-28452

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 25, 2026

Summary

Recreates the changes from #28452.

Adds a new --exclude flag to the gh aw logs command and a corresponding exclude_workflows parameter to the MCP logs tool, allowing users to skip specified workflows when downloading logs.

Excluded runs are filtered before artifact download, which avoids unnecessary GitHub API requests and artifact download network traffic for the excluded workflows.

Changes

  • pkg/cli/logs_command.go: New --exclude (StringSlice) flag. Supports comma-separated values or repeated --exclude flags. Calls DownloadWorkflowLogsWithOptions directly with named fields for clarity.
  • pkg/cli/logs_orchestrator.go: Introduces DownloadWorkflowLogsOptions struct grouping all parameters. DownloadWorkflowLogsWithOptions is the primary implementation; DownloadWorkflowLogs is a thin wrapper that maps positional arguments into DownloadWorkflowLogsOptions. The resolved exclude list is applied to each batch of runs before downloadRunArtifactsConcurrent is called.
  • pkg/cli/logs_utils.go: Two helpers:
    • resolveExcludeWorkflows: loads workflow.GetAllWorkflows() once and builds an in-memory map (keyed by display name and workflow ID, case-insensitive) to batch-resolve all excludes without repeated filesystem scans. Falls back to keeping the raw value when resolution fails.
    • isWorkflowExcluded: case-insensitive comparison against both the display name and a slugified form (spaces→hyphens), so --exclude weekly-research correctly matches a run named "Weekly Research" even when no local lock files are present.
  • pkg/cli/mcp_tools_privileged.go: New exclude_workflows []string field in the logsArgs struct with JSON schema description. Passes --exclude to the CLI subprocess.

Usage

# Exclude a single workflow by ID
gh aw logs --exclude weekly-research

# Exclude by display name
gh aw logs --exclude "Weekly Research"

# Exclude multiple workflows (comma-separated)
gh aw logs --exclude ci-tests,nightly-build

# Works with other filters
gh aw logs --start-date -1w --exclude ci-tests --engine copilot

Tests

  • TestLogsCommandExcludeFlag: verifies the flag is registered with correct type and default
  • TestIsWorkflowExcluded: table-driven tests for exact match, case-insensitive match, slug match (ID matching display name), no match, empty excludes, and multiple excludes
  • TestResolveExcludeWorkflows: table-driven tests for nil/empty input, blank-entry trimming, unknown workflow fallback, and whitespace stripping

Copilot AI and others added 2 commits April 25, 2026 15:41
Copilot AI requested a review from pelikhan April 25, 2026 15:43
@pelikhan pelikhan marked this pull request as ready for review April 25, 2026 15:56
Copilot AI review requested due to automatic review settings April 25, 2026 15:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds workflow exclusion support to gh aw logs (and the MCP logs tool) so specified workflows can be skipped before artifact download, reducing unnecessary API calls and network traffic.

Changes:

  • Added --exclude (StringSlice) to gh aw logs and plumbed it through a new DownloadWorkflowLogsOptions struct-based entrypoint.
  • Implemented exclude resolution + matching helpers and applied filtering prior to artifact downloads.
  • Extended the MCP privileged logs tool with exclude_workflows and added unit tests covering the new behavior.
Show a summary per file
File Description
pkg/cli/logs_command.go Adds --exclude flag and passes it via DownloadWorkflowLogsOptions.
pkg/cli/logs_orchestrator.go Introduces DownloadWorkflowLogsOptions / DownloadWorkflowLogsWithOptions and applies pre-download exclusion filtering.
pkg/cli/logs_utils.go Adds helpers to resolve excludes against local workflows and perform case-insensitive/slug matching.
pkg/cli/mcp_tools_privileged.go Adds exclude_workflows to MCP logs tool args and forwards it to the CLI via --exclude.
pkg/cli/logs_command_test.go Adds tests for --exclude flag registration and isWorkflowExcluded matching behavior.
pkg/cli/logs_json_stderr_order_test.go Updates calls to include the new exclude argument.
pkg/cli/logs_ci_scenario_test.go Updates calls to include the new exclude argument.
pkg/cli/context_cancellation_test.go Updates calls to include the new exclude argument.
pkg/cli/logs_download_test.go Updates calls to include the new exclude argument.
docs/adr/28452-workflow-exclusion-filter-for-logs-command.md Adds ADR documenting the workflow exclusion decision/spec.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (1)

docs/adr/28452-workflow-exclusion-filter-for-logs-command.md:60

  • The normative spec says implementations MUST pass the exclude list to DownloadWorkflowLogs via an excludeWorkflows parameter, but the CLI implementation calls DownloadWorkflowLogsWithOptions directly. Update the spec to match the actual public entrypoint(s) (e.g., require populating DownloadWorkflowLogsOptions.ExcludeWorkflows and/or define which function is canonical).
### Exclusion Flag and Parameter

1. The `logs` CLI command **MUST** expose an `--exclude` flag of type `StringSlice` that accepts one or more workflow names or IDs, either comma-separated or via repeated flags.
2. The MCP `logs` tool **MUST** expose an `exclude_workflows` array field in its argument struct with a JSON schema description.
3. Implementations **MUST** pass the exclude list to `DownloadWorkflowLogs` as the `excludeWorkflows []string` parameter.

  • Files reviewed: 10/10 changed files
  • Comments generated: 2

Comment thread pkg/cli/logs_orchestrator.go Outdated
}

// DownloadWorkflowLogs downloads and analyzes workflow logs with metrics.
// It is a thin wrapper around DownloadWorkflowLogsWithOptions for backward compatibility.
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

The comment says this wrapper is for backward compatibility, but the function signature itself has changed by adding excludeWorkflows []string, which is a breaking change for any external callers. Either keep the old DownloadWorkflowLogs signature and route new functionality through DownloadWorkflowLogsWithOptions, or update the comment to avoid claiming backward compatibility.

Suggested change
// It is a thin wrapper around DownloadWorkflowLogsWithOptions for backward compatibility.
// It is a thin wrapper around DownloadWorkflowLogsWithOptions that maps the
// positional arguments into DownloadWorkflowLogsOptions.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +42
#### Negative
- `DownloadWorkflowLogs` gains yet another parameter, worsening an already long function signature. This may be a motivation for future refactoring of the signature into a struct.
- If lock files are absent or out of date, `resolveExcludeWorkflows` silently falls back to raw-value matching, which may produce unexpected results without a clear error to the user.
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

This ADR notes that adding excludeWorkflows worsens the long DownloadWorkflowLogs signature and suggests a future refactor into a struct, but this PR already introduces DownloadWorkflowLogsOptions. The ADR should be updated to reflect the implemented design (options struct as primary API) to avoid misleading future readers.

This issue also appears on line 55 of the same file.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

✅ Design Decision Gate — ADR Verified

The implementation in this PR aligns with the stated Architecture Decision Record.

ADR reviewed: ADR-28452: Pre-Download Workflow Exclusion Filter for the Logs Command

Verification Summary

All normative requirements from the ADR are satisfied:

Requirement File Status
--exclude StringSlice flag on logs command pkg/cli/logs_command.go
exclude_workflows array field in MCP logs tool pkg/cli/mcp_tools_privileged.go
Lock-file resolution of workflow names pkg/cli/logs_utils.goresolveExcludeWorkflows
Fallback to raw value when resolution fails (no error thrown) pkg/cli/logs_utils.go
Pre-download filter applied before downloadRunArtifactsConcurrent pkg/cli/logs_orchestrator.go
Case-insensitive matching (strings.ToLower on both sides) pkg/cli/logs_utils.goisWorkflowExcluded
Slug-form matching (spaces → hyphens for IDs without lock files) pkg/cli/logs_utils.goisWorkflowExcluded
Verbose stderr logging for excluded runs pkg/cli/logs_orchestrator.go
📋 Scope note: Options struct refactoring

The ADR lists the long DownloadWorkflowLogs parameter list as a negative consequence and mentions struct refactoring as a future possibility. This PR proactively addresses that by introducing DownloadWorkflowLogsOptions and DownloadWorkflowLogsWithOptions, keeping DownloadWorkflowLogs as a backward-compatible wrapper. This is additive and consistent with the ADR's intent — it does not constitute a divergence.

The design decision has been recorded and the implementation follows it. Great work! 🏗️

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 93.9K ·

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 65/100

⚠️ Acceptable, with suggestions

Metric Value
New/modified tests analyzed 2
✅ Design tests (behavioral contracts) 1 (50%)
⚠️ Implementation tests (low value) 1 (50%)
Tests with error/edge cases 1 (50%)
Duplicate test clusters 0
Test inflation detected No
🚨 Coding-guideline violations None

Test Classification Details

Test File Classification Issues Detected
TestLogsCommandExcludeFlag pkg/cli/logs_command_test.go:267 ⚠️ Implementation Only verifies flag registration metadata; no error cases; doesn't test actual exclusion behavior
TestIsWorkflowExcluded pkg/cli/logs_command_test.go:284 ✅ Design Table-driven with 8 cases; covers exact match, case-insensitive, slug match, nil excludes, no-match, multiple excludes

i️ Other test file changes (context_cancellation_test.go, logs_ci_scenario_test.go, logs_download_test.go, logs_json_stderr_order_test.go) are purely signature updates (adding nil for the new excludeWorkflows parameter). No new test functions were added in those files.


Flagged Tests — Requires Review

⚠️ TestLogsCommandExcludeFlag (pkg/cli/logs_command_test.go:267)

Classification: Implementation test
Issue: The test only verifies that the --exclude flag is registered on the command object with the correct type, default value, and usage string. It does not exercise the flag's effect on actual workflow filtering.
What design invariant does this test enforce? The CLI exposes an --exclude flag — a structural/registration check rather than a behavioral one.
What would break if deleted? Only if the flag were removed or renamed; a bug in the actual exclusion logic (e.g., the flag value not being passed to isWorkflowExcluded) would not be caught.
Suggested improvement: Add a test that actually invokes the command (or calls RunDownloadLogs/DownloadWorkflowLogs) with --exclude set and verifies that the specified workflow is filtered out of the results, or that the exclusion list is correctly threaded through to the orchestrator.


Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 2 new test functions — all unit (//go:build !integration) ✅
  • 🟨 JavaScript (*.test.cjs, *.test.js): 0 tests

Verdict

Check failed. 50% of new tests are classified as low-value implementation tests (threshold: 30%). TestLogsCommandExcludeFlag tests only flag registration metadata. Please add a behavioral test that verifies the --exclude flag actually filters workflows end-to-end before merging.


📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls or registration metadata
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

References:

🧪 Test quality analysis by Test Quality Sentinel · ● 563.6K ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

❌ Test Quality Sentinel: 65/100. 50% of new tests are classified as low-value implementation tests (threshold: 30%). TestLogsCommandExcludeFlag only verifies flag registration metadata — it doesn't test that the --exclude flag actually filters workflows. Please add a behavioral end-to-end test before merging. See the comment above for a detailed breakdown and suggested improvement.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot delete adr file, recompile

Add tests

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 25, 2026

@copilot delete adr file, recompile

Add tests

Done in 81b4a3f:

  • Deleted the ADR file
  • Ran make fmt recompile
  • Added TestResolveExcludeWorkflows (6 table-driven cases covering nil/empty input, blank-entry trimming, unknown workflow fallback, and whitespace stripping)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw aYgGoBt/Gg462MDs-1 (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv (http block)
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv h ../../../.prettierignore (http block)
  • https://api.github.com/repos/github/gh-aw
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw --jq .default_branch (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main, fix conflicts, recompile

…ges-from-28452

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 25, 2026

@copilot merge main, fix conflicts, recompile

Done in d6f4dba — merged main (no conflicts), rebuilt the binary, and recompiled all 202 workflow files successfully.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GeQ-aHN/w6VBGXSW-1 (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv (http block)
  • https://api.github.com/repos/github/gh-aw
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw --jq .default_branch (http block)

If you need me to access, download, or install something from one of these locations, you can either:

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