Skip to content

Commit 77c9100

Browse files
authored
Merge branch 'main' into issue1063
2 parents 95da812 + 5a76699 commit 77c9100

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3287
-789
lines changed
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Swagger
1+
name: Codegen
22

33
on:
44
workflow_call:
@@ -8,7 +8,7 @@ permissions:
88

99
jobs:
1010
swagger:
11-
name: Verify Swagger
11+
name: Verify code generation
1212
runs-on: ubuntu-latest
1313

1414
steps:
@@ -21,16 +21,16 @@ jobs:
2121
with:
2222
version: 3.x
2323
repo-token: ${{ secrets.GITHUB_TOKEN }}
24-
- name: Install swagger
25-
run: task swagger-install
26-
- name: Generate swagger files
27-
run: task swagger-gen
24+
- name: Install mockgen
25+
run: task mock-install
26+
- name: Generate code files
27+
run: task gen
2828
- name: Check for changes
2929
run: |
3030
if ! git diff --exit-code docs/server/; then
31-
echo "❌ Swagger files are not up to date!"
32-
echo "Please run 'task swagger-gen' or 'swag init -g pkg/api/server.go --v3.1 -o docs/server' and commit the changes."
31+
echo "❌ Generated code files are not up to date!"
32+
echo "Please run 'task gen' and commit the changes."
3333
exit 1
3434
else
35-
echo "✅ Swagger files are up to date!"
35+
echo "✅ Generated code files are up to date!"
3636
fi

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ task test-e2e
4141
# Run all tests (unit and e2e)
4242
task test-all
4343

44-
# Generate OpenAPI/Swagger documentation
45-
task swagger-gen
44+
# Generate mocks
45+
task gen
4646

4747
# Generate CLI documentation
4848
task docs

