Skip to content

Commit 55b0bcf

Browse files
committed
move to two flag approach to match prompt
1 parent 927b602 commit 55b0bcf

10 files changed

Lines changed: 352 additions & 40 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
description:
3+
globs: *.go
4+
alwaysApply: false
5+
---
6+
After modifying any Go file:
7+
1. Check for a corresponding _test.go file in the same directory
8+
2. If found, inspect the test file to identify test cases related to your changes
9+
3. Recommend any tests to add, update, or remove to cover the new implementation and behavior
10+
11+
When adding new flags or command options, be sure to add:
12+
1. Tests for the flag parsing/presence in help text
13+
2. Tests for the actual behavior when the flag is set or not set
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
6+
After modifying any file:
7+
1. Use grep and/or search project index for the old feature name/variable names that were replaced
8+
2. Check for references in documentation, comments, and test files
9+
3. Look for any deprecated or unused code that can be safely removed or updated
10+
4. Update all related tests to reflect the new implementation
11+
5. Verify any usage examples in documentation are consistent with code changes

.gitignore

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

37-
# Cursor rules
38-
.cursor/rules
39-
4037
# Temp log files
4138
*.log
4239

cmd/upgrade/upgrade.go

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

3333
func NewCommand(clients *shared.ClientFactory) *cobra.Command {
34-
var autoApprove bool
34+
var cli bool
35+
var sdk bool
3536

3637
cmd := &cobra.Command{
3738
Use: "upgrade",
@@ -46,21 +47,24 @@ func NewCommand(clients *shared.ClientFactory) *cobra.Command {
4647
}, "\n"),
4748
Example: style.ExampleCommandsf([]style.ExampleCommand{
4849
{Command: "upgrade", Meaning: "Check for any available updates"},
49-
{Command: "upgrade --auto-approve", Meaning: "Check for updates and automatically upgrade without confirmation"},
50+
{Command: "upgrade --cli", Meaning: "Check for CLI updates and automatically upgrade without confirmation"},
51+
{Command: "upgrade --sdk", Meaning: "Check for SDK updates and automatically upgrade without confirmation"},
52+
{Command: "upgrade --cli --sdk", Meaning: "Check for updates and automatically upgrade both CLI and SDK without confirmation"},
5053
}),
5154
RunE: func(cmd *cobra.Command, args []string) error {
52-
return checkForUpdatesFunc(clients, cmd, autoApprove)
55+
return checkForUpdatesFunc(clients, cmd, cli, sdk)
5356
},
5457
}
5558

56-
cmd.Flags().BoolVar(&autoApprove, "auto-approve", false, "automatically approve and install updates without prompting")
59+
cmd.Flags().BoolVar(&cli, "cli", false, "automatically approve and install CLI updates without prompting")
60+
cmd.Flags().BoolVar(&sdk, "sdk", false, "automatically approve and install SDK updates without prompting")
5761

5862
return cmd
5963
}
6064

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

@@ -77,9 +81,9 @@ func checkForUpdates(clients *shared.ClientFactory, cmd *cobra.Command, autoAppr
7781
// Update notification messages are printed by the root command's persistent post-run (cmd/root.go).
7882
// So this command only needs to print a message when everything is up-to-date.
7983
if updateNotification.HasUpdate() {
80-
if autoApprove {
81-
// Automatically install updates without prompting when auto-approve flag is set
82-
if err := updateNotification.InstallUpdatesWithoutPrompt(cmd); err != nil {
84+
// Automatically install updates without prompting when cli or sdk flags are set
85+
if cli || sdk {
86+
if err := updateNotification.InstallUpdatesWithComponentFlags(cmd, cli, sdk); err != nil {
8387
return err
8488
}
8589
return nil

cmd/upgrade/upgrade_test.go

Lines changed: 72 additions & 18 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, autoApprove bool) error {
33-
args := m.Called(clients, cmd, autoApprove)
32+
func (m *UpdatePkgMock) CheckForUpdates(clients *shared.ClientFactory, cmd *cobra.Command, cli bool, sdk bool) error {
33+
args := m.Called(clients, cmd, cli, sdk)
3434
return args.Error(0)
3535
}
3636

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

52-
// Test default behavior (no auto-approve)
53-
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything, false).Return(nil)
52+
// Test default behavior (no flags)
53+
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything, false, false).Return(nil)
5454
err := cmd.ExecuteContext(ctx)
5555
if err != nil {
5656
assert.Fail(t, "cmd.Upgrade had unexpected error")
5757
}
58-
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything, false)
58+
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything, false, false)
5959

60-
// Test with auto-approve flag
60+
// Test with CLI flag
6161
cmd = NewCommand(clients)
6262
testutil.MockCmdIO(clients.IO, cmd)
63-
cmd.SetArgs([]string{"--auto-approve"})
63+
cmd.SetArgs([]string{"--cli"})
6464

6565
updatePkgMock = new(UpdatePkgMock)
6666
checkForUpdatesFunc = updatePkgMock.CheckForUpdates
67-
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything, true).Return(nil)
67+
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything, true, false).Return(nil)
6868

