From 22ed643eb866d98b0483533387c5bfedb8a6396d Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 20 Nov 2025 15:21:29 -0500 Subject: [PATCH 1/7] unhide read-only collaborator setting for deployed apps --- cmd/collaborators/add.go | 64 ++++---------------------- cmd/collaborators/add_test.go | 6 --- cmd/collaborators/update.go | 48 ++++++++++++------- cmd/collaborators/update_test.go | 34 ++++++++------ docs/reference/experiments.md | 1 - internal/experiment/experiment.go | 5 -- internal/experiment/experiment_test.go | 1 - 7 files changed, 60 insertions(+), 99 deletions(-) diff --git a/cmd/collaborators/add.go b/cmd/collaborators/add.go index c0b07800..61bca43e 100644 --- a/cmd/collaborators/add.go +++ b/cmd/collaborators/add.go @@ -22,7 +22,6 @@ import ( "github.com/opentracing/opentracing-go" "github.com/slackapi/slack-cli/internal/cmdutil" - "github.com/slackapi/slack-cli/internal/experiment" "github.com/slackapi/slack-cli/internal/iostreams" "github.com/slackapi/slack-cli/internal/prompts" "github.com/slackapi/slack-cli/internal/shared" @@ -62,8 +61,7 @@ func NewAddCommand(clients *shared.ClientFactory) *cobra.Command { return runAddCommandFunc(ctx, clients, cmd, args) }, } - cmd.Flags().StringVarP(&addFlags.permissionType, "permission-type", "P", "", "collaborator permission type: reader, owner") - cmd.Flag("permission-type").Hidden = true + cmd.Flags().StringVarP(&addFlags.permissionType, "permission-type", "P", "", "collaborator permission type: [reader|owner]") return cmd } @@ -87,7 +85,7 @@ func runAddCommandFunc(ctx context.Context, clients *shared.ClientFactory, cmd * } err = clients.API().AddCollaborator(ctx, selection.Auth.Token, selection.App.AppID, slackUser) if err != nil { - if clients.Config.WithExperimentOn(experiment.ReadOnlyAppCollaborators) && strings.Contains(err.Error(), "user_already_owner") { + if strings.Contains(err.Error(), "user_already_owner") { cmd.Println() cmd.Println(style.Sectionf(style.TextSection{ Emoji: "bulb", @@ -123,14 +121,15 @@ func promptCollaboratorsAdd( if err != nil { return types.SlackUser{}, err } + switch clients.Config.Flags.Lookup("permission-type").Changed { case true: slackUser.PermissionType, err = promptCollaboratorsAddPermissionFlags(ctx, clients, addFlags.permissionType) + if err != nil { + return types.SlackUser{}, err + } default: - slackUser.PermissionType, err = promptCollaboratorsAddPermissionPrompts(ctx, clients) - } - if err != nil { - return types.SlackUser{}, err + slackUser.PermissionType = types.OWNER } return slackUser, nil } @@ -181,40 +180,7 @@ func promptCollaboratorsAddSlackUserPrompts( return slackUser, nil } -// promptCollaboratorsAddPermissionPrompts gathers the collaborator permission -// from selection if the experiment allows -func promptCollaboratorsAddPermissionPrompts( - ctx context.Context, - clients *shared.ClientFactory, -) ( - permission types.AppCollaboratorPermission, - err error, -) { - switch clients.Config.WithExperimentOn(experiment.ReadOnlyAppCollaborators) { - case false: - return types.OWNER, nil - default: - permissionLabels := []string{ - "owner", - "reader", - } - response, err := clients.IO.SelectPrompt( - ctx, - "Decide the collaborator permission", - permissionLabels, - iostreams.SelectPromptConfig{ - Required: true, - }, - ) - if err != nil { - return "", err - } - return types.StringToAppCollaboratorPermission(response.Option) - } -} - -// promptCollaboratorsAddPermissionFlags gathers the collaborator permission -// from flags if the experiment allows +// promptCollaboratorsAddPermissionFlags fetches collaborator permission from the flag func promptCollaboratorsAddPermissionFlags( ctx context.Context, clients *shared.ClientFactory, @@ -223,19 +189,7 @@ func promptCollaboratorsAddPermissionFlags( permission types.AppCollaboratorPermission, err error, ) { - switch clients.Config.WithExperimentOn(experiment.ReadOnlyAppCollaborators) { - case true: - return types.StringToAppCollaboratorPermission(addFlags.permissionType) - default: - clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{ - Emoji: "construction", - Text: fmt.Sprintf("This command is under construction. Use at your own risk %s", style.Emoji("skull")), - Secondary: []string{ - fmt.Sprintf("Bypass this message with the %s flag", style.Highlight("--experiment read-only-collaborators")), - }, - })) - return "", slackerror.New(slackerror.ErrMissingExperiment) - } + return types.StringToAppCollaboratorPermission(addFlags.permissionType) } // printCollaboratorsAddSuccess outputs a message when addition is done diff --git a/cmd/collaborators/add_test.go b/cmd/collaborators/add_test.go index 69139d99..2a8b12dd 100644 --- a/cmd/collaborators/add_test.go +++ b/cmd/collaborators/add_test.go @@ -37,9 +37,6 @@ func TestAddCommand(t *testing.T) { appSelectMock := prompts.NewAppSelectMock() appSelectPromptFunc = appSelectMock.AppSelectPrompt appSelectMock.On("AppSelectPrompt", mock.Anything, mock.Anything, prompts.ShowHostedOnly, prompts.ShowInstalledAndUninstalledApps).Return(prompts.SelectedApp{App: types.App{AppID: "A123"}, Auth: types.SlackAuth{}}, nil) - // Set experiment flag - cm.Config.ExperimentsFlag = append(cm.Config.ExperimentsFlag, "read-only-collaborators") - cm.Config.LoadExperiments(ctx, cm.IO.PrintDebug) // Mock API call cm.API.On("AddCollaborator", mock.Anything, mock.Anything, "A123", @@ -61,9 +58,6 @@ func TestAddCommand(t *testing.T) { appSelectMock := prompts.NewAppSelectMock() appSelectPromptFunc = appSelectMock.AppSelectPrompt appSelectMock.On("AppSelectPrompt", mock.Anything, mock.Anything, prompts.ShowHostedOnly, prompts.ShowInstalledAndUninstalledApps).Return(prompts.SelectedApp{App: types.App{AppID: "A123"}, Auth: types.SlackAuth{}}, nil) - // Set experiment flag - cm.Config.ExperimentsFlag = append(cm.Config.ExperimentsFlag, "read-only-collaborators") - cm.Config.LoadExperiments(ctx, cm.IO.PrintDebug) // Mock API call cm.API.On("AddCollaborator", mock.Anything, mock.Anything, "A123", diff --git a/cmd/collaborators/update.go b/cmd/collaborators/update.go index 78e056bb..6f620242 100644 --- a/cmd/collaborators/update.go +++ b/cmd/collaborators/update.go @@ -15,12 +15,12 @@ package collaborators import ( - "fmt" + "context" "net/mail" "github.com/opentracing/opentracing-go" "github.com/slackapi/slack-cli/internal/cmdutil" - "github.com/slackapi/slack-cli/internal/experiment" + "github.com/slackapi/slack-cli/internal/iostreams" "github.com/slackapi/slack-cli/internal/prompts" "github.com/slackapi/slack-cli/internal/shared" "github.com/slackapi/slack-cli/internal/shared/types" @@ -51,18 +51,6 @@ func NewUpdateCommand(clients *shared.ClientFactory) *cobra.Command { return cmdutil.IsValidProjectDirectory(clients) }, RunE: func(cmd *cobra.Command, args []string) error { - if !clients.Config.WithExperimentOn(experiment.ReadOnlyAppCollaborators) { - cmd.Println() - cmd.Println(style.Sectionf(style.TextSection{ - Emoji: "construction", - Text: fmt.Sprintf("This command is under construction. Use at your own risk %s", style.Emoji("skull")), - Secondary: []string{ - fmt.Sprintf("Bypass this message with the %s flag", style.Highlight("--experiment read-only-collaborators")), - }, - })) - return nil - } - return runUpdateCommand(cmd, clients, args) }, } @@ -92,8 +80,10 @@ func runUpdateCommand(cmd *cobra.Command, clients *shared.ClientFactory, args [] return err } } else { - cmd.Println(fmt.Sprintf("\n%s Specify a permission type for your collaborator with the %s flag\n", style.Emoji("warning"), style.Highlight("--permission-type"))) - return nil + slackUser.PermissionType, err = promptCollaboratorPermissionSelection(ctx, clients) + if err != nil { + return err + } } // Get the app auth selection from the flag or prompt @@ -117,3 +107,29 @@ func runUpdateCommand(cmd *cobra.Command, clients *shared.ClientFactory, args [] return nil } + +// promptCollaboratorPermissionSelection fetches collaborator permission from the prompt +func promptCollaboratorPermissionSelection( + ctx context.Context, + clients *shared.ClientFactory, +) ( + permission types.AppCollaboratorPermission, + err error, +) { + permissionLabels := []string{ + "owner", + "reader", + } + response, err := clients.IO.SelectPrompt( + ctx, + "Select a permission type for this collaborator", + permissionLabels, + iostreams.SelectPromptConfig{ + Required: true, + }, + ) + if err != nil { + return "", err + } + return types.StringToAppCollaboratorPermission(response.Option) +} diff --git a/cmd/collaborators/update_test.go b/cmd/collaborators/update_test.go index f2ab1ed4..b77aab20 100644 --- a/cmd/collaborators/update_test.go +++ b/cmd/collaborators/update_test.go @@ -18,6 +18,7 @@ import ( "context" "testing" + "github.com/slackapi/slack-cli/internal/iostreams" "github.com/slackapi/slack-cli/internal/prompts" "github.com/slackapi/slack-cli/internal/shared" "github.com/slackapi/slack-cli/internal/shared/types" @@ -37,9 +38,6 @@ func TestUpdateCommand(t *testing.T) { appSelectMock := prompts.NewAppSelectMock() appSelectPromptFunc = appSelectMock.AppSelectPrompt appSelectMock.On("AppSelectPrompt", mock.Anything, mock.Anything, prompts.ShowHostedOnly, prompts.ShowInstalledAndUninstalledApps).Return(prompts.SelectedApp{App: types.App{AppID: "A123"}, Auth: types.SlackAuth{}}, nil) - // Set experiment flag - clientsMock.Config.ExperimentsFlag = append(clientsMock.Config.ExperimentsFlag, "read-only-collaborators") - clientsMock.Config.LoadExperiments(ctx, clientsMock.IO.PrintDebug) // Mock APi call clientsMock.API.On("UpdateCollaborator", mock.Anything, mock.Anything, "A123", @@ -55,23 +53,32 @@ func TestUpdateCommand(t *testing.T) { appSelectMock := prompts.NewAppSelectMock() appSelectPromptFunc = appSelectMock.AppSelectPrompt appSelectMock.On("AppSelectPrompt", mock.Anything, mock.Anything, prompts.ShowHostedOnly, prompts.ShowInstalledAndUninstalledApps).Return(prompts.SelectedApp{App: types.App{AppID: "A123"}, Auth: types.SlackAuth{}}, nil) - // Set experiment flag - clientsMock.Config.ExperimentsFlag = append(clientsMock.Config.ExperimentsFlag, "read-only-collaborators") - clientsMock.Config.LoadExperiments(ctx, clientsMock.IO.PrintDebug) - // Mock APi call + // Mock API call clientsMock.API.On("UpdateCollaborator", mock.Anything, mock.Anything, "A123", types.SlackUser{Email: "joe.smith@company.com", PermissionType: types.OWNER}).Return(nil) }, }, - "permission type must be specified": { + "prompts when permission type not specified": { CmdArgs: []string{"joe.smith@company.com"}, - ExpectedOutputs: []string{"Specify a permission type for your collaborator"}, + ExpectedOutputs: []string{"joe.smith@company.com successfully updated as a reader collaborator on this app"}, Setup: func(t *testing.T, ctx context.Context, clientsMock *shared.ClientsMock, clients *shared.ClientFactory) { clientsMock.AddDefaultMocks() - // Set experiment flag - clientsMock.Config.ExperimentsFlag = append(clientsMock.Config.ExperimentsFlag, "read-only-collaborators") - clientsMock.Config.LoadExperiments(ctx, clientsMock.IO.PrintDebug) + // Mock app selection + appSelectMock := prompts.NewAppSelectMock() + appSelectPromptFunc = appSelectMock.AppSelectPrompt + appSelectMock.On("AppSelectPrompt", mock.Anything, mock.Anything, prompts.ShowHostedOnly, prompts.ShowInstalledAndUninstalledApps).Return(prompts.SelectedApp{App: types.App{AppID: "A123"}, Auth: types.SlackAuth{}}, nil) + // Mock permission selection prompt + clientsMock.IO.On("SelectPrompt", mock.Anything, "Select a permission type for this collaborator", mock.Anything, mock.Anything).Return( + iostreams.SelectPromptResponse{ + Prompt: true, + Option: "reader", + Index: 1, + }, nil) + // Mock API call + clientsMock.API.On("UpdateCollaborator", mock.Anything, mock.Anything, + "A123", + types.SlackUser{Email: "joe.smith@company.com", PermissionType: types.READER}).Return(nil) }, }, "user ID must be provided": { @@ -79,9 +86,6 @@ func TestUpdateCommand(t *testing.T) { ExpectedErrorStrings: []string{"accepts 1 arg(s), received 0"}, Setup: func(t *testing.T, ctx context.Context, clientsMock *shared.ClientsMock, clients *shared.ClientFactory) { clientsMock.AddDefaultMocks() - // Set experiment flag - clientsMock.Config.ExperimentsFlag = append(clientsMock.Config.ExperimentsFlag, "read-only-collaborators") - clientsMock.Config.LoadExperiments(ctx, clientsMock.IO.PrintDebug) }, }, }, func(clients *shared.ClientFactory) *cobra.Command { diff --git a/docs/reference/experiments.md b/docs/reference/experiments.md index 9b73a32f..a163f9c7 100644 --- a/docs/reference/experiments.md +++ b/docs/reference/experiments.md @@ -9,7 +9,6 @@ The following is a list of currently available experiments. We'll remove experim * `bolt-install`: enables creating, installing, and running Bolt projects that manage their app manifest on app settings (remote manifest). * `slack create` and `slack init` now set manifest source to "app settings" (remote) for Bolt JS & Bolt Python projects ([PR#96](https://github.com/slackapi/slack-cli/pull/96)). * `slack run` and `slack install` support creating and installing Bolt Framework apps that have the manifest source set to "app settings (remote)" ([PR#111](https://github.com/slackapi/slack-cli/pull/111), [PR#154](https://github.com/slackapi/slack-cli/pull/154)). -* `read-only-collaborators`: enables creating and modifying collaborator permissions via the `slack collaborator` commands. ## Experiments changelog diff --git a/internal/experiment/experiment.go b/internal/experiment/experiment.go index 65878654..d4de14dd 100644 --- a/internal/experiment/experiment.go +++ b/internal/experiment/experiment.go @@ -38,10 +38,6 @@ const ( // manage their app manifest on app settings (remote manifest). BoltInstall Experiment = "bolt-install" - // The ReadOnlyAppCollaborators experiment enables creating and modifying collaborator - // permissions via the `collaborator` commands. - ReadOnlyAppCollaborators Experiment = "read-only-collaborators" - // Placeholder experiment is a placeholder for testing and does nothing... or does it? Placeholder Experiment = "placeholder" ) @@ -51,7 +47,6 @@ const ( var AllExperiments = []Experiment{ BoltFrameworks, BoltInstall, - ReadOnlyAppCollaborators, Placeholder, } diff --git a/internal/experiment/experiment_test.go b/internal/experiment/experiment_test.go index b9e94df6..699f6e90 100644 --- a/internal/experiment/experiment_test.go +++ b/internal/experiment/experiment_test.go @@ -26,7 +26,6 @@ func Test_Includes(t *testing.T) { // Test expected experiments require.Equal(t, true, Includes(Experiment("bolt"))) - require.Equal(t, true, Includes(Experiment("read-only-collaborators"))) // Test invalid experiment require.Equal(t, false, Includes(Experiment("should-fail"))) From 1100c37967b2a0f311c983f1b475207bf93258da Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 20 Nov 2025 16:00:20 -0500 Subject: [PATCH 2/7] update --- cmd/collaborators/update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/collaborators/update.go b/cmd/collaborators/update.go index 6f620242..61638276 100644 --- a/cmd/collaborators/update.go +++ b/cmd/collaborators/update.go @@ -55,7 +55,7 @@ func NewUpdateCommand(clients *shared.ClientFactory) *cobra.Command { }, } - cmd.Flags().StringVarP(&updateFlags.permissionType, "permission-type", "P", "", "collaborator permission type: reader, owner") + cmd.Flags().StringVarP(&updateFlags.permissionType, "permission-type", "P", "", "collaborator permission type: [reader|owner]") return cmd } From 48841e074e4b01d110fb06aa42dd2753fe05004b Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 20 Nov 2025 17:08:29 -0500 Subject: [PATCH 3/7] update prompt wording --- cmd/collaborators/update.go | 2 +- cmd/collaborators/update_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/collaborators/update.go b/cmd/collaborators/update.go index 61638276..1a48994d 100644 --- a/cmd/collaborators/update.go +++ b/cmd/collaborators/update.go @@ -122,7 +122,7 @@ func promptCollaboratorPermissionSelection( } response, err := clients.IO.SelectPrompt( ctx, - "Select a permission type for this collaborator", + "Select a permission type", permissionLabels, iostreams.SelectPromptConfig{ Required: true, diff --git a/cmd/collaborators/update_test.go b/cmd/collaborators/update_test.go index b77aab20..a52cc076 100644 --- a/cmd/collaborators/update_test.go +++ b/cmd/collaborators/update_test.go @@ -69,7 +69,7 @@ func TestUpdateCommand(t *testing.T) { appSelectPromptFunc = appSelectMock.AppSelectPrompt appSelectMock.On("AppSelectPrompt", mock.Anything, mock.Anything, prompts.ShowHostedOnly, prompts.ShowInstalledAndUninstalledApps).Return(prompts.SelectedApp{App: types.App{AppID: "A123"}, Auth: types.SlackAuth{}}, nil) // Mock permission selection prompt - clientsMock.IO.On("SelectPrompt", mock.Anything, "Select a permission type for this collaborator", mock.Anything, mock.Anything).Return( + clientsMock.IO.On("SelectPrompt", mock.Anything, "Select a permission type", mock.Anything, mock.Anything).Return( iostreams.SelectPromptResponse{ Prompt: true, Option: "reader", From 6c020f72b4d821b175a842ab387f8b2832c6c216 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Wed, 26 Nov 2025 19:28:01 -0500 Subject: [PATCH 4/7] Update cmd/collaborators/add.go Co-authored-by: Michael Brooks --- cmd/collaborators/add.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/collaborators/add.go b/cmd/collaborators/add.go index 61bca43e..7a0db5ed 100644 --- a/cmd/collaborators/add.go +++ b/cmd/collaborators/add.go @@ -61,7 +61,11 @@ func NewAddCommand(clients *shared.ClientFactory) *cobra.Command { return runAddCommandFunc(ctx, clients, cmd, args) }, } - cmd.Flags().StringVarP(&addFlags.permissionType, "permission-type", "P", "", "collaborator permission type: [reader|owner]") + cmd.Flags().StringVarP(&addFlags.permissionType, "permission-type", "P", string(types.OWNER), fmt.Sprintf( + "collaborator permission type\n(\"%s\" or \"%s\")", + string(types.OWNER), + string(types.READER), + )) return cmd } From 8e68452cfc40a75dc1d14f532982c4192c75e029 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 27 Nov 2025 10:56:13 -0500 Subject: [PATCH 5/7] Update cmd/collaborators/update.go Co-authored-by: Michael Brooks --- cmd/collaborators/update.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/collaborators/update.go b/cmd/collaborators/update.go index 1a48994d..050044e3 100644 --- a/cmd/collaborators/update.go +++ b/cmd/collaborators/update.go @@ -55,7 +55,11 @@ func NewUpdateCommand(clients *shared.ClientFactory) *cobra.Command { }, } - cmd.Flags().StringVarP(&updateFlags.permissionType, "permission-type", "P", "", "collaborator permission type: [reader|owner]") + cmd.Flags().StringVarP(&updateFlags.permissionType, "permission-type", "P", "", fmt.Sprintf( + "collaborator permission type\n(\"%s\" or \"%s\")", + string(types.OWNER), + string(types.READER), + ))``` return cmd } From b12ed2b69ed1eca61a9ceb9bd068467b6f419467 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 27 Nov 2025 11:15:25 -0500 Subject: [PATCH 6/7] error out when flag not provided --- cmd/collaborators/update.go | 37 ++++---------------------------- cmd/collaborators/update_test.go | 23 +++++--------------- 2 files changed, 9 insertions(+), 51 deletions(-) diff --git a/cmd/collaborators/update.go b/cmd/collaborators/update.go index 050044e3..cd8beebe 100644 --- a/cmd/collaborators/update.go +++ b/cmd/collaborators/update.go @@ -15,12 +15,11 @@ package collaborators import ( - "context" + "fmt" "net/mail" "github.com/opentracing/opentracing-go" "github.com/slackapi/slack-cli/internal/cmdutil" - "github.com/slackapi/slack-cli/internal/iostreams" "github.com/slackapi/slack-cli/internal/prompts" "github.com/slackapi/slack-cli/internal/shared" "github.com/slackapi/slack-cli/internal/shared/types" @@ -59,7 +58,7 @@ func NewUpdateCommand(clients *shared.ClientFactory) *cobra.Command { "collaborator permission type\n(\"%s\" or \"%s\")", string(types.OWNER), string(types.READER), - ))``` + )) return cmd } @@ -84,10 +83,8 @@ func runUpdateCommand(cmd *cobra.Command, clients *shared.ClientFactory, args [] return err } } else { - slackUser.PermissionType, err = promptCollaboratorPermissionSelection(ctx, clients) - if err != nil { - return err - } + cmd.Println(fmt.Sprintf("\n%s Specify a permission type for your collaborator with the %s flag\n", style.Emoji("warning"), style.Highlight("--permission-type"))) + return nil } // Get the app auth selection from the flag or prompt @@ -111,29 +108,3 @@ func runUpdateCommand(cmd *cobra.Command, clients *shared.ClientFactory, args [] return nil } - -// promptCollaboratorPermissionSelection fetches collaborator permission from the prompt -func promptCollaboratorPermissionSelection( - ctx context.Context, - clients *shared.ClientFactory, -) ( - permission types.AppCollaboratorPermission, - err error, -) { - permissionLabels := []string{ - "owner", - "reader", - } - response, err := clients.IO.SelectPrompt( - ctx, - "Select a permission type", - permissionLabels, - iostreams.SelectPromptConfig{ - Required: true, - }, - ) - if err != nil { - return "", err - } - return types.StringToAppCollaboratorPermission(response.Option) -} diff --git a/cmd/collaborators/update_test.go b/cmd/collaborators/update_test.go index a52cc076..e1ea7f0c 100644 --- a/cmd/collaborators/update_test.go +++ b/cmd/collaborators/update_test.go @@ -18,7 +18,6 @@ import ( "context" "testing" - "github.com/slackapi/slack-cli/internal/iostreams" "github.com/slackapi/slack-cli/internal/prompts" "github.com/slackapi/slack-cli/internal/shared" "github.com/slackapi/slack-cli/internal/shared/types" @@ -59,26 +58,14 @@ func TestUpdateCommand(t *testing.T) { types.SlackUser{Email: "joe.smith@company.com", PermissionType: types.OWNER}).Return(nil) }, }, - "prompts when permission type not specified": { + "permission type must be specified": { CmdArgs: []string{"joe.smith@company.com"}, - ExpectedOutputs: []string{"joe.smith@company.com successfully updated as a reader collaborator on this app"}, + ExpectedOutputs: []string{"Specify a permission type for your collaborator"}, Setup: func(t *testing.T, ctx context.Context, clientsMock *shared.ClientsMock, clients *shared.ClientFactory) { clientsMock.AddDefaultMocks() - // Mock app selection - appSelectMock := prompts.NewAppSelectMock() - appSelectPromptFunc = appSelectMock.AppSelectPrompt - appSelectMock.On("AppSelectPrompt", mock.Anything, mock.Anything, prompts.ShowHostedOnly, prompts.ShowInstalledAndUninstalledApps).Return(prompts.SelectedApp{App: types.App{AppID: "A123"}, Auth: types.SlackAuth{}}, nil) - // Mock permission selection prompt - clientsMock.IO.On("SelectPrompt", mock.Anything, "Select a permission type", mock.Anything, mock.Anything).Return( - iostreams.SelectPromptResponse{ - Prompt: true, - Option: "reader", - Index: 1, - }, nil) - // Mock API call - clientsMock.API.On("UpdateCollaborator", mock.Anything, mock.Anything, - "A123", - types.SlackUser{Email: "joe.smith@company.com", PermissionType: types.READER}).Return(nil) + // Set experiment flag + clientsMock.Config.ExperimentsFlag = append(clientsMock.Config.ExperimentsFlag, "read-only-collaborators") + clientsMock.Config.LoadExperiments(ctx, clientsMock.IO.PrintDebug) }, }, "user ID must be provided": { From fa544dd97957daa0ef6a8fe09a197e51234f9109 Mon Sep 17 00:00:00 2001 From: Elaine Vegeris Date: Thu, 27 Nov 2025 11:49:21 -0500 Subject: [PATCH 7/7] update error message --- internal/shared/types/permissions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/shared/types/permissions.go b/internal/shared/types/permissions.go index cd6f7d27..f4c73390 100644 --- a/internal/shared/types/permissions.go +++ b/internal/shared/types/permissions.go @@ -37,7 +37,7 @@ func StringToAppCollaboratorPermission(input string) (AppCollaboratorPermission, case "reader": return READER, nil default: - return "", fmt.Errorf("invalid") + return "", fmt.Errorf("invalid permission; accepted values are \"owner\" or \"reader\"") } }