Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: append config.toml when creating new function #3212

Merged
merged 3 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 53 additions & 36 deletions internal/functions/new/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
4 changes: 4 additions & 0 deletions internal/functions/new/new_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions internal/functions/new/templates/config.toml
Original file line number Diff line number Diff line change
@@ -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" ]
12 changes: 0 additions & 12 deletions pkg/config/templates/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down