6969
err = cmd.ExecuteContext(ctx)
7070
if err != nil {
71-
assert.Fail(t, "cmd.Upgrade with auto-approve had unexpected error")
71+
assert.Fail(t, "cmd.Upgrade with cli flag had unexpected error")
7272
}
73-
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything, true)
73+
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything, true, false)
74+
75+
// Test with SDK flag
76+
cmd = NewCommand(clients)
77+
testutil.MockCmdIO(clients.IO, cmd)
78+
cmd.SetArgs([]string{"--sdk"})
79+
80+
updatePkgMock = new(UpdatePkgMock)
81+
checkForUpdatesFunc = updatePkgMock.CheckForUpdates
82+
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything, false, true).Return(nil)
83+
84+
err = cmd.ExecuteContext(ctx)
85+
if err != nil {
86+
assert.Fail(t, "cmd.Upgrade with sdk flag had unexpected error")
87+
}
88+
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything, false, true)
89+
90+
// Test with both CLI and SDK flags
91+
cmd = NewCommand(clients)
92+
testutil.MockCmdIO(clients.IO, cmd)
93+
cmd.SetArgs([]string{"--cli", "--sdk"})
94+
95+
updatePkgMock = new(UpdatePkgMock)
96+
checkForUpdatesFunc = updatePkgMock.CheckForUpdates
97+
updatePkgMock.On("CheckForUpdates", mock.Anything, mock.Anything, true, true).Return(nil)
98+
99+
err = cmd.ExecuteContext(ctx)
100+
if err != nil {
101+
assert.Fail(t, "cmd.Upgrade with both cli and sdk flags had unexpected error")
102+
}
103+
updatePkgMock.AssertCalled(t, "CheckForUpdates", mock.Anything, mock.Anything, true, true)
74104
}
75105

