From 2b70a6c94b5a7b5999f88e1dfe0db545b890b799 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 3 Mar 2026 22:08:58 -0800 Subject: [PATCH] chore(experiment): remove defaulted bolt and bolt-install experiments --- cmd/app/add.go | 4 - cmd/app/add_test.go | 23 +-- docs/reference/experiments.md | 4 +- internal/experiment/experiment.go | 15 +- internal/experiment/experiment_test.go | 1 - internal/pkg/apps/install.go | 94 +++---------- internal/pkg/apps/install_test.go | 185 ++++++++----------------- internal/pkg/create/create.go | 15 +- internal/pkg/create/create_test.go | 8 +- 9 files changed, 104 insertions(+), 245 deletions(-) diff --git a/cmd/app/add.go b/cmd/app/add.go index 39b4623c..726ae61e 100644 --- a/cmd/app/add.go +++ b/cmd/app/add.go @@ -21,7 +21,6 @@ import ( "github.com/slackapi/slack-cli/internal/app" "github.com/slackapi/slack-cli/internal/cmdutil" "github.com/slackapi/slack-cli/internal/config" - "github.com/slackapi/slack-cli/internal/experiment" "github.com/slackapi/slack-cli/internal/logger" "github.com/slackapi/slack-cli/internal/pkg/apps" "github.com/slackapi/slack-cli/internal/prompts" @@ -85,9 +84,6 @@ func preRunAddCommand(ctx context.Context, clients *shared.ClientFactory, cmd *c if err != nil { return err } - if !clients.Config.WithExperimentOn(experiment.BoltFrameworks) { - return nil - } clients.Config.SetFlags(cmd) return nil } diff --git a/cmd/app/add_test.go b/cmd/app/add_test.go index 8b549b69..e3fd2182 100644 --- a/cmd/app/add_test.go +++ b/cmd/app/add_test.go @@ -23,7 +23,6 @@ import ( "github.com/slackapi/slack-cli/internal/cache" "github.com/slackapi/slack-cli/internal/cmdutil" "github.com/slackapi/slack-cli/internal/config" - "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" @@ -85,25 +84,21 @@ func TestAppAddCommandPreRun(t *testing.T) { cf.SDKConfig.WorkingDirectory = "." }, }, - "proceeds if manifest.source is local with the bolt experiment": { + "proceeds if manifest.source is local": { ExpectedError: nil, Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { cf.SDKConfig.WorkingDirectory = "." cm.AddDefaultMocks() - cm.Config.ExperimentsFlag = append(cm.Config.ExperimentsFlag, string(experiment.BoltFrameworks)) - cm.Config.LoadExperiments(ctx, cm.IO.PrintDebug) mockProjectConfig := config.NewProjectConfigMock() mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) cm.Config.ProjectConfig = mockProjectConfig }, }, - "proceeds if manifest.source is remote with the bolt experiment": { + "proceeds if manifest.source is remote": { ExpectedError: nil, Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { cf.SDKConfig.WorkingDirectory = "." cm.AddDefaultMocks() - cm.Config.ExperimentsFlag = append(cm.Config.ExperimentsFlag, string(experiment.BoltFrameworks)) - cm.Config.LoadExperiments(ctx, cm.IO.PrintDebug) mockProjectConfig := config.NewProjectConfigMock() mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceRemote, nil) cm.Config.ProjectConfig = mockProjectConfig @@ -207,6 +202,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -279,6 +275,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -343,7 +340,7 @@ func TestAppAddCommand(t *testing.T) { nil, ) - // Mock existing and updated cache + // Mock existing and updated cache - hashes must match for update to proceed cm.API.On( "ExportAppManifest", mock.Anything, @@ -357,10 +354,11 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("GetManifestHash", mock.Anything, mock.Anything). Return(cache.Hash("b4b4"), nil) mockProjectCache.On("NewManifestHash", mock.Anything, mock.Anything). - Return(cache.Hash("xoxo"), nil) + Return(cache.Hash("b4b4"), nil) // matching hash allows update to proceed mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -428,6 +426,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -515,6 +514,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -599,6 +599,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -685,6 +686,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -760,6 +762,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -816,6 +819,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, @@ -872,6 +876,7 @@ func TestAppAddCommand(t *testing.T) { mockProjectCache.On("SetManifestHash", mock.Anything, mock.Anything, mock.Anything). Return(nil) mockProjectConfig := config.NewProjectConfigMock() + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(config.ManifestSourceLocal, nil) mockProjectConfig.On("Cache").Return(mockProjectCache) cm.Config.ProjectConfig = mockProjectConfig }, diff --git a/docs/reference/experiments.md b/docs/reference/experiments.md index ae29bc61..945597ee 100644 --- a/docs/reference/experiments.md +++ b/docs/reference/experiments.md @@ -6,15 +6,13 @@ The Slack CLI has an experiment (`-e`) flag behind which we put features current The following is a list of currently available experiments. We'll remove experiments from this page if we decide they are no longer needed or once they are released, in which case we'll make an announcement about the feature's general availability in the [developer changelog](https://docs.slack.dev/changelog). -- `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)). - `charm`: shows beautiful prompts ([PR#348](https://github.com/slackapi/slack-cli/pull/348)). ## Experiments changelog Below is a list of updates related to experiments. +- **March 2026**: Concluded the `bolt` and `bolt-install` experiments with full Bolt framework support now enabled by default in the Slack CLI. All Bolt project features including remote manifest management are now standard functionality. See the announcement [here](https://slack.dev/slackcli-supports-bolt-apps/). - **February 2026**: Added the `charm` experiment. - **December 2025**: Concluded the `read-only-collaborators` experiment with full support introduced to the Slack CLI. See the changelog announcement [here](https://docs.slack.dev/changelog/2025/12/04/slack-cli). - **June 2025**: diff --git a/internal/experiment/experiment.go b/internal/experiment/experiment.go index c7b90149..7a0f4345 100644 --- a/internal/experiment/experiment.go +++ b/internal/experiment/experiment.go @@ -30,14 +30,6 @@ type Experiment string // e.g. --experiment=first-toggle,second-toggle const ( - // BoltFrameworks experiment adds CLI support for Bolt JavaScript & Bolt Python. - // These frameworks will be introducing remote function support. - BoltFrameworks Experiment = "bolt" - - // BoltInstall experiment enables developerInstall to work with Bolt projects that - // manage their app manifest on app settings (remote manifest). - BoltInstall Experiment = "bolt-install" - // Charm experiment enables beautiful prompts. Charm Experiment = "charm" @@ -48,18 +40,13 @@ const ( // AllExperiments is a list of all available experiments that can be enabled // Please also add here 👇 var AllExperiments = []Experiment{ - BoltFrameworks, - BoltInstall, Charm, Placeholder, } // EnabledExperiments is a list of experiments that are permanently enabled // Please also add here 👇 -var EnabledExperiments = []Experiment{ - BoltFrameworks, - BoltInstall, -} +var EnabledExperiments = []Experiment{} // Includes checks that a supplied experiment is included within AllExperiments func Includes(expToCheck Experiment) bool { diff --git a/internal/experiment/experiment_test.go b/internal/experiment/experiment_test.go index fa27f80b..b138a921 100644 --- a/internal/experiment/experiment_test.go +++ b/internal/experiment/experiment_test.go @@ -25,7 +25,6 @@ func Test_Includes(t *testing.T) { require.Equal(t, true, Includes(Experiment(Placeholder))) // Test expected experiments - require.Equal(t, true, Includes(Experiment("bolt"))) require.Equal(t, true, Includes(Experiment("charm"))) // Test invalid experiment diff --git a/internal/pkg/apps/install.go b/internal/pkg/apps/install.go index 7bfe922a..52e44390 100644 --- a/internal/pkg/apps/install.go +++ b/internal/pkg/apps/install.go @@ -24,7 +24,6 @@ import ( "github.com/opentracing/opentracing-go" "github.com/slackapi/slack-cli/internal/api" "github.com/slackapi/slack-cli/internal/config" - "github.com/slackapi/slack-cli/internal/experiment" "github.com/slackapi/slack-cli/internal/logger" "github.com/slackapi/slack-cli/internal/pkg/manifest" "github.com/slackapi/slack-cli/internal/shared" @@ -55,12 +54,6 @@ func Install(ctx context.Context, clients *shared.ClientFactory, log *logger.Log return types.App{}, "", err } - if !clients.Config.WithExperimentOn(experiment.BoltInstall) { - if !manifestUpdates && !manifestCreates { - return app, "", nil - } - } - // Get the token for the authenticated workspace apiInterface := clients.API() token := auth.Token @@ -84,31 +77,21 @@ func Install(ctx context.Context, clients *shared.ClientFactory, log *logger.Log app.EnterpriseID = *authSession.EnterpriseID } - // When the BoltInstall experiment is enabled, we need to get the manifest from the local file - // if the manifest source is local or if we are creating a new app. After an app is created, - // app settings becomes the source of truth for remote manifests, so updates and installs always - // get the latest manifest from app settings. - // When the BoltInstall experiment is disabled, we get the manifest from the local file because - // this is how the original implementation worked. + // Get the manifest from the local file if the manifest source is local or if we are creating + // a new app. After an app is created, app settings becomes the source of truth for remote + // manifests, so updates and installs always get the latest manifest from app settings. var slackManifest types.SlackYaml - if clients.Config.WithExperimentOn(experiment.BoltInstall) { - manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx) + manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx) + if err != nil { + return app, "", err + } + if manifestSource.Equals(config.ManifestSourceLocal) || manifestCreates { + slackManifest, err = clients.AppClient().Manifest.GetManifestLocal(ctx, clients.SDKConfig, clients.HookExecutor) if err != nil { return app, "", err } - if manifestSource.Equals(config.ManifestSourceLocal) || manifestCreates { - slackManifest, err = clients.AppClient().Manifest.GetManifestLocal(ctx, clients.SDKConfig, clients.HookExecutor) - if err != nil { - return app, "", err - } - } else { - slackManifest, err = clients.AppClient().Manifest.GetManifestRemote(ctx, auth.Token, app.AppID) - if err != nil { - return app, "", err - } - } } else { - slackManifest, err = clients.AppClient().Manifest.GetManifestLocal(ctx, clients.SDKConfig, clients.HookExecutor) + slackManifest, err = clients.AppClient().Manifest.GetManifestRemote(ctx, auth.Token, app.AppID) if err != nil { return app, "", err } @@ -369,12 +352,6 @@ func InstallLocalApp(ctx context.Context, clients *shared.ClientFactory, orgGran return types.App{}, api.DeveloperAppInstallResult{}, "", err } - if !clients.Config.WithExperimentOn(experiment.BoltInstall) { - if !manifestUpdates && !manifestCreates { - return app, api.DeveloperAppInstallResult{}, "", nil - } - } - apiInterface := clients.API() token := auth.Token authSession, err := apiInterface.ValidateSession(ctx, token) @@ -398,31 +375,21 @@ func InstallLocalApp(ctx context.Context, clients *shared.ClientFactory, orgGran // app.EnterpriseID = *authSession.EnterpriseID } - // When the BoltInstall experiment is enabled, we need to get the manifest from the local file - // if the manifest source is local or if we are creating a new app. After an app is created, - // app settings becomes the source of truth for remote manifests, so updates and installs always - // get the latest manifest from app settings. - // When the BoltInstall experiment is disabled, we get the manifest from the local file because - // this is how the original implementation worked. + // Get the manifest from the local file if the manifest source is local or if we are creating + // a new app. After an app is created, app settings becomes the source of truth for remote + // manifests, so updates and installs always get the latest manifest from app settings. var slackManifest types.SlackYaml - if clients.Config.WithExperimentOn(experiment.BoltInstall) { - manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx) + manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx) + if err != nil { + return app, api.DeveloperAppInstallResult{}, "", err + } + if manifestSource.Equals(config.ManifestSourceLocal) || manifestCreates { + slackManifest, err = clients.AppClient().Manifest.GetManifestLocal(ctx, clients.SDKConfig, clients.HookExecutor) if err != nil { return app, api.DeveloperAppInstallResult{}, "", err } - if manifestSource.Equals(config.ManifestSourceLocal) || manifestCreates { - slackManifest, err = clients.AppClient().Manifest.GetManifestLocal(ctx, clients.SDKConfig, clients.HookExecutor) - if err != nil { - return app, api.DeveloperAppInstallResult{}, "", err - } - } else { - slackManifest, err = clients.AppClient().Manifest.GetManifestRemote(ctx, auth.Token, app.AppID) - if err != nil { - return app, api.DeveloperAppInstallResult{}, "", err - } - } } else { - slackManifest, err = clients.AppClient().Manifest.GetManifestLocal(ctx, clients.SDKConfig, clients.HookExecutor) + slackManifest, err = clients.AppClient().Manifest.GetManifestRemote(ctx, auth.Token, app.AppID) if err != nil { return app, api.DeveloperAppInstallResult{}, "", err } @@ -700,27 +667,11 @@ func updateIcon(ctx context.Context, clients *shared.ClientFactory, iconPath, ap // shouldCreateManifest decides if an app manifest needs to be created for an // app to exist func shouldCreateManifest(ctx context.Context, clients *shared.ClientFactory, app types.App) (bool, error) { - if !clients.Config.WithExperimentOn(experiment.BoltFrameworks) { - return app.AppID == "", nil - } - - // When the BoltInstall experiment is enabled, apps can always be created with any manifest source. - if clients.Config.WithExperimentOn(experiment.BoltInstall) { - return app.AppID == "", nil - } - - manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx) - if err != nil { - return false, err - } - return app.AppID == "" && manifestSource == config.ManifestSourceLocal, nil + return app.AppID == "", nil } // shouldCacheManifest decides if an app manifest hash should be saved to cache func shouldCacheManifest(ctx context.Context, clients *shared.ClientFactory, app types.App) (bool, error) { - if !clients.Config.WithExperimentOn(experiment.BoltFrameworks) { - return false, nil - } manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx) if err != nil { return false, err @@ -753,9 +704,6 @@ func shouldUpdateManifest(ctx context.Context, clients *shared.ClientFactory, ap if app.AppID == "" { return false, nil } - if !clients.Config.WithExperimentOn(experiment.BoltFrameworks) { - return true, nil - } manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx) if err != nil { return false, err diff --git a/internal/pkg/apps/install_test.go b/internal/pkg/apps/install_test.go index 60503614..53d9b3db 100644 --- a/internal/pkg/apps/install_test.go +++ b/internal/pkg/apps/install_test.go @@ -22,7 +22,6 @@ import ( "github.com/slackapi/slack-cli/internal/app" "github.com/slackapi/slack-cli/internal/cache" "github.com/slackapi/slack-cli/internal/config" - "github.com/slackapi/slack-cli/internal/experiment" "github.com/slackapi/slack-cli/internal/logger" "github.com/slackapi/slack-cli/internal/shared" "github.com/slackapi/slack-cli/internal/shared/types" @@ -52,7 +51,6 @@ func TestInstall(t *testing.T) { mockAPIUpdateError error mockAuth types.SlackAuth mockAuthSession api.AuthSession - mockBoltExperiment bool mockConfirmPrompt bool mockIsTTY bool mockManifestAppLocal types.SlackYaml @@ -87,7 +85,6 @@ func TestInstall(t *testing.T) { TeamName: &mockTeamDomain, UserID: &mockUserID, }, - mockBoltExperiment: true, mockManifestSource: config.ManifestSourceLocal, mockManifestAppLocal: types.SlackYaml{ AppManifest: types.AppManifest{ @@ -146,7 +143,6 @@ func TestInstall(t *testing.T) { TeamName: &mockTeamDomain, UserID: &mockUserID, }, - mockBoltExperiment: true, mockManifestSource: config.ManifestSourceLocal, mockManifestAppLocal: types.SlackYaml{ AppManifest: types.AppManifest{ @@ -206,7 +202,6 @@ func TestInstall(t *testing.T) { TeamName: &mockTeamDomain, UserID: &mockUserID, }, - mockBoltExperiment: true, mockConfirmPrompt: true, mockIsTTY: true, mockManifestSource: config.ManifestSourceLocal, @@ -272,6 +267,7 @@ func TestInstall(t *testing.T) { TeamName: &mockTeamDomain, UserID: &mockUserID, }, + mockManifestSource: config.ManifestSourceLocal, mockManifestAppLocal: types.SlackYaml{ AppManifest: types.AppManifest{ DisplayInformation: types.DisplayInformation{ @@ -283,7 +279,7 @@ func TestInstall(t *testing.T) { }, }, mockManifestHashInitial: cache.Hash("123"), - mockManifestHashUpdated: cache.Hash("789"), + mockManifestHashUpdated: cache.Hash("123"), // matching hash allows update to proceed expectedApp: types.App{ AppID: "A003", TeamID: mockTeamID, @@ -318,7 +314,6 @@ func TestInstall(t *testing.T) { TeamName: &mockTeamDomain, UserID: &mockUserID, }, - mockBoltExperiment: true, mockManifestSource: config.ManifestSourceRemote, mockManifestAppLocal: types.SlackYaml{ AppManifest: types.AppManifest{ @@ -371,7 +366,6 @@ func TestInstall(t *testing.T) { }, mockAPICreateError: slackerror.New(slackerror.ErrAppCreate), mockAPIUpdateError: slackerror.New(slackerror.ErrAppAdd), - mockBoltExperiment: true, mockManifestSource: config.ManifestSourceRemote, expectedApp: types.App{ AppID: "A004", @@ -400,7 +394,6 @@ func TestInstall(t *testing.T) { mockAPICreateError: slackerror.New(slackerror.ErrAppCreate), mockAPIUpdateError: slackerror.New(slackerror.ErrAppAdd), mockAPIInstallError: slackerror.New(slackerror.ErrAppInstall), - mockBoltExperiment: true, mockManifestHashInitial: "pt1", mockManifestHashUpdated: "pt2", mockManifestSource: config.ManifestSourceLocal, @@ -436,9 +429,8 @@ func TestInstall(t *testing.T) { TeamName: &mockTeamDomain, UserID: &mockUserID, }, - mockBoltExperiment: true, - mockConfirmPrompt: false, - mockIsTTY: true, + mockConfirmPrompt: false, + mockIsTTY: true, mockManifestAppLocal: types.SlackYaml{ AppManifest: types.AppManifest{ Metadata: &types.ManifestMetadata{ @@ -478,7 +470,6 @@ func TestInstall(t *testing.T) { TeamName: &mockTeamDomain, UserID: &mockUserID, }, - mockBoltExperiment: true, mockManifestAppRemote: types.SlackYaml{ AppManifest: types.AppManifest{ Metadata: &types.ManifestMetadata{ @@ -594,11 +585,7 @@ func TestInstall(t *testing.T) { manifestMock.On("GetManifestRemote", mock.Anything, mock.Anything, mock.Anything).Return(tc.mockManifestAppRemote, nil) clientsMock.AppClient.Manifest = manifestMock mockProjectConfig := config.NewProjectConfigMock() - if tc.mockBoltExperiment { - clientsMock.Config.ExperimentsFlag = append(clientsMock.Config.ExperimentsFlag, string(experiment.BoltFrameworks)) - clientsMock.Config.LoadExperiments(ctx, clientsMock.IO.PrintDebug) - mockProjectConfig.On("GetManifestSource", mock.Anything).Return(tc.mockManifestSource, nil) - } + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(tc.mockManifestSource, nil) mockProjectCache := cache.NewCacheMock() mockProjectCache.On( "GetManifestHash", @@ -696,32 +683,30 @@ func TestInstallLocalApp(t *testing.T) { mockUserID := "U001" tests := map[string]struct { - mockApp types.App - mockAPICreate api.CreateAppResult - mockAPICreateError error - mockAPIInstall api.DeveloperAppInstallResult - mockAPIInstallState types.InstallState - mockAPIInstallError error - mockAPIUpdate api.UpdateAppResult - mockAPIUpdateError error - mockAuth types.SlackAuth - mockAuthSession api.AuthSession - mockBoltExperiment bool - mockBoltInstallExperiment bool - mockConfirmPrompt bool - mockIsTTY bool - mockManifest types.SlackYaml - mockManifestHashInitial cache.Hash - mockManifestHashUpdated cache.Hash - mockManifestSource config.ManifestSource - mockOrgGrantWorkspaceID string - expectedApp types.App - expectedCreate bool - expectedInstallState types.InstallState - expectedManifest types.AppManifest - expectedUpdate bool + mockApp types.App + mockAPICreate api.CreateAppResult + mockAPICreateError error + mockAPIInstall api.DeveloperAppInstallResult + mockAPIInstallState types.InstallState + mockAPIInstallError error + mockAPIUpdate api.UpdateAppResult + mockAPIUpdateError error + mockAuth types.SlackAuth + mockAuthSession api.AuthSession + mockConfirmPrompt bool + mockIsTTY bool + mockManifest types.SlackYaml + mockManifestHashInitial cache.Hash + mockManifestHashUpdated cache.Hash + mockManifestSource config.ManifestSource + mockOrgGrantWorkspaceID string + expectedApp types.App + expectedCreate bool + expectedInstallState types.InstallState + expectedManifest types.AppManifest + expectedUpdate bool }{ - "create and install a new ROSI app with a local function runtime using expected rosi defaults when the BoltInstall experiment is disabled": { + "create and install a new ROSI app with a local function runtime using expected rosi defaults": { mockApp: types.App{}, mockAPICreate: api.CreateAppResult{ AppID: "A001", @@ -782,7 +767,7 @@ func TestInstallLocalApp(t *testing.T) { expectedInstallState: types.InstallSuccess, expectedUpdate: false, }, - "update and install an existing local bolt app with a remote function runtime without manifest changes when the BoltInstall experiment is disabled": { + "update and install an existing local bolt app with a remote function runtime without manifest changes": { mockApp: types.App{ AppID: "A002", TeamID: mockTeamID, @@ -826,7 +811,7 @@ func TestInstallLocalApp(t *testing.T) { }, }, mockManifestHashInitial: cache.Hash("123"), - mockManifestHashUpdated: cache.Hash("789"), + mockManifestHashUpdated: cache.Hash("123"), // matching hash allows update to proceed mockAPIInstallState: types.InstallSuccess, expectedApp: types.App{ AppID: "A002", @@ -857,7 +842,7 @@ func TestInstallLocalApp(t *testing.T) { expectedInstallState: types.InstallSuccess, expectedUpdate: true, }, - "update and install an existing local bolt app without a function runtime without manifest changes when the BoltInstall experiment is disabled": { + "update and install an existing local bolt app without a function runtime without manifest changes": { mockApp: types.App{ AppID: "A003", TeamID: mockTeamID, @@ -879,7 +864,6 @@ func TestInstallLocalApp(t *testing.T) { TeamName: &mockTeamDomain, UserID: &mockUserID, }, - mockBoltExperiment: true, mockAPIInstallState: types.InstallSuccess, mockConfirmPrompt: true, mockIsTTY: true, @@ -923,40 +907,7 @@ func TestInstallLocalApp(t *testing.T) { expectedInstallState: types.InstallSuccess, expectedUpdate: true, }, - "skip updating and skip installing an app with a remote manifest when the BoltInstall experiment is disabled": { - mockApp: types.App{ - AppID: "A004", - IsDev: true, - TeamID: mockTeamID, - UserID: mockUserID, - }, - mockAuth: types.SlackAuth{ - TeamID: mockTeamID, - TeamDomain: mockTeamDomain, - Token: mockToken, - UserID: mockUserID, - }, - mockAuthSession: api.AuthSession{ - TeamID: &mockTeamID, - TeamName: &mockTeamDomain, - UserID: &mockUserID, - }, - mockAPICreateError: slackerror.New(slackerror.ErrAppCreate), - mockAPIUpdateError: slackerror.New(slackerror.ErrAppAdd), - mockBoltExperiment: true, - mockBoltInstallExperiment: false, - mockManifestSource: config.ManifestSourceRemote, - expectedApp: types.App{ - AppID: "A004", - IsDev: true, - TeamID: mockTeamID, - UserID: mockUserID, - }, - expectedCreate: false, - expectedInstallState: "", - expectedUpdate: false, - }, - "create and install a new ROSI app when manifest is local and BoltInstall experiment is enabled": { + "create and install a new ROSI app when manifest is local": { mockApp: types.App{}, mockAPICreate: api.CreateAppResult{ AppID: "A001", @@ -988,10 +939,8 @@ func TestInstallLocalApp(t *testing.T) { }, }, }, - mockBoltExperiment: true, - mockBoltInstallExperiment: true, - mockManifestSource: config.ManifestSourceLocal, - mockAPIInstallState: types.InstallSuccess, + mockManifestSource: config.ManifestSourceLocal, + mockAPIInstallState: types.InstallSuccess, expectedApp: types.App{ AppID: "A001", EnterpriseID: mockEnterpriseID, @@ -1020,7 +969,7 @@ func TestInstallLocalApp(t *testing.T) { expectedInstallState: types.InstallSuccess, expectedUpdate: false, }, - "update and install an existing ROSI app when manifest is local and BoltInstall experiment is enabled": { + "update and install an existing ROSI app when manifest is local": { mockApp: types.App{ AppID: "A002", TeamID: mockTeamID, @@ -1055,12 +1004,10 @@ func TestInstallLocalApp(t *testing.T) { }, }, }, - mockBoltExperiment: true, - mockBoltInstallExperiment: true, - mockManifestSource: config.ManifestSourceLocal, - mockManifestHashInitial: cache.Hash("123"), - mockManifestHashUpdated: cache.Hash("789"), - mockAPIInstallState: types.InstallSuccess, + mockManifestSource: config.ManifestSourceLocal, + mockManifestHashInitial: cache.Hash("123"), + mockManifestHashUpdated: cache.Hash("789"), + mockAPIInstallState: types.InstallSuccess, expectedApp: types.App{ AppID: "A002", IsDev: true, @@ -1087,7 +1034,7 @@ func TestInstallLocalApp(t *testing.T) { expectedInstallState: types.InstallSuccess, expectedUpdate: true, }, - "create and install a new bolt app when manifest is local and BoltInstall experiment is enabled": { + "create and install a new bolt app when manifest is local": { mockApp: types.App{}, mockAPICreate: api.CreateAppResult{ AppID: "A001", @@ -1121,10 +1068,8 @@ func TestInstallLocalApp(t *testing.T) { }, }, }, - mockBoltExperiment: true, - mockBoltInstallExperiment: true, - mockAPIInstallState: types.InstallSuccess, - mockManifestSource: config.ManifestSourceLocal, + mockAPIInstallState: types.InstallSuccess, + mockManifestSource: config.ManifestSourceLocal, expectedApp: types.App{ AppID: "A001", EnterpriseID: mockEnterpriseID, @@ -1150,7 +1095,7 @@ func TestInstallLocalApp(t *testing.T) { expectedInstallState: types.InstallSuccess, expectedUpdate: false, }, - "update and install an existing bolt app with a local manifest when the BoltInstall experiment is enabled": { + "update and install an existing bolt app with a local manifest": { mockApp: types.App{ AppID: "A004", IsDev: true, @@ -1187,14 +1132,12 @@ func TestInstallLocalApp(t *testing.T) { mockAPIUpdate: api.UpdateAppResult{ AppID: "A004", }, - mockBoltExperiment: true, - mockBoltInstallExperiment: true, - mockAPIInstallState: types.InstallSuccess, - mockManifestSource: config.ManifestSourceLocal, - mockManifestHashInitial: cache.Hash("123"), - mockManifestHashUpdated: cache.Hash("789"), - mockConfirmPrompt: true, - mockIsTTY: true, + mockAPIInstallState: types.InstallSuccess, + mockManifestSource: config.ManifestSourceLocal, + mockManifestHashInitial: cache.Hash("123"), + mockManifestHashUpdated: cache.Hash("789"), + mockConfirmPrompt: true, + mockIsTTY: true, expectedApp: types.App{ AppID: "A004", IsDev: true, @@ -1218,7 +1161,7 @@ func TestInstallLocalApp(t *testing.T) { expectedInstallState: types.InstallSuccess, expectedUpdate: true, }, - "create and install a new bolt app when manifest is remote and BoltInstall experiment is enabled": { + "create and install a new bolt app when manifest is remote": { mockApp: types.App{}, mockAPICreate: api.CreateAppResult{ AppID: "A001", @@ -1252,10 +1195,8 @@ func TestInstallLocalApp(t *testing.T) { }, }, }, - mockBoltExperiment: true, - mockBoltInstallExperiment: true, - mockManifestSource: config.ManifestSourceRemote, - mockAPIInstallState: types.InstallSuccess, + mockManifestSource: config.ManifestSourceRemote, + mockAPIInstallState: types.InstallSuccess, expectedApp: types.App{ AppID: "A001", EnterpriseID: mockEnterpriseID, @@ -1281,7 +1222,7 @@ func TestInstallLocalApp(t *testing.T) { expectedInstallState: types.InstallSuccess, expectedUpdate: false, }, - "skip updating and allow installing an existing bolt app when manifest is remote and BoltInstall experiment is enabled": { + "skip updating and allow installing an existing bolt app when manifest is remote": { mockApp: types.App{ AppID: "A004", IsDev: true, @@ -1314,12 +1255,10 @@ func TestInstallLocalApp(t *testing.T) { }, }, }, - mockAPICreateError: slackerror.New(slackerror.ErrAppCreate), - mockAPIUpdateError: slackerror.New(slackerror.ErrAppAdd), - mockAPIInstallState: types.InstallSuccess, - mockBoltExperiment: true, - mockBoltInstallExperiment: true, - mockManifestSource: config.ManifestSourceRemote, + mockAPICreateError: slackerror.New(slackerror.ErrAppCreate), + mockAPIUpdateError: slackerror.New(slackerror.ErrAppAdd), + mockAPIInstallState: types.InstallSuccess, + mockManifestSource: config.ManifestSourceRemote, expectedApp: types.App{ AppID: "A004", IsDev: true, @@ -1418,15 +1357,7 @@ func TestInstallLocalApp(t *testing.T) { manifestMock.On("GetManifestRemote", mock.Anything, mock.Anything, mock.Anything).Return(tc.mockManifest, nil) clientsMock.AppClient.Manifest = manifestMock mockProjectConfig := config.NewProjectConfigMock() - if tc.mockBoltExperiment { - clientsMock.Config.ExperimentsFlag = append(clientsMock.Config.ExperimentsFlag, string(experiment.BoltFrameworks)) - clientsMock.Config.LoadExperiments(ctx, clientsMock.IO.PrintDebug) - mockProjectConfig.On("GetManifestSource", mock.Anything).Return(tc.mockManifestSource, nil) - } - if tc.mockBoltInstallExperiment { - clientsMock.Config.ExperimentsFlag = append(clientsMock.Config.ExperimentsFlag, string(experiment.BoltInstall)) - clientsMock.Config.LoadExperiments(ctx, clientsMock.IO.PrintDebug) - } + mockProjectConfig.On("GetManifestSource", mock.Anything).Return(tc.mockManifestSource, nil) mockProjectCache := cache.NewCacheMock() mockProjectCache.On( "GetManifestHash", diff --git a/internal/pkg/create/create.go b/internal/pkg/create/create.go index ee079fb3..e36dfbe3 100644 --- a/internal/pkg/create/create.go +++ b/internal/pkg/create/create.go @@ -32,7 +32,6 @@ import ( "github.com/slackapi/slack-cli/internal/archiveutil" "github.com/slackapi/slack-cli/internal/config" "github.com/slackapi/slack-cli/internal/deputil" - "github.com/slackapi/slack-cli/internal/experiment" "github.com/slackapi/slack-cli/internal/goutils" "github.com/slackapi/slack-cli/internal/logger" "github.com/slackapi/slack-cli/internal/shared" @@ -520,14 +519,12 @@ func InstallProjectDependencies( manifestSource = config.ManifestSourceLocal } - // When the BoltInstall experiment is enabled, set non-ROSI projects to ManifestSourceRemote. - if clients.Config.WithExperimentOn(experiment.BoltInstall) { - // TODO: should check if Slack hosted project, but the SDKConfig has not been initialized yet. - if clients.Runtime != nil { - isDenoProject := strings.Contains(strings.ToLower(clients.Runtime.Name()), "deno") - if !isDenoProject { - manifestSource = config.ManifestSourceRemote - } + // Set non-Deno (non-ROSI) projects to ManifestSourceRemote. + // TODO: should check if Slack hosted project, but the SDKConfig has not been initialized yet. + if clients.Runtime != nil { + isDenoProject := strings.Contains(strings.ToLower(clients.Runtime.Name()), "deno") + if !isDenoProject { + manifestSource = config.ManifestSourceRemote } } diff --git a/internal/pkg/create/create_test.go b/internal/pkg/create/create_test.go index baaa5583..90c72e0b 100644 --- a/internal/pkg/create/create_test.go +++ b/internal/pkg/create/create_test.go @@ -387,15 +387,13 @@ func Test_Create_installProjectDependencies(t *testing.T) { `Updated config.json manifest source to "app settings" (remote)`, }, }, - "When bolt-install experiment and Deno project, should set manifest source to project (local)": { - experiments: []string{"bolt-install"}, + "When Deno project, should set manifest source to project (local)": { expectedOutputs: []string{ `Updated config.json manifest source to "project" (local)`, }, }, - "When bolt-install experiment and non-Deno project, should set manifest source to app settings (remote)": { - experiments: []string{"bolt-install"}, - runtime: "node", + "When non-Deno project, should set manifest source to app settings (remote)": { + runtime: "node", expectedOutputs: []string{ `Updated config.json manifest source to "app settings" (remote)`, },