Skip to content

Commit

Permalink
feat(build): adds --non-interactive flag
Browse files Browse the repository at this point in the history
  • Loading branch information
mattevans committed Jan 19, 2025
1 parent 6d3e428 commit 6bbf460
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 48 deletions.
45 changes: 25 additions & 20 deletions cmd/cli/commands/update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,33 +117,38 @@ func updateContributoor(
cfg = sidecarCfg.Get()

// Update the sidecar.
success, err = updateSidecar(log, cfg, docker, systemd, binary)
success, err = updateSidecar(c, log, cfg, docker, systemd, binary)
if err != nil {
return err
}

return nil
}

func updateSidecar(log *logrus.Logger, cfg *config.Config, docker sidecar.DockerSidecar, systemd sidecar.SystemdSidecar, binary sidecar.BinarySidecar) (bool, error) {
func updateSidecar(
c *cli.Context,
log *logrus.Logger,
cfg *config.Config,
docker sidecar.DockerSidecar,
systemd sidecar.SystemdSidecar,
binary sidecar.BinarySidecar,
) (bool, error) {
switch cfg.RunMethod {
case config.RunMethod_RUN_METHOD_DOCKER:
return updateDocker(log, cfg, docker)
return updateDocker(c, log, cfg, docker)
case config.RunMethod_RUN_METHOD_SYSTEMD:
return updateSystemd(log, cfg, systemd)
return updateSystemd(c, log, cfg, systemd)
case config.RunMethod_RUN_METHOD_BINARY:
return updateBinary(log, cfg, binary)
return updateBinary(c, log, cfg, binary)
default:
return false, fmt.Errorf("invalid sidecar run method: %s", cfg.RunMethod)
}
}

func updateSystemd(log *logrus.Logger, cfg *config.Config, systemd sidecar.SystemdSidecar) (bool, error) {
func updateSystemd(c *cli.Context, log *logrus.Logger, cfg *config.Config, systemd sidecar.SystemdSidecar) (bool, error) {
// Check if sidecar is currently running.
running, err := systemd.IsRunning()
if err != nil {
log.Errorf("could not check sidecar status: %v", err)

return false, err
}

Expand All @@ -155,24 +160,26 @@ func updateSystemd(log *logrus.Logger, cfg *config.Config, systemd sidecar.Syste
}

if err := systemd.Update(); err != nil {
log.Errorf("could not update sidecar: %v", err)

return false, err
}

fmt.Printf("%sContributoor updated successfully to version %s%s\n", tui.TerminalColorGreen, cfg.Version, tui.TerminalColorReset)

// If it was running, start it again for them.
if running {
if err := systemd.Start(); err != nil {
return true, fmt.Errorf("failed to start sidecar: %w", err)
if c.GlobalBool("non-interactive") || tui.Confirm("Would you like to restart Contributoor with the new version?") {
if err := systemd.Start(); err != nil {
return true, fmt.Errorf("failed to start sidecar: %w", err)
}
} else {
fmt.Printf("%sContributoor will remain stopped until manually started%s\n", tui.TerminalColorYellow, tui.TerminalColorReset)
}
}

return true, nil
}

func updateBinary(log *logrus.Logger, cfg *config.Config, binary sidecar.BinarySidecar) (bool, error) {
func updateBinary(c *cli.Context, log *logrus.Logger, cfg *config.Config, binary sidecar.BinarySidecar) (bool, error) {
// Check if sidecar is currently running.
running, err := binary.IsRunning()
if err != nil {
Expand All @@ -183,9 +190,7 @@ func updateBinary(log *logrus.Logger, cfg *config.Config, binary sidecar.BinaryS

// If the sidecar is running, we need to stop it before we can update the binary.
if running {
fmt.Printf("\n")

if tui.Confirm("Contributoor is running. In order to update, it must be stopped. Would you like to stop it?") {
if c.GlobalBool("non-interactive") || tui.Confirm("Contributoor is running. In order to update, it must be stopped. Would you like to stop it?") {
if err := binary.Stop(); err != nil {
return false, fmt.Errorf("failed to stop sidecar: %w", err)
}
Expand Down Expand Up @@ -214,14 +219,14 @@ func updateBinary(log *logrus.Logger, cfg *config.Config, binary sidecar.BinaryS
return true, nil
}

func updateDocker(log *logrus.Logger, cfg *config.Config, docker sidecar.DockerSidecar) (bool, error) {
func updateDocker(c *cli.Context, log *logrus.Logger, cfg *config.Config, docker sidecar.DockerSidecar) (bool, error) {
if err := docker.Update(); err != nil {
log.Errorf("could not update service: %v", err)

return false, err
}

fmt.Printf("%sContributoor updated successfully to version %s%s\n", tui.TerminalColorGreen, cfg.Version, tui.TerminalColorReset)
fmt.Printf("%sContributoor updated successfully to version %s%s", tui.TerminalColorGreen, cfg.Version, tui.TerminalColorReset)

// Check if service is currently running.
running, err := docker.IsRunning()
Expand All @@ -235,7 +240,7 @@ func updateDocker(log *logrus.Logger, cfg *config.Config, docker sidecar.DockerS

// If the service is running, we need to restart it with the new version.
if running {
if tui.Confirm("Contributoor is running. Would you like to restart it with the new version?") {
if c.GlobalBool("non-interactive") || tui.Confirm("Contributoor is running. Would you like to restart it with the new version?") {
if err := docker.Stop(); err != nil {
return true, fmt.Errorf("failed to stop sidecar: %w", err)
}
Expand All @@ -247,7 +252,7 @@ func updateDocker(log *logrus.Logger, cfg *config.Config, docker sidecar.DockerS
fmt.Printf("%sContributoor will continue running with the previous version until next restart%s\n", tui.TerminalColorYellow, tui.TerminalColorReset)
}
} else {
if tui.Confirm("Contributoor is not running. Would you like to start it?") {
if c.GlobalBool("non-interactive") || tui.Confirm("Contributoor is not running. Would you like to start it?") {
if err := docker.Start(); err != nil {
return true, fmt.Errorf("failed to start service: %w", err)
}
Expand Down
144 changes: 116 additions & 28 deletions cmd/cli/commands/update/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,19 @@ func TestUpdateContributoor(t *testing.T) {
confirmResponse = true

tests := []struct {
name string
runMethod config.RunMethod
version string
confirmPrompt bool
setupMocks func(*mock.MockConfigManager, *mock.MockDockerSidecar, *mock.MockSystemdSidecar, *mock.MockBinarySidecar, *smock.MockGitHubService)
expectedError string
name string
runMethod config.RunMethod
version string
confirmPrompt bool
nonInteractive bool
setupMocks func(*mock.MockConfigManager, *mock.MockDockerSidecar, *mock.MockSystemdSidecar, *mock.MockBinarySidecar, *smock.MockGitHubService)
expectedError string
}{
{
name: "docker - updates service successfully",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
confirmPrompt: true,
name: "docker - updates service successfully",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
confirmPrompt: true,
nonInteractive: false,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_DOCKER,
Expand All @@ -65,8 +67,9 @@ func TestUpdateContributoor(t *testing.T) {
},
},
{
name: "docker - already at latest version",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
name: "docker - already at latest version",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
nonInteractive: false,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_DOCKER,
Expand All @@ -76,8 +79,10 @@ func TestUpdateContributoor(t *testing.T) {
},
},
{
name: "docker - update fails",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
name: "docker - update fails",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
confirmPrompt: true,
nonInteractive: false,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_DOCKER,
Expand All @@ -97,10 +102,11 @@ func TestUpdateContributoor(t *testing.T) {
expectedError: "update failed",
},
{
name: "specific version - exists",
version: "v1.1.0",
confirmPrompt: true,
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
name: "specific version - exists",
version: "v1.1.0",
confirmPrompt: true,
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
nonInteractive: false,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_DOCKER,
Expand All @@ -122,9 +128,10 @@ func TestUpdateContributoor(t *testing.T) {
},
},
{
name: "specific version - does not exist",
version: "v999.0.0",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
name: "specific version - does not exist",
version: "v999.0.0",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
nonInteractive: false,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_DOCKER,
Expand All @@ -134,9 +141,10 @@ func TestUpdateContributoor(t *testing.T) {
},
},
{
name: "binary - updates service successfully",
runMethod: config.RunMethod_RUN_METHOD_BINARY,
confirmPrompt: true,
name: "binary - updates service successfully",
runMethod: config.RunMethod_RUN_METHOD_BINARY,
confirmPrompt: true,
nonInteractive: false,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_BINARY,
Expand All @@ -158,8 +166,9 @@ func TestUpdateContributoor(t *testing.T) {
},
},
{
name: "binary - already at latest version",
runMethod: config.RunMethod_RUN_METHOD_BINARY,
name: "binary - already at latest version",
runMethod: config.RunMethod_RUN_METHOD_BINARY,
nonInteractive: false,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_BINARY,
Expand All @@ -169,9 +178,10 @@ func TestUpdateContributoor(t *testing.T) {
},
},
{
name: "binary - update fails",
runMethod: config.RunMethod_RUN_METHOD_BINARY,
confirmPrompt: true,
name: "binary - update fails",
runMethod: config.RunMethod_RUN_METHOD_BINARY,
confirmPrompt: true,
nonInteractive: false,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_BINARY,
Expand All @@ -193,6 +203,80 @@ func TestUpdateContributoor(t *testing.T) {
},
expectedError: "update failed",
},
{
name: "docker - non-interactive mode auto-restarts",
runMethod: config.RunMethod_RUN_METHOD_DOCKER,
nonInteractive: true,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_DOCKER,
Version: "v1.0.0",
}).Times(2)
g.EXPECT().GetLatestVersion().Return("v1.1.0", nil)
d.EXPECT().Update().Return(nil)
cfg.EXPECT().Update(gomock.Any()).Return(nil)
cfg.EXPECT().Save().Return(nil)

// Check if service is running.
d.EXPECT().IsRunning().Return(true, nil)

// In non-interactive mode, should auto-restart.
d.EXPECT().Stop().Return(nil)
d.EXPECT().Start().Return(nil)
},
},
{
name: "systemd - non-interactive mode auto-restarts",
runMethod: config.RunMethod_RUN_METHOD_SYSTEMD,
nonInteractive: true,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_SYSTEMD,
Version: "v1.0.0",
}).Times(2)
g.EXPECT().GetLatestVersion().Return("v1.1.0", nil)

// Check if service is running.
s.EXPECT().IsRunning().Return(true, nil)

// Should stop before update.
s.EXPECT().Stop().Return(nil)

// Expect update.
s.EXPECT().Update().Return(nil)
cfg.EXPECT().Update(gomock.Any()).Return(nil)
cfg.EXPECT().Save().Return(nil)

// In non-interactive mode, should auto-restart.
s.EXPECT().Start().Return(nil)
},
},
{
name: "binary - non-interactive mode auto-restarts",
runMethod: config.RunMethod_RUN_METHOD_BINARY,
nonInteractive: true,
setupMocks: func(cfg *mock.MockConfigManager, d *mock.MockDockerSidecar, s *mock.MockSystemdSidecar, b *mock.MockBinarySidecar, g *smock.MockGitHubService) {
cfg.EXPECT().Get().Return(&config.Config{
RunMethod: config.RunMethod_RUN_METHOD_BINARY,
Version: "v1.0.0",
}).Times(2)
g.EXPECT().GetLatestVersion().Return("v1.1.0", nil)

// Check if service is running.
b.EXPECT().IsRunning().Return(true, nil)

// Should stop before update.
b.EXPECT().Stop().Return(nil)

// Expect update.
b.EXPECT().Update().Return(nil)
cfg.EXPECT().Update(gomock.Any()).Return(nil)
cfg.EXPECT().Save().Return(nil)

// In non-interactive mode, should auto-restart.
b.EXPECT().Start().Return(nil)
},
},
}

for _, tt := range tests {
Expand All @@ -212,9 +296,13 @@ func TestUpdateContributoor(t *testing.T) {
cli.StringFlag{
Name: "version, v",
},
cli.BoolFlag{
Name: "non-interactive",
},
}
set := flag.NewFlagSet("test", 0)
set.String("version", "", "")
set.Bool("non-interactive", tt.nonInteractive, "")
if tt.version != "" {
err := set.Set("version", tt.version)
require.NoError(t, err)
Expand Down
4 changes: 4 additions & 0 deletions cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ func main() {
Usage: "Contributoor config asset `path`",
Value: "~/.contributoor",
},
cli.BoolFlag{
Name: "non-interactive",
Usage: "Skip all interactive prompts and use default values",
},
cli.BoolFlag{
Name: "release, r",
Usage: "Print release and exit",
Expand Down

0 comments on commit 6bbf460

Please sign in to comment.