Skip to content
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
3 changes: 1 addition & 2 deletions cmd/internal/migrations/lists.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ var Migrations = []Migration{
To: "<4.0.0-0",
Functions: []MigrationFn{
v3migrations.MigrateHandlerSignatures,
v3migrations.MigrateViewBind,
v3migrations.MigrateParserMethods,
v3migrations.MigrateAllParams,
v3migrations.MigrateRedirectMethods,
v3migrations.MigrateGenericHelpers,
v3migrations.MigrateAddMethod,
Expand All @@ -43,7 +43,6 @@ var Migrations = []Migration{
v3migrations.MigrateListenerCallbacks,
v3migrations.MigrateListenMethods,
v3migrations.MigrateContextMethods,
v3migrations.MigrateViewBind,
v3migrations.MigrateCORSConfig,
v3migrations.MigrateCSRFConfig,
v3migrations.MigrateMonitorImport,
Expand Down
70 changes: 23 additions & 47 deletions cmd/internal/migrations/v3/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,14 @@ func MigrateRedirectMethods(cmd *cobra.Command, cwd string, _, _ *semver.Version

// MigrateGenericHelpers migrates helper functions that now use generics
func MigrateGenericHelpers(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
reParamsInt := regexp.MustCompile(`(\w+)\.ParamsInt\(`)
reQueryInt := regexp.MustCompile(`(\w+)\.QueryInt\(`)
reQueryFloat := regexp.MustCompile(`(\w+)\.QueryFloat\(`)
reQueryBool := regexp.MustCompile(`(\w+)\.QueryBool\(`)
err := internal.ChangeFileContent(cwd, func(content string) string {
reParamsInt := regexp.MustCompile(`(\w+)\.ParamsInt\(`)
content = reParamsInt.ReplaceAllString(content, "fiber.Params[int]($1, ")

reQueryInt := regexp.MustCompile(`(\w+)\.QueryInt\(`)
content = reQueryInt.ReplaceAllString(content, "fiber.Query[int]($1, ")

reQueryFloat := regexp.MustCompile(`(\w+)\.QueryFloat\(`)
content = reQueryFloat.ReplaceAllString(content, "fiber.Query[float64]($1, ")

reQueryBool := regexp.MustCompile(`(\w+)\.QueryBool\(`)
content = reQueryBool.ReplaceAllString(content, "fiber.Query[bool]($1, ")

return content
Expand Down Expand Up @@ -113,10 +110,11 @@ func MigrateContextMethods(cmd *cobra.Command, cwd string, _, _ *semver.Version)

// MigrateViewBind replaces the old Ctx.Bind view binding helper with ViewBind
func MigrateViewBind(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
replacer := strings.NewReplacer(".Bind(", ".ViewBind(")
// Replace .Bind() with arguments, not the Bind() from the binding package
reViewBind := regexp.MustCompile(`\.Bind\(([^)]+)\)`)

err := internal.ChangeFileContent(cwd, func(content string) string {
return replacer.Replace(content)
return reViewBind.ReplaceAllString(content, ".ViewBind($1)")
})
if err != nil {
return fmt.Errorf("failed to migrate ViewBind calls: %w", err)
Expand All @@ -126,23 +124,6 @@ func MigrateViewBind(cmd *cobra.Command, cwd string, _, _ *semver.Version) error
return nil
}

// MigrateAllParams replaces deprecated AllParams helper with the new binding API
func MigrateAllParams(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
replacer := strings.NewReplacer(
".AllParams(", ".Bind().URI(",
)

err := internal.ChangeFileContent(cwd, func(content string) string {
return replacer.Replace(content)
})
if err != nil {
return fmt.Errorf("failed to migrate AllParams: %w", err)
}

cmd.Println("Migrating AllParams")
return nil
}

// MigrateMount replaces app.Mount with app.Use
func MigrateMount(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
replacer := strings.NewReplacer(".Mount(", ".Use(")
Expand All @@ -160,8 +141,9 @@ func MigrateMount(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {

// MigrateAddMethod adapts the Add method signature
func MigrateAddMethod(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
re := regexp.MustCompile(`\.Add\(\s*([^,\n]+)\s*,`)

err := internal.ChangeFileContent(cwd, func(content string) string {
re := regexp.MustCompile(`\.Add\(\s*([^,\n]+)\s*,`)
return re.ReplaceAllString(content, ".Add([]string{$1},")
})
if err != nil {
Expand All @@ -174,6 +156,11 @@ func MigrateAddMethod(cmd *cobra.Command, cwd string, _, _ *semver.Version) erro

// MigrateCORSConfig updates cors middleware configuration fields
func MigrateCORSConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
reOrigins := regexp.MustCompile(`AllowOrigins:\s*"([^"]*)"`)
reMethods := regexp.MustCompile(`AllowMethods:\s*"([^"]*)"`)
reHeaders := regexp.MustCompile(`AllowHeaders:\s*"([^"]*)"`)
reExpose := regexp.MustCompile(`ExposeHeaders:\s*"([^"]*)"`)

err := internal.ChangeFileContent(cwd, func(content string) string {
conv := func(src string, re *regexp.Regexp, field string) string {
return re.ReplaceAllStringFunc(src, func(s string) string {
Expand All @@ -189,16 +176,9 @@ func MigrateCORSConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) err
})
}

reOrigins := regexp.MustCompile(`AllowOrigins:\s*"([^"]*)"`)
content = conv(content, reOrigins, "AllowOrigins")

reMethods := regexp.MustCompile(`AllowMethods:\s*"([^"]*)"`)
content = conv(content, reMethods, "AllowMethods")

reHeaders := regexp.MustCompile(`AllowHeaders:\s*"([^"]*)"`)
content = conv(content, reHeaders, "AllowHeaders")

reExpose := regexp.MustCompile(`ExposeHeaders:\s*"([^"]*)"`)
content = conv(content, reExpose, "ExposeHeaders")

return content
Expand All @@ -214,10 +194,9 @@ func MigrateCORSConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) err
// MigrateCSRFConfig updates csrf middleware configuration fields
func MigrateCSRFConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
replacer := strings.NewReplacer("Expiration:", "IdleTimeout:")

re := regexp.MustCompile(`\s*SessionKey:\s*[^,]+,?\n`)
err := internal.ChangeFileContent(cwd, func(content string) string {
content = replacer.Replace(content)
re := regexp.MustCompile(`\s*SessionKey:\s*[^,]+,?\n`)
return re.ReplaceAllString(content, "")
})
if err != nil {
Expand All @@ -230,10 +209,9 @@ func MigrateCSRFConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) err

// MigrateMonitorImport updates monitor middleware import path
func MigrateMonitorImport(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
re := regexp.MustCompile(`github\.com/gofiber/fiber/([^/]+)/middleware/monitor`)
err := internal.ChangeFileContent(cwd, func(content string) string {
return strings.ReplaceAll(content,
"github.com/gofiber/fiber/v2/middleware/monitor",
"github.com/gofiber/contrib/monitor")
return re.ReplaceAllString(content, "github.com/gofiber/contrib/monitor")
})
if err != nil {
return fmt.Errorf("failed to migrate monitor import: %w", err)
Expand All @@ -245,8 +223,8 @@ func MigrateMonitorImport(cmd *cobra.Command, cwd string, _, _ *semver.Version)

// MigrateProxyTLSConfig updates proxy TLS helper to new client configuration
func MigrateProxyTLSConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
re := regexp.MustCompile(`proxy\.WithTlsConfig\(([^)]+)\)`)
err := internal.ChangeFileContent(cwd, func(content string) string {
re := regexp.MustCompile(`proxy\.WithTlsConfig\(([^)]+)\)`)
return re.ReplaceAllString(content,
"proxy.WithClient(&fasthttp.Client{TLSConfig: $1})")
})
Expand Down Expand Up @@ -336,11 +314,10 @@ func MigrateStaticRoutes(cmd *cobra.Command, cwd string, _, _ *semver.Version) e

// MigrateTrustedProxyConfig updates trusted proxy configuration options
func MigrateTrustedProxyConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
reEnable := regexp.MustCompile(`EnableTrustedProxyCheck`)
reProxies := regexp.MustCompile(`TrustedProxies:\s*([^,\n]+),`)
err := internal.ChangeFileContent(cwd, func(content string) string {
reEnable := regexp.MustCompile(`EnableTrustedProxyCheck`)
content = reEnable.ReplaceAllString(content, "TrustProxy")

reProxies := regexp.MustCompile(`TrustedProxies:\s*([^,\n]+),`)
content = reProxies.ReplaceAllString(content, "TrustProxyConfig: fiber.TrustProxyConfig{Proxies: $1},")

return content
Expand Down Expand Up @@ -375,11 +352,10 @@ func MigrateConfigListenerFields(cmd *cobra.Command, cwd string, _, _ *semver.Ve
// MigrateListenerCallbacks removes deprecated OnShutdown callbacks from
// ListenerConfig. Fiber v3 replaces these with the OnPostShutdown hook.
func MigrateListenerCallbacks(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
reErr := regexp.MustCompile(`\s*OnShutdownError:\s*[^,]+,?\n`)
reSuccess := regexp.MustCompile(`\s*OnShutdownSuccess:\s*[^,]+,?\n`)
err := internal.ChangeFileContent(cwd, func(content string) string {
reErr := regexp.MustCompile(`\s*OnShutdownError:\s*[^,]+,?\n`)
content = reErr.ReplaceAllString(content, "")

reSuccess := regexp.MustCompile(`\s*OnShutdownSuccess:\s*[^,]+,?\n`)
content = reSuccess.ReplaceAllString(content, "")

return content
Expand Down Expand Up @@ -428,8 +404,8 @@ func MigrateFilesystemMiddleware(cmd *cobra.Command, cwd string, _, _ *semver.Ve

// MigrateEnvVarConfig removes deprecated ExcludeVars field from envvar middleware configuration
func MigrateEnvVarConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) error {
re := regexp.MustCompile(`\s*ExcludeVars:\s*[^,]+,?\n`)
err := internal.ChangeFileContent(cwd, func(content string) string {
re := regexp.MustCompile(`\s*ExcludeVars:\s*[^,]+,?\n`)
return re.ReplaceAllString(content, "")
})
if err != nil {
Expand Down
27 changes: 2 additions & 25 deletions cmd/internal/migrations/v3/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func handler(c fiber.Ctx) error {
c.CookieParser(&v)
c.ParamsParser(&v)
c.QueryParser(&v)
c.AllParams(&p)
return nil
}
`)
Expand Down Expand Up @@ -184,7 +185,7 @@ func Test_MigrateViewBind(t *testing.T) {
file := writeTempFile(t, dir, `package main
import "github.com/gofiber/fiber/v2"
func handler(c fiber.Ctx) error {
return c.Bind("index", fiber.Map{})
return c.Bind(fiber.Map{})
}`)

var buf bytes.Buffer
Expand All @@ -197,30 +198,6 @@ func handler(c fiber.Ctx) error {
assert.Contains(t, buf.String(), "Migrating view binding helpers")
}

func Test_MigrateAllParams(t *testing.T) {
t.Parallel()

dir, err := os.MkdirTemp("", "maptest")
require.NoError(t, err)
defer func() { require.NoError(t, os.RemoveAll(dir)) }()

file := writeTempFile(t, dir, `package main
import "github.com/gofiber/fiber/v2"
func handler(c fiber.Ctx) error {
var p any
c.AllParams(&p)
return nil
}`)

var buf bytes.Buffer
cmd := newCmd(&buf)
require.NoError(t, MigrateAllParams(cmd, dir, nil, nil))

content := readFile(t, file)
assert.Contains(t, content, ".Bind().URI(&p)")
assert.Contains(t, buf.String(), "Migrating AllParams")
}

func Test_MigrateMount(t *testing.T) {
t.Parallel()

Expand Down
32 changes: 20 additions & 12 deletions cmd/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,41 @@ import (
"strings"

"github.com/Masterminds/semver/v3"
"github.com/gofiber/cli/cmd/internal/migrations"
"github.com/muesli/termenv"
"github.com/spf13/cobra"

"github.com/gofiber/cli/cmd/internal/migrations"
)

var targetVersionS string
func newMigrateCmd(currentVersionFile string) *cobra.Command {
var targetVersionS string

cmd := &cobra.Command{
Use: "migrate",
Short: "Migrate Fiber project version to a newer version",
}

func init() {
latestFiberVersion, err := LatestFiberVersion()
if err != nil {
latestFiberVersion = ""
}

migrateCmd.Flags().StringVarP(&targetVersionS, "to", "t", "", "Migrate to a specific version e.g:"+latestFiberVersion+" Format: X.Y.Z")
if err := migrateCmd.MarkFlagRequired("to"); err != nil {
cmd.Flags().StringVarP(&targetVersionS, "to", "t", "", "Migrate to a specific version e.g:"+latestFiberVersion+" Format: X.Y.Z")
if err := cmd.MarkFlagRequired("to"); err != nil {
panic(err)
}
}

var migrateCmd = &cobra.Command{
Use: "migrate",
Short: "Migrate Fiber project version to a newer version",
RunE: migrateRunE,
cmd.RunE = func(cmd *cobra.Command, _ []string) error {
return migrateRunE(cmd, currentVersionFile, targetVersionS)
}

return cmd
}

func migrateRunE(cmd *cobra.Command, _ []string) error {
currentVersionS, err := currentVersion()
var migrateCmd = newMigrateCmd("go.mod")

func migrateRunE(cmd *cobra.Command, currentVersionFile, targetVersionS string) error {
currentVersionS, err := currentVersionFromFile(currentVersionFile)
if err != nil {
return fmt.Errorf("current fiber project version not found: %w", err)
}
Expand Down
96 changes: 96 additions & 0 deletions cmd/migrate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package cmd

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func readFileTB(tb testing.TB, path string) string {
tb.Helper()
b, err := os.ReadFile(filepath.Clean(path))
require.NoError(tb, err)
return string(b)
}

func Test_Migrate_V2_to_V3(t *testing.T) {
dir, err := os.MkdirTemp("", "migrate_v2_v3")
require.NoError(t, err)
defer func() { require.NoError(t, os.RemoveAll(dir)) }()

gomod := `module example.com/demo

go 1.20

require github.com/gofiber/fiber/v2 v2.0.6
`
require.NoError(t, os.WriteFile(filepath.Join(dir, "go.mod"), []byte(gomod), 0o600))

main := `package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/monitor"
)

func handler(c *fiber.Ctx) error {
var v any
c.BodyParser(&v)
c.RedirectBack()
_ = c.ParamsInt("id", 0)
ctx := c.Context()
uc := c.UserContext()
c.SetUserContext(uc)
_ = ctx
return c.Bind(fiber.Map{})
}

func main() {
app := fiber.New(fiber.Config{
EnableTrustedProxyCheck: true,
Prefork: true,
Network: "tcp",
})
app.Static("/", "./public")
app.Add(fiber.MethodGet, "/foo", handler)
app.Mount("/api", app)
app.ListenTLS(":443", "cert.pem", "key.pem")
_ = fiber.MIMEApplicationJavaScript
_ = monitor.New()
}
`
require.NoError(t, os.WriteFile(filepath.Join(dir, "main.go"), []byte(main), 0o600))

cwd, err := os.Getwd()
require.NoError(t, err)
require.NoError(t, os.Chdir(dir))
defer func() { require.NoError(t, os.Chdir(cwd)) }()

cmd := newMigrateCmd("go.mod")
out, err := runCobraCmd(cmd, "-t=3.0.0")
require.NoError(t, err)

content := readFileTB(t, filepath.Join(dir, "main.go"))
at := assert.New(t)
at.Contains(content, "github.com/gofiber/fiber/v3")
at.Contains(content, "github.com/gofiber/contrib/monitor")
at.NotContains(content, "*fiber.Ctx")
at.Contains(content, "fiber.Ctx")
at.Contains(content, ".Bind().Body(&v)")
at.Contains(content, ".ViewBind(fiber.Map{})")
at.Contains(content, ".Redirect().Back()")
at.Contains(content, "fiber.Params[int](c, \"id\"")
at.Contains(content, ".Use(\"/api\", app)")
at.Contains(content, ".Listen(")
at.Contains(content, "MIMETextJavaScript")
at.NotContains(content, "MIMEApplicationJavaScript")

gm := readFileTB(t, filepath.Join(dir, "go.mod"))
at.Contains(gm, "github.com/gofiber/fiber/v3 v3.0.0")

at.Contains(out, "Migration from Fiber 2.0.6 to 3.0.0")
at.Contains(out, "Migrating Go packages")
at.Contains(out, "Migrating handler signatures")
}
Loading
Loading