• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / cli / 20128715106

11 Dec 2025 09:43AM UTC coverage: 56.046% (-0.2%) from 56.237%
20128715106

Pull #4606

github

web-flow
Merge e5bcc615b into f513dbecb
Pull Request #4606: refactor(cli): replace IDE flags with interactive mode in init

12 of 44 new or added lines in 4 files covered. (27.27%)

13 existing lines in 3 files now uncovered.

6813 of 12156 relevant lines covered (56.05%)

6.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.9
/internal/init/init.go
1
package init
2

3
import (
4
        "bytes"
5
        "context"
6
        _ "embed"
7
        "encoding/json"
8
        "fmt"
9
        "io"
10
        "os"
11
        "path/filepath"
12

13
        "github.com/go-errors/errors"
14
        "github.com/spf13/afero"
15
        "github.com/supabase/cli/internal/utils"
16
        "github.com/tidwall/jsonc"
17
)
18

19
var (
20
        vscodeDir      = ".vscode"
21
        extensionsPath = filepath.Join(vscodeDir, "extensions.json")
22
        settingsPath   = filepath.Join(vscodeDir, "settings.json")
23
        intellijDir    = ".idea"
24
        denoPath       = filepath.Join(intellijDir, "deno.xml")
25

26
        //go:embed templates/.gitignore
27
        initGitignore []byte
28
        //go:embed templates/.vscode/extensions.json
29
        vscodeExtensions string
30
        //go:embed templates/.vscode/settings.json
31
        vscodeSettings string
32
        //go:embed templates/.idea/deno.xml
33
        intelliJDeno string
34
)
35

36
func Run(ctx context.Context, fsys afero.Fs, interactive bool, params utils.InitParams) error {
4✔
37
        // 1. Write `config.toml`.
4✔
38
        if err := utils.InitConfig(params, fsys); err != nil {
7✔
39
                if errors.Is(err, os.ErrExist) {
4✔
40
                        utils.CmdSuggestion = fmt.Sprintf("Run %s to overwrite existing config file.", utils.Aqua("supabase init --force"))
1✔
41
                }
1✔
42
                return err
3✔
43
        }
44

45
        // 2. Append to `.gitignore`.
46
        if utils.IsGitRepo() {
2✔
47
                if err := updateGitIgnore(utils.GitIgnorePath, fsys); err != nil {
1✔
48
                        return err
×
49
                }
×
50
        }
51

52
        // 3. Prompt for IDE settings in interactive mode.
53
        if interactive {
1✔
NEW
54
                if err := PromptForIDESettings(ctx, fsys); err != nil {
×
NEW
55
                        return err
×
NEW
56
                }
×
57
        }
58
        return nil
1✔
59
}
60

61
// PromptForIDESettings prompts the user to generate IDE settings for Deno.
62
func PromptForIDESettings(ctx context.Context, fsys afero.Fs) error {
1✔
63
        console := utils.NewConsole()
1✔
64
        if isVscode, err := console.PromptYesNo(ctx, "Generate VS Code settings for Deno?", true); err != nil {
1✔
NEW
65
                return err
×
66
        } else if isVscode {
2✔
67
                return WriteVscodeConfig(fsys)
1✔
68
        }
1✔
NEW
69
        if isIntelliJ, err := console.PromptYesNo(ctx, "Generate IntelliJ IDEA settings for Deno?", false); err != nil {
×
NEW
70
                return err
×
NEW
71
        } else if isIntelliJ {
×
UNCOV
72
                return WriteIntelliJConfig(fsys)
×
UNCOV
73
        }
×
UNCOV
74
        return nil
×
75
}
76

