diff --git a/internal/functions/new/new.go b/internal/functions/new/new.go index 67a9893e2..f41097cfd 100644 --- a/internal/functions/new/new.go +++ b/internal/functions/new/new.go @@ -21,8 +21,11 @@ var ( denoEmbed string //go:embed templates/.npmrc npmrcEmbed string + //go:embed templates/config.toml + configEmbed string - indexTemplate = template.Must(template.New("index").Parse(indexEmbed)) + indexTemplate = template.Must(template.New("index").Parse(indexEmbed)) + configTemplate = template.Must(template.New("config").Parse(configEmbed)) ) type indexConfig struct { @@ -32,49 +35,63 @@ type indexConfig struct { func Run(ctx context.Context, slug string, fsys afero.Fs) error { // 1. Sanity checks. - funcDir := filepath.Join(utils.FunctionsDir, slug) - { - if err := utils.ValidateFunctionSlug(slug); err != nil { - return err - } + if err := utils.ValidateFunctionSlug(slug); err != nil { + return err } - // 2. Create new function. - { - if err := utils.MkdirIfNotExistFS(fsys, funcDir); err != nil { - return err - } - - // Load config if available - if err := flags.LoadConfig(fsys); err != nil { - utils.CmdSuggestion = "" - } - - if err := createTemplateFile(fsys, filepath.Join(funcDir, "index.ts"), indexTemplate, indexConfig{ - URL: utils.GetApiUrl("/functions/v1/" + slug), - Token: utils.Config.Auth.AnonKey, - }); err != nil { - return errors.Errorf("failed to create function entrypoint: %w", err) - } - - if err := afero.WriteFile(fsys, filepath.Join(funcDir, "deno.json"), []byte(denoEmbed), 0644); err != nil { - return errors.Errorf("failed to create deno.json config: %w", err) - } - - if err := afero.WriteFile(fsys, filepath.Join(funcDir, ".npmrc"), []byte(npmrcEmbed), 0644); err != nil { - return errors.Errorf("failed to create .npmrc config: %w", err) - } + funcDir := filepath.Join(utils.FunctionsDir, slug) + if err := utils.MkdirIfNotExistFS(fsys, funcDir); err != nil { + return err + } + // Load config if available + if err := flags.LoadConfig(fsys); err != nil { + utils.CmdSuggestion = "" + } + if err := createEntrypointFile(slug, fsys); err != nil { + return err + } + if err := appendConfigFile(slug, fsys); err != nil { + return err + } + // 3. Create optional files + if err := afero.WriteFile(fsys, filepath.Join(funcDir, "deno.json"), []byte(denoEmbed), 0644); err != nil { + return errors.Errorf("failed to create deno.json config: %w", err) + } + if err := afero.WriteFile(fsys, filepath.Join(funcDir, ".npmrc"), []byte(npmrcEmbed), 0644); err != nil { + return errors.Errorf("failed to create .npmrc config: %w", err) } - fmt.Println("Created new Function at " + utils.Bold(funcDir)) return nil } -func createTemplateFile(fsys afero.Fs, path string, tmpl *template.Template, data interface{}) error { - f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) +func createEntrypointFile(slug string, fsys afero.Fs) error { + entrypointPath := filepath.Join(utils.FunctionsDir, slug, "index.ts") + f, err := fsys.OpenFile(entrypointPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) if err != nil { - return err + return errors.Errorf("failed to create entrypoint: %w", err) + } + defer f.Close() + if err := indexTemplate.Option("missingkey=error").Execute(f, indexConfig{ + URL: utils.GetApiUrl("/functions/v1/" + slug), + Token: utils.Config.Auth.AnonKey, + }); err != nil { + return errors.Errorf("failed to write entrypoint: %w", err) + } + return nil +} + +func appendConfigFile(slug string, fsys afero.Fs) error { + if _, exists := utils.Config.Functions[slug]; exists { + fmt.Fprintf(os.Stderr, "[functions.%s] is already declared in %s\n", slug, utils.Bold(utils.ConfigPath)) + return nil + } + f, err := fsys.OpenFile(utils.ConfigPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + if err != nil { + return errors.Errorf("failed to append config: %w", err) } defer f.Close() - return tmpl.Option("missingkey=error").Execute(f, data) + if err := configTemplate.Option("missingkey=error").Execute(f, slug); err != nil { + return errors.Errorf("failed to append template: %w", err) + } + return nil } diff --git a/internal/functions/new/new_test.go b/internal/functions/new/new_test.go index 8e00fa656..df082d0d0 100644 --- a/internal/functions/new/new_test.go +++ b/internal/functions/new/new_test.go @@ -25,6 +25,10 @@ func TestNewCommand(t *testing.T) { "curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/test-func'", ) + // Verify config.toml is updated + _, err = afero.ReadFile(fsys, utils.ConfigPath) + assert.NoError(t, err, "config.toml should be created") + // Verify deno.json exists denoPath := filepath.Join(utils.FunctionsDir, "test-func", "deno.json") _, err = afero.ReadFile(fsys, denoPath) diff --git a/internal/functions/new/templates/config.toml b/internal/functions/new/templates/config.toml new file mode 100644 index 000000000..9b3b19709 --- /dev/null +++ b/internal/functions/new/templates/config.toml @@ -0,0 +1,11 @@ + +[functions.{{ . }}] +enabled = true +verify_jwt = true +import_map = "./functions/{{ . }}/deno.json" +# Uncomment to specify a custom file path to the entrypoint. +# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx +entrypoint = "./functions/{{ . }}/index.ts" +# Specifies static files to be bundled with the function. Supports glob patterns. +# For example, if you want to serve static HTML pages in your function: +# static_files = [ "./functions/{{ . }}/*.html" ] diff --git a/pkg/config/templates/config.toml b/pkg/config/templates/config.toml index 842be7128..8e84899a2 100644 --- a/pkg/config/templates/config.toml +++ b/pkg/config/templates/config.toml @@ -263,18 +263,6 @@ policy = "oneshot" # Port to attach the Chrome inspector for debugging edge functions. inspector_port = 8083 -# Use these configurations to customize your Edge Function. -# [functions.MY_FUNCTION_NAME] -# enabled = true -# verify_jwt = true -# import_map = "./functions/MY_FUNCTION_NAME/deno.json" -# Uncomment to specify a custom file path to the entrypoint. -# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx -# entrypoint = "./functions/MY_FUNCTION_NAME/index.ts" -# Specifies static files to be bundled with the function. Supports glob patterns. -# For example, if you want to serve static HTML pages in your function: -# static_files = [ "./functions/MY_FUNCTION_NAME/*.html" ] - [analytics] enabled = true port = 54327