go-codemod
by github
Implement and test Go codemods for the gh aw fix command.
npx skills add https://github.com/github/gh-aw --skill go-codemodGo Codemod Implementation Guide
Use this skill when adding or updating codemods used by gh aw fix.
Understand the fix pipeline first
- Review
pkg/cli/fix_command.goto understand execution flow:- codemods are loaded once via
GetAllCodemods() - each codemod is applied in registry order
- frontmatter is re-parsed before each codemod
- codemods must return
(newContent, applied, error)and be safe for no-op input
- codemods are loaded once via
- Review the codemod registry in
pkg/cli/fix_codemods.go. - Review helper utilities in
pkg/cli/yaml_frontmatter_utils.goand reusable codemod helper constructors inpkg/cli/codemod_factory.go.
Implementation steps
- Create a new codemod file in
pkg/cli/namedcodemod_<feature>.go. - Add a package logger with
logger.New("cli:codemod_<feature>"). - Implement
get<Feature>Codemod() Codemodand populate all metadata fields:ID(stable, unique)Name(human-readable)Description(clear migration behavior)IntroducedIn(release version)
- In
Apply:- check frontmatter preconditions first
- return unchanged content and
applied=falsewhen migration is not needed - transform only frontmatter using
applyFrontmatterLineTransformfrompkg/cli/yaml_frontmatter_utils.go - preserve comments/formatting/markdown body
- avoid lossy rewrites and avoid touching unrelated keys
- Prefer existing helpers before writing custom parsing logic:
findAndReplaceInLineremoveFieldFromBlockremoveParentBlockIfTrulyEmptynewFieldRemovalCodemodnewMoveTopLevelKeyToOnBlockCodemod
- If the codemod depends on external data or side effects, inject dependencies through a
...WithDepsconstructor so tests can mock behavior. - Register the codemod in
pkg/cli/fix_codemods.gowithinGetAllCodemods().
Testing requirements
Create pkg/cli/codemod_<feature>_test.go and cover:
- Metadata correctness (
ID,Name,Description,IntroducedIn,Apply != nil). - Happy path migration with expected output.
- No-op behavior when deprecated input is absent.
- Idempotence behavior (already-migrated input remains unchanged).
- Preservation guarantees:
- inline comments
- indentation
- markdown body after frontmatter
- Edge cases specific to the codemod (nested fields, mixed forms, ordering constraints, strict-mode checks, etc.).
- Dependency-injection behavior if
...WithDepsexists (success and fallback/error paths).
When complexity is high (expression rewriting, parser-like behavior), add fuzz tests in codemod_<feature>_fuzz_test.go using the pattern in pkg/cli/codemod_steps_run_secrets_env_fuzz_test.go.
Registry/order tests
After adding a codemod, update pkg/cli/fix_codemods_test.go:
- Expected codemod IDs list.
- Expected codemod order list.
Order matters because codemods run sequentially and later codemods observe prior transformations.
Validation commands
Run targeted checks first:
go test -v ./pkg/cli -run Codemod -count=1go test -v ./pkg/cli -run Fix -count=1
Then run repository standards:
make buildmake test-unitmake lint
Quality bar
A codemod is ready only when it is:
- deterministic
- safe on repeated runs
- conservative (no unrelated rewrites)
- fully covered by tests for migration and no-op paths
- registered and order-verified in fix codemod registry tests