Taskfile.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,27 @@ includes:
88
tasks:
99
docs:
1010
desc: Regenerate the docs
11+
deps: [swagger-install]
1112
cmds:
1213
- rm -rf docs/cli/*
1314
- go run cmd/help/main.go --dir docs/cli
15+
- swag init -g pkg/api/server.go --v3.1 -o docs/server
1416

1517
swagger-install:
1618
desc: Install the swag tool for OpenAPI/Swagger generation
1719
cmds:
1820
- go install github.com/swaggo/swag/v2/cmd/swag@latest
1921

20-
swagger-gen:
21-
desc: Generate OpenAPI/Swagger documentation
22-
deps: [swagger-install]
22+
mock-install:
23+
desc: Install the mockgen tool for mock generation
2324
cmds:
24-
- swag init -g pkg/api/server.go --v3.1 -o docs/server
25+
- go install go.uber.org/mock/mockgen@latest
26+
27+
gen:
28+
desc: Generate mock files using go generate
29+
deps: [mock-install]
30+
cmds:
31+
- go generate ./...
2532

2633
lint:
2734
desc: Run linting tools
@@ -53,6 +60,7 @@ tasks:
5360

5461
test:
5562
desc: Run unit tests (excluding e2e tests)
63+
deps: [gen]
5664
cmds:
5765
- task: test-unixlike
5866
platforms: [linux, darwin]
@@ -128,6 +136,7 @@ tasks:
128136

129137
build:
130138
desc: Build the binary
139+
deps: [gen]
131140
vars:
132141
VERSION:
133142
sh: git describe --tags --always --dirty --match "v*" || echo "dev"

cmd/thv-proxyrunner/app/run.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,10 @@ func runCmdFunc(cmd *cobra.Command, args []string) error {
266266
return fmt.Errorf("failed to create RunConfig: %v", err)
267267
}
268268

269-
workloadManager := workloads.NewManagerFromRuntime(rt)
269+
workloadManager, err := workloads.NewManagerFromRuntime(rt)
270+
if err != nil {
271+
return fmt.Errorf("failed to create workload manager: %v", err)
272+
}
270273
return workloadManager.RunWorkload(ctx, runConfig)
271274
}
272275

cmd/thv/app/client.go

Lines changed: 115 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/stacklok/toolhive/pkg/config"
1313
"github.com/stacklok/toolhive/pkg/core"
1414
"github.com/stacklok/toolhive/pkg/groups"
15+
"github.com/stacklok/toolhive/pkg/logger"
1516
"github.com/stacklok/toolhive/pkg/workloads"
1617
)
1718

@@ -104,6 +105,8 @@ func init() {
104105
// TODO: Re-enable when group functionality is complete
105106
//clientRegisterCmd.Flags().StringSliceVar(
106107
// &groupNames, "group", []string{"default"}, "Only register workloads from specified groups")
108+
//clientRemoveCmd.Flags().StringSliceVar(
109+
// &groupNames, "group", []string{}, "Remove client from specified groups (if not set, removes all workloads from the client)")
107110
}
108111

109112
func clientStatusCmdFunc(_ *cobra.Command, _ []string) error {
@@ -208,21 +211,7 @@ func clientRemoveCmdFunc(cmd *cobra.Command, args []string) error {
208211
clientType)
209212
}
210213

211-
ctx := cmd.Context()
212-
213-
manager, err := client.NewManager(ctx)
214-
if err != nil {
215-
return fmt.Errorf("failed to create client manager: %w", err)
216-
}
217-
218-
err = manager.UnregisterClients(ctx, []client.Client{
219-
{Name: client.MCPClient(clientType)},
220-
})
221-
if err != nil {
222-
return fmt.Errorf("failed to remove client %s: %w", clientType, err)
223-
}
224-
225-
return nil
214+
return performClientRemoval(cmd.Context(), client.Client{Name: client.MCPClient(clientType)}, groupNames)
226215
}
227216

228217
func listRegisteredClientsCmdFunc(_ *cobra.Command, _ []string) error {
@@ -339,3 +328,114 @@ func registerClientsGlobally(
339328

340329
return nil
341330
}
331+
332+
func performClientRemoval(ctx context.Context, clientToRemove client.Client, groupNames []string) error {
333+
clientManager, err := client.NewManager(ctx)
334+
if err != nil {
335+
return fmt.Errorf("failed to create client manager: %w", err)
336+
}
337+
338+
workloadManager, err := workloads.NewManager(ctx)
339+
if err != nil {
340+
return fmt.Errorf("failed to create workload manager: %w", err)
341+
}
342+
343+
runningWorkloads, err := workloadManager.ListWorkloads(ctx, false)
344+
if err != nil {
345+
return fmt.Errorf("failed to list running workloads: %w", err)
346+
}
347+
348+
groupManager, err := groups.NewManager()
349+
if err != nil {
350+
return fmt.Errorf("failed to create group manager: %w", err)
351+
}
352+
353+
if len(groupNames) > 0 {
354+
return removeClientFromGroups(ctx, clientToRemove, groupNames, runningWorkloads, groupManager, clientManager)
355+
}
356+
357+
return removeClientGlobally(ctx, clientToRemove, runningWorkloads, groupManager, clientManager)
358+
}
359+
360+
func removeClientFromGroups(
361+
ctx context.Context,
362+
clientToRemove client.Client,
363+
groupNames []string,
364+
runningWorkloads []core.Workload,
365+
groupManager groups.Manager,
366+
clientManager client.Manager,
367+
) error {
368+
fmt.Printf("Filtering workloads to groups: %v\n", groupNames)
369+
370+
// Remove client from specific groups only
371+
filteredWorkloads, err := workloads.FilterByGroups(runningWorkloads, groupNames)
372+
if err != nil {
373+
return fmt.Errorf("failed to filter workloads by groups: %w", err)
374+
}
375+
376+
// Remove the workloads from the client's configuration file
377+
err = clientManager.UnregisterClients(ctx, []client.Client{clientToRemove}, filteredWorkloads)
378+
if err != nil {
379+
return fmt.Errorf("failed to unregister client: %w", err)
380+
}
381+
382+
// Remove the client from the groups
383+
err = groupManager.UnregisterClients(ctx, groupNames, []string{string(clientToRemove.Name)})
384+
if err != nil {
385+
return fmt.Errorf("failed to unregister client from groups: %w", err)
386+
}
387+
388+
fmt.Printf("Successfully removed client %s from groups: %v\n", clientToRemove.Name, groupNames)
389+
390+
return nil
391+
}
392+
393+
func removeClientGlobally(
394+
ctx context.Context,
395+
clientToRemove client.Client,
396+
runningWorkloads []core.Workload,
397+
groupManager groups.Manager,
398+
clientManager client.Manager,
399+
) error {
400+
// Remove the workloads from the client's configuration file
401+
err := clientManager.UnregisterClients(ctx, []client.Client{clientToRemove}, runningWorkloads)
402+
if err != nil {
403+
return fmt.Errorf("failed to unregister client: %w", err)
404+
}
405+
406+
allGroups, err := groupManager.List(ctx)
407+
if err != nil {
408+
return fmt.Errorf("failed to list groups: %w", err)
409+
}
410+
411+
if len(allGroups) > 0 {
412+
// Remove client from all groups first
413+
allGroupNames := make([]string, len(allGroups))
414+
for i, group := range allGroups {
415+
allGroupNames[i] = group.Name
416+
}
417+
418+
err = groupManager.UnregisterClients(ctx, allGroupNames, []string{string(clientToRemove.Name)})
419+
if err != nil {
420+
return fmt.Errorf("failed to unregister client from groups: %w", err)
421+
}
422+
}
423+
424+
// Remove client from global registered clients list
425+
err = config.UpdateConfig(func(c *config.Config) {
426+
for i, registeredClient := range c.Clients.RegisteredClients {
427+
if registeredClient == string(clientToRemove.Name) {
428+
// Remove client from slice
429+
c.Clients.RegisteredClients = append(c.Clients.RegisteredClients[:i], c.Clients.RegisteredClients[i+1:]...)
430+
logger.Infof("Successfully unregistered client: %s\n", clientToRemove.Name)
431+
return
432+
}
433+
}
434+
logger.Warnf("Client %s was not found in registered clients list", clientToRemove.Name)
435+
})
436+
if err != nil {
437+
return fmt.Errorf("failed to update configuration for client %s: %w", clientToRemove.Name, err)
438+
}
439+
440+
return nil
441+
}

cmd/thv/app/mcp.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ func newMCPCommand() *cobra.Command {
3535
Long: `The mcp command provides subcommands to interact with MCP (Model Context Protocol) servers for debugging purposes.`,
3636
}
3737

38+
// Add serve subcommand
39+
cmd.AddCommand(newMCPServeCommand())
40+
3841
// Create list command
3942
listCmd := &cobra.Command{
4043
Use: "list [tools|resources|prompts]",

0 commit comments

Comments
 (0)