Skip to content

Commit 1255bac

Browse files
KevyVojordanstephenslionello
authored
fix overwriting mcp config bug (#1394)
Co-authored-by: Jordan Stephens <[email protected]> Co-authored-by: Lio李歐 <[email protected]>
1 parent 74389b5 commit 1255bac

File tree

6 files changed

+473
-61
lines changed

6 files changed

+473
-61
lines changed

src/pkg/cli/compose/fixup_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"testing"
77

8+
"github.com/DefangLabs/defang/src/pkg"
89
"github.com/DefangLabs/defang/src/pkg/cli/client"
910
composeTypes "github.com/compose-spec/compose-go/v2/types"
1011
)
@@ -32,7 +33,7 @@ func TestFixup(t *testing.T) {
3233
t.Fatal(err)
3334
}
3435

35-
if err := compare(actual, path+".fixup"); err != nil {
36+
if err := pkg.Compare(actual, path+".fixup"); err != nil {
3637
t.Error(err)
3738
}
3839
})

src/pkg/cli/compose/loader_test.go

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
package compose
22

33
import (
4-
"bytes"
54
"context"
6-
"fmt"
75
"os"
86
"path/filepath"
97
"regexp"
108
"testing"
119

12-
"github.com/hexops/gotextdiff"
13-
"github.com/hexops/gotextdiff/myers"
14-
"github.com/hexops/gotextdiff/span"
10+
"github.com/DefangLabs/defang/src/pkg"
1511
)
1612

1713
func TestLoader(t *testing.T) {
@@ -28,41 +24,12 @@ func TestLoader(t *testing.T) {
2824
}
2925

3026
// Compare the output with the golden file
31-
if err := compare(yaml, path+".golden"); err != nil {
27+
if err := pkg.Compare(yaml, path+".golden"); err != nil {
3228
t.Error(err)
3329
}
3430
})
3531
}
3632

37-
func compare(actual []byte, goldenFile string) error {
38-
// Replace the absolute path in context to make the golden file portable
39-
absPath, _ := filepath.Abs(goldenFile)
40-
actual = bytes.ReplaceAll(actual, []byte(filepath.Dir(absPath)), []byte{'.'})
41-
42-
golden, err := os.ReadFile(goldenFile)
43-
if err != nil {
44-
if !os.IsNotExist(err) {
45-
return fmt.Errorf("Failed to read golden file: %w", err)
46-
}
47-
return os.WriteFile(goldenFile, actual, 0644)
48-
} else {
49-
if err := diff(string(actual), string(golden)); err != nil {
50-
return fmt.Errorf("%s %w", goldenFile, err)
51-
}
52-
}
53-
return nil
54-
}
55-
56-
func diff(actualRaw, goldenRaw string) error {
57-
if actualRaw == goldenRaw {
58-
return nil
59-
}
60-
61-
edits := myers.ComputeEdits(span.URIFromPath("expected"), goldenRaw, actualRaw)
62-
diff := fmt.Sprint(gotextdiff.ToUnified("expected", "actual", goldenRaw, edits))
63-
return fmt.Errorf("mismatch:\n%s", diff)
64-
}
65-
6633
func testRunCompose(t *testing.T, f func(t *testing.T, path string)) {
6734
t.Helper()
6835

src/pkg/cli/compose/validation_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"testing"
1111

12+
"github.com/DefangLabs/defang/src/pkg"
1213
"github.com/DefangLabs/defang/src/pkg/cli/client"
1314
"github.com/DefangLabs/defang/src/pkg/term"
1415
defangv1 "github.com/DefangLabs/defang/src/protos/io/defang/v1"
@@ -66,7 +67,7 @@ func TestValidationAndConvert(t *testing.T) {
6667
logs = bytes.NewBufferString(strings.Join(logLines, ""))
6768

6869
// Compare the logs with the warnings file
69-
if err := compare(logs.Bytes(), path+".warnings"); err != nil {
70+
if err := pkg.Compare(logs.Bytes(), path+".warnings"); err != nil {
7071
t.Error(err)
7172
}
7273
})

src/pkg/mcp/setup.go

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -244,17 +244,10 @@ func handleVSCodeConfig(configPath string) error {
244244
}
245245

246246
// Check if the file exists
247-
if _, err := os.Stat(configPath); err == nil {
248-
// File exists, read it
249-
data, err := os.ReadFile(configPath)
250-
if err != nil {
251-
return fmt.Errorf("failed to read config file: %w", err)
252-
}
253-
254-
// Parse the JSON into a generic map to preserve all settings
247+
if data, err := os.ReadFile(configPath); err == nil {
248+
// File exists, parse it
255249
if err := json.Unmarshal(data, &existingData); err != nil {
256-
// If we can't parse it, start fresh
257-
existingData = make(map[string]any)
250+
return fmt.Errorf("failed to unmarshal existing vscode config %w", err)
258251
}
259252

260253
// Check if "servers" section exists
@@ -271,6 +264,8 @@ func handleVSCodeConfig(configPath string) error {
271264
} else {
272265
return errors.New("failed to assert 'servers' section as map[string]any")
273266
}
267+
} else if !os.IsNotExist(err) {
268+
return fmt.Errorf("failed to read config file: %w", err)
274269
} else {
275270
// File doesn't exist, create a new config with minimal settings
276271
existingData = map[string]any{
@@ -296,28 +291,33 @@ func handleVSCodeConfig(configPath string) error {
296291

297292
func handleStandardConfig(configPath string) error {
298293
// For all other clients, use the standard format
294+
var existingData map[string]any
299295
var config MCPConfig
300296

301297
// Check if the file exists
302-
if _, err := os.Stat(configPath); err == nil {
303-
// File exists, read it
304-
data, err := os.ReadFile(configPath)
305-
if err != nil {
306-
return fmt.Errorf("failed to read config file: %w", err)
298+
if data, err := os.ReadFile(configPath); err == nil {
299+
// Parse the JSON into a generic map to preserve all settings
300+
if err := json.Unmarshal(data, &existingData); err != nil {
301+
return fmt.Errorf("failed to unmarshal existing config: %w", err)
307302
}
308303

309-
// Parse the JSON
310-
if err := json.Unmarshal(data, &config); err != nil {
311-
// If we can't parse it, start fresh
312-
config = MCPConfig{
313-
MCPServers: make(map[string]MCPServerConfig),
304+
// Try to extract MCPServers from existing data
305+
if mcpServersData, ok := existingData["mcpServers"]; ok {
306+
// Convert back to MCPConfig structure
307+
mcpServersJSON, err := json.Marshal(map[string]any{"mcpServers": mcpServersData})
308+
if err != nil {
309+
return fmt.Errorf("failed to marshal mcpServers: %w", err)
310+
}
311+
err = json.Unmarshal(mcpServersJSON, &config)
312+
if err != nil {
313+
return fmt.Errorf("failed to unmarshal mcpServers: %w", err)
314314
}
315315
}
316+
} else if !os.IsNotExist(err) {
317+
return fmt.Errorf("failed to read config file: %w", err)
316318
} else {
317319
// File doesn't exist, create a new config
318-
config = MCPConfig{
319-
MCPServers: make(map[string]MCPServerConfig),
320-
}
320+
existingData = make(map[string]any)
321321
}
322322

323323
if config.MCPServers == nil {
@@ -331,8 +331,11 @@ func handleStandardConfig(configPath string) error {
331331
// Add or update the Defang MCP server config
332332
config.MCPServers["defang"] = *defangConfig
333333

334+
// Update the existingData with the new MCPServers
335+
existingData["mcpServers"] = config.MCPServers
336+
334337
// Write the config to the file
335-
data, err := json.MarshalIndent(config, "", " ")
338+
data, err := json.MarshalIndent(existingData, "", " ")
336339
if err != nil {
337340
return fmt.Errorf("failed to marshal config: %w", err)
338341
}

0 commit comments

Comments
 (0)