diff --git a/cmd/internal/migrations/v3/filesystem_middleware.go b/cmd/internal/migrations/v3/filesystem_middleware.go index a8c502f..79e7373 100644 --- a/cmd/internal/migrations/v3/filesystem_middleware.go +++ b/cmd/internal/migrations/v3/filesystem_middleware.go @@ -11,6 +11,14 @@ import ( "github.com/gofiber/cli/cmd/internal" ) +var ( + reFilesystemNew = regexp.MustCompile(`filesystem\.New\s*\(`) + reFilesystemRootHTTP = regexp.MustCompile(`Root:\s*http.Dir\(([^)]+)\)`) + reFilesystemRoot = regexp.MustCompile(`Root:\s*([^,\n]+)`) + reFilesystemIndex = regexp.MustCompile(`Index:\s*([^,\n]+)`) + reFilesystemNotFoundFile = regexp.MustCompile(`(?m)^(\s*)(NotFoundFile:\s*[^,\n]+)(,?)`) +) + func MigrateFilesystemMiddleware(cmd *cobra.Command, cwd string, _, _ *semver.Version) error { changed, err := internal.ChangeFileContent(cwd, func(content string) string { content = strings.ReplaceAll(content, @@ -20,19 +28,23 @@ func MigrateFilesystemMiddleware(cmd *cobra.Command, cwd string, _, _ *semver.Ve "github.com/gofiber/fiber/v3/middleware/filesystem", "github.com/gofiber/fiber/v3/middleware/static") - reNew := regexp.MustCompile(`filesystem\.New\s*\(`) - content = reNew.ReplaceAllString(content, `static.New("", `) + content = reFilesystemNew.ReplaceAllString(content, `static.New("", `) content = strings.ReplaceAll(content, "filesystem.Config{", "static.Config{") - reRootHTTP := regexp.MustCompile(`Root:\s*http.Dir\(([^)]+)\)`) - content = reRootHTTP.ReplaceAllString(content, `FS: os.DirFS($1)`) + content = reFilesystemRootHTTP.ReplaceAllString(content, `FS: os.DirFS($1)`) + + content = reFilesystemRoot.ReplaceAllString(content, `FS: os.DirFS($1)`) - reRoot := regexp.MustCompile(`Root:\s*([^,\n]+)`) - content = reRoot.ReplaceAllString(content, `FS: os.DirFS($1)`) + content = reFilesystemIndex.ReplaceAllString(content, `IndexNames: []string{$1}`) - reIndex := regexp.MustCompile(`Index:\s*([^,\n]+)`) - content = reIndex.ReplaceAllString(content, `IndexNames: []string{$1}`) + // Handle NotFoundFile migration - comment it out and add TODO for NotFoundHandler + // Only migrate if not already migrated (check for TODO comment) + if !strings.Contains(content, "TODO: Migrate to NotFoundHandler") { + content = reFilesystemNotFoundFile.ReplaceAllString(content, + `$1// TODO: Migrate to NotFoundHandler (fiber.Handler) - NotFoundFile is deprecated +$1// $2$3`) + } return content }) diff --git a/cmd/internal/migrations/v3/filesystem_middleware_test.go b/cmd/internal/migrations/v3/filesystem_middleware_test.go index 9a47c38..6b649db 100644 --- a/cmd/internal/migrations/v3/filesystem_middleware_test.go +++ b/cmd/internal/migrations/v3/filesystem_middleware_test.go @@ -3,6 +3,7 @@ package v3_test import ( "bytes" "os" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -40,3 +41,79 @@ func main() { assert.Contains(t, content, `IndexNames: []string{"index.html"}`) assert.Contains(t, buf.String(), "Migrating filesystem middleware") } + +func Test_MigrateFilesystemMiddleware_WithNotFoundFile(t *testing.T) { + t.Parallel() + + dir, err := os.MkdirTemp("", "mfs-notfound") + require.NoError(t, err) + defer func() { require.NoError(t, os.RemoveAll(dir)) }() + + file := writeTempFile(t, dir, `package main +import ( + "github.com/gofiber/fiber/v2/middleware/filesystem" + "net/http" +) +func main() { + app.All("/*", filesystem.New(filesystem.Config{ + Root: http.Dir("./dist"), + NotFoundFile: "index.html", + Index: "index.html", + })) +}`) + + var buf bytes.Buffer + cmd := newCmd(&buf) + require.NoError(t, v3.MigrateFilesystemMiddleware(cmd, dir, nil, nil)) + + content := readFile(t, file) + // Check that NotFoundFile is commented out + assert.Contains(t, content, "// NotFoundFile: \"index.html\"") + // Check that TODO comment is added + assert.Contains(t, content, "// TODO: Migrate to NotFoundHandler (fiber.Handler) - NotFoundFile is deprecated") + // Check that static migration happened + assert.Contains(t, content, `static.New("", static.Config{`) + assert.Contains(t, content, `FS: os.DirFS("./dist")`) + assert.Contains(t, content, `IndexNames: []string{"index.html"}`) +} + +func Test_MigrateFilesystemMiddleware_NotFoundFileIdempotent(t *testing.T) { + t.Parallel() + + dir, err := os.MkdirTemp("", "mfs-idempotent") + require.NoError(t, err) + defer func() { require.NoError(t, os.RemoveAll(dir)) }() + + file := writeTempFile(t, dir, `package main +import ( + "github.com/gofiber/fiber/v2/middleware/filesystem" + "net/http" +) +func main() { + app.All("/*", filesystem.New(filesystem.Config{ + Root: http.Dir("./dist"), + NotFoundFile: "index.html", + Index: "index.html", + })) +}`) + + var buf bytes.Buffer + cmd := newCmd(&buf) + + // First migration + require.NoError(t, v3.MigrateFilesystemMiddleware(cmd, dir, nil, nil)) + firstContent := readFile(t, file) + + // Second migration - should be idempotent + buf.Reset() + require.NoError(t, v3.MigrateFilesystemMiddleware(cmd, dir, nil, nil)) + secondContent := readFile(t, file) + + // Content should be exactly the same after second migration + assert.Equal(t, firstContent, secondContent, "Migration should be idempotent") + + // Verify the TODO comment is only present once + assert.Equal(t, 1, strings.Count(secondContent, "TODO: Migrate to NotFoundHandler")) + // Verify the NotFoundFile comment is only present once + assert.Equal(t, 1, strings.Count(secondContent, "// NotFoundFile:")) +}