Skip to content

Commit

Permalink
refactor: Improve deployment process with event-based feedback and sp…
Browse files Browse the repository at this point in the history
…inner UI
  • Loading branch information
yarlson committed Nov 3, 2024
1 parent 5629f8d commit f6d35e8
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 48 deletions.
59 changes: 41 additions & 18 deletions cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"path/filepath"

"github.com/pterm/pterm"
"github.com/spf13/cobra"

"github.com/yarlson/ftl/pkg/config"
Expand Down Expand Up @@ -38,8 +39,6 @@ func runDeploy(cmd *cobra.Command, args []string) {
console.ErrPrintln("Deployment failed:", err)
return
}

console.Success("Deployment completed successfully.")
}

func parseConfig(filename string) (*config.Config, error) {
Expand Down Expand Up @@ -78,32 +77,56 @@ func deployToServer(project string, cfg *config.Config, server config.Server) er

deploy := deployment.NewDeployment(client)

var spinner *pterm.SpinnerPrinter

for event, err := range deploy.Deploy(project, cfg) {
if err != nil {
console.ErrPrintln(fmt.Sprintf("Deployment error: %v", err))
if spinner != nil {
spinner.Fail(fmt.Sprintf("Deployment error: %v", err))
} else {
console.ErrPrintln(fmt.Sprintf("Deployment error: %v", err))
}
return err
}

switch event.Type {
case "network":
console.Info(event.Message)
case "volume":
console.Info(event.Message)
case "dependency":
console.Info(event.Message)
case "service":
console.Info(event.Message)
case "proxy":
console.Info(event.Message)
case "certrenewer":
console.Info(event.Message)
case "complete":
console.Success(event.Message)
case deployment.EventTypeStart:
if spinner != nil {
spinner.Success()
}
spinner = console.NewSpinner(event.Message)
case deployment.EventTypeProgress:
if spinner != nil {
spinner.UpdateText(event.Message)
} else {
console.Info(event.Message)
}
case deployment.EventTypeFinish:
if spinner != nil {
spinner.Success(event.Message)
spinner = nil
} else {
console.Success(event.Message)
}
case deployment.EventTypeComplete:
if spinner != nil {
spinner.Success(event.Message)
} else {
console.Success(event.Message)
}
default:
console.Info(event.Message)
if spinner != nil {
spinner.UpdateText(event.Message)
} else {
console.Info(event.Message)
}
}
}

if spinner != nil {
_ = spinner.Stop()
}

return nil
}

Expand Down
58 changes: 28 additions & 30 deletions pkg/deployment/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,21 @@ type Executor interface {
CopyFile(ctx context.Context, from, to string) error
}

