Skip to content

Commit

Permalink
add command for migration purpose
Browse files Browse the repository at this point in the history
  • Loading branch information
ReneWerner87 committed Apr 21, 2024
1 parent 057bbd9 commit 29b596d
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 38 deletions.
41 changes: 41 additions & 0 deletions cmd/internal/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package internal

import (
"fmt"
"os"
"path/filepath"
"strings"

tea "github.com/charmbracelet/bubbletea"
"github.com/containerd/console"
Expand All @@ -27,3 +30,41 @@ func errCmd(err error) tea.Cmd {
return finishedMsg{err}
}
}

type FileProcessor func(content string) string

func ChangeFileContent(cwd string, processorFn FileProcessor) error {
// change go files in project
err := filepath.Walk(cwd, func(path string, info os.FileInfo, err error) error {
if err != nil {
//fmt.Printf("Error while traversing %s: %v\n", path, err)
return err
}

// Skip directories named "vendor"
if info.IsDir() && info.Name() == "vendor" {
//fmt.Printf("Skipping directory: %s\n", path)
return filepath.SkipDir
}

// Check if the file is a Go file (ending with ".go")
if info.IsDir() || !strings.HasSuffix(info.Name(), ".go") {
return nil
}
//fmt.Printf("Processing Go file: %s\n", path)
fileContent, err := os.ReadFile(path)

// update go.mod file
if err2 := os.WriteFile(path, []byte(processorFn(string(fileContent))), 0644); err != nil {
return err2
}

return nil
})

if err != nil {
return fmt.Errorf("Error while traversing the directory tree: %v\n", err)
}

return nil
}
53 changes: 53 additions & 0 deletions cmd/internal/migrations/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package migrations

import (
"fmt"
"github.com/Masterminds/semver/v3"

Check failure on line 5 in cmd/internal/migrations/common.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] cmd/internal/migrations/common.go#L5

"github.com/Masterminds/semver/v3" imported but not used (typecheck)
Raw output
cmd/internal/migrations/common.go:5:2: "github.com/Masterminds/semver/v3" imported but not used (typecheck)
	"github.com/Masterminds/semver/v3"
	^
"github.com/spf13/cobra"
"os"
"regexp"
"strconv"
"strings"

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

var (
pkgRegex = regexp.MustCompile(`(github\.com\/gofiber\/fiber\/)(v\d+)( *?)(v[\w.-]+)`)
)

func MigrateGoPkgs(cmd *cobra.Command, cwd string, curr *semver.Version, target *semver.Version) error {

Check failure on line 19 in cmd/internal/migrations/common.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] cmd/internal/migrations/common.go#L19

undeclared name: `semver` (typecheck)
Raw output
cmd/internal/migrations/common.go:19:58: undeclared name: `semver` (typecheck)
func MigrateGoPkgs(cmd *cobra.Command, cwd string, curr *semver.Version, target *semver.Version) error {
                                                         ^
pkgReplacer := strings.NewReplacer(
"github.com/gofiber/fiber/v"+strconv.FormatUint(curr.Major(), 10),
"github.com/gofiber/fiber/v"+strconv.FormatUint(target.Major(), 10),
)

err := internal.ChangeFileContent(cwd, func(content string) string {
return pkgReplacer.Replace(content)
})
if err != nil {
return fmt.Errorf("failed to migrate Go packages: %v", err)
}

// get go.mod file
modFile := "go.mod"
fileContent, err := os.ReadFile(modFile)
if err != nil {
return err
}

// replace old version with new version in go.mod file
fileContentStr := pkgRegex.ReplaceAllString(
string(fileContent),
"${1}v"+strconv.FormatUint(target.Major(), 10)+"${3}v"+target.String(),
)

// update go.mod file
if err := os.WriteFile(modFile, []byte(fileContentStr), 0644); err != nil {
return err
}

cmd.Println("Migrating Go packages")

return nil
}
54 changes: 54 additions & 0 deletions cmd/internal/migrations/lists.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package migrations

import (
"fmt"
"github.com/Masterminds/semver/v3"

Check failure on line 5 in cmd/internal/migrations/lists.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] cmd/internal/migrations/lists.go#L5

other declaration of v3 (typecheck)
Raw output
cmd/internal/migrations/lists.go:5:2: other declaration of v3 (typecheck)
	"github.com/Masterminds/semver/v3"
	^
