Skip to content

Commit 15b39cb

Browse files
committed
Consolidate Go tools into go_analyze, go_fix, and enhanced go_test
1 parent 3abb0e0 commit 15b39cb

File tree

3 files changed

+284
-121
lines changed

3 files changed

+284
-121
lines changed

src/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,14 @@ export async function main(): Promise<void> {
5555
role: 'user',
5656
content: {
5757
type: 'text',
58-
text: `This is the ${SERVER_NAME} server. You can use Go tools like go_find_dead_code, go_vet, go_format (using gofumpt), go_lint (using golangci-lint), go_test, and go_mod_tidy to analyze and test Go code.`
58+
text: `This is the ${SERVER_NAME} server. You can use the following Go tools:
59+
60+
1. go_analyze: Comprehensive code analysis using golangci-lint with customizable severity levels and auto-fix options
61+
2. go_fix: Code cleanup tool that can run go mod tidy, goimports, and gofumpt in sequence
62+
3. go_test: Enhanced test runner with coverage reports and benchmark support
63+
4. go_mod_tidy: Dependency management tool that runs go mod tidy
64+
65+
Each tool accepts a working directory (wd) parameter that must be an absolute path.`
5966
}
6067
}]
6168
})

src/tools/__tests__/goTools.test.ts

Lines changed: 84 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,33 @@ import { registerGoTools } from '../goTools.js'
77
vi.mock('child_process', () => ({
88
exec: vi.fn(),
99
execSync: vi.fn((cmd) => {
10-
if (cmd.includes('go vet')) {
11-
return '# mocked go vet output'
10+
if (cmd.includes('golangci-lint run')) {
11+
if (cmd.includes('--severity=error')) {
12+
return 'main.go:15:9: [error] SA4006: this value of `err` is never used (staticcheck)\n'
13+
} else if (cmd.includes('--fix')) {
14+
return 'main.go:15:9: fixed issue SA4006 (staticcheck)\n'
15+
} else {
16+
return 'main.go:15:9: [warning] SA4006: this value of `err` is never used (staticcheck)\n'
17+
}
1218
} else if (cmd.includes('gofumpt')) {
1319
if (cmd.includes('-extra')) {
1420
return 'main.go (with extra formatting)\n'
1521
}
1622
return 'main.go\n'
23+
} else if (cmd.includes('goimports')) {
24+
return 'Organized imports in 3 files\n'
1725
} else if (cmd.includes('go test')) {
18-
return 'ok github.com/example/pkg 0.123s\n'
26+
if (cmd.includes('-coverprofile')) {
27+
return 'ok github.com/example/pkg 0.123s coverage: 75.0% of statements\n'
28+
} else if (cmd.includes('-bench')) {
29+
return 'goos: linux\ngoarch: amd64\nBenchmarkFunction-8 1000000 1234 ns/op\nok github.com/example/pkg 1.234s\n'
30+
} else {
31+
return 'ok github.com/example/pkg 0.123s\n'
32+
}
33+
} else if (cmd.includes('go tool cover')) {
34+
return 'github.com/example/pkg/main.go:10: Function 75.0%\ntotal: 75.0%\n'
1935
} else if (cmd.includes('go mod tidy')) {
2036
return ''
21-
} else if (cmd.includes('deadcode')) {
22-
return 'main.go:10:6: unreachable func: unusedFunction\n'
23-
} else if (cmd.includes('golangci-lint')) {
24-
return 'main.go:15:9: SA4006: this value of `err` is never used (staticcheck)\n'
2537
} else {
2638
return 'mocked output for: ' + cmd
2739
}
@@ -40,19 +52,41 @@ describe('Go Tools', () => {
4052
vi.clearAllMocks()
4153
})
4254

43-
describe('go_find_dead_code', () => {
44-
it('should report dead code when found', async () => {
45-
const result = await server.callTool('go_find_dead_code', {
55+
describe('go_analyze', () => {
56+
it('should analyze code with golangci-lint', async () => {
57+
const result = await server.callTool('go_analyze', {
4658
wd: testWorkingDir,
4759
path: './...'
4860
})
4961

5062
expect(result.content[0].type).toBe('text')
51-
expect(result.content[0].text).toContain('unreachable func')
63+
expect(result.content[0].text).toContain('staticcheck')
64+
})
65+
66+
it('should respect severity level', async () => {
67+
const result = await server.callTool('go_analyze', {
68+
wd: testWorkingDir,
69+
path: './...',
70+
severity: 'error'
71+
})
72+
73+
expect(result.content[0].type).toBe('text')
74+
expect(result.content[0].text).toContain('[error]')
75+
})
76+
77+
it('should support automatic fixing', async () => {
78+
const result = await server.callTool('go_analyze', {
79+
wd: testWorkingDir,
80+
path: './...',
81+
fix: true
82+
})
83+
84+
expect(result.content[0].type).toBe('text')
85+
expect(result.content[0].text).toContain('fixed issue')
5286
})
5387

5488
it('should reject non-absolute working directory paths', async () => {
55-
const result = await server.callTool('go_find_dead_code', {
89+
const result = await server.callTool('go_analyze', {
5690
wd: 'relative/path',
5791
path: './...'
5892
})
@@ -62,35 +96,41 @@ describe('Go Tools', () => {
6296
})
6397
})
6498

65-
describe('go_vet', () => {
66-
it('should run go vet successfully', async () => {
67-
const result = await server.callTool('go_vet', {
99+
describe('go_fix', () => {
100+
it('should fix Go code with all tools enabled', async () => {
101+
// For this test, we'll trust that the tool correctly constructs the commands
102+
// and focus on verifying the parameters are handled correctly
103+
const result = await server.callTool('go_fix', {
68104
wd: testWorkingDir,
69105
path: './...'
70106
})
71107

72108
expect(result.content[0].type).toBe('text')
73-
expect(result.content[0].text).toContain('mocked go vet output')
109+
// Just make sure we get a result
110+
expect(result.content[0].text).toBeTruthy()
74111
})
75-
})
76112

77-
describe('go_format', () => {
78-
it('should format Go code with gofumpt', async () => {
79-
const result = await server.callTool('go_format', {
113+
it('should support selective tool usage', async () => {
114+
const result = await server.callTool('go_fix', {
80115
wd: testWorkingDir,
81116
path: './...',
82-
write: true
117+
deps: false,
118+
imports: true,
119+
format: true
83120
})
84121

85122
expect(result.content[0].type).toBe('text')
123+
expect(result.content[0].text).toContain('Organized imports')
86124
expect(result.content[0].text).toContain('main.go')
87125
})
88126

89127
it('should support extra formatting options', async () => {
90-
const result = await server.callTool('go_format', {
128+
const result = await server.callTool('go_fix', {
91129
wd: testWorkingDir,
92130
path: './...',
93-
write: true,
131+
deps: false,
132+
imports: false,
133+
format: true,
94134
extra: true
95135
})
96136

@@ -99,27 +139,39 @@ describe('Go Tools', () => {
99139
})
100140
})
101141

102-
describe('go_lint', () => {
103-
it('should run golangci-lint on Go code', async () => {
104-
const result = await server.callTool('go_lint', {
142+
describe('go_test', () => {
143+
it('should run Go tests', async () => {
144+
const result = await server.callTool('go_test', {
105145
wd: testWorkingDir,
106146
path: './...'
107147
})
108148

109149
expect(result.content[0].type).toBe('text')
110-
expect(result.content[0].text).toContain('staticcheck')
150+
expect(result.content[0].text).toContain('ok')
111151
})
112-
})
113152

114-
describe('go_test', () => {
115-
it('should run Go tests', async () => {
153+
it('should run tests with coverage', async () => {
116154
const result = await server.callTool('go_test', {
117155
wd: testWorkingDir,
118-
path: './...'
156+
path: './...',
157+
coverage: true
119158
})
120159

121160
expect(result.content[0].type).toBe('text')
122-
expect(result.content[0].text).toContain('ok')
161+
expect(result.content[0].text).toContain('coverage: 75.0%')
162+
expect(result.content[0].text).toContain('total:')
163+
})
164+
165+
it('should run benchmarks', async () => {
166+
const result = await server.callTool('go_test', {
167+
wd: testWorkingDir,
168+
path: './...',
169+
bench: 'Function'
170+
})
171+
172+
expect(result.content[0].type).toBe('text')
173+
expect(result.content[0].text).toContain('BenchmarkFunction')
174+
expect(result.content[0].text).toContain('ns/op')
123175
})
124176
})
125177

0 commit comments

Comments
 (0)