GitHub CLI extension that syncs issues to local markdown files with YAML frontmatter.
main.go— Entry pointcmd/— Cobra command definitions (root, pull, push, status)cmd/cmd_test.go— Command tests using mock clientinternal/sync/— Core sync logic, Client interface, and GHClient (gh CLI)internal/sync/client.go— Client interface (abstraction for testability)internal/sync/github.go— GHClient: real implementation usingghCLIinternal/sync/push.go— Push logic with milestone title-to-number resolutioninternal/sync/issue.go— Issue and IssueFrontmatter typesinternal/frontmatter/— Generic YAML frontmatter marshal/unmarshalmise/tasks/— Build, test, lint tasks (bash scripts with#MISEpragmas).github/workflows/— CI (build+test+lint) and release (precompile on tag)
- Build:
mise run buildorgo build ./... - Test:
mise run testorgo test -cover ./... - Lint:
mise run lint(go vet + prettier) - All checks:
mise run check
- Go code uses standard
go vetlinting - Non-Go files use prettier for formatting
- Mise tasks are the source of truth for all build/lint/test logic
- CI workflows are thin wrappers around mise tasks
- Commit messages follow conventional commits (
feat:,fix:,chore:,docs:)
- Client interface (
sync.Client): All GitHub operations go through this interface. The realGHClientshells out toghCLI. Tests use a mock client. This keeps commands testable without network access. - Frontmatter is generic: The
frontmatterpackage knows nothing about GitHub. It just serializes/deserializes YAML frontmatter + markdown body. - Pull requests are filtered: GitHub's issues API returns PRs too. We filter
them out via the
pull_requestfield. - Milestone resolution: Push resolves milestone titles to numbers via the milestones API. Status compares milestone titles directly.
- Label/assignee comparison is order-independent: Status sorts before comparing to avoid false positives from API ordering.