Skip to content

Commit bed795a

Browse files
mwbrookszimeg
andauthored
feat(bolt-install): support using 'install' command with remote manifests (#154)
* feat(bolt-install): support using 'install' command with remote manifests * feat(bolt-install): support using 'install' command with remote manifests * feat(bolt-install): default --environment deployed when --team provided and --environment unset * feat(bolt-install): add PR number * feat(bolt-install): add example of using the --environment flag * feat(bolt-install): fix --environment flag support * fix: allow mixing-and-matching --team and --environment * fix: warning message * test: fix failing add_test.go * fix: refactor code to be tighter * fix: remove the UserID comment to avoid unexpected behaviour * Update cmd/app/add.go Co-authored-by: Eden Zimbelman <[email protected]> * test: refactor mockLocalManifest to mockManifestAppLocal (and Remote) * fix: install command to handle --app local and --app deployed * fix: install command skips environment prompt when --app is set * fix: skip defaulting to deployed environment when app id is provided * fix: skip defaulting to deployed environment when --team provided --------- Co-authored-by: Eden Zimbelman <[email protected]>
1 parent ffbe0b5 commit bed795a

File tree

8 files changed

+683
-90
lines changed

8 files changed

+683
-90
lines changed

cmd/app/add.go

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ var appSelectPromptFunc = prompts.AppSelectPrompt
4242

4343
type addCmdFlags struct {
4444
orgGrantWorkspaceID string
45+
environmentFlag string
4546
}
4647

4748
var addFlags addCmdFlags
@@ -55,11 +56,12 @@ func NewAddCommand(clients *shared.ClientFactory) *cobra.Command {
5556
Long: "Install the app to a team",
5657
Example: style.ExampleCommandsf([]style.ExampleCommand{
5758
{Command: "app install", Meaning: "Install a production app to a team"},
58-
{Command: "app install --team T0123456", Meaning: "Install a production app to a specific team"},
59+
{Command: "app install --team T0123456 --environment deployed", Meaning: "Install a production app to a specific team"},
60+
{Command: "app install --team T0123456 --environment local", Meaning: "Install a local dev app to a specific team"},
5961
}),
6062
PreRunE: func(cmd *cobra.Command, args []string) error {
6163
ctx := cmd.Context()
62-
return preRunAddCommand(ctx, clients)
64+
return preRunAddCommand(ctx, clients, cmd)
6365
},
6466
RunE: func(cmd *cobra.Command, args []string) error {
6567
ctx := cmd.Context()
@@ -72,51 +74,106 @@ func NewAddCommand(clients *shared.ClientFactory) *cobra.Command {
7274
}
7375

7476
cmd.Flags().StringVar(&addFlags.orgGrantWorkspaceID, cmdutil.OrgGrantWorkspaceFlag, "", cmdutil.OrgGrantWorkspaceDescription())
77+
cmd.Flags().StringVarP(&addFlags.environmentFlag, "environment", "E", "", "environment of app (local, deployed)")
7578

7679
return cmd
7780
}
7881

7982
// preRunAddCommand confirms an app is available for installation
80-
func preRunAddCommand(ctx context.Context, clients *shared.ClientFactory) error {
83+
func preRunAddCommand(ctx context.Context, clients *shared.ClientFactory, cmd *cobra.Command) error {
8184
err := cmdutil.IsValidProjectDirectory(clients)
8285
if err != nil {
8386
return err
8487
}
8588
if !clients.Config.WithExperimentOn(experiment.BoltFrameworks) {
8689
return nil
8790
}
88-
manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx)
89-
if err != nil {
90-
return err
91-
}
92-
if manifestSource.Equals(config.ManifestSourceRemote) {
93-
return slackerror.New(slackerror.ErrAppInstall).
94-
WithMessage("Apps cannot be installed due to project configurations").
95-
WithRemediation(
96-
"Install an app on app settings: %s\nLink an app to this project with %s\nList apps saved with this project using %s",
97-
style.LinkText("https://api.slack.com/apps"),
98-
style.Commandf("app link", false),
99-
style.Commandf("app list", false),
100-
).
101-
WithDetails(slackerror.ErrorDetails{
102-
slackerror.ErrorDetail{
103-
Code: slackerror.ErrProjectConfigManifestSource,
104-
Message: "Cannot install apps with manifests sourced from app settings",
105-
},
106-
})
107-
}
91+
clients.Config.SetFlags(cmd)
10892
return nil
10993
}
11094

11195
// RunAddCommand executes the workspace install command, prints output, and returns any errors.
11296
func RunAddCommand(ctx context.Context, clients *shared.ClientFactory, selection *prompts.SelectedApp, orgGrantWorkspaceID string) (context.Context, types.InstallState, types.App, error) {
11397
if selection == nil {
114-
selected, err := appSelectPromptFunc(ctx, clients, prompts.ShowHostedOnly, prompts.ShowAllApps)
115-
if err != nil {
116-
return ctx, "", types.App{}, err
98+
// TODO: Move to the promptIsProduction when the prompt is refactored and tested.
99+
// Validate that the --app flag is not an app ID when the --environment flag is set.
100+
if types.IsAppID(clients.Config.AppFlag) && addFlags.environmentFlag != "" {
101+
return ctx, "", types.App{}, slackerror.New(slackerror.ErrMismatchedFlags).WithRemediation("When '--app <app_id>' is set, please do not set the flag --environment.")
102+
}
103+
104+
// TODO: Move to the promptIsProduction when the prompt is refactored and tested.
105+
// Validate that the --environment flag matches the --app flag, when the value is `--app local` or `--app deployed`.
106+
if types.IsAppFlagEnvironment(clients.Config.AppFlag) {
107+
if addFlags.environmentFlag != "" && addFlags.environmentFlag != clients.Config.AppFlag {
108+
return ctx, "", types.App{}, slackerror.New(slackerror.ErrMismatchedFlags).WithRemediation("When '--app local' or '--app deployed' is set, please set the flag --environment to match the --app flag.")
109+
}
110+
111+
if addFlags.environmentFlag == "" {
112+
err := clients.Config.Flags.Lookup("environment").Value.Set(clients.Config.AppFlag)
113+
if err != nil {
114+
return ctx, "", types.App{}, err
115+
}
116+
clients.Config.Flags.Lookup("environment").Changed = true
117+
}
118+
}
119+
120+
// Default to `--environment deployed` when there is no `--environment` flag and `--team <id>` is set.
121+
// Skip when `--app <id>` flag is set, because the environment is looked up in the app selector prompt.
122+
// TODO(semver:major): This is backwards compatibility for when `install` only supported deployed environments.
123+
if !types.IsAppID(clients.Config.AppFlag) && (addFlags.environmentFlag == "" && clients.Config.TeamFlag != "") {
124+
err := clients.Config.Flags.Lookup("environment").Value.Set("deployed")
125+
if err != nil {
126+
return ctx, "", types.App{}, err
127+
}
128+
clients.Config.Flags.Lookup("environment").Changed = true
129+
130+
clients.IO.PrintInfo(ctx, false, "\n"+style.Sectionf(style.TextSection{
131+
Emoji: "warning",
132+
Text: "Warning: Default App Environment",
133+
Secondary: []string{
134+
"App environment is set to deployed when only the --team flag is provided.",
135+
"The next major version will change this behavior.",
136+
"When the --team flag is provided, the --environment flag will be required.",
137+
"Add the '--environment deployed' to avoid breaking changes.",
138+
},
139+
}))
140+
}
141+
142+
// When the app flag is an app ID, the app select prompt can resolve the app.
143+
// Otherwise, prompt for the app environment and app.
144+
if types.IsAppID(clients.Config.AppFlag) {
145+
selected, err := appSelectPromptFunc(ctx, clients, prompts.ShowAllEnvironments, prompts.ShowAllApps)
146+
if err != nil {
147+
return ctx, "", types.App{}, err
148+
}
149+
selection = &selected
150+
} else {
151+
// Prompt for deployed or local app environment.
152+
isProductionApp, err := promptIsProduction(ctx, clients)
153+
if err != nil {
154+
return ctx, "", types.App{}, err
155+
}
156+
157+
// Set the app environment type based on the prompt.
158+
var appEnvironmentType prompts.AppEnvironmentType
159+
if isProductionApp {
160+
appEnvironmentType = prompts.ShowHostedOnly
161+
} else {
162+
appEnvironmentType = prompts.ShowLocalOnly
163+
}
164+
165+
selected, err := appSelectPromptFunc(ctx, clients, appEnvironmentType, prompts.ShowAllApps)
166+
if err != nil {
167+
return ctx, "", types.App{}, err
168+
}
169+
selection = &selected
170+
171+
if !isProductionApp {
172+
selection.App.IsDev = true
173+
}
117174
}
118-
selection = &selected
119175
}
176+
120177
if selection.Auth.TeamDomain == "" {
121178
return ctx, "", types.App{}, slackerror.New(slackerror.ErrCredentialsNotFound)
122179
}

0 commit comments

Comments
 (0)