Skip to content

Generate init/upgrade dispatcher file lists from github/gh-aw with embedded fallback#36493

Merged
pelikhan merged 14 commits into
mainfrom
copilot/fix-gh-aw-upgrade-init
Jun 2, 2026
Merged

Generate init/upgrade dispatcher file lists from github/gh-aw with embedded fallback#36493
pelikhan merged 14 commits into
mainfrom
copilot/fix-gh-aw-upgrade-init

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 2, 2026

gh aw init and gh aw upgrade previously generated dispatcher file lists from local .github/aw contents. This caused incorrect behavior when local repository state did not match the canonical github/gh-aw workflow prompt set.

This change updates dispatcher generation to use the canonical source and remain resilient when network access fails.

  • Canonical .github/aw source for dispatcher generation

    • Updated buildAgenticWorkflowsSkillContent to fetch markdown workflow file names dynamically from github/gh-aw/.github/aw (GitHub Contents API on main).
    • Dispatcher file lists are now based on the canonical repository folder, not local .github/aw files.
  • Embedded fallback when remote fetch fails

    • Added an embedded precomputed fallback list (pkg/cli/data/agentic_workflows_fallback_aw_files.json).
    • If the remote fetch fails (including timeout/non-200/decode errors), generation falls back to the embedded list and emits a warning.
    • Added timeout-specific error messaging and fallback parse warning behavior.
  • Test updates

    • Updated unit coverage to mock dynamic file-list fetching and validate both remote-success and embedded-fallback paths.
    • Kept integration validation for init/upgrade behavior with .github/aw non-markdown artifacts (e.g. actions-lock.json, logs/) to ensure commands still succeed and preserve those files.

Copilot AI and others added 5 commits June 2, 2026 17:32
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix gh aw upgrade and init failures for empty .github/aw directory Handle empty .github/aw directories in init/upgrade dispatcher generation Jun 2, 2026
Copilot AI requested a review from pelikhan June 2, 2026 17:37
@pelikhan pelikhan marked this pull request as ready for review June 2, 2026 17:38
Copilot AI review requested due to automatic review settings June 2, 2026 17:38
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

This PR fixes gh aw init / gh aw upgrade failing when .github/aw exists but contains no *.md files (e.g., only actions-lock.json and logs/). It updates dispatcher skill generation to treat that state as valid and adds both unit and integration coverage to prevent regressions.

Changes:

  • Treat “.github/aw exists but has no markdown files” as a valid state by generating the same minimal dispatcher skill content used when the directory is absent.
  • Add unit test coverage to assert empty-.md .github/aw produces identical dispatcher content to the no-directory case.
  • Add an integration test that runs init and upgrade against a repo with .github/aw/actions-lock.json and .github/aw/logs/, ensuring both commands succeed and preserve those artifacts.
Show a summary per file
File Description
pkg/cli/upgrade_integration_test.go Adds an integration test covering init + upgrade behavior when .github/aw contains only non-markdown artifacts.
pkg/cli/copilot_agents.go Updates dispatcher skill generation to fall back to minimal content when .github/aw exists but has no *.md files.
pkg/cli/copilot_agents_test.go Adds unit coverage asserting empty-.md .github/aw matches the no-directory generated dispatcher content.

Copilot's findings

Tip

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

  • Files reviewed: 3/3 changed files
  • Comments generated: 0

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #36493 does not have the 'implementation' label and has 82 new lines (≤100 threshold) in business logic directories.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

PR Code Quality Reviewer completed the code quality review.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions github-actions Bot mentioned this pull request Jun 2, 2026
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.

Skills-Based Review 🧠

Applied /diagnose and /tdd — approving with one minor style suggestion.

📋 Key Themes & Highlights

Key Themes

  • Root cause correctly addressed: The premature error return in buildAgenticWorkflowsSkillContent was the exact failure point; the fix targets it directly without over-engineering.
  • Fallback semantics are clear: Empty .github/aw → same minimal output as no .github/aw at all. This is the right mental model and the comment in the code explains it well.
  • Coverage is solid: Unit test asserts output equality with the no-dir case and placeholder replacement; integration test exercises the full init → upgrade cycle and verifies non-markdown artifact preservation.

