Skip to content

Commit baeb674

Browse files
authored
Merge e5bcc61 into f513dbe
2 parents f513dbe + e5bcc61 commit baeb674

File tree

6 files changed

+65
-158
lines changed

6 files changed

+65
-158
lines changed

cmd/init.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@ package cmd
22

33
import (
44
"fmt"
5+
"os"
56

67
"github.com/spf13/afero"
78
"github.com/spf13/cobra"
89
"github.com/spf13/viper"
910
_init "github.com/supabase/cli/internal/init"
1011
"github.com/supabase/cli/internal/utils"
12+
"golang.org/x/term"
1113
)
1214

1315
var (
14-
createVscodeSettings = new(bool)
15-
createIntellijSettings = new(bool)
16+
initInteractive bool
17+
createVscodeSettings bool
18+
createIntellijSettings bool
1619
initParams = utils.InitParams{}
1720

1821
initCmd = &cobra.Command{
@@ -32,15 +35,24 @@ var (
3235
}
3336
},
3437
RunE: func(cmd *cobra.Command, args []string) error {
38+
ctx := cmd.Context()
3539
fsys := afero.NewOsFs()
36-
if !cmd.Flags().Changed("with-vscode-settings") && !cmd.Flags().Changed("with-vscode-workspace") {
37-
createVscodeSettings = nil
40+
interactive := initInteractive && term.IsTerminal(int(os.Stdin.Fd()))
41+
if err := _init.Run(ctx, fsys, interactive, initParams); err != nil {
42+
return err
3843
}
39-
40-
if !cmd.Flags().Changed("with-intellij-settings") {
41-
createIntellijSettings = nil
44+
// Handle backwards compatibility flags
45+
if createVscodeSettings {
46+
if err := _init.WriteVscodeConfig(fsys); err != nil {
47+
return err
48+
}
49+
}
50+
if createIntellijSettings {
51+
if err := _init.WriteIntelliJConfig(fsys); err != nil {
52+
return err
53+
}
4254
}
43-
return _init.Run(fsys, createVscodeSettings, createIntellijSettings, initParams)
55+
return nil
4456
},
4557
PostRun: func(cmd *cobra.Command, args []string) {
4658
fmt.Println("Finished " + utils.Aqua("supabase init") + ".")
@@ -50,11 +62,15 @@ var (
5062

5163
func init() {
5264
flags := initCmd.Flags()
53-
flags.BoolVar(createVscodeSettings, "with-vscode-workspace", false, "Generate VS Code workspace.")
54-
cobra.CheckErr(flags.MarkHidden("with-vscode-workspace"))
55-
flags.BoolVar(createVscodeSettings, "with-vscode-settings", false, "Generate VS Code settings for Deno.")
56-
flags.BoolVar(createIntellijSettings, "with-intellij-settings", false, "Generate IntelliJ IDEA settings for Deno.")
65+
flags.BoolVarP(&initInteractive, "interactive", "i", false, "Enables interactive mode to configure IDE settings.")
5766
flags.BoolVar(&initParams.UseOrioleDB, "use-orioledb", false, "Use OrioleDB storage engine for Postgres.")
5867
flags.BoolVar(&initParams.Overwrite, "force", false, "Overwrite existing "+utils.ConfigPath+".")
68+
// Backwards compatibility flags (hidden)
69+
flags.BoolVar(&createVscodeSettings, "with-vscode-workspace", false, "Generate VS Code workspace.")
70+
cobra.CheckErr(flags.MarkHidden("with-vscode-workspace"))
71+
flags.BoolVar(&createVscodeSettings, "with-vscode-settings", false, "Generate VS Code settings for Deno.")
72+
cobra.CheckErr(flags.MarkHidden("with-vscode-settings"))
73+
flags.BoolVar(&createIntellijSettings, "with-intellij-settings", false, "Generate IntelliJ IDEA settings for Deno.")
74+
cobra.CheckErr(flags.MarkHidden("with-intellij-settings"))
5975
rootCmd.AddCommand(initCmd)
6076
}

internal/bootstrap/bootstrap.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func Run(ctx context.Context, starter StarterTemplate, fsys afero.Fs, options ..
6060
if err := downloadSample(ctx, client, starter.Url, fsys); err != nil {
6161
return err
6262
}
63-
} else if err := initBlank.Run(fsys, nil, nil, utils.InitParams{Overwrite: true}); err != nil {
63+
} else if err := initBlank.Run(ctx, fsys, false, utils.InitParams{Overwrite: true}); err != nil {
6464
return err
6565
}
6666
// 1. Login

internal/functions/new/new.go

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/go-errors/errors"
1212
"github.com/spf13/afero"
13+
"github.com/supabase/cli/internal/functions/deploy"
1314
_init "github.com/supabase/cli/internal/init"
1415
"github.com/supabase/cli/internal/utils"
1516
"github.com/supabase/cli/internal/utils/flags"
@@ -39,7 +40,12 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error {
3940
if err := utils.ValidateFunctionSlug(slug); err != nil {
4041
return err
4142
}
42-
isFirstFunction := isFirstFunctionCreation(fsys)
43+
// Check if this is the first function being created
44+
existingSlugs, err := deploy.GetFunctionSlugs(fsys)
45+
if err != nil {
46+
fmt.Fprintln(utils.GetDebugLogger(), err)
47+
}
48+
isFirstFunction := len(existingSlugs) == 0
4349

4450
// 2. Create new function.
4551
funcDir := filepath.Join(utils.FunctionsDir, slug)
@@ -66,45 +72,13 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error {
6672
fmt.Println("Created new Function at " + utils.Bold(funcDir))
6773

6874
if isFirstFunction {
69-
if err := promptForIDESettings(ctx, fsys); err != nil {
75+
if err := _init.PromptForIDESettings(ctx, fsys); err != nil {
7076
return err
7177
}
7278
}
7379
return nil
7480
}
7581

76-
// Checks if this is the first function being created.
77-
// Returns true if the functions directory doesn't exist or is empty.
78-
func isFirstFunctionCreation(fsys afero.Fs) bool {
79-
entries, err := afero.ReadDir(fsys, utils.FunctionsDir)
80-
if err != nil {
81-
// Directory doesn't exist, this is the first function
82-
return true
83-
}
84-
// Check if there are any subdirectories (existing functions)
85-
for _, entry := range entries {
86-
if entry.IsDir() {
87-
return false
88-
}
89-
}
90-
return true
91-
}
92-
93-
func promptForIDESettings(ctx context.Context, fsys afero.Fs) error {
94-
console := utils.NewConsole()
95-
if isVscode, err := console.PromptYesNo(ctx, "Generate VS Code settings for Deno?", true); err != nil {
96-
return err
97-
} else if isVscode {
98-
return _init.WriteVscodeConfig(fsys)
99-
}
100-
if isIntelliJ, err := console.PromptYesNo(ctx, "Generate IntelliJ IDEA settings for Deno?", false); err != nil {
101-
return err
102-
} else if isIntelliJ {
103-
return _init.WriteIntelliJConfig(fsys)
104-
}
105-
return nil
106-
}
107-
10882
func createEntrypointFile(slug string, fsys afero.Fs) error {
10983
entrypointPath := filepath.Join(utils.FunctionsDir, slug, "index.ts")
11084
f, err := fsys.OpenFile(entrypointPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)

internal/functions/new/new_test.go

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -60,52 +60,3 @@ func TestNewCommand(t *testing.T) {
6060
assert.Error(t, Run(context.Background(), "test-func", fsys))
6161
})
6262
}
63-
64-
func TestIsFirstFunctionCreation(t *testing.T) {
65-
t.Run("returns true when functions directory does not exist", func(t *testing.T) {
66-
// Setup in-memory fs without functions directory
67-
fsys := afero.NewMemMapFs()
68-
// Run test
69-
assert.True(t, isFirstFunctionCreation(fsys))
70-
})
71-
72-
t.Run("returns true when functions directory is empty", func(t *testing.T) {
73-
// Setup in-memory fs with empty functions directory
74-
fsys := afero.NewMemMapFs()
75-
require.NoError(t, fsys.MkdirAll(utils.FunctionsDir, 0755))
76-
// Run test
77-
assert.True(t, isFirstFunctionCreation(fsys))
78-
})
79-
80-
t.Run("returns true when functions directory has only files", func(t *testing.T) {
81-
// Setup in-memory fs with functions directory containing only files
82-
fsys := afero.NewMemMapFs()
83-
require.NoError(t, fsys.MkdirAll(utils.FunctionsDir, 0755))
84-
// Create files (not directories) in functions directory
85-
require.NoError(t, afero.WriteFile(fsys, filepath.Join(utils.FunctionsDir, "import_map.json"), []byte("{}"), 0644))
86-
require.NoError(t, afero.WriteFile(fsys, filepath.Join(utils.FunctionsDir, ".env"), []byte(""), 0644))
87-
// Run test
88-
assert.True(t, isFirstFunctionCreation(fsys))
89-
})
90-
91-
t.Run("returns false when functions directory has subdirectories", func(t *testing.T) {
92-
// Setup in-memory fs with existing function
93-
fsys := afero.NewMemMapFs()
94-
existingFuncDir := filepath.Join(utils.FunctionsDir, "existing-func")
95-
require.NoError(t, fsys.MkdirAll(existingFuncDir, 0755))
96-
require.NoError(t, afero.WriteFile(fsys, filepath.Join(existingFuncDir, "index.ts"), []byte(""), 0644))
97-
// Run test
98-
assert.False(t, isFirstFunctionCreation(fsys))
99-
})
100-
101-
t.Run("returns false when multiple functions exist", func(t *testing.T) {
102-
// Setup in-memory fs with multiple existing functions
103-
fsys := afero.NewMemMapFs()
104-
func1Dir := filepath.Join(utils.FunctionsDir, "func1")
105-
func2Dir := filepath.Join(utils.FunctionsDir, "func2")
106-
require.NoError(t, fsys.MkdirAll(func1Dir, 0755))
107-
require.NoError(t, fsys.MkdirAll(func2Dir, 0755))
108-
// Run test
109-
assert.False(t, isFirstFunctionCreation(fsys))
110-
})
111-
}

internal/init/init.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package init
22

33
import (
44
"bytes"
5+
"context"
56
_ "embed"
67
"encoding/json"
78
"fmt"
@@ -32,7 +33,7 @@ var (
3233
intelliJDeno string
3334
)
3435

35-
func Run(fsys afero.Fs, createVscodeSettings, createIntellijSettings *bool, params utils.InitParams) error {
36+
func Run(ctx context.Context, fsys afero.Fs, interactive bool, params utils.InitParams) error {
3637
// 1. Write `config.toml`.
3738
if err := utils.InitConfig(params, fsys); err != nil {
3839
if errors.Is(err, os.ErrExist) {
@@ -48,11 +49,26 @@ func Run(fsys afero.Fs, createVscodeSettings, createIntellijSettings *bool, para
4849
}
4950
}
5051

51-
// 3. Generate VS Code or IntelliJ settings if explicitly requested via flags.
52-
if createVscodeSettings != nil && *createVscodeSettings {
52+
// 3. Prompt for IDE settings in interactive mode.
53+
if interactive {
54+
if err := PromptForIDESettings(ctx, fsys); err != nil {
55+
return err
56+
}
57+
}
58+
return nil
59+
}
60+
61+
// PromptForIDESettings prompts the user to generate IDE settings for Deno.
62+
func PromptForIDESettings(ctx context.Context, fsys afero.Fs) error {
63+
console := utils.NewConsole()
64+
if isVscode, err := console.PromptYesNo(ctx, "Generate VS Code settings for Deno?", true); err != nil {
65+
return err
66+
} else if isVscode {
5367
return WriteVscodeConfig(fsys)
5468
}
55-
if createIntellijSettings != nil && *createIntellijSettings {
69+
if isIntelliJ, err := console.PromptYesNo(ctx, "Generate IntelliJ IDEA settings for Deno?", false); err != nil {
70+
return err
71+
} else if isIntelliJ {
5672
return WriteIntelliJConfig(fsys)
5773
}
5874
return nil
@@ -142,7 +158,7 @@ func WriteVscodeConfig(fsys afero.Fs) error {
142158
return err
143159
}
144160
fmt.Println("Generated VS Code settings in " + utils.Bold(settingsPath) + ".")
145-
fmt.Println("Please install the Deno extension for VS Code: " + utils.Aqua("https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno"))
161+
fmt.Println("Please install the Deno extension for VS Code: " + utils.Bold("https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno"))
146162
return nil
147163
}
148164

@@ -151,6 +167,6 @@ func WriteIntelliJConfig(fsys afero.Fs) error {
151167
return err
152168
}
153169
fmt.Println("Generated IntelliJ settings in " + utils.Bold(denoPath) + ".")
154-
fmt.Println("Please install the Deno plugin for IntelliJ: " + utils.Aqua("https://plugins.jetbrains.com/plugin/14382-deno"))
170+
fmt.Println("Please install the Deno plugin for IntelliJ: " + utils.Bold("https://plugins.jetbrains.com/plugin/14382-deno"))
155171
return nil
156172
}

internal/init/init_test.go

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package init
22

33
import (
4+
"context"
45
"encoding/json"
56
"os"
67
"testing"
@@ -10,16 +11,15 @@ import (
1011
"github.com/stretchr/testify/require"
1112
"github.com/supabase/cli/internal/testing/fstest"
1213
"github.com/supabase/cli/internal/utils"
13-
"github.com/supabase/cli/pkg/cast"
1414
)
1515

1616
func TestInitCommand(t *testing.T) {
1717
t.Run("creates config file", func(t *testing.T) {
1818
// Setup in-memory fs
1919
fsys := &afero.MemMapFs{}
2020
require.NoError(t, fsys.Mkdir(".git", 0755))
21-
// Run test
22-
assert.NoError(t, Run(fsys, nil, nil, utils.InitParams{}))
21+
// Run test (non-interactive mode)
22+
assert.NoError(t, Run(context.Background(), fsys, false, utils.InitParams{}))
2323
// Validate generated config.toml
2424
exists, err := afero.Exists(fsys, utils.ConfigPath)
2525
assert.NoError(t, err)
@@ -47,14 +47,14 @@ func TestInitCommand(t *testing.T) {
4747
_, err := fsys.Create(utils.ConfigPath)
4848
require.NoError(t, err)
4949
// Run test
50-
assert.Error(t, Run(fsys, nil, nil, utils.InitParams{}))
50+
assert.Error(t, Run(context.Background(), fsys, false, utils.InitParams{}))
5151
})
5252

5353
t.Run("throws error on permission denied", func(t *testing.T) {
5454
// Setup in-memory fs
5555
fsys := &fstest.OpenErrorFs{DenyPath: utils.ConfigPath}
5656
// Run test
57-
err := Run(fsys, nil, nil, utils.InitParams{})
57+
err := Run(context.Background(), fsys, false, utils.InitParams{})
5858
// Check error
5959
assert.ErrorIs(t, err, os.ErrPermission)
6060
})
@@ -63,57 +63,7 @@ func TestInitCommand(t *testing.T) {
6363
// Setup read-only fs
6464
fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
6565
// Run test
66-
assert.Error(t, Run(fsys, nil, nil, utils.InitParams{}))
67-
})
68-
69-
t.Run("creates vscode settings file", func(t *testing.T) {
70-
// Setup in-memory fs
71-
fsys := &afero.MemMapFs{}
72-
// Run test
73-
assert.NoError(t, Run(fsys, cast.Ptr(true), nil, utils.InitParams{}))
74-
// Validate generated vscode settings
75-
exists, err := afero.Exists(fsys, settingsPath)
76-
assert.NoError(t, err)
77-
assert.True(t, exists)
78-
exists, err = afero.Exists(fsys, extensionsPath)
79-
assert.NoError(t, err)
80-
assert.True(t, exists)
81-
})
82-
83-
t.Run("does not create vscode settings file", func(t *testing.T) {
84-
// Setup in-memory fs
85-
fsys := &afero.MemMapFs{}
86-
// Run test
87-
assert.NoError(t, Run(fsys, cast.Ptr(false), nil, utils.InitParams{}))
88-
// Validate vscode settings file isn't generated
89-
exists, err := afero.Exists(fsys, settingsPath)
90-
assert.NoError(t, err)
91-
assert.False(t, exists)
92-
exists, err = afero.Exists(fsys, extensionsPath)
93-
assert.NoError(t, err)
94-
assert.False(t, exists)
95-
})
96-
97-
t.Run("creates intellij deno file", func(t *testing.T) {
98-
// Setup in-memory fs
99-
fsys := &afero.MemMapFs{}
100-
// Run test
101-
assert.NoError(t, Run(fsys, nil, cast.Ptr(true), utils.InitParams{}))
102-
// Validate generated intellij deno config
103-
exists, err := afero.Exists(fsys, denoPath)
104-
assert.NoError(t, err)
105-
assert.True(t, exists)
106-
})
107-
108-
t.Run("does not create intellij deno file", func(t *testing.T) {
109-
// Setup in-memory fs
110-
fsys := &afero.MemMapFs{}
111-
// Run test
112-
assert.NoError(t, Run(fsys, nil, cast.Ptr(false), utils.InitParams{}))
113-
// Validate intellij deno config file isn't generated
114-
exists, err := afero.Exists(fsys, denoPath)
115-
assert.NoError(t, err)
116-
assert.False(t, exists)
66+
assert.Error(t, Run(context.Background(), fsys, false, utils.InitParams{}))
11767
})
11868
}
11969

0 commit comments

Comments
 (0)