77
func updateGitIgnore(ignorePath string, fsys afero.Fs) error {
5✔
78
        var contents []byte
5✔
79

5✔
80
        if contained, err := afero.FileContainsBytes(fsys, ignorePath, initGitignore); contained {
6✔
81
                return nil
1✔
82
        } else if err == nil {
6✔
83
                // Add a line break when appending
1✔
84
                contents = append(contents, '\n')
1✔
85
        } else if !errors.Is(err, os.ErrNotExist) {
5✔
86
                return errors.Errorf("failed to read git ignore file: %w", err)
1✔
87
        }
1✔
88

89
        f, err := fsys.OpenFile(ignorePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
3✔
90
        if err != nil {
4✔
91
                return errors.Errorf("failed to create git ignore file: %w", err)
1✔
92
        }
1✔
93
        defer f.Close()
2✔
94

2✔
95
        if _, err := f.Write(append(contents, initGitignore...)); err != nil {
2✔
96
                return errors.Errorf("failed to write git ignore file: %w", err)
×
97
        }
×
98

99
        return nil
2✔
100
}
101

102
type VSCodeSettings map[string]any
103

104
func loadUserSettings(path string, fsys afero.Fs) (VSCodeSettings, error) {
9✔
105
        data, err := afero.ReadFile(fsys, path)
9✔
106
        if err != nil {
14✔
107
                return nil, errors.Errorf("failed to load settings file: %w", err)
5✔
108
        }
5✔
109
        data = jsonc.ToJSONInPlace(data)
4✔
110
        // Parse and unmarshal JSON file.
4✔
111
        var userSettings VSCodeSettings
4✔
112
        dec := json.NewDecoder(bytes.NewReader(data))
4✔
113
        if err := dec.Decode(&userSettings); err != nil {
5✔
114
                return nil, errors.Errorf("failed to parse settings: %w", err)
1✔
115
        }
1✔
116
        return userSettings, nil
3✔
117
}
118

119
func saveUserSettings(path string, settings VSCodeSettings, fsys afero.Fs) error {
2✔
120
        // Open our jsonFile
2✔
121
        jsonFile, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
2✔
122
        if err != nil {
3✔
123
                return errors.Errorf("failed to create settings file: %w", err)
1✔
124
        }
1✔
125
        defer jsonFile.Close()
1✔
126
        // Marshal JSON to file.
1✔
127
        enc := json.NewEncoder(jsonFile)
1✔
128
        enc.SetIndent("", "  ")
1✔
129
        if err := enc.Encode(settings); err != nil {
1✔
130
                return errors.Errorf("failed to save settings: %w", err)
×
131
        }
×
132
        return nil
1✔
133
}
134

135
func updateJsonFile(path string, template string, fsys afero.Fs) error {
9✔
136
        userSettings, err := loadUserSettings(path, fsys)
9✔
137
        if errors.Is(err, os.ErrNotExist) || errors.Is(err, io.EOF) {
13✔
138
                return afero.WriteFile(fsys, path, []byte(template), 0644)
4✔
139
        } else if err != nil {
11✔
140
                return err
2✔
141
        }
2✔
142
        // Merge template into user settings.
143
        if err := json.Unmarshal([]byte(template), &userSettings); err != nil {
4✔
144
                return errors.Errorf("failed to copy template: %w", err)
1✔
145
        }
1✔
146
        return saveUserSettings(path, userSettings, fsys)
2✔
147
}
148

149
func WriteVscodeConfig(fsys afero.Fs) error {
4✔
150
        // Create VS Code settings for Deno.
4✔
151
        if err := utils.MkdirIfNotExistFS(fsys, vscodeDir); err != nil {
5✔
152
                return err
1✔
153
        }
1✔
154
        if err := updateJsonFile(extensionsPath, vscodeExtensions, fsys); err != nil {
4✔
155
                return err
1✔
156
        }
1✔
157
        if err := updateJsonFile(settingsPath, vscodeSettings, fsys); err != nil {
3✔
158
                return err
1✔
159
        }
1✔
160
        fmt.Println("Generated VS Code settings in " + utils.Bold(settingsPath) + ".")
1✔
161
        fmt.Println("Please install the Deno extension for VS Code: " + utils.Bold("https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno"))
1✔
162
        return nil
1✔
163
}
164

UNCOV
165
func WriteIntelliJConfig(fsys afero.Fs) error {
×
UNCOV
166
        if err := utils.WriteFile(denoPath, []byte(intelliJDeno), fsys); err != nil {
×
167
                return err
×
168
        }
×
UNCOV
169
        fmt.Println("Generated IntelliJ settings in " + utils.Bold(denoPath) + ".")
×
NEW
170
        fmt.Println("Please install the Deno plugin for IntelliJ: " + utils.Bold("https://plugins.jetbrains.com/plugin/14382-deno"))
×
UNCOV
171
        return nil
×
172
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc