Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions internal/ask/ask_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import (
"testing"
)

type mockProvider struct {
type stubProvider struct {
resp string
err error
}

func (m *mockProvider) Complete(ctx context.Context, system, userMsg string) (string, error) {
return m.resp, m.err
func (s *stubProvider) Complete(ctx context.Context, system, userMsg string) (string, error) {
return s.resp, s.err
}

func TestRun(t *testing.T) {
Expand Down Expand Up @@ -69,7 +69,7 @@ func TestRun(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var output bytes.Buffer
provider := &mockProvider{resp: tt.resp, err: tt.err}
provider := &stubProvider{resp: tt.resp, err: tt.err}

err := Run(context.Background(), provider, &output, tt.args)

Expand All @@ -87,7 +87,7 @@ func TestRun(t *testing.T) {
}

func TestRun_NilOutputDefaultsToDiscard(t *testing.T) {
provider := &mockProvider{resp: "test response"}
provider := &stubProvider{resp: "test response"}
err := Run(context.Background(), provider, nil, []string{"test"})
if err != nil {
t.Errorf("Run() with nil output error = %v, want nil", err)
Expand Down
46 changes: 23 additions & 23 deletions internal/commit/commit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import (
"time"
)

type mockProvider struct {
type stubProvider struct {
resp string
err error
}

func (m *mockProvider) Complete(ctx context.Context, system, userMsg string) (string, error) {
return m.resp, m.err
func (s *stubProvider) Complete(ctx context.Context, system, userMsg string) (string, error) {
return s.resp, s.err
}

type mockGitClient struct {
type stubGitClient struct {
diff string
branch string
hasParent bool
Expand All @@ -26,24 +26,24 @@ type mockGitClient struct {
branchErr error
}

func (m *mockGitClient) GetStagedDiff() (string, error) {
return m.diff, m.diffErr
func (s *stubGitClient) GetStagedDiff() (string, error) {
return s.diff, s.diffErr
}

func (m *mockGitClient) GetDiffFromRevision(revision string) (string, error) {
return m.diff, m.diffErr
func (s *stubGitClient) GetDiffFromRevision(revision string) (string, error) {
return s.diff, s.diffErr
}

func (m *mockGitClient) GetCurrentBranch() (string, error) {
return m.branch, m.branchErr
func (s *stubGitClient) GetCurrentBranch() (string, error) {
return s.branch, s.branchErr
}

func (m *mockGitClient) HasParentCommit() (bool, error) {
return m.hasParent, nil
func (s *stubGitClient) HasParentCommit() (bool, error) {
return s.hasParent, nil
}

func (m *mockGitClient) Commit(msg string, amend bool) error {
return m.commitErr
func (s *stubGitClient) Commit(msg string, amend bool) error {
return s.commitErr
}

func TestParseConfig(t *testing.T) {
Expand Down Expand Up @@ -147,7 +147,7 @@ func TestGenerateCommitMessage(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var stderr bytes.Buffer
provider := &mockProvider{resp: tt.resp, err: tt.err}
provider := &stubProvider{resp: tt.resp, err: tt.err}
tickerFactory := func(d time.Duration) *time.Ticker {
return time.NewTicker(d)
}
Expand All @@ -170,15 +170,15 @@ func TestRun(t *testing.T) {
tests := []struct {
name string
args []string
git *mockGitClient
git *stubGitClient
resp string
provErr error
wantErr bool
}{
{
name: "successful commit flow",
args: []string{},
git: &mockGitClient{
git: &stubGitClient{
diff: "some changes",
branch: "feature/test",
},
Expand All @@ -188,7 +188,7 @@ func TestRun(t *testing.T) {
{
name: "successful commit with issue in branch",
args: []string{},
git: &mockGitClient{
git: &stubGitClient{
diff: "some changes",
branch: "feature/PROJ-123-fix",
},
Expand All @@ -198,15 +198,15 @@ func TestRun(t *testing.T) {
{
name: "no staged changes",
args: []string{},
git: &mockGitClient{
git: &stubGitClient{
diff: "",
},
wantErr: true,
},
{
name: "no changes to amend",
args: []string{"-a"},
git: &mockGitClient{
git: &stubGitClient{
diff: "",
hasParent: true, // HEAD~1 exists
},
Expand All @@ -215,7 +215,7 @@ func TestRun(t *testing.T) {
{
name: "provider fails",
args: []string{},
git: &mockGitClient{
git: &stubGitClient{
diff: "some changes",
branch: "main",
},
Expand All @@ -225,7 +225,7 @@ func TestRun(t *testing.T) {
{
name: "git commit fails",
args: []string{},
git: &mockGitClient{
git: &stubGitClient{
diff: "some changes",
branch: "main",
commitErr: errors.New("commit failed"),
Expand All @@ -238,7 +238,7 @@ func TestRun(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var stderr bytes.Buffer
provider := &mockProvider{resp: tt.resp, err: tt.provErr}
provider := &stubProvider{resp: tt.resp, err: tt.provErr}
err := Run(context.Background(), provider, tt.git, &stderr, tt.args)

if (err != nil) != tt.wantErr {
Expand Down
46 changes: 35 additions & 11 deletions internal/commit/prompt.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
You generate git commit messages following the conventional commits format for semantic versioning.
You generate git commit messages following the conventional commits format for semantic versioning. You receive a git diff as input and respond with ONLY the commit message — no explanation, no commentary, no markdown fences.

## Commit Type Selection

Expand All @@ -24,42 +24,66 @@ When in doubt, prefer non-versioning types over feat/fix.
```gitcommit
type(scope): concise description

optional body with details
- bullet points listing specific changes (only if the subject line alone is insufficient)

optional footer (Closes: #issue, BREAKING CHANGE, etc.)
```

## Examples

Simple changes — subject line is enough:

```gitcommit
fix(auth): return 401 instead of 500 when session token is expired
```

```gitcommit
chore: upgrade linting dependencies to latest minor versions
```

```gitcommit
fix: prevent null pointer exception in user validation
refactor: extract validation logic into reusable helper functions
```

```gitcommit
feat(api): add pagination to search results endpoint
perf: cache parsed config to avoid re-reading from disk on each request
```

Multi-part changes — bullet points listing what changed:

```gitcommit
refactor: extract database connection logic into separate module
feat(api): add rate limiting to public endpoints

* move connection pooling to db/pool.py
* update imports in affected services
- Add token bucket middleware with configurable limits per route
- Add rate limit headers to responses
- Return 429 with Retry-After header when limit exceeded
```

```gitcommit
chore: upgrade pytest from 7.1.0 to 7.4.2
refactor: rename mock types to stub in test files

- Rename mockProvider to stubProvider
- Rename mockClient to stubClient
- Update method receivers from m to s
```

```gitcommit
feat!: change user ID format from integer to UUID
feat!: replace integer IDs with UUIDs across all entities

- Update model definitions and repository methods to use UUIDs
- Add database migration to alter primary key column types

BREAKING CHANGE: user IDs are now UUIDs instead of integers
BREAKING CHANGE: all API responses now return string UUIDs instead of integer IDs
```

Never include back-ticks in final commit

## Rules
- Return ONLY the raw commit message text — nothing else
- NEVER explain, summarize, or describe the diff — your entire output IS the commit message
- NEVER write introductory or concluding paragraphs
- Use bullet points for the body, not prose
- The subject line should be self-sufficient — only add a body when there are multiple distinct changes worth enumerating
- Match the style and tone of the repository's recent commits
- Infer the scope from the changed file paths if appropriate
- Reference issues in the footer if an issue number is available
- Return ONLY the commit message text, no markdown formatting or explanation