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
105 changes: 85 additions & 20 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,49 +1,114 @@
version: "2"
output:
sort-order:
- file
linters:
default: none
enable:
- bidichk
- bodyclose
- dogsled
- dupl
- depguard
- errcheck
- exhaustive
- goconst
- forbidigo
- gocheckcompilerdirectives
- gocritic
- gocyclo
- goprintffuncname
- gosec
- govet
- ineffassign
- misspell
- mirror
- modernize
- nakedret
- noctx
- nilnil
- nolintlint
- rowserrcheck
- perfsprint
- revive
- staticcheck
- testifylint
- unconvert
- unparam
- unused
- whitespace
- usestdlibvars
- usetesting
- wastedassign
settings:
depguard:
rules:
main:
deny:
- pkg: io/ioutil
desc: use os or io instead
- pkg: golang.org/x/exp
desc: it's experimental and unreliable
- pkg: github.com/pkg/errors
desc: use builtin errors package instead
nolintlint:
allow-unused: false
require-explanation: true
require-specific: true
gocritic:
enabled-checks:
- equalFold
disabled-checks: []
revive:
severity: error
rules:
- name: blank-imports
- name: constant-logical-expr
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: empty-lines
- name: error-return
- name: error-strings
- name: exported
- name: identical-branches
- name: if-return
- name: increment-decrement
- name: modifies-value-receiver
- name: package-comments
- name: redefines-builtin-id
- name: superfluous-else
- name: time-naming
- name: unexported-return
- name: var-declaration
- name: var-naming
disabled: true
staticcheck:
checks:
- all
testifylint: {}
usetesting:
os-temp-dir: true
perfsprint:
concat-loop: false
govet:
enable:
- nilness
- unusedwrite
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
rules:
- linters:
- errcheck
- staticcheck
- unparam
path: _test\.go
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofmt
- gofumpt
- goimports
- golines
settings:
gofumpt:
extra-rules: true
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
run:
timeout: 10m
5 changes: 2 additions & 3 deletions cmd/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"html"
"io"
"maps"
"os"
"path"
"strings"
Expand Down Expand Up @@ -136,9 +137,7 @@ var commitCmd = &cobra.Command{
data := util.Data{}
// Add template variables
if vars := util.ConvertToMap(templateVars); len(vars) > 0 {
for k, v := range vars {
data[k] = v
}
maps.Copy(data, vars)
}

// Add template variables from file
Expand Down
4 changes: 2 additions & 2 deletions cmd/textarea.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func initialPrompt(value string) model {
ti.InsertString(value)

maxWidth := 0
for _, line := range strings.Split(value, "\n") {
for line := range strings.SplitSeq(value, "\n") {
if len(line) > maxWidth {
maxWidth = len(line)
}
Expand All @@ -57,7 +57,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.Type { //nolint:exhaustive
switch msg.Type { //nolint:exhaustive // only handling specific key types
case tea.KeyEsc:
if m.textarea.Focused() {
m.textarea.Blur()
Expand Down
2 changes: 1 addition & 1 deletion cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func printVersion(format string, v VersionInfo) error {
// Print each row with colored label and default value color
for _, row := range rows {
blue.Print(row[0])
fmt.Printf(" %s\n", row[1])
color.White(" %s\n", row[1])
}
return nil
}
Expand Down
30 changes: 25 additions & 5 deletions core/transport/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
if m.resp != nil || m.err != nil {
return m.resp, m.err
}
return &http.Response{StatusCode: 200, Body: http.NoBody, Request: req}, nil
return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody, Request: req}, nil
}

func TestDefaultHeaderTransport_CustomHeaders(t *testing.T) {
Expand All @@ -34,7 +34,12 @@ func TestDefaultHeaderTransport_CustomHeaders(t *testing.T) {
AppName: "myapp",
AppVersion: "1.2.3",
}
req, _ := http.NewRequestWithContext(context.Background(), "GET", "http://example.com", nil)
req, _ := http.NewRequestWithContext(
context.Background(),
http.MethodGet,
"http://example.com",
nil,
)
resp, err := tr.RoundTrip(req)
if err != nil {
t.Fatalf("RoundTrip error: %v", err)
Expand Down Expand Up @@ -65,7 +70,12 @@ func TestDefaultHeaderTransport_EmptyHeadersAndAppInfo(t *testing.T) {
AppName: "",
AppVersion: "",
}
req, _ := http.NewRequestWithContext(context.Background(), "GET", "http://example.com", nil)
req, _ := http.NewRequestWithContext(
context.Background(),
http.MethodGet,
"http://example.com",
nil,
)
resp, err := tr.RoundTrip(req)
if err != nil {
t.Fatalf("RoundTrip error: %v", err)
Expand All @@ -91,7 +101,12 @@ func TestDefaultHeaderTransport_OriginErrorPropagation(t *testing.T) {
AppName: "",
AppVersion: "",
}
req, _ := http.NewRequestWithContext(context.Background(), "GET", "http://example.com", nil)
req, _ := http.NewRequestWithContext(
context.Background(),
http.MethodGet,
"http://example.com",
nil,
)
resp, err := tr.RoundTrip(req)
if resp != nil && resp.Body != nil {
resp.Body.Close()
Expand All @@ -111,7 +126,12 @@ func TestDefaultHeaderTransport_MultipleHeaderValues(t *testing.T) {
AppName: "app",
AppVersion: "v",
}
req, _ := http.NewRequestWithContext(context.Background(), "GET", "http://example.com", nil)
req, _ := http.NewRequestWithContext(
context.Background(),
http.MethodGet,
"http://example.com",
nil,
)
resp, err := tr.RoundTrip(req)
if err != nil {
t.Fatalf("RoundTrip error: %v", err)
Expand Down
9 changes: 6 additions & 3 deletions git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package git
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"path"
Expand Down Expand Up @@ -138,7 +137,7 @@ func (c *Command) commit(ctx context.Context, val string) *exec.Cmd {
"commit",
"--no-verify",
"--signoff",
fmt.Sprintf("--message=%s", val),
"--message=" + val,
}

if c.isAmend {
Expand Down Expand Up @@ -234,7 +233,11 @@ func (c *Command) InstallHook(ctx context.Context) error {
}

// Write the hook file with executable permissions (0o755)
return os.WriteFile(target, content, 0o755) //nolint:gosec
return os.WriteFile(
target,
content,
0o755,
) //nolint:gosec // hook file needs executable permissions
}

// UninstallHook removes the prepare-commit-msg hook if it exists.
Expand Down
32 changes: 4 additions & 28 deletions git/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,12 @@ func TestCanExecuteGitDiff(t *testing.T) {
tmpDir := t.TempDir()

// Change to the temporary directory
originalDir, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current directory: %v", err)
}
defer func() {
if err := os.Chdir(originalDir); err != nil {
t.Logf("Failed to restore directory: %v", err)
}
}()

if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to change directory: %v", err)
}
t.Chdir(tmpDir)

cmd := New()
ctx := context.Background()

err = cmd.CanExecuteGitDiff(ctx)
err := cmd.CanExecuteGitDiff(ctx)
if err == nil {
t.Error("CanExecuteGitDiff() should fail in a non-git directory")
}
Expand All @@ -63,24 +51,12 @@ func TestCanExecuteGitDiff(t *testing.T) {
defer os.RemoveAll(tmpDir)

// Change to the subdirectory
originalDir, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current directory: %v", err)
}
defer func() {
if err := os.Chdir(originalDir); err != nil {
t.Logf("Failed to restore directory: %v", err)
}
}()

if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to change directory: %v", err)
}
t.Chdir(tmpDir)

cmd := New()
ctx := context.Background()

err = cmd.CanExecuteGitDiff(ctx)
err := cmd.CanExecuteGitDiff(ctx)
if err != nil {
t.Errorf(
"CanExecuteGitDiff() should succeed in a git repository subdirectory, got error: %v",
Expand Down
2 changes: 1 addition & 1 deletion git/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (

// init initializes the Git hook templates by loading them from embedded files.
// If there's an error loading the templates, the function logs a fatal error and terminates the program.
func init() { //nolint:gochecknoinits
func init() { //nolint:gochecknoinits // required to load embedded templates at startup
if err := util.LoadTemplates(files); err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion prompt/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const (
)

// Initializes the prompt package by loading the templates from the embedded file system.
func init() { //nolint:gochecknoinits
func init() { //nolint:gochecknoinits // required to load embedded templates at startup
if err := util.LoadTemplates(templatesFS); err != nil {
log.Fatal(err)
}
Expand Down
22 changes: 14 additions & 8 deletions provider/anthropic/anthropic.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ func (c *Client) Completion(ctx context.Context, content string) (*core.Response
if err != nil {
var e *anthropic.APIError
if errors.As(err, &e) {
fmt.Printf("Messages error, type: %s, message: %s", e.Type, e.Message)
} else {
fmt.Printf("Messages error: %v\n", err)
return nil, fmt.Errorf(
"messages error, type: %s, message: %s: %w",
e.Type,
e.Message,
err,
)
}
return nil, err
return nil, fmt.Errorf("messages error: %w", err)
}

usage := core.Usage{
Expand Down Expand Up @@ -97,11 +100,14 @@ func (c *Client) CompletionStream(
if err != nil {
var e *anthropic.APIError
if errors.As(err, &e) {
fmt.Printf("Messages error, type: %s, message: %s", e.Type, e.Message)
} else {
fmt.Printf("Messages error: %v\n", err)
return nil, fmt.Errorf(
"messages error, type: %s, message: %s: %w",
e.Type,
e.Message,
err,
)
}
return nil, err
return nil, fmt.Errorf("messages error: %w", err)
}

if writeErr != nil {
Expand Down
2 changes: 1 addition & 1 deletion provider/openai/openai.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func (c *Client) completion(
return nil, err
}
if len(r.Choices) == 0 {
return nil, fmt.Errorf("no choices returned from API")
return nil, errors.New("no choices returned from API")
}
// Support reasoning models: prefer Content, fallback to ReasoningContent if empty
resp.Content = r.Choices[0].Message.Content
Expand Down
Loading
Loading