Skip to content

Commit b7ae43a

Browse files
committed
feat: Add --auto-approve flag to upgrade command
1 parent 1129877 commit b7ae43a

7 files changed

Lines changed: 87 additions & 10 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ package-lock.json
3434
# VSCode extensions
3535
*.http
3636

37+
# Cursor rules
38+
.cursor/rules
39+
3740
# Temp log files
3841
*.log
3942

cmd/upgrade/upgrade.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ var checkForUpdatesFunc = checkForUpdates
3131
const changelogURL = "https://docs.slack.dev/changelog"
3232

3333
func NewCommand(clients *shared.ClientFactory) *cobra.Command {
34-
return &cobra.Command{
34+
var autoApprove bool
35+
36+
cmd := &cobra.Command{
3537
Use: "upgrade",
3638
Aliases: []string{"update"},
3739
Short: "Checks for available updates to the CLI or SDK",
@@ -44,16 +46,21 @@ func NewCommand(clients *shared.ClientFactory) *cobra.Command {
4446
}, "\n"),
4547
Example: style.ExampleCommandsf([]style.ExampleCommand{
4648
{Command: "upgrade", Meaning: "Check for any available updates"},
49+
{Command: "upgrade --auto-approve", Meaning: "Check for updates and automatically upgrade without confirmation"},
4750
}),
4851
RunE: func(cmd *cobra.Command, args []string) error {
49-
return checkForUpdatesFunc(clients, cmd)
52+
return checkForUpdatesFunc(clients, cmd, autoApprove)
5053
},
5154
}
55+
56+
cmd.Flags().BoolVar(&autoApprove, "auto-approve", false, "automatically approve and install updates without prompting")
57+
58+
return cmd
5259
}
5360

5461
// checkForUpdates will check for CLI/SDK updates and print a message when no updates are available.
5562
// When there are updates, the function will *not* print a message because the root command handles printing update notifications.
56-
func checkForUpdates(clients *shared.ClientFactory, cmd *cobra.Command) error {
63+
func checkForUpdates(clients *shared.ClientFactory, cmd *cobra.Command, autoApprove bool) error {
5764
ctx := cmd.Context()
5865
updateNotification := update.New(clients, version.Get(), "SLACK_SKIP_UPDATE")
5966

@@ -70,6 +77,11 @@ func checkForUpdates(clients *shared.ClientFactory, cmd *cobra.Command) error {
7077
// Update notification messages are printed by the root command's persistent post-run (cmd/root.go).
7178
// So this command only needs to print a message when everything is up-to-date.
7279
if updateNotification.HasUpdate() {
80+
if autoApprove {
81+
// Automatically install updates without prompting when auto-approve flag is set
82+
updateNotification.InstallUpdatesWithoutPrompt(cmd)
83+
return nil
84+
}
7385
return nil
7486
}
7587

cmd/upgrade/upgrade_test.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ type UpdatePkgMock struct {
2929
mock.Mock
3030
}
3131

32-
func (m *UpdatePkgMock) CheckForUpdates(clients *shared.ClientFactory, cmd *cobra.Command) error {
33-
args := m.Called(clients, cmd)
32+
func (m *UpdatePkgMock) CheckForUpdates(clients *shared.ClientFactory, cmd *cobra.Command, autoApprove bool) error {
33+
args := m.Called(clients, cmd, autoApprove)
3434
return args.Error(0)
3535
}
3636

@@ -49,11 +49,26 @@ func TestUpgradeCommand(t *testing.T) {
4949
updatePkgMock := new(UpdatePkgMock)
5050
checkForUpdatesFunc = updatePkgMock.CheckForUpdates
5151

52-
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything).Return(nil)
52+
// Test default behavior (no auto-approve)
53+
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything, false).Return(nil)
5354
err := cmd.ExecuteContext(ctx)
5455
if err != nil {
5556
assert.Fail(t, "cmd.Upgrade had unexpected error")
5657
}
58+
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything, false)
5759

58-
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything)
60+
// Test with auto-approve flag
61+
cmd = NewCommand(clients)
62+
testutil.MockCmdIO(clients.IO, cmd)
63+
cmd.SetArgs([]string{"--auto-approve"})
64+
65+
updatePkgMock = new(UpdatePkgMock)
66+
checkForUpdatesFunc = updatePkgMock.CheckForUpdates
67+
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything, true).Return(nil)
68+
69+
err = cmd.ExecuteContext(ctx)
70+
if err != nil {
71+
assert.Fail(t, "cmd.Upgrade with auto-approve had unexpected error")
72+
}
73+
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything, true)
5974
}

