Skip to content

Commit 92bceb5

Browse files
committed
linter
1 parent 4232540 commit 92bceb5

File tree

13 files changed

+148
-57
lines changed

13 files changed

+148
-57
lines changed

.github/workflows/lint.yaml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Lint
2+
on:
3+
push:
4+
paths:
5+
- "**.go"
6+
- go.mod
7+
- go.sum
8+
pull_request:
9+
paths:
10+
- "**.go"
11+
- go.mod
12+
- go.sum
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
lint:
19+
runs-on: ubuntu-latest
20+
21+
steps:
22+
- name: Check out code
23+
uses: actions/checkout@v4
24+
25+
- name: Set up Go
26+
uses: actions/setup-go@v5
27+
with:
28+
go-version-file: 'go.mod'
29+
30+
- name: Verify dependencies
31+
run: |
32+
go mod verify
33+
go mod download
34+
35+
LINT_VERSION=1.64.8
36+
curl -fsSL https://github.com/golangci/golangci-lint/releases/download/v${LINT_VERSION}/golangci-lint-${LINT_VERSION}-linux-amd64.tar.gz | \
37+
tar xz --strip-components 1 --wildcards \*/golangci-lint
38+
mkdir -p bin && mv golangci-lint bin/
39+
40+
- name: Run checks
41+
run: |
42+
STATUS=0
43+
assert-nothing-changed() {
44+
local diff
45+
"$@" >/dev/null || return 1
46+
if ! diff="$(git diff -U1 --color --exit-code)"; then
47+
printf '\e[31mError: running `\e[1m%s\e[22m` results in modifications that you must check into version control:\e[0m\n%s\n\n' "$*" "$diff" >&2
48+
git checkout -- .
49+
STATUS=1
50+
fi
51+
}
52+
53+
assert-nothing-changed go fmt ./...
54+
assert-nothing-changed go mod tidy
55+
56+
bin/golangci-lint run --out-format=colored-line-number --timeout=3m || STATUS=$?
57+
58+
exit $STATUS

.golangci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
run:
2+
timeout: 5m
3+
tests: true
4+
concurrency: 4
5+
6+
linters:
7+
enable:
8+
- govet
9+
- errcheck
10+
- staticcheck
11+
- gofmt
12+
- goimports
13+
- revive
14+
- ineffassign
15+
- typecheck
16+
- unused
17+
- gosimple
18+
- misspell
19+
- nakedret
20+
- bodyclose
21+
- gocritic
22+
- makezero
23+
- gosec
24+
25+
output:
26+
formats: colored-line-number
27+
print-issued-lines: true
28+
print-linter-name: true