76-
func TestUpgradeCommandWithAutoApproveError(t *testing.T) {
77-
// Create a mock of UpdateNotification that returns an error on InstallUpdatesWithoutPrompt
106+
func TestUpgradeCommandWithFlagError(t *testing.T) {
107+
// Create a mock of UpdateNotification that returns an error on InstallUpdatesWithComponentFlags
78108
originalCheckForUpdates := checkForUpdatesFunc
79109
defer func() {
80110
checkForUpdatesFunc = originalCheckForUpdates
@@ -87,23 +117,47 @@ func TestUpgradeCommandWithAutoApproveError(t *testing.T) {
87117
// Create clients that is mocked for testing
88118
clients := shared.NewClientFactory(clientsMock.MockClientFactory())
89119

90-
// Mock the checkForUpdates function to simulate an error during auto-approve updates
91-
checkForUpdatesFunc = func(clients *shared.ClientFactory, cmd *cobra.Command, autoApprove bool) error {
92-
if autoApprove {
93-
return assert.AnError // Simulate error when auto-approve is true
120+
// Mock the checkForUpdates function to simulate an error during flag-based updates
121+
checkForUpdatesFunc = func(clients *shared.ClientFactory, cmd *cobra.Command, cli bool, sdk bool) error {
122+
if cli || sdk {
123+
return assert.AnError // Simulate error when either flag is true
94124
}
95125
return nil
96126
}
97127

98-
// Create the command with auto-approve flag
128+
// Test with CLI flag causing error
99129
cmd := NewCommand(clients)
100130
testutil.MockCmdIO(clients.IO, cmd)
101-
cmd.SetArgs([]string{"--auto-approve"})
131+
cmd.SetArgs([]string{"--cli"})
102132

103133
// Execute the command and verify it returns the error
104134
err := cmd.ExecuteContext(ctx)
105135

106136
// Verify the error was properly propagated
107137
assert.Error(t, err)
108138
assert.Equal(t, assert.AnError, err)
139+
140+
// Test with SDK flag causing error
141+
cmd = NewCommand(clients)
142+
testutil.MockCmdIO(clients.IO, cmd)
143+
cmd.SetArgs([]string{"--sdk"})
144+
145+
// Execute the command and verify it returns the error
146+
err = cmd.ExecuteContext(ctx)
147+
148+
// Verify the error was properly propagated
149+
assert.Error(t, err)
150+
assert.Equal(t, assert.AnError, err)
151+
152+
// Test with both flags causing error
153+
cmd = NewCommand(clients)
154+
testutil.MockCmdIO(clients.IO, cmd)
155+
cmd.SetArgs([]string{"--cli", "--sdk"})
156+
157+
// Execute the command and verify it returns the error
158+
err = cmd.ExecuteContext(ctx)
159+
160+
// Verify the error was properly propagated
161+
assert.Error(t, err)
162+
assert.Equal(t, assert.AnError, err)
109163
}

docs/reference/commands/slack_upgrade.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@ 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
21+
$ slack upgrade --cli # Check for CLI updates and automatically upgrade without confirmation
22+
$ slack upgrade --sdk # Check for SDK updates and automatically upgrade without confirmation
23+
$ slack upgrade --cli --sdk # Check for updates and automatically upgrade both CLI and SDK without confirmation
2224
```
2325

2426
### Options
2527

2628
```
27-
--auto-approve automatically approve and install updates without prompting
29+
--cli automatically approve and install CLI updates without prompting
2830
-h, --help help for upgrade
31+
--sdk automatically approve and install SDK updates without prompting
2932
```
3033

3134
### Options inherited from parent commands

internal/update/cli.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@ func (c *CLIDependency) PrintUpdateNotification(cmd *cobra.Command) (bool, error
9494
style.CommandText("https://tools.slack.dev/slack-cli"),
9595
)
9696

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 {
97+
// Check for cli flag from upgrade command
98+
if cmd.Name() == "upgrade" && cmd.Flags().Changed("cli") {
99+
cli, _ := cmd.Flags().GetBool("cli")
100+
if cli {
101101
return true, nil
102102
}
103103
}

internal/update/sdk.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,10 @@ 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 {
322+
// Check for sdk flag from upgrade command
323+
if cmd.Name() == "upgrade" && cmd.Flags().Changed("sdk") {
324+
sdk, _ := cmd.Flags().GetBool("sdk")
325+
if sdk {
326326
return true, nil
327327
}
328328
}

internal/update/update.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ import (
3030
"github.com/spf13/cobra"
3131
)
3232

33+
// Functions for type checking that can be replaced in tests
34+
var isDependencyCLI = func(d Dependency) bool {
35+
_, isCLI := d.(*CLIDependency)
36+
return isCLI
37+
}
38+
39+
var isDependencySDK = func(d Dependency) bool {
40+
_, isSDK := d.(*SDKDependency)
41+
return isSDK
42+
}
43+
3344
// UpdateNotification checks for an update (non-blocking in the background or blocking).
3445
// It provides the release information for the latest update of each dependency.
3546
type UpdateNotification struct {
@@ -254,7 +265,7 @@ func newHTTPClient() (*http.Client, error) {
254265
}
255266

256267
// InstallUpdatesWithoutPrompt automatically installs updates without prompting the user
257-
// This is used by the upgrade command when the --auto-approve flag is set
268+
// This is a legacy method maintained for backward compatibility
258269
func (u *UpdateNotification) InstallUpdatesWithoutPrompt(cmd *cobra.Command) error {
259270
ctx := cmd.Context()
260271

@@ -280,3 +291,40 @@ func (u *UpdateNotification) InstallUpdatesWithoutPrompt(cmd *cobra.Command) err
280291
}
281292
return nil
282293
}
294+
295+
// InstallUpdatesWithComponentFlags automatically installs updates for specified components
296+
// without prompting the user. This is used by the upgrade command when the --cli
297+
// or --sdk flags are set.
298+
func (u *UpdateNotification) InstallUpdatesWithComponentFlags(cmd *cobra.Command, cli bool, sdk bool) error {
299+
ctx := cmd.Context()
300+
301+
for _, dependency := range u.Dependencies() {
302+
// Skip dependencies that don't match the specified flags
303+
if isDependencyCLI(dependency) && !cli {
304+
continue
305+
}
306+
if isDependencySDK(dependency) && !sdk {
307+
continue
308+
}
309+
310+
hasUpdate, err := dependency.HasUpdate()
311+
if err != nil {
312+
return slackerror.Wrap(err, "An error occurred while fetching a dependency")
313+
}
314+
315+
if hasUpdate {
316+
// Print update notification but skip the confirmation prompt
317+
_, err := dependency.PrintUpdateNotification(cmd)
318+
if err != nil {
319+
return err
320+
}
321+
322+
// Install the update without prompting
323+
cmd.Printf("%s Installing update automatically...\n", style.Styler().Green("✓").String())
324+
if err := dependency.InstallUpdate(ctx); err != nil {
325+
return err
326+
}
327+
}
328+
}
329+
return nil
330+
}

0 commit comments

Comments
 (0)