Skip to content

Commit

Permalink
APPS-9765 Add command to restart apps (#1608)
Browse files Browse the repository at this point in the history
* APPS-9765 Add command to restart apps

* add test

* bump godo and vendor
  • Loading branch information
blesswinsamuel authored Nov 19, 2024
1 parent 3d3b6ec commit 5510cad
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 6 deletions.
2 changes: 2 additions & 0 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ const (
ArgNoPrefix = "no-prefix"
// ArgAppForceRebuild forces a deployment rebuild
ArgAppForceRebuild = "force-rebuild"
// ArgAppComponents is a list of components to restart.
ArgAppComponents = "components"
// ArgAppAlertDestinations is a path to an app alert destination file.
ArgAppAlertDestinations = "app-alert-destinations"
// ArgClusterName is a cluster name argument.
Expand Down
57 changes: 57 additions & 0 deletions commands/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,21 @@ This permanently deletes the app and all of its associated deployments.`,
AddBoolFlag(deleteApp, doctl.ArgForce, doctl.ArgShortForce, false, "Delete the App without a confirmation prompt")
deleteApp.Example = `The following example deletes an app with the ID ` + "`" + `f81d4fae-7dec-11d0-a765-00a0c91e6bf6` + "`" + `: doctl apps delete f81d4fae-7dec-11d0-a765-00a0c91e6bf6`

restartApp := CmdBuilder(
cmd,
RunAppsRestart,
"restart <app id>",
"Restarts an app",
`Restarts the specified app or some of its components.`,
Writer,
aliasOpt("r"),
displayerType(&displayers.Deployments{}),
)
AddStringSliceFlag(restartApp, doctl.ArgAppComponents, "", nil, "The components to restart. If not provided, all components are restarted.")
AddBoolFlag(restartApp, doctl.ArgCommandWait, "", false,
"Boolean that specifies whether to wait for the restart to complete before allowing further terminal input. This can be helpful for scripting.")
restartApp.Example = `The following example restarts an app with the ID ` + "`" + `f81d4fae-7dec-11d0-a765-00a0c91e6bf6` + "`" + `. Additionally, the command returns the app's ID and status: doctl apps restart f81d4fae-7dec-11d0-a765-00a0c91e6bf6 --format ID,Status`

deploymentCreate := CmdBuilder(
cmd,
RunAppsCreateDeployment,
Expand Down Expand Up @@ -469,6 +484,48 @@ func RunAppsDelete(c *CmdConfig) error {
return nil
}

// RunAppsRestart restarts an app.
func RunAppsRestart(c *CmdConfig) error {
if len(c.Args) < 1 {
return doctl.NewMissingArgsErr(c.NS)
}
appID := c.Args[0]
components, err := c.Doit.GetStringSlice(c.NS, doctl.ArgAppComponents)
if err != nil {
return err
}

wait, err := c.Doit.GetBool(c.NS, doctl.ArgCommandWait)
if err != nil {
return err
}

deployment, err := c.Apps().Restart(appID, components)
if err != nil {
return err
}

var errs error

if wait {
apps := c.Apps()
notice("Restart is in progress, waiting for the restart to complete")
err := waitForActiveDeployment(apps, appID, deployment.ID)
if err != nil {
errs = multierror.Append(errs, fmt.Errorf("app deployment couldn't enter `running` state: %v", err))
if err := c.Display(displayers.Deployments{deployment}); err != nil {
errs = multierror.Append(errs, err)
}
return errs
}
deployment, _ = c.Apps().GetDeployment(appID, deployment.ID)
}

notice("Restarted")

return c.Display(displayers.Deployments{deployment})
}

// RunAppsCreateDeployment creates a deployment for an app.
func RunAppsCreateDeployment(c *CmdConfig) error {
if len(c.Args) < 1 {
Expand Down
105 changes: 105 additions & 0 deletions commands/apps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestAppsCommand(t *testing.T) {
"list-regions",
"logs",
"propose",
"restart",
"spec",
"tier",
"list-alerts",
Expand Down Expand Up @@ -344,6 +345,110 @@ func TestRunAppsCreateDeploymentWithWait(t *testing.T) {
})
}

func TestRunAppsRestart(t *testing.T) {
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
appID := uuid.New().String()
deployment := &godo.Deployment{
ID: uuid.New().String(),
Spec: &testAppSpec,
Services: []*godo.DeploymentService{{
Name: "service",
SourceCommitHash: "commit",
}},
Cause: "Manual",
Phase: godo.DeploymentPhase_PendingDeploy,
Progress: &godo.DeploymentProgress{
PendingSteps: 1,
RunningSteps: 0,
SuccessSteps: 0,
ErrorSteps: 0,
TotalSteps: 1,

Steps: []*godo.DeploymentProgressStep{{
Name: "name",
Status: "pending",
StartedAt: time.Now(),
}},
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}

tm.apps.EXPECT().Restart(appID, []string{"component1", "component2"}).Times(1).Return(deployment, nil)

config.Args = append(config.Args, appID)
config.Doit.Set(config.NS, doctl.ArgAppComponents, []string{"component1", "component2"})

err := RunAppsRestart(config)
require.NoError(t, err)
})
}

func TestRunAppsRestartWithWait(t *testing.T) {
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
appID := uuid.New().String()
deployment := &godo.Deployment{
ID: uuid.New().String(),
Spec: &testAppSpec,
Services: []*godo.DeploymentService{{
Name: "service",
SourceCommitHash: "commit",
}},
Cause: "Manual",
Phase: godo.DeploymentPhase_PendingDeploy,
Progress: &godo.DeploymentProgress{
PendingSteps: 1,
RunningSteps: 0,
SuccessSteps: 0,
ErrorSteps: 0,
TotalSteps: 1,

Steps: []*godo.DeploymentProgressStep{{
Name: "name",
Status: "pending",
StartedAt: time.Now(),
}},
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
activeDeployment := &godo.Deployment{
ID: uuid.New().String(),
Spec: &testAppSpec,
Services: []*godo.DeploymentService{{
Name: "service",
SourceCommitHash: "commit",
}},
Cause: "Manual",
Phase: godo.DeploymentPhase_Active,
Progress: &godo.DeploymentProgress{
PendingSteps: 1,
RunningSteps: 0,
SuccessSteps: 1,
ErrorSteps: 0,
TotalSteps: 1,

Steps: []*godo.DeploymentProgressStep{{
Name: "name",
Status: "pending",
StartedAt: time.Now(),
}},
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}

tm.apps.EXPECT().Restart(appID, nil).Times(1).Return(deployment, nil)
tm.apps.EXPECT().GetDeployment(appID, deployment.ID).Times(2).Return(activeDeployment, nil)

config.Args = append(config.Args, appID)
config.Doit.Set(config.NS, doctl.ArgCommandWait, true)

err := RunAppsRestart(config)
require.NoError(t, err)
})
}

func TestRunAppsGetDeployment(t *testing.T) {
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
appID := uuid.New().String()
Expand Down
11 changes: 11 additions & 0 deletions do/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type AppsService interface {
Delete(appID string) error
Propose(req *godo.AppProposeRequest) (*godo.AppProposeResponse, error)

Restart(appID string, components []string) (*godo.Deployment, error)
CreateDeployment(appID string, forceRebuild bool) (*godo.Deployment, error)
GetDeployment(appID, deploymentID string) (*godo.Deployment, error)
ListDeployments(appID string) ([]*godo.Deployment, error)
Expand Down Expand Up @@ -132,6 +133,16 @@ func (s *appsService) Propose(req *godo.AppProposeRequest) (*godo.AppProposeResp
return res, nil
}

func (s *appsService) Restart(appID string, components []string) (*godo.Deployment, error) {
deployment, _, err := s.client.Apps.Restart(s.ctx, appID, &godo.AppRestartRequest{
Components: components,
})
if err != nil {
return nil, err
}
return deployment, nil
}

func (s *appsService) CreateDeployment(appID string, forceRebuild bool) (*godo.Deployment, error) {
deployment, _, err := s.client.Apps.CreateDeployment(s.ctx, appID, &godo.DeploymentCreateRequest{
ForceBuild: forceRebuild,
Expand Down
15 changes: 15 additions & 0 deletions do/mocks/AppsService.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22
require (
github.com/blang/semver v3.5.1+incompatible
github.com/creack/pty v1.1.21
github.com/digitalocean/godo v1.130.0
github.com/digitalocean/godo v1.130.1-0.20241119155329-45ad288c38bd
github.com/docker/cli v24.0.5+incompatible
github.com/docker/docker v25.0.6+incompatible
github.com/docker/docker-credential-helpers v0.7.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/digitalocean/godo v1.130.0 h1:DbJg0wvBxTkYjY5Q9S1mwzAZLd5Wht3r57yFH4yeMCk=
github.com/digitalocean/godo v1.130.0/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc=
github.com/digitalocean/godo v1.130.1-0.20241119155329-45ad288c38bd h1:3TCd+SNAbaRHQSiWmMJWtPitvZt2lTq3th87CxMl9Xo=
github.com/digitalocean/godo v1.130.1-0.20241119155329-45ad288c38bd/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
Expand Down
4 changes: 2 additions & 2 deletions vendor/github.com/digitalocean/godo/apps.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions vendor/github.com/digitalocean/godo/apps.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ github.com/creack/pty
# github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
## explicit
github.com/davecgh/go-spew/spew
# github.com/digitalocean/godo v1.130.0
# github.com/digitalocean/godo v1.130.1-0.20241119155329-45ad288c38bd
## explicit; go 1.22
github.com/digitalocean/godo
github.com/digitalocean/godo/metrics
Expand Down

0 comments on commit 5510cad

Please sign in to comment.