diff --git a/internal/ask/ask_test.go b/internal/ask/ask_test.go index bc09fcc..24b98a6 100644 --- a/internal/ask/ask_test.go +++ b/internal/ask/ask_test.go @@ -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) { @@ -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) @@ -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) diff --git a/internal/commit/commit_test.go b/internal/commit/commit_test.go index 4998954..d674150 100644 --- a/internal/commit/commit_test.go +++ b/internal/commit/commit_test.go @@ -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 @@ -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) { @@ -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) } @@ -170,7 +170,7 @@ func TestRun(t *testing.T) { tests := []struct { name string args []string - git *mockGitClient + git *stubGitClient resp string provErr error wantErr bool @@ -178,7 +178,7 @@ func TestRun(t *testing.T) { { name: "successful commit flow", args: []string{}, - git: &mockGitClient{ + git: &stubGitClient{ diff: "some changes", branch: "feature/test", }, @@ -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", }, @@ -198,7 +198,7 @@ func TestRun(t *testing.T) { { name: "no staged changes", args: []string{}, - git: &mockGitClient{ + git: &stubGitClient{ diff: "", }, wantErr: true, @@ -206,7 +206,7 @@ func TestRun(t *testing.T) { { name: "no changes to amend", args: []string{"-a"}, - git: &mockGitClient{ + git: &stubGitClient{ diff: "", hasParent: true, // HEAD~1 exists }, @@ -215,7 +215,7 @@ func TestRun(t *testing.T) { { name: "provider fails", args: []string{}, - git: &mockGitClient{ + git: &stubGitClient{ diff: "some changes", branch: "main", }, @@ -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"), @@ -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 { diff --git a/internal/commit/prompt.md b/internal/commit/prompt.md index ba57604..f00634c 100644 --- a/internal/commit/prompt.md +++ b/internal/commit/prompt.md @@ -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 @@ -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