docs/reference/commands/slack_upgrade.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ slack upgrade [flags]
1818

1919
```
2020
$ slack upgrade # Check for any available updates
21+
$ slack upgrade --auto-approve # Check for updates and automatically upgrade without confirmation
2122
```
2223

2324
### Options
2425

2526
```
26-
-h, --help help for upgrade
27+
--auto-approve automatically approve and install updates without prompting
28+
-h, --help help for upgrade
2729
```
2830

2931
### Options inherited from parent commands

internal/update/cli.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,25 @@ func (c *CLIDependency) PrintUpdateNotification(cmd *cobra.Command) (bool, error
8787
"\n To update with Homebrew, run: %s\n\n",
8888
style.CommandText(fmt.Sprintf("brew update && brew upgrade %s", processName)),
8989
)
90+
return false, nil
9091
} else {
9192
cmd.Printf(
9293
"\n To manually update, visit the download page:\n %s\n\n",
9394
style.CommandText("https://tools.slack.dev/slack-cli"),
9495
)
96+
97+
// Check for auto-approve from upgrade command
98+
if cmd.Name() == "upgrade" && cmd.Flags().Changed("auto-approve") {
99+
autoApprove, _ := cmd.Flags().GetBool("auto-approve")
100+
if autoApprove {
101+
return true, nil
102+
}
103+
}
104+
95105
selfUpdatePrompt := fmt.Sprintf("%sDo you want to auto-update to the latest version now?", style.Emoji("rocket"))
96106
return c.clients.IO.ConfirmPrompt(ctx, selfUpdatePrompt, false)
97107
}
98108

99-
return false, nil
100-
101109
// TODO: Uncomment when open sourced to display the latest release URL that includes release notes
102110
// cmd.Printf(
103111
// "\n%s\n\n",

internal/update/sdk.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,14 @@ func (c *SDKDependency) PrintUpdateNotification(cmd *cobra.Command) (bool, error
319319

320320
// If `install-update` hook available, prompt to auto-update
321321
if c.clients.SDKConfig.Hooks.InstallUpdate.IsAvailable() {
322+
// Check for auto-approve from upgrade command
323+
if cmd.Name() == "upgrade" && cmd.Flags().Changed("auto-approve") {
324+
autoApprove, _ := cmd.Flags().GetBool("auto-approve")
325+
if autoApprove {
326+
return true, nil
327+
}
328+
}
329+
322330
autoUpdatePrompt := fmt.Sprintf("%sDo you want to auto-update to the latest versions now?", style.Emoji("rocket"))
323331
return c.clients.IO.ConfirmPrompt(ctx, autoUpdatePrompt, false)
324332
}

internal/update/update.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/slackapi/slack-cli/internal/goutils"
2727
"github.com/slackapi/slack-cli/internal/shared"
2828
"github.com/slackapi/slack-cli/internal/slackerror"
29+
"github.com/slackapi/slack-cli/internal/style"
2930
"github.com/spf13/cobra"
3031
)
3132

@@ -251,3 +252,31 @@ func (u *UpdateNotification) isLastUpdateCheckedAtGreaterThan(ctx context.Contex
251252
func newHTTPClient() (*http.Client, error) {
252253
return api.NewHTTPClient(api.HTTPClientOptions{TotalTimeOut: 60 * time.Second}), nil
253254
}
255+
256+
// InstallUpdatesWithoutPrompt automatically installs updates without prompting the user
257+
// This is used by the upgrade command when the --auto-approve flag is set
258+
func (u *UpdateNotification) InstallUpdatesWithoutPrompt(cmd *cobra.Command) error {
259+
ctx := cmd.Context()
260+
261+
for _, dependency := range u.Dependencies() {
262+
hasUpdate, err := dependency.HasUpdate()
263+
if err != nil {
264+
return slackerror.Wrap(err, "An error occurred while fetching a dependency")
265+
}
266+
267+
if hasUpdate {
268+
// Print update notification but skip the confirmation prompt
269+
_, err := dependency.PrintUpdateNotification(cmd)
270+
if err != nil {
271+
return err
272+
}
273+
274+
// Install the update without prompting
275+
cmd.Printf("%s Installing update automatically...\n", style.Styler().Green("✓").String())
276+
if err := dependency.InstallUpdate(ctx); err != nil {
277+
return err
278+
}
279+
}
280+
}
281+
return nil
282+
}

0 commit comments

Comments
 (0)