Positive Highlights

  • ✅ One-line fix with zero unrelated changes — surgical and easy to reason about.
  • ✅ Integration test covers a realistic repository state (logs dir + lock file) and both commands.
  • ✅ Good use of require for setup assertions so failures are reported clearly.

Minor Observation

  • One trailing t.Fatalf in the new unit test could use assert.NotContains for consistency (inline comment posted).

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 1M

Comment thread pkg/cli/copilot_agents_test.go Outdated
expected, err := buildAgenticWorkflowsSkillContent(withoutAWDir)
require.NoError(t, err, "buildAgenticWorkflowsSkillContent() without .github/aw directory returned error")
assert.Equal(t, expected, content, "skill content with empty .github/aw should match content without .github/aw")
if strings.Contains(content, agenticWorkflowsSkillFileListPlaceholder) {
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] Minor style nit: this trailing t.Fatalf check is inconsistent with the testify imports added just above, and the assert.Equal check already implicitly validates the placeholder is absent.

💡 Suggestion

Replace with assert.NotContains:

assert.NotContains(t, content, agenticWorkflowsSkillFileListPlaceholder,
    "expected placeholder to be replaced in skill content")

Keeps assertion style uniform throughout the test.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

🧪 Test Quality Sentinel Report

Test Quality Score: 80/100 — Excellent

Analyzed 3 test(s): 3 design, 0 implementation, 0 guideline violations.

📊 Metrics & Test Classification (3 tests analyzed)
Metric Value
New/modified tests analyzed 3
✅ Design tests (behavioral contracts) 3 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 3 (100%)
Duplicate test clusters 0
Test inflation detected Yes (copilot_agents_test.go: 23 lines added vs 3 production lines — 7.7:1 ratio)
🚨 Coding-guideline violations 0

Test Classification Details

Test File Classification Issues Detected
TestBuildAgenticWorkflowsSkillContentWithoutAWDirectory (modified) pkg/cli/copilot_agents_test.go ✅ Design None — adds missing assertion for no file-list entries in output
TestBuildAgenticWorkflowsSkillContentWithEmptyAWDirectory pkg/cli/copilot_agents_test.go ✅ Design None — verifies observable output equality for empty-aw-dir edge case
TestInitAndUpgradeWithEmptyAWDirectory pkg/cli/upgrade_integration_test.go ✅ Design None — end-to-end coverage of init+upgrade with non-markdown artifacts present

Language Support

Tests analyzed:

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

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). Build tags are present on all files. All assertions carry descriptive messages.

i️ Inflation note: the 7.7:1 test-to-production line ratio (23 vs 3 lines) is expected here — a one-line behavior change requires meaningful test scaffolding to cover the new edge case. This is not a concern in context.

📖 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 (mocking internals)
  • 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.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 1.2M ·

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: 80/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 3 new/modified tests verify behavioral contracts with edge case coverage. Build tags and assertion messages are correct.

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.

Non-blocking observations only — no blockers found.

### Review summary

The fix is correct and the motivation is sound: .github/aw legitimately exists in repos that use non-markdown artifacts (lock files, log dirs) before any workflow .md files are authored, so failing hard there is too strict.

Two non-blocking concerns flagged inline:

  1. Silent fallback (medium) — the new empty-dir path produces no warning, so users who accidentally misname their workflow files get no feedback. A console.FormatWarningMessage call before the return would preserve the fix without losing discoverability.

  2. Duplicated return expression (low) — the len(awFiles)==0 path is byte-for-byte identical to the os.IsNotExist path above it. A tiny minimalSkillContent() helper would make the shared intent explicit and reduce future drift risk.

Tests are solid: the new unit test correctly compares empty-dir output against no-dir output, and the integration test covers the full init→upgrade lifecycle with a real binary.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 154.9K

Comment thread pkg/cli/copilot_agents.go Outdated
return "", fmt.Errorf("no markdown files found in %s - ensure .github/aw contains workflow documentation files", awRoot)
// .github/aw may exist for non-markdown artifacts (e.g. actions-lock.json, logs/).
// Emit a minimal skill without an explicit file list in that case.
return strings.Replace(agenticWorkflowsSkillTemplate, agenticWorkflowsSkillFileListPlaceholder, "", 1), nil
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.

Silent degradation hides user misconfiguration: when .github/aw exists but has no .md files, the code silently returns a minimal skill — indistinguishable from the "directory absent" case — with no log or warning.