type DeploymentEvent struct {
Type string
type EventType string

const (
EventTypeStart EventType = "start"
EventTypeProgress EventType = "progress"
EventTypeFinish EventType = "finish"
EventTypeComplete EventType = "complete"
)

type Event struct {
Type EventType
Message string
}

type DeploymentIterator func(yield func(*DeploymentEvent, error) bool)
type Iterator func(yield func(*Event, error) bool)

type Deployment struct {
executor Executor
Expand All @@ -39,22 +48,20 @@ func NewDeployment(executor Executor) *Deployment {
return &Deployment{executor: executor}
}

func (d *Deployment) Deploy(project string, cfg *config.Config) DeploymentIterator {
return func(yield func(*DeploymentEvent, error) bool) {
// Network creation
if !yield(&DeploymentEvent{Type: "network", Message: "Creating network"}, nil) {
func (d *Deployment) Deploy(project string, cfg *config.Config) Iterator {
return func(yield func(*Event, error) bool) {
if !yield(&Event{Type: EventTypeStart, Message: "Creating network"}, nil) {
return
}
if err := d.createNetwork(project); err != nil {
yield(nil, fmt.Errorf("failed to create network: %w", err))
return
}
if !yield(&DeploymentEvent{Type: "network", Message: "Network created"}, nil) {
if !yield(&Event{Type: EventTypeFinish, Message: "Network created"}, nil) {
return
}

// Volume creation
if !yield(&DeploymentEvent{Type: "volume", Message: "Creating volumes"}, nil) {
if !yield(&Event{Type: EventTypeStart, Message: "Creating volumes"}, nil) {
return
}
for _, volume := range cfg.Volumes {
Expand All @@ -63,70 +70,61 @@ func (d *Deployment) Deploy(project string, cfg *config.Config) DeploymentIterat
return
}
}
if !yield(&DeploymentEvent{Type: "volume", Message: "Volumes created"}, nil) {
if !yield(&Event{Type: EventTypeFinish, Message: "Volumes created"}, nil) {
return
}

// Dependencies
if !yield(&DeploymentEvent{Type: "dependency", Message: "Creating dependencies"}, nil) {
if !yield(&Event{Type: EventTypeStart, Message: "Creating dependencies"}, nil) {
return
}
for _, dependency := range cfg.Dependencies {
if err := d.startDependency(project, &dependency); err != nil {
yield(nil, fmt.Errorf("failed to create dependency %s: %w", dependency.Name, err))
return
}
if !yield(&DeploymentEvent{Type: "dependency", Message: fmt.Sprintf("Dependency %s created", dependency.Name)}, nil) {
if !yield(&Event{Type: EventTypeProgress, Message: fmt.Sprintf("Dependency %s created", dependency.Name)}, nil) {
return
}
}
if !yield(&DeploymentEvent{Type: "dependency", Message: "Dependencies created"}, nil) {
if !yield(&Event{Type: EventTypeFinish, Message: "Dependencies created"}, nil) {
return
}

// Services
if !yield(&DeploymentEvent{Type: "service", Message: "Deploying services"}, nil) {
if !yield(&Event{Type: EventTypeStart, Message: "Deploying services"}, nil) {
return
}
for _, service := range cfg.Services {
if err := d.deployService(project, &service); err != nil {
yield(nil, fmt.Errorf("failed to deploy service %s: %w", service.Name, err))
return
}
if !yield(&DeploymentEvent{Type: "service", Message: fmt.Sprintf("Service %s deployed", service.Name)}, nil) {
if !yield(&Event{Type: EventTypeProgress, Message: fmt.Sprintf("Service %s deployed", service.Name)}, nil) {
return
}
}
if !yield(&DeploymentEvent{Type: "service", Message: "Services deployed"}, nil) {
if !yield(&Event{Type: EventTypeFinish, Message: "Services deployed"}, nil) {
return
}

// Proxy
if !yield(&DeploymentEvent{Type: "proxy", Message: "Starting proxy"}, nil) {
if !yield(&Event{Type: EventTypeStart, Message: "Starting proxy"}, nil) {
return
}
if err := d.startProxy(cfg.Project.Name, cfg); err != nil {
yield(nil, fmt.Errorf("failed to start proxy: %w", err))
return
}
if !yield(&DeploymentEvent{Type: "proxy", Message: "Proxy started"}, nil) {
if !yield(&Event{Type: EventTypeFinish, Message: "Proxy started"}, nil) {
return
}

// Cert Renewer
if !yield(&DeploymentEvent{Type: "certrenewer", Message: "Deploying cert renewer"}, nil) {
if !yield(&Event{Type: EventTypeStart, Message: "Deploying cert renewer"}, nil) {
return
}
if err := d.deployCertRenewer(project, cfg); err != nil {
yield(nil, fmt.Errorf("failed to deploy cert renewer: %w", err))
return
}
if !yield(&DeploymentEvent{Type: "certrenewer", Message: "Cert renewer deployed"}, nil) {
return
}

// Deployment complete
if !yield(&DeploymentEvent{Type: "complete", Message: "Deployment completed successfully"}, nil) {
if !yield(&Event{Type: EventTypeFinish, Message: "Cert renewer deployed"}, nil) {
return
}
}
Expand Down

0 comments on commit f6d35e8

Please sign in to comment.