Skip to content

Commit 0a5a906

Browse files
authored
Merge pull request #1 from nsheaps/claude/gh-ext-issue-sync-VD8Vs
Add gh-ext-issue-sync: GitHub CLI extension for syncing issues
2 parents 735759e + fbff669 commit 0a5a906

32 files changed

Lines changed: 2348 additions & 0 deletions

.editorconfig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# http://editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
charset = utf-8
9+
trim_trailing_whitespace = true
10+
insert_final_newline = true
11+
12+
[*.go]
13+
indent_style = tab
14+
indent_size = 4
15+
16+
[Makefile]
17+
indent_style = tab
18+
19+
[*.md]
20+
trim_trailing_whitespace = false

.github/workflows/ci.yaml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: ci
2+
3+
'on':
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
workflow_dispatch:
9+
10+
concurrency:
11+
group: ${{ github.ref == 'refs/heads/main' && 'ci-cd-main' || format('ci-{0}', github.ref) }}
12+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
13+
14+
jobs:
15+
build-and-test:
16+
runs-on: ubuntu-latest
17+
permissions:
18+
contents: read
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
23+
- name: Set up Go
24+
uses: actions/setup-go@v5
25+
with:
26+
go-version-file: go.mod
27+
28+
- name: Install tools
29+
uses: jdx/mise-action@v3
30+
with:
31+
install: true
32+
cache: ${{ github.event_name == 'pull_request' }}
33+
34+
- name: Build
35+
run: go build -v ./...
36+
37+
- name: Test with coverage
38+
run: go test -v -coverprofile=coverage.out -covermode=atomic ./...
39+
40+
- name: Display coverage summary
41+
run: go tool cover -func=coverage.out
42+
43+
lint:
44+
runs-on: ubuntu-latest
45+
permissions:
46+
contents: read
47+
steps:
48+
- name: Checkout code
49+
uses: actions/checkout@v4
50+
51+
- name: Set up Go
52+
uses: actions/setup-go@v5
53+
with:
54+
go-version-file: go.mod
55+
56+
- name: Install tools
57+
uses: jdx/mise-action@v3
58+
with:
59+
install: true
60+
cache: ${{ github.event_name == 'pull_request' }}
61+
62+
- name: Go vet
63+
run: go vet ./...
64+
65+
- name: Prettier check
66+
run: prettier --check .

.github/workflows/release.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: release
2+
3+
'on':
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Set up Go
21+
uses: actions/setup-go@v5
22+
with:
23+
go-version-file: go.mod
24+
25+
- name: Build binaries
26+
uses: cli/gh-extension-precompile@v2

.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Binary
2+
gh-ext-issue-sync
3+
gh-ext--issue-sync
4+
dist/
5+
6+
# Go
7+
coverage.out
8+
*.exe
9+
*.dll
10+
*.so
11+
*.dylib
12+
*.test
13+
*.out
14+
15+
# IDE
16+
.idea/
17+
.vscode/
18+
*.swp
19+
*.swo
20+
21+
# OS
22+
.DS_Store
23+
Thumbs.db
24+
25+
# Claude Code
26+
.claude/settings.local.json

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.go
2+
go.mod
3+
go.sum

.prettierrc.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
overrides:
2+
- files: '*.md'
3+
options:
4+
proseWrap: always
5+
- files: '*.yaml'
6+
options:
7+
singleQuote: true

CLAUDE.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# gh-ext--issue-sync
2+
3+
GitHub CLI extension that syncs issues to local markdown files with YAML
4+
frontmatter.
5+
6+
## Project Structure
7+
8+
- `main.go` — Entry point
9+
- `cmd/` — Cobra command definitions (root, pull, push, status)
10+
- `cmd/cmd_test.go` — Command tests using mock client
11+
- `internal/sync/` — Core sync logic, Client interface, and GHClient (gh CLI)
12+
- `internal/sync/client.go` — Client interface (abstraction for testability)
13+
- `internal/sync/github.go` — GHClient: real implementation using `gh` CLI
14+
- `internal/sync/push.go` — Push logic with milestone title-to-number resolution
15+
- `internal/sync/issue.go` — Issue and IssueFrontmatter types
16+
- `internal/frontmatter/` — Generic YAML frontmatter marshal/unmarshal
17+
- `mise/tasks/` — Build, test, lint tasks (bash scripts with `#MISE` pragmas)
18+
- `.github/workflows/` — CI (build+test+lint) and release (precompile on tag)
19+
20+
## Development
21+
22+
- **Build**: `mise run build` or `go build ./...`
23+
- **Test**: `mise run test` or `go test -cover ./...`
24+
- **Lint**: `mise run lint` (go vet + prettier)
25+
- **All checks**: `mise run check`
26+
27+
## Conventions
28+
29+
- Go code uses standard `go vet` linting
30+
- Non-Go files use prettier for formatting
31+
- Mise tasks are the source of truth for all build/lint/test logic
32+
- CI workflows are thin wrappers around mise tasks
33+
- Commit messages follow conventional commits (`feat:`, `fix:`, `chore:`,
34+
`docs:`)
35+
36+
## Architecture Decisions
37+
38+
- **Client interface** (`sync.Client`): All GitHub operations go through this
39+
interface. The real `GHClient` shells out to `gh` CLI. Tests use a mock
40+
client. This keeps commands testable without network access.
41+
- **Frontmatter is generic**: The `frontmatter` package knows nothing about
42+
GitHub. It just serializes/deserializes YAML frontmatter + markdown body.
43+
- **Pull requests are filtered**: GitHub's issues API returns PRs too. We filter
44+
them out via the `pull_request` field.
45+
- **Milestone resolution**: Push resolves milestone titles to numbers via the
46+
milestones API. Status compares milestone titles directly.
47+
- **Label/assignee comparison is order-independent**: Status sorts before
48+
comparing to avoid false positives from API ordering.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 nsheaps
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)