"github.com/spf13/cobra"

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

Check failure on line 8 in cmd/internal/migrations/lists.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] cmd/internal/migrations/lists.go#L8

`v3` redeclared in this block (typecheck)
Raw output
cmd/internal/migrations/lists.go:8:2: `v3` redeclared in this block (typecheck)
	"github.com/gofiber/cli/cmd/internal/migrations/v3"
	^
)

// MigrationFn is a function that will be called during migration
type MigrationFn func(cmd *cobra.Command, cwd string, curr *semver.Version, target *semver.Version) error

Check failure on line 12 in cmd/internal/migrations/lists.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] cmd/internal/migrations/lists.go#L12

undeclared name: `semver` (typecheck)
Raw output
cmd/internal/migrations/lists.go:12:61: undeclared name: `semver` (typecheck)
type MigrationFn func(cmd *cobra.Command, cwd string, curr *semver.Version, target *semver.Version) error
                                                            ^

// Migration is a single migration
type Migration struct {
From string
To string
Functions []MigrationFn
}

// Migrations is a list of all migrations
// Example structure:
// {"from": ">=2.0.0", "to": "<=3.*.*", "fn": [MigrateFN, MigrateFN]}
var Migrations = []Migration{
{From: ">=2.0.0", To: "<4.0.0-0", Functions: []MigrationFn{v3.MigrateHandlerSignatures}},
{From: ">=1.0.0", To: ">=0.0.0-0", Functions: []MigrationFn{MigrateGoPkgs}},
}

// DoMigration runs all migrations
// It will run all migrations that match the current and target version
func DoMigration(cmd *cobra.Command, cwd string, curr *semver.Version, target *semver.Version) error {
for _, m := range Migrations {
toC, err := semver.NewConstraint(m.To)
if err != nil {
return err
}
fromC, err := semver.NewConstraint(m.From)
if err != nil {
return err
}

if fromC.Check(curr) && toC.Check(target) {
for _, fn := range m.Functions {
if err := fn(cmd, cwd, curr, target); err != nil {
return err
}
}
} else {
fmt.Printf("Skipping migration from %s to %s\n", m.From, m.To)
}
}

return nil
}
25 changes: 25 additions & 0 deletions cmd/internal/migrations/v3/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package v3

import (
"fmt"
"github.com/Masterminds/semver/v3"

Check failure on line 5 in cmd/internal/migrations/v3/common.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] cmd/internal/migrations/v3/common.go#L5

"github.com/Masterminds/semver/v3" imported but not used (typecheck)
Raw output
cmd/internal/migrations/v3/common.go:5:2: "github.com/Masterminds/semver/v3" imported but not used (typecheck)
	"github.com/Masterminds/semver/v3"
	^
"github.com/spf13/cobra"
"strings"

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

func MigrateHandlerSignatures(cmd *cobra.Command, cwd string, _ *semver.Version, _ *semver.Version) error {

Check failure on line 12 in cmd/internal/migrations/v3/common.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] cmd/internal/migrations/v3/common.go#L12

undeclared name: `semver` (typecheck)
Raw output
cmd/internal/migrations/v3/common.go:12:66: undeclared name: `semver` (typecheck)
func MigrateHandlerSignatures(cmd *cobra.Command, cwd string, _ *semver.Version, _ *semver.Version) error {
                                                                 ^
sigReplacer := strings.NewReplacer("*fiber.Ctx", "fiber.Ctx")

err := internal.ChangeFileContent(cwd, func(content string) string {
return sigReplacer.Replace(content)
})
if err != nil {
return fmt.Errorf("failed to migrate handler signatures: %v", err)
}

cmd.Println("Migrating handler signatures")

return nil
}
69 changes: 38 additions & 31 deletions cmd/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,63 @@ package cmd

import (
"fmt"
"os"

"github.com/gofiber/cli/cmd/internal"
"github.com/Masterminds/semver/v3"

Check failure on line 5 in cmd/migrate.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] cmd/migrate.go#L5

"github.com/Masterminds/semver/v3" imported but not used (typecheck)
Raw output
cmd/migrate.go:5:2: "github.com/Masterminds/semver/v3" imported but not used (typecheck)
	"github.com/Masterminds/semver/v3"
	^
"github.com/gofiber/cli/cmd/internal/migrations"
"github.com/muesli/termenv"
"github.com/spf13/cobra"
"os"
"strings"
)

