Skip to content

Commit

Permalink
fix: check git configuration before exec world create (#74)
Browse files Browse the repository at this point in the history
Closes: WORLD-1177

## Overview

When user trying to exec `world create` but git configuration `.gitconfig` for username and password is not configured it will be returned error, but the gameshard dir is already created.

The issue is because on the last step of `world create` it will exec git commit, and it will need username and email to be configured in `.gitconfig`

Solutions
Before executing `world create`, world cli will check the git configuration is configured or not. if it's not, world cli will tell the command how to configure the git config.

## Brief Changelog

- Create func for checking git configuration
- Call the function at the first execution of `world create` command

## Testing and Verifying
- Added unit test for checkGitConfig func
  • Loading branch information
zulkhair committed Sep 30, 2024
1 parent 6eee015 commit 9888454
Show file tree
Hide file tree
Showing 22 changed files with 786 additions and 267 deletions.
1 change: 0 additions & 1 deletion cmd/world/cardinal/cardinal.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ var BaseCmd = &cobra.Command{
dependency.Go,
dependency.Git,
dependency.Docker,
dependency.DockerCompose,
dependency.DockerDaemon,
)
},
Expand Down
39 changes: 25 additions & 14 deletions cmd/world/cardinal/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,20 +132,26 @@ func startCardinalDevMode(ctx context.Context, cfg *config.Config, prettyLog boo
// Check and wait until Redis is running and is available in the expected port
isRedisHealthy := false
for !isRedisHealthy {
redisAddress := fmt.Sprintf("localhost:%s", RedisPort)
conn, err := net.DialTimeout("tcp", redisAddress, time.Second)
if err != nil {
logger.Printf("Failed to connect to Redis at %s: %s\n", redisAddress, err)
time.Sleep(1 * time.Second)
continue
}
// using select to allow for context cancellation
select {
case <-ctx.Done():
return eris.Wrap(ctx.Err(), "Context canceled")

Check warning on line 138 in cmd/world/cardinal/dev.go

View check run for this annotation

Codecov / codecov/patch

cmd/world/cardinal/dev.go#L137-L138

Added lines #L137 - L138 were not covered by tests
default:
redisAddress := fmt.Sprintf("localhost:%s", RedisPort)
conn, err := net.DialTimeout("tcp", redisAddress, time.Second)
if err != nil {
logger.Printf("Failed to connect to Redis at %s: %s\n", redisAddress, err)
time.Sleep(1 * time.Second)
continue
}

// Cleanup connection
if err := conn.Close(); err != nil {
continue
}
// Cleanup connection
if err := conn.Close(); err != nil {
continue

Check warning on line 150 in cmd/world/cardinal/dev.go

View check run for this annotation

Codecov / codecov/patch

cmd/world/cardinal/dev.go#L150

Added line #L150 was not covered by tests
}

isRedisHealthy = true
isRedisHealthy = true
}
}

// Move into the cardinal directory
Expand Down Expand Up @@ -236,10 +242,14 @@ func startRedis(ctx context.Context, cfg *config.Config) error {
}
defer dockerClient.Close()

// Create context with cancel
ctx, cancel := context.WithCancel(ctx)

// Start Redis container
group.Go(func() error {
cfg.Detach = true
if err := dockerClient.Start(ctx, cfg, service.Redis); err != nil {
if err := dockerClient.Start(ctx, service.Redis); err != nil {
cancel()

Check warning on line 252 in cmd/world/cardinal/dev.go

View check run for this annotation

Codecov / codecov/patch

cmd/world/cardinal/dev.go#L252

Added line #L252 was not covered by tests
return eris.Wrap(err, "Encountered an error with Redis")
}
return nil
Expand All @@ -251,7 +261,8 @@ func startRedis(ctx context.Context, cfg *config.Config) error {
// 2) The parent context is canceled for whatever reason.
group.Go(func() error {
<-ctx.Done()
if err := dockerClient.Stop(cfg, service.Redis); err != nil {
// Using context background because cmd context is already done
if err := dockerClient.Stop(context.Background(), service.Redis); err != nil {
return err
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion cmd/world/cardinal/purge.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ This command stop all Docker services and remove all Docker volumes.`,
}
defer dockerClient.Close()

err = dockerClient.Purge(cfg, service.Nakama, service.Cardinal, service.NakamaDB, service.Redis)
err = dockerClient.Purge(cmd.Context(), service.Nakama, service.Cardinal, service.NakamaDB, service.Redis)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/world/cardinal/restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ This will restart the following Docker services:
}
defer dockerClient.Close()

err = dockerClient.Restart(cmd.Context(), cfg, service.Cardinal, service.Nakama)
err = dockerClient.Restart(cmd.Context(), service.Cardinal, service.Nakama)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/world/cardinal/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ This will start the following Docker services and its dependencies:

// Start the World Engine stack
group.Go(func() error {
if err := dockerClient.Start(ctx, cfg, service.NakamaDB,
if err := dockerClient.Start(ctx, service.NakamaDB,
service.Redis, service.Cardinal, service.Nakama); err != nil {
return eris.Wrap(err, "Encountered an error with Docker")
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/world/cardinal/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ This will stop the following Docker services:
}
defer dockerClient.Close()

err = dockerClient.Stop(cfg, service.Nakama, service.Cardinal, service.NakamaDB, service.Redis)
err = dockerClient.Stop(cmd.Context(), service.Nakama, service.Cardinal, service.NakamaDB, service.Redis)
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/world/cardinal/util_editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ import (
"github.com/rotisserie/eris"
"golang.org/x/sync/errgroup"

"pkg.world.dev/world-cli/common/teacmd"
"pkg.world.dev/world-cli/common/editor"
)

const ceReadTimeout = 5 * time.Second

// startCardinalEditor runs the Cardinal Editor
func startCardinalEditor(ctx context.Context, rootDir string, gameDir string, port int) error {
if err := teacmd.SetupCardinalEditor(rootDir, gameDir); err != nil {
if err := editor.SetupCardinalEditor(rootDir, gameDir); err != nil {

Check warning on line 20 in cmd/world/cardinal/util_editor.go

View check run for this annotation

Codecov / codecov/patch

cmd/world/cardinal/util_editor.go#L20

Added line #L20 was not covered by tests
return err
}

// Create a new HTTP server
fs := http.FileServer(http.Dir(filepath.Join(rootDir, teacmd.TargetEditorDir)))
fs := http.FileServer(http.Dir(filepath.Join(rootDir, editor.EditorDir)))

Check warning on line 25 in cmd/world/cardinal/util_editor.go

View check run for this annotation

Codecov / codecov/patch

cmd/world/cardinal/util_editor.go#L25

Added line #L25 was not covered by tests
http.Handle("/", fs)
server := &http.Server{
Addr: fmt.Sprintf(":%d", port),
Expand Down
7 changes: 4 additions & 3 deletions cmd/world/evm/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,15 @@ var startCmd = &cobra.Command{
cfg.Detach = false
cfg.Timeout = 0

err = dockerClient.Start(cmd.Context(), cfg, service.EVM)
err = dockerClient.Start(cmd.Context(), service.EVM)
if err != nil {
return fmt.Errorf("error starting %s docker container: %w", teacmd.DockerServiceEVM, err)
}

// Stop the DA service if it was started in dev mode
if cfg.DevDA {
err = dockerClient.Stop(cfg, service.CelestiaDevNet)
// using context background because cmd.Context() is already done
err = dockerClient.Stop(context.Background(), service.CelestiaDevNet)
if err != nil {
return eris.Wrap(err, "Failed to stop DA service")
}
Expand All @@ -80,7 +81,7 @@ func validateDevDALayer(ctx context.Context, cfg *config.Config, dockerClient *d
cfg.Detach = true
cfg.Timeout = -1
logger.Println("starting DA docker service for dev mode...")
if err := dockerClient.Start(ctx, cfg, service.CelestiaDevNet); err != nil {
if err := dockerClient.Start(ctx, service.CelestiaDevNet); err != nil {
return fmt.Errorf("error starting %s docker container: %w", daService, err)
}
logger.Println("started DA service...")
Expand Down
2 changes: 1 addition & 1 deletion cmd/world/evm/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ var stopCmd = &cobra.Command{
}
defer dockerClient.Close()

err = dockerClient.Stop(cfg, service.EVM, service.CelestiaDevNet)
err = dockerClient.Stop(cmd.Context(), service.EVM, service.CelestiaDevNet)

Check warning on line 30 in cmd/world/evm/stop.go

View check run for this annotation

Codecov / codecov/patch

cmd/world/evm/stop.go#L30

Added line #L30 was not covered by tests
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/world/root/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"

"pkg.world.dev/world-cli/common/editor"
"pkg.world.dev/world-cli/common/teacmd"
"pkg.world.dev/world-cli/tea/component/steps"
"pkg.world.dev/world-cli/tea/style"
Expand Down Expand Up @@ -123,7 +124,7 @@ func (m WorldCreateModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
)
}
if msg.Index == 2 { //nolint:gomnd
err := teacmd.SetupCardinalEditor(".", "cardinal")
err := editor.SetupCardinalEditor(".", "cardinal")
teaCmd := func() tea.Msg {
return teacmd.GitCloneFinishMsg{Err: err}
}
Expand Down
108 changes: 74 additions & 34 deletions common/docker/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,36 @@ import (
"pkg.world.dev/world-cli/common/logger"
)

const (
START processType = iota
STOP
REMOVE
CREATE
)

var (
processName = map[processType]string{
START: "start",
STOP: "stop",
REMOVE: "remove",
CREATE: "create",
}

processInitName = map[processType]string{
START: "starting",
STOP: "stopping",
REMOVE: "removing",
CREATE: "creating",
}

processFinishName = map[processType]string{
START: "started",
STOP: "stopped",
REMOVE: "removed",
CREATE: "created",
}
)

type Client struct {
client *client.Client
cfg *config.Config
Expand All @@ -39,32 +69,33 @@ func (c *Client) Close() error {
return c.client.Close()
}

func (c *Client) Start(ctx context.Context, cfg *config.Config,
func (c *Client) Start(ctx context.Context,
serviceBuilders ...service.Builder) error {
defer func() {
if !cfg.Detach {
err := c.Stop(cfg, serviceBuilders...)
if !c.cfg.Detach {
err := c.Stop(context.Background(), serviceBuilders...)
if err != nil {
logger.Error("Failed to stop containers", err)
}
}
}()

namespace := cfg.DockerEnv["CARDINAL_NAMESPACE"]
namespace := c.cfg.DockerEnv["CARDINAL_NAMESPACE"]
err := c.createNetworkIfNotExists(ctx, namespace)
if err != nil {
return eris.Wrap(err, "Failed to create network")
}

err = c.createVolumeIfNotExists(ctx, namespace)
err = c.processVolume(ctx, CREATE, namespace)
if err != nil {
return eris.Wrap(err, "Failed to create volume")
}

// get all services
dockerServices := make([]service.Service, 0)
for _, sb := range serviceBuilders {
dockerServices = append(dockerServices, sb(cfg))
ds := sb(c.cfg)
dockerServices = append(dockerServices, ds)
}

// Pull all images before starting containers
Expand All @@ -73,67 +104,76 @@ func (c *Client) Start(ctx context.Context, cfg *config.Config,
return eris.Wrap(err, "Failed to pull images")
}

// Start all containers
for _, dockerService := range dockerServices {
// build image if needed
if cfg.Build && dockerService.Dockerfile != "" {
if err := c.buildImage(ctx, dockerService.Dockerfile, dockerService.BuildTarget, dockerService.Image); err != nil {
return eris.Wrap(err, "Failed to build image")
}
// Build all images before starting containers
if c.cfg.Build {
err = c.buildImages(ctx, dockerServices...)
if err != nil {
return eris.Wrap(err, "Failed to build images")

Check warning on line 111 in common/docker/client.go

View check run for this annotation

Codecov / codecov/patch

common/docker/client.go#L109-L111

Added lines #L109 - L111 were not covered by tests
}
}

// create container & start
if err := c.startContainer(ctx, dockerService); err != nil {
return eris.Wrap(err, "Failed to create container")
}
// Start all containers
err = c.processMultipleContainers(ctx, START, dockerServices...)
if err != nil {
return eris.Wrap(err, "Failed to start containers")

Check warning on line 118 in common/docker/client.go

View check run for this annotation

Codecov / codecov/patch

common/docker/client.go#L118

Added line #L118 was not covered by tests
}

// log containers if not detached
if !cfg.Detach {
if !c.cfg.Detach {
c.logMultipleContainers(ctx, dockerServices...)
}

return nil
}

func (c *Client) Stop(cfg *config.Config, serviceBuilders ...service.Builder) error {
ctx := context.Background()
func (c *Client) Stop(ctx context.Context, serviceBuilders ...service.Builder) error {
// get all services
dockerServices := make([]service.Service, 0)
for _, sb := range serviceBuilders {
dockerService := sb(cfg)
if err := c.stopContainer(ctx, dockerService.Name); err != nil {
return eris.Wrap(err, "Failed to stop container")
}
ds := sb(c.cfg)
dockerServices = append(dockerServices, ds)
}

// Stop all containers
err := c.processMultipleContainers(ctx, STOP, dockerServices...)
if err != nil {
return eris.Wrap(err, "Failed to stop containers")

Check warning on line 140 in common/docker/client.go

View check run for this annotation

Codecov / codecov/patch

common/docker/client.go#L140

Added line #L140 was not covered by tests
}

return nil
}

func (c *Client) Purge(cfg *config.Config, serviceBuilders ...service.Builder) error {
ctx := context.Background()
func (c *Client) Purge(ctx context.Context, serviceBuilders ...service.Builder) error {
// get all services
dockerServices := make([]service.Service, 0)
for _, sb := range serviceBuilders {
dockerService := sb(cfg)
if err := c.removeContainer(ctx, dockerService.Name); err != nil {
return eris.Wrap(err, "Failed to remove container")
}
ds := sb(c.cfg)
dockerServices = append(dockerServices, ds)
}

// remove all containers
err := c.processMultipleContainers(ctx, REMOVE, dockerServices...)
if err != nil {
return eris.Wrap(err, "Failed to remove containers")

Check warning on line 157 in common/docker/client.go

View check run for this annotation

Codecov / codecov/patch

common/docker/client.go#L157

Added line #L157 was not covered by tests
}

err := c.removeVolume(ctx, cfg.DockerEnv["CARDINAL_NAMESPACE"])
err = c.processVolume(ctx, REMOVE, c.cfg.DockerEnv["CARDINAL_NAMESPACE"])
if err != nil {
return err
}

return nil
}

func (c *Client) Restart(ctx context.Context, cfg *config.Config,
func (c *Client) Restart(ctx context.Context,
serviceBuilders ...service.Builder) error {
// stop containers
err := c.Stop(cfg, serviceBuilders...)
err := c.Stop(ctx, serviceBuilders...)
if err != nil {
return err
}

return c.Start(ctx, cfg, serviceBuilders...)
return c.Start(ctx, serviceBuilders...)
}

func (c *Client) Exec(ctx context.Context, containerID string, cmd []string) (string, error) {
Expand Down
Loading

0 comments on commit 9888454

Please # to comment.