cmd/github-mcp-server/main.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var (
3030
Use: "stdio",
3131
Short: "Start stdio server",
3232
Long: `Start a server that communicates via standard input/output streams using JSON-RPC messages.`,
33-
Run: func(cmd *cobra.Command, args []string) {
33+
Run: func(_ *cobra.Command, _ []string) {
3434
logFile := viper.GetString("log-file")
3535
readOnly := viper.GetBool("read-only")
3636
exportTranslations := viper.GetBool("export-translations")
@@ -57,11 +57,11 @@ func init() {
5757
rootCmd.PersistentFlags().String("gh-host", "", "Specify the GitHub hostname (for GitHub Enterprise etc.)")
5858

5959
// Bind flag to viper
60-
viper.BindPFlag("read-only", rootCmd.PersistentFlags().Lookup("read-only"))
61-
viper.BindPFlag("log-file", rootCmd.PersistentFlags().Lookup("log-file"))
62-
viper.BindPFlag("enable-command-logging", rootCmd.PersistentFlags().Lookup("enable-command-logging"))
63-
viper.BindPFlag("export-translations", rootCmd.PersistentFlags().Lookup("export-translations"))
64-
viper.BindPFlag("gh-host", rootCmd.PersistentFlags().Lookup("gh-host"))
60+
_ = viper.BindPFlag("read-only", rootCmd.PersistentFlags().Lookup("read-only"))
61+
_ = viper.BindPFlag("log-file", rootCmd.PersistentFlags().Lookup("log-file"))
62+
_ = viper.BindPFlag("enable-command-logging", rootCmd.PersistentFlags().Lookup("enable-command-logging"))
63+
_ = viper.BindPFlag("export-translations", rootCmd.PersistentFlags().Lookup("export-translations"))
64+
_ = viper.BindPFlag("gh-host", rootCmd.PersistentFlags().Lookup("gh-host"))
6565

6666
// Add subcommands
6767
rootCmd.AddCommand(stdioCmd)

cmd/mcpcurl/main.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"encoding/json"
66
"fmt"
7-
"golang.org/x/exp/rand"
87
"io"
98
"os"
109
"os/exec"
@@ -13,6 +12,7 @@ import (
1312

1413
"github.com/spf13/cobra"
1514
"github.com/spf13/viper"
15+
"golang.org/x/exp/rand"
1616
)
1717

1818
type (
@@ -99,7 +99,7 @@ var (
9999
Use: "mcpcurl",
100100
Short: "CLI tool with dynamically generated commands",
101101
Long: "A CLI tool for interacting with MCP API based on dynamically loaded schemas",
102-
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
102+
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
103103
// Skip validation for help and completion commands
104104
if cmd.Name() == "help" || cmd.Name() == "completion" {
105105
return nil
@@ -119,7 +119,7 @@ var (
119119
Use: "schema",
120120
Short: "Fetch schema from MCP server",
121121
Long: "Fetches the tools schema from the MCP server specified by --stdio-server-cmd",
122-
RunE: func(cmd *cobra.Command, args []string) error {
122+
RunE: func(cmd *cobra.Command, _ []string) error {
123123
serverCmd, _ := cmd.Flags().GetString("stdio-server-cmd")
124124
if serverCmd == "" {
125125
return fmt.Errorf("--stdio-server-cmd is required")
@@ -206,7 +206,7 @@ func addCommandFromTool(toolsCmd *cobra.Command, tool *Tool, prettyPrint bool) {
206206
cmd := &cobra.Command{
207207
Use: tool.Name,
208208
Short: tool.Description,
209-
Run: func(cmd *cobra.Command, args []string) {
209+
Run: func(cmd *cobra.Command, _ []string) {
210210
// Build a map of arguments from flags
211211
arguments, err := buildArgumentsMap(cmd, tool)
212212
if err != nil {
@@ -257,15 +257,15 @@ func addCommandFromTool(toolsCmd *cobra.Command, tool *Tool, prettyPrint bool) {
257257
// Enhance description to indicate if parameter is optional
258258
description := prop.Description
259259
if !isRequired {
260-
description = description + " (optional)"
260+
description += " (optional)"
261261
}
262262

263263
switch prop.Type {
264264
case "string":
265265
cmd.Flags().String(name, "", description)
266266
if len(prop.Enum) > 0 {
267267
// Add validation in PreRun for enum values
268-
cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
268+
cmd.PreRunE = func(cmd *cobra.Command, _ []string) error {
269269
for flagName, property := range tool.InputSchema.Properties {
270270
if len(property.Enum) > 0 {
271271
value, _ := cmd.Flags().GetString(flagName)
@@ -373,7 +373,7 @@ func executeServerCommand(cmdStr, jsonRequest string) (string, error) {
373373
return "", fmt.Errorf("empty command")
374374
}
375375

376-
cmd := exec.Command(cmdParts[0], cmdParts[1:]...)
376+
cmd := exec.Command(cmdParts[0], cmdParts[1:]...) //nolint:gosec //mcpcurl is a test command that needs to execute arbitrary shell commands
377377

378378
// Setup stdin pipe
379379
stdin, err := cmd.StdinPipe()

pkg/github/code_scanning_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func Test_GetCodeScanningAlert(t *testing.T) {
6262
mockedClient: mock.NewMockedHTTPClient(
6363
mock.WithRequestMatchHandler(
6464
mock.GetReposCodeScanningAlertsByOwnerByRepoByAlertNumber,
65-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
65+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
6666
w.WriteHeader(http.StatusNotFound)
6767
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
6868
}),
@@ -176,7 +176,7 @@ func Test_ListCodeScanningAlerts(t *testing.T) {
176176
mockedClient: mock.NewMockedHTTPClient(
177177
mock.WithRequestMatchHandler(
178178
mock.GetReposCodeScanningAlertsByOwnerByRepo,
179-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
179+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
180180
w.WriteHeader(http.StatusUnauthorized)
181181
_, _ = w.Write([]byte(`{"message": "Unauthorized access"}`))
182182
}),

pkg/github/helper_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@ package github
22

33
import (
44
"encoding/json"
5-
"github.com/stretchr/testify/assert"
65
"net/http"
76
"testing"
87

98
"github.com/mark3labs/mcp-go/mcp"
9+
"github.com/stretchr/testify/assert"
1010
"github.com/stretchr/testify/require"
1111
)
1212

1313
// mockResponse is a helper function to create a mock HTTP response handler
14-
// that returns a specified status code and marshalled body.
14+
// that returns a specified status code and marshaled body.
1515
func mockResponse(t *testing.T, code int, body interface{}) http.HandlerFunc {
1616
t.Helper()
17-
return func(w http.ResponseWriter, r *http.Request) {
17+
return func(w http.ResponseWriter, _ *http.Request) {
1818
w.WriteHeader(code)
1919
b, err := json.Marshal(body)
2020
require.NoError(t, err)

pkg/github/issues_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func Test_AddIssueComment(t *testing.T) {
164164
mockedClient: mock.NewMockedHTTPClient(
165165
mock.WithRequestMatchHandler(
166166
mock.PostReposIssuesCommentsByOwnerByRepoByIssueNumber,
167-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
167+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
168168
w.WriteHeader(http.StatusUnprocessableEntity)
169169
_, _ = w.Write([]byte(`{"message": "Invalid request"}`))
170170
}),
@@ -323,7 +323,7 @@ func Test_SearchIssues(t *testing.T) {
323323
mockedClient: mock.NewMockedHTTPClient(
324324
mock.WithRequestMatchHandler(
325325
mock.GetSearchIssues,
326-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
326+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
327327
w.WriteHeader(http.StatusBadRequest)
328328
_, _ = w.Write([]byte(`{"message": "Validation Failed"}`))
329329
}),
@@ -463,7 +463,7 @@ func Test_CreateIssue(t *testing.T) {
463463
mockedClient: mock.NewMockedHTTPClient(
464464
mock.WithRequestMatchHandler(
465465
mock.PostReposIssuesByOwnerByRepo,
466-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
466+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
467467
w.WriteHeader(http.StatusUnprocessableEntity)
468468
_, _ = w.Write([]byte(`{"message": "Validation failed"}`))
469469
}),
@@ -646,7 +646,7 @@ func Test_ListIssues(t *testing.T) {
646646
mockedClient: mock.NewMockedHTTPClient(
647647
mock.WithRequestMatchHandler(
648648
mock.GetReposIssuesByOwnerByRepo,
649-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
649+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
650650
w.WriteHeader(http.StatusNotFound)
651651
_, _ = w.Write([]byte(`{"message": "Repository not found"}`))
652652
}),
@@ -799,7 +799,7 @@ func Test_UpdateIssue(t *testing.T) {
799799
mockedClient: mock.NewMockedHTTPClient(
800800
mock.WithRequestMatchHandler(
801801
mock.PatchReposIssuesByOwnerByRepoByIssueNumber,
802-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
802+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
803803
w.WriteHeader(http.StatusNotFound)
804804
_, _ = w.Write([]byte(`{"message": "Issue not found"}`))
805805
}),
@@ -819,7 +819,7 @@ func Test_UpdateIssue(t *testing.T) {
819819
mockedClient: mock.NewMockedHTTPClient(
820820
mock.WithRequestMatchHandler(
821821
mock.PatchReposIssuesByOwnerByRepoByIssueNumber,
822-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
822+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
823823
w.WriteHeader(http.StatusUnprocessableEntity)
824824
_, _ = w.Write([]byte(`{"message": "Invalid state value"}`))
825825
}),
@@ -881,15 +881,15 @@ func Test_UpdateIssue(t *testing.T) {
881881
}
882882

883883
// Check assignees if expected
884-
if tc.expectedIssue.Assignees != nil && len(tc.expectedIssue.Assignees) > 0 {
884+
if len(tc.expectedIssue.Assignees) > 0 {
885885
assert.Len(t, returnedIssue.Assignees, len(tc.expectedIssue.Assignees))
886886
for i, assignee := range returnedIssue.Assignees {
887887
assert.Equal(t, *tc.expectedIssue.Assignees[i].Login, *assignee.Login)
888888
}
889889
}
890890

891891
// Check labels if expected
892-
if tc.expectedIssue.Labels != nil && len(tc.expectedIssue.Labels) > 0 {
892+
if len(tc.expectedIssue.Labels) > 0 {
893893
assert.Len(t, returnedIssue.Labels, len(tc.expectedIssue.Labels))
894894
for i, label := range returnedIssue.Labels {
895895
assert.Equal(t, *tc.expectedIssue.Labels[i].Name, *label.Name)

pkg/github/pullrequests_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func Test_GetPullRequest(t *testing.T) {
7474
mockedClient: mock.NewMockedHTTPClient(
7575
mock.WithRequestMatchHandler(
7676
mock.GetReposPullsByOwnerByRepoByPullNumber,
77-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
77+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
7878
w.WriteHeader(http.StatusNotFound)
7979
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
8080
}),
@@ -193,7 +193,7 @@ func Test_ListPullRequests(t *testing.T) {
193193
mockedClient: mock.NewMockedHTTPClient(
194194
mock.WithRequestMatchHandler(
195195
mock.GetReposPullsByOwnerByRepo,
196-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
196+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
197197
w.WriteHeader(http.StatusBadRequest)
198198
_, _ = w.Write([]byte(`{"message": "Invalid request"}`))
199199
}),
@@ -302,7 +302,7 @@ func Test_MergePullRequest(t *testing.T) {
302302
mockedClient: mock.NewMockedHTTPClient(
303303
mock.WithRequestMatchHandler(
304304
mock.PutReposPullsMergeByOwnerByRepoByPullNumber,
305-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
305+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
306306
w.WriteHeader(http.StatusMethodNotAllowed)
307307
_, _ = w.Write([]byte(`{"message": "Pull request cannot be merged"}`))
308308
}),
@@ -414,7 +414,7 @@ func Test_GetPullRequestFiles(t *testing.T) {
414414
mockedClient: mock.NewMockedHTTPClient(
415415
mock.WithRequestMatchHandler(
416416
mock.GetReposPullsFilesByOwnerByRepoByPullNumber,
417-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
417+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
418418
w.WriteHeader(http.StatusNotFound)
419419
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
420420
}),
@@ -551,7 +551,7 @@ func Test_GetPullRequestStatus(t *testing.T) {
551551
mockedClient: mock.NewMockedHTTPClient(
552552
mock.WithRequestMatchHandler(
553553
mock.GetReposPullsByOwnerByRepoByPullNumber,
554-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
554+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
555555
w.WriteHeader(http.StatusNotFound)
556556
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
557557
}),
@@ -574,7 +574,7 @@ func Test_GetPullRequestStatus(t *testing.T) {
574574
),
575575
mock.WithRequestMatchHandler(
576576
mock.GetReposCommitsStatusesByOwnerByRepoByRef,
577-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
577+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
578578
w.WriteHeader(http.StatusNotFound)
579579
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
580580
}),
@@ -695,7 +695,7 @@ func Test_UpdatePullRequestBranch(t *testing.T) {
695695
mockedClient: mock.NewMockedHTTPClient(
696696
mock.WithRequestMatchHandler(
697697
mock.PutReposPullsUpdateBranchByOwnerByRepoByPullNumber,
698-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
698+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
699699
w.WriteHeader(http.StatusConflict)
700700
_, _ = w.Write([]byte(`{"message": "Merge conflict"}`))
701701
}),
@@ -811,7 +811,7 @@ func Test_GetPullRequestComments(t *testing.T) {
811811
mockedClient: mock.NewMockedHTTPClient(
812812
mock.WithRequestMatchHandler(
813813
mock.GetReposPullsCommentsByOwnerByRepoByPullNumber,
814-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
814+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
815815
w.WriteHeader(http.StatusNotFound)
816816
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
817817
}),
@@ -934,7 +934,7 @@ func Test_GetPullRequestReviews(t *testing.T) {
934934
mockedClient: mock.NewMockedHTTPClient(
935935
mock.WithRequestMatchHandler(
936936
mock.GetReposPullsReviewsByOwnerByRepoByPullNumber,
937-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
937+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
938938
w.WriteHeader(http.StatusNotFound)
939939
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
940940
}),
@@ -1099,7 +1099,7 @@ func Test_CreatePullRequestReview(t *testing.T) {
10991099
mockedClient: mock.NewMockedHTTPClient(
11001100
mock.WithRequestMatchHandler(
11011101
mock.PostReposPullsReviewsByOwnerByRepoByPullNumber,
1102-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1102+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
11031103
w.WriteHeader(http.StatusUnprocessableEntity)
11041104
_, _ = w.Write([]byte(`{"message": "Invalid comment format"}`))
11051105
}),
@@ -1126,7 +1126,7 @@ func Test_CreatePullRequestReview(t *testing.T) {
11261126
mockedClient: mock.NewMockedHTTPClient(
11271127
mock.WithRequestMatchHandler(
11281128
mock.PostReposPullsReviewsByOwnerByRepoByPullNumber,
1129-
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1129+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
11301130
w.WriteHeader(http.StatusUnprocessableEntity)
11311131
_, _ = w.Write([]byte(`{"message": "Invalid comment format"}`))
11321132
}),

0 commit comments

Comments
 (0)