💡 Why this matters and a suggested fix

A user who accidentally misnamed workflow docs (e.g. workflow.yaml instead of workflow.md, or placed files one directory too deep) will get no signal at all. The original fmt.Errorf was the only indicator that the directory is present but useless.

Since callers already use console.FormatWarningMessage for similar info-messages, emitting a non-fatal warning preserves the new behavior while still alerting users:

if len(awFiles) == 0 {
    fmt.Fprintln(os.Stderr, console.FormatWarningMessage(
        ".github/aw exists but contains no markdown workflow files — emitting minimal skill"))
    return strings.Replace(agenticWorkflowsSkillTemplate, agenticWorkflowsSkillFileListPlaceholder, "", 1), nil
}

This keeps the fix non-breaking while restoring discoverability for misconfigured repos.

Comment thread pkg/cli/copilot_agents.go Outdated
return "", fmt.Errorf("no markdown files found in %s - ensure .github/aw contains workflow documentation files", awRoot)
// .github/aw may exist for non-markdown artifacts (e.g. actions-lock.json, logs/).
// Emit a minimal skill without an explicit file list in that case.
return strings.Replace(agenticWorkflowsSkillTemplate, agenticWorkflowsSkillFileListPlaceholder, "", 1), nil
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.

Duplicate code paths are semantically indistinguishable: the new len(awFiles) == 0 return (line 174) is byte-for-byte identical to the os.IsNotExist return at line 157. Two distinct states — directory absent vs directory present but devoid of markdown — now produce the same output with no way to differentiate them.

💡 Suggested refactor

Extract a shared helper to make intent explicit and reduce duplication:

func minimalSkillContent() string {
    return strings.Replace(agenticWorkflowsSkillTemplate, agenticWorkflowsSkillFileListPlaceholder, "", 1)
}

Then both call sites become return minimalSkillContent(), nil, and a future reader immediately understands this is an intentional shared code path rather than an accidental copy.

@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Jun 2, 2026

@copilot review all comments and review comments. apply copilot-review skill.

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

Copilot AI commented Jun 2, 2026

@copilot review all comments and review comments. apply copilot-review skill.

Done in 2815e20. I reviewed all PR comments/review comments and applied the actionable items: added a shared minimal-skill helper, emit a warning when .github/aw exists with no markdown files, and aligned the unit assertion style with assert.NotContains. Targeted unit/integration tests and final validation passed.

@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Jun 2, 2026

@copilot the file list should be based on .github/aw in the github/gh-aw respository folder - NOT THE LOCAL FILES!!!!! Fetch the file list dynamically and bail out to a precomputed list of files into an embedded file in the compiler if connection fails.

Copilot AI and others added 2 commits June 2, 2026 18:37
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jun 2, 2026

@copilot the file list should be based on .github/aw in the github/gh-aw respository folder - NOT THE LOCAL FILES!!!!! Fetch the file list dynamically and bail out to a precomputed list of files into ...

Addressed in 3d70182. Dispatcher file-list generation now fetches .github/aw markdown files dynamically from github/gh-aw (GitHub contents API) instead of reading local repo files, and falls back to an embedded precomputed file list in the binary when the fetch fails.

Copilot AI changed the title Handle empty .github/aw directories in init/upgrade dispatcher generation Generate init/upgrade dispatcher file lists from github/gh-aw with embedded fallback Jun 2, 2026
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Jun 2, 2026

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

Copilot AI commented Jun 2, 2026

@copilot lint go https://github.com/github/gh-aw/actions/runs/26842846417/job/79154383164?pr=36493

Addressed in ce381ba. I investigated the referenced CI job, reproduced the golint errors, and fixed them by removing the unused minimalAgenticWorkflowsSkillContent helper and replacing two static fmt.Errorf(...) calls with errors.New(...) in pkg/cli/copilot_agents.go. I re-ran incremental lint and targeted pkg/cli tests locally.

@pelikhan pelikhan merged commit 1895158 into main Jun 2, 2026
@pelikhan pelikhan deleted the copilot/fix-gh-aw-upgrade-init branch June 2, 2026 19:42
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.

gh aw upgrade and gh aw init fail when .github/aw exists but contains no markdown files

3 participants