var (
targetVersionS string
latestFiberVersion string
)

func init() {
latestFiberVersion, _ := latestVersion(false)

migrateCmd.Flags().StringVarP(&targetVersionS, "to", "t", "", "Migrate to a specific version e.g: "+latestFiberVersion+" Format: X.Y.Z")
migrateCmd.MarkFlagRequired("to")
}

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

var migrated bool

// TODO: fetch current version from go.mod
// TODO: use the --to flag to specify the version to migrate
// TODO: build migration scripts in a separate folder

func migrateRunE(cmd *cobra.Command, _ []string) error {
cliLatestVersion, err := latestVersion(true)
currentVersionS, err := currentVersion()
if err != nil {
return err
return fmt.Errorf("current fiber project version not found: %v", err)
}
currentVersionS = strings.TrimPrefix(currentVersionS, "v")
currentVersion := semver.MustParse(currentVersionS)

if version != cliLatestVersion {
migrate(cmd, cliLatestVersion)
} else {
msg := fmt.Sprintf("Currently Fiber cli is the latest version %s.", cliLatestVersion)
cmd.Println(termenv.String(msg).
Foreground(termenv.ANSIBrightBlue))
targetVersionS = strings.TrimPrefix(targetVersionS, "v")
targetVersion, err := semver.NewVersion(targetVersionS)
if err != nil {
return fmt.Errorf("invalid version for \"%s\": %v", targetVersionS, err)
}

return nil
}

func migrate(cmd *cobra.Command, cliLatestVersion string) {
migrater := execCommand("go", "get", "-u", "-v", "github.com/gofiber/cli/fiber")
migrater.Env = append(migrater.Env, os.Environ()...)
migrater.Env = append(migrater.Env, "GO111MODULE=off")
if !targetVersion.GreaterThan(currentVersion) {
return fmt.Errorf("target version v%s is not greater than current version v%s", targetVersionS, currentVersionS)
}

scmd := internal.NewSpinnerCmd(migrater, "Upgrading")
wd, err := os.Getwd()
if err != nil {
return fmt.Errorf("cannot get current working directory: %v", err)
}

if err := scmd.Run(); err != nil && !skipSpinner {
cmd.Printf("fiber: failed to migrate: %v", err)
return
err = migrations.DoMigration(cmd, wd, currentVersion, targetVersion)
if err != nil {
return fmt.Errorf("migration failed %v", err)
}

success := fmt.Sprintf("Done! Fiber cli is now at v%s!", cliLatestVersion)
cmd.Println(termenv.String(success).Foreground(termenv.ANSIBrightGreen))
msg := fmt.Sprintf("Migration from Fiber %s to %s", currentVersionS, targetVersionS)
cmd.Println(termenv.String(msg).
Foreground(termenv.ANSIBrightBlue))

migrated = true
return nil
}
7 changes: 4 additions & 3 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package cmd
import (
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"os"
"regexp"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -39,7 +40,7 @@ var currentVersionRegexp = regexp.MustCompile(`github\.com/gofiber/fiber[^\n]*?
var currentVersionFile = "go.mod"

func currentVersion() (string, error) {
b, err := ioutil.ReadFile(currentVersionFile)
b, err := os.ReadFile(currentVersionFile)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -73,7 +74,7 @@ func latestVersion(isCli bool) (v string, err error) {
_ = res.Body.Close()
}()

if b, err = ioutil.ReadAll(res.Body); err != nil {
if b, err = io.ReadAll(res.Body); err != nil {
return
}

Expand Down
8 changes: 4 additions & 4 deletions development.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Local Development

Install [reflex](github.com/cespare/reflex)
Install [air](github.com/cosmtrek/air)
```bash
go install github.com/cespare/reflex@latest
go install github.com/cosmtrek/air@latest
```

Use reflex to watch for changes in the project and recompile the binary
Use air to watch for changes in the project and recompile the binary
```bash
reflex -r '\.go$' -- go install ./fiber
air --build.cmd="go install ./fiber"
```

Test the binary in fiber project
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/gofiber/cli
go 1.21

require (
github.com/Masterminds/semver/v3 v3.2.1
github.com/charmbracelet/bubbles v0.18.0
github.com/charmbracelet/bubbletea v0.25.0
github.com/containerd/console v1.0.4
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
Expand Down

0 comments on commit 29b596d

Please sign in to comment.