diff --git a/cmd/internal/migrations/v3/common.go b/cmd/internal/migrations/v3/common.go index b87be89..28fc9dc 100644 --- a/cmd/internal/migrations/v3/common.go +++ b/cmd/internal/migrations/v3/common.go @@ -291,6 +291,8 @@ func extractCall(src string, start int) (int, string) { // the opening delimiter at the start position. Start must point to the first // character after the opening delimiter. It handles nested delimiters and // quoted strings. +// +//nolint:unparam // keep open for potential future delimiters func extractBlock(src string, start int, open, closeDelim byte) int { depth := 1 inStr := false diff --git a/cmd/internal/migrations/v3/config_listener_fields.go b/cmd/internal/migrations/v3/config_listener_fields.go index 1951b65..c6dd888 100644 --- a/cmd/internal/migrations/v3/config_listener_fields.go +++ b/cmd/internal/migrations/v3/config_listener_fields.go @@ -19,8 +19,9 @@ func MigrateConfigListenerFields(cmd *cobra.Command, cwd string, _, _ *semver.Ve reField := regexp.MustCompile(`\s*(Prefork|Network|DisableStartupMessage|EnablePrintRoutes):\s*([^,}]+),?\s*(//[^\n]*)?`) changed1, err := internal.ChangeFileContent(cwd, func(content string) string { - reConfig := regexp.MustCompile(`fiber\.Config\{[^}]*\}`) - return reConfig.ReplaceAllStringFunc(content, func(cfg string) string { + reConfigStart := regexp.MustCompile(`fiber\.Config{`) + + process := func(cfg string) string { inner := cfg[len("fiber.Config{") : len(cfg)-1] inner = reField.ReplaceAllStringFunc(inner, func(f string) string { sub := reField.FindStringSubmatch(f) @@ -63,7 +64,25 @@ func MigrateConfigListenerFields(cmd *cobra.Command, cwd string, _, _ *semver.Ve } inner = strings.TrimSuffix(inner, ",") return "fiber.Config{" + inner + "}" - }) + } + + var b strings.Builder + last := 0 + for _, loc := range reConfigStart.FindAllStringIndex(content, -1) { + b.WriteString(content[last:loc[0]]) //nolint:errcheck // WriteString never returns an error + start := loc[1] + end := extractBlock(content, start, '{', '}') + if end > start { + cfg := content[loc[0]:end] + b.WriteString(process(cfg)) //nolint:errcheck // WriteString never returns an error + last = end + } else { + b.WriteString(content[loc[0]:loc[1]]) //nolint:errcheck // WriteString never returns an error + last = loc[1] + } + } + b.WriteString(content[last:]) //nolint:errcheck // WriteString never returns an error + return b.String() }) if err != nil { return fmt.Errorf("failed to migrate listener related config fields: %w", err) diff --git a/cmd/internal/migrations/v3/config_listener_fields_test.go b/cmd/internal/migrations/v3/config_listener_fields_test.go index b1cf8c8..7219d21 100644 --- a/cmd/internal/migrations/v3/config_listener_fields_test.go +++ b/cmd/internal/migrations/v3/config_listener_fields_test.go @@ -283,3 +283,50 @@ func main() { assert.Contains(t, content, `app.Listen(":3000", fiber.ListenConfig{EnablePrefork: prod})`) assert.Contains(t, buf.String(), "Migrating listener related config fields") } + +func Test_MigrateConfigListenerFields_WithErrorHandler(t *testing.T) { + t.Parallel() + + dir, err := os.MkdirTemp("", "mconf_errhandler") + require.NoError(t, err) + defer func() { require.NoError(t, os.RemoveAll(dir)) }() + + file1 := filepath.Join(dir, "app.go") + require.NoError(t, os.WriteFile(file1, []byte(`package main +import ( + "github.com/gofiber/fiber/v2" + "net/http" +) +func newApp() *fiber.App { + var timesHandlingError int + return fiber.New(fiber.Config{ + ErrorHandler: func(ctx *fiber.Ctx, err error) error { + timesHandlingError++ + if err != nil { + return fiber.NewError(http.StatusInternalServerError, err.Error()) + } + return nil + }, + Prefork: true, + }) +}`), 0o600)) + + file2 := filepath.Join(dir, "main.go") + require.NoError(t, os.WriteFile(file2, []byte(`package main +func main() { + app := newApp() + app.Listen(":3000") +}`), 0o600)) + + var buf bytes.Buffer + cmd := newCmd(&buf) + require.NoError(t, v3.MigrateConfigListenerFields(cmd, dir, nil, nil)) + + content1 := readFile(t, file1) + assert.Contains(t, content1, "ErrorHandler: func(ctx *fiber.Ctx, err error) error {") + assert.NotContains(t, content1, "Prefork:") + + content2 := readFile(t, file2) + assert.Contains(t, content2, `app.Listen(":3000", fiber.ListenConfig{EnablePrefork: true})`) + assert.Contains(t, buf.String(), "Migrating listener related config fields") +}