Skip to content

Commit 9b4abf2

Browse files
srtaalejzimeg
andauthored
feat(create): cleanup app creation outputs when slack create -app passed (#598)
Co-authored-by: Eden Zimbelman <eden.zimbelman@salesforce.com>
1 parent 4565149 commit 9b4abf2

7 files changed

Lines changed: 78 additions & 112 deletions

File tree

cmd/app/link.go

Lines changed: 40 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ import (
3232
"github.com/spf13/cobra"
3333
)
3434

35-
// LinkAppConfirmPromptText is displayed when prompting to add an existing app
36-
const LinkAppConfirmPromptText = "Do you want to add an existing app?"
37-
3835
// appLinkFlagSet contains flag values to reference
3936
type appLinkFlagSet struct {
4037
environmentFlag string
@@ -97,58 +94,8 @@ func LinkCommandRunE(ctx context.Context, clients *shared.ClientFactory, app *ty
9794
// Add empty line between executed command and first output
9895
clients.IO.PrintInfo(ctx, false, "")
9996

100-
err = LinkExistingApp(ctx, clients, app, false)
101-
if err != nil {
102-
return err
103-
}
104-
105-
return nil
106-
}
107-
108-
// LinkAppHeaderSection displays a section explaining how to find existing apps.
109-
// External callers can use extraSecondaryText to show additional information.
110-
// When shouldConfirm is true, additional information is included in the header
111-
// explaining how to link apps, in case the user declines.
112-
func LinkAppHeaderSection(ctx context.Context, clients *shared.ClientFactory, shouldConfirm bool) {
113-
var secondaryText = []string{
114-
"Add an existing app from app settings",
115-
"Find your existing apps at: " + style.Underline("https://api.slack.com/apps"),
116-
}
117-
118-
if shouldConfirm {
119-
secondaryText = append(secondaryText, "Manually add apps later with "+style.Commandf("app link", true))
120-
}
121-
122-
clients.IO.PrintInfo(ctx, false, "%s", style.Sectionf(style.TextSection{
123-
Emoji: "house",
124-
Text: "App Link",
125-
Secondary: secondaryText,
126-
}))
127-
}
128-
129-
// LinkExistingApp prompts for an existing App ID and saves the details to the project.
130-
// When shouldConfirm is true, a confirmation prompt will ask the user if they want to
131-
// link an existing app and additional information is included in the header.
132-
// The shouldConfirm option is encouraged for third-party callers.
133-
func LinkExistingApp(ctx context.Context, clients *shared.ClientFactory, app *types.App, shouldConfirm bool) (err error) {
13497
// Header section
135-
LinkAppHeaderSection(ctx, clients, shouldConfirm)
136-
137-
// Confirm to add an existing app; useful for third-party callers
138-
if shouldConfirm {
139-
proceed, err := clients.IO.ConfirmPrompt(ctx, LinkAppConfirmPromptText, true)
140-
if err != nil {
141-
clients.IO.PrintDebug(ctx, "Error prompting to add an existing app: %s", err)
142-
return err
143-
}
144-
145-
// Add newline to match the trailing newline inserted from the footer section
146-
clients.IO.PrintInfo(ctx, false, "")
147-
148-
if !proceed {
149-
return nil
150-
}
151-
}
98+
LinkAppHeaderSection(ctx, clients)
15299

153100
// App Manifest section
154101
manifestSource, err := clients.Config.ProjectConfig.GetManifestSource(ctx)
@@ -166,6 +113,45 @@ func LinkExistingApp(ctx context.Context, clients *shared.ClientFactory, app *ty
166113
},
167114
}))
168115

116+
err = LinkExistingApp(ctx, clients, app)
117+
if err != nil {
118+
return err
119+
}
120+
121+
// App summary section
122+
clients.IO.PrintInfo(ctx, false, "%s", style.Sectionf(style.TextSection{
123+
Emoji: "house",
124+
Text: "App",
125+
Secondary: FormatListSuccess([]types.App{*app}),
126+
}))
127+
128+
// Footer section
129+
clients.IO.PrintInfo(ctx, false, "%s", style.Sectionf(style.TextSection{
130+
Emoji: "house_with_garden",
131+
Text: "App Link",
132+
Secondary: []string{
133+
"Added existing app to project",
134+
},
135+
}))
136+
137+
return nil
138+
}
139+
140+
// LinkAppHeaderSection displays a section explaining how to find existing apps.
141+
func LinkAppHeaderSection(ctx context.Context, clients *shared.ClientFactory) {
142+
clients.IO.PrintInfo(ctx, false, "%s", style.Sectionf(style.TextSection{
143+
Emoji: "house",
144+
Text: "App Link",
145+
Secondary: []string{
146+
"Add an existing app from app settings",
147+
"Find your existing apps at: " + style.Underline("https://api.slack.com/apps"),
148+
},
149+
}))
150+
}
151+
152+
// LinkExistingApp resolves app details, validates the app, and saves it to the
153+
// project. It produces no output — callers handle their own display.
154+
func LinkExistingApp(ctx context.Context, clients *shared.ClientFactory, app *types.App) (err error) {
169155
// Prompt to get app details
170156
var auth *types.SlackAuth
171157
*app, auth, err = promptExistingApp(ctx, clients)
@@ -186,28 +172,9 @@ func LinkExistingApp(ctx context.Context, clients *shared.ClientFactory, app *ty
186172
return err
187173
}
188174

189-
// Footer section
190-
LinkAppFooterSection(ctx, clients, app)
191-
192175
return nil
193176
}
194177

195-
// LinkAppFooterSection displays the details of app that was added to the project.
196-
func LinkAppFooterSection(ctx context.Context, clients *shared.ClientFactory, app *types.App) {
197-
clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{
198-
Emoji: "house",
199-
Text: "App",
200-
Secondary: formatListSuccess([]types.App{*app}),
201-
}))
202-
clients.IO.PrintInfo(ctx, false, "%s", style.Sectionf(style.TextSection{
203-
Emoji: "house_with_garden",
204-
Text: "App Link",
205-
Secondary: []string{
206-
"Added existing app to project",
207-
},
208-
}))
209-
}
210-
211178
// promptExistingApp gathers details to represent app information
212179
func promptExistingApp(ctx context.Context, clients *shared.ClientFactory) (types.App, *types.SlackAuth, error) {
213180
slackAuth, err := prompts.PromptTeamSlackAuth(ctx, clients, "Select the existing app team", nil)

cmd/app/link_test.go

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -573,50 +573,28 @@ func Test_Apps_Link(t *testing.T) {
573573

574574
func Test_Apps_LinkAppHeaderSection(t *testing.T) {
575575
tests := map[string]struct {
576-
shouldConfirm bool
577-
expectedOutputs []string
578-
unexpectedOutputs []string
576+
expectedOutputs []string
579577
}{
580-
"When shouldConfirm is false": {
581-
shouldConfirm: false,
578+
"Displays app link header with base information": {
582579
expectedOutputs: []string{
583580
"Add an existing app from app settings",
584581
"Find your existing apps at: https://api.slack.com/apps",
585582
},
586-
unexpectedOutputs: []string{
587-
"Manually add apps later with",
588-
},
589-
},
590-
"When shouldConfirm is true": {
591-
shouldConfirm: true,
592-
expectedOutputs: []string{
593-
"Add an existing app from app settings",
594-
"Find your existing apps at: https://api.slack.com/apps",
595-
"Manually add apps later with",
596-
},
597583
},
598584
}
599585
for name, tc := range tests {
600586
t.Run(name, func(t *testing.T) {
601-
// Create mocks
602587
ctx := slackcontext.MockContext(t.Context())
603588
clientsMock := shared.NewClientsMock()
604589
clientsMock.AddDefaultMocks()
605-
606-
// Create clients that is mocked for testing
607590
clients := shared.NewClientFactory(clientsMock.MockClientFactory())
608591

609-
// Run the test
610-
LinkAppHeaderSection(ctx, clients, tc.shouldConfirm)
592+
LinkAppHeaderSection(ctx, clients)
611593

612-
// Assertions
613594
output := clientsMock.GetCombinedOutput()
614595
for _, expectedOutput := range tc.expectedOutputs {
615596
require.Contains(t, output, expectedOutput)
616597
}
617-
for _, unexpectedOutput := range tc.unexpectedOutputs {
618-
require.NotContains(t, output, unexpectedOutput)
619-
}
620598
})
621599
}
622600
}

cmd/app/list.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ func runListCommand(cmd *cobra.Command, clients *shared.ClientFactory) error {
7373
clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{
7474
Emoji: "house_buildings",
7575
Text: "Apps",
76-
Secondary: formatListSuccess(envs),
76+
Secondary: FormatListSuccess(envs),
7777
}))
7878
return nil
7979
}
8080

81-
// formatListSuccess formats details about the list of project apps
82-
func formatListSuccess(apps []types.App) (secondaryText []string) {
81+
// FormatListSuccess formats details about the list of project apps
82+
func FormatListSuccess(apps []types.App) (secondaryText []string) {
8383
for _, app := range apps {
8484
if app.AppID == "" {
8585
continue

cmd/app/list_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ func TestAppsListFormat(t *testing.T) {
218218
for name, tc := range tests {
219219
t.Run(name, func(t *testing.T) {
220220
listFlags = tc.Flags
221-
formattedList := formatListSuccess(tc.Apps)
221+
formattedList := FormatListSuccess(tc.Apps)
222222
for ii, value := range formattedList {
223223
formattedList[ii] = strings.TrimRight(value, ":")
224224
}

cmd/project/create.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,15 @@ func runCreateCommand(clients *shared.ClientFactory, cmd *cobra.Command, args []
229229
defer func() {
230230
_ = os.Chdir(originalDir)
231231
}()
232-
if err := app.LinkExistingApp(ctx, clients, &types.App{}, false); err != nil {
232+
linkedApp := &types.App{}
233+
if err := app.LinkExistingApp(ctx, clients, linkedApp); err != nil {
233234
return err
234235
}
236+
clients.IO.PrintInfo(ctx, false, "%s", style.Sectionf(style.TextSection{
237+
Emoji: "house",
238+
Text: "App",
239+
Secondary: app.FormatListSuccess([]types.App{*linkedApp}),
240+
}))
235241
}
236242

237243
printCreateSuccess(ctx, clients, appDirPath)

cmd/project/init.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import (
2929
"github.com/spf13/cobra"
3030
)
3131

32+
const linkAppConfirmPromptText = "Do you want to add an existing app?"
33+
3234
// NewInitCommand returns a Cobra command to initialize projects with Slack CLI support
3335
func NewInitCommand(clients *shared.ClientFactory) *cobra.Command {
3436
cmd := &cobra.Command{
@@ -109,11 +111,25 @@ func projectInitCommandRunE(clients *shared.ClientFactory, cmd *cobra.Command, a
109111
// Existing projects initialized always default to config.ManifestSourceLocal.
110112
_ = create.InstallProjectDependencies(ctx, clients, projectDirPath)
111113

112-
// Add an existing app to the project
113-
err = app.LinkExistingApp(ctx, clients, &types.App{}, true)
114+
// Prompt to add an existing app to the project
115+
app.LinkAppHeaderSection(ctx, clients)
116+
proceed, err := clients.IO.ConfirmPrompt(ctx, linkAppConfirmPromptText, true)
114117
if err != nil {
115-
// Display the error but continue to init
116-
clients.IO.PrintError(ctx, "%s", err.Error())
118+
return err
119+
}
120+
if proceed {
121+
linkedApp := &types.App{}
122+
err = app.LinkExistingApp(ctx, clients, linkedApp)
123+
if err != nil {
124+
// Display the error but continue to init
125+
clients.IO.PrintError(ctx, "%s", err.Error())
126+
} else {
127+
clients.IO.PrintInfo(ctx, false, "%s", style.Sectionf(style.TextSection{
128+
Emoji: "house",
129+
Text: "App",
130+
Secondary: app.FormatListSuccess([]types.App{*linkedApp}),
131+
}))
132+
}
117133
}
118134

119135
printNextStepSection(ctx, clients, projectDirPath)

cmd/project/init_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"path/filepath"
2121
"testing"
2222

23-
"github.com/slackapi/slack-cli/cmd/app"
2423
"github.com/slackapi/slack-cli/internal/api"
2524
internalApp "github.com/slackapi/slack-cli/internal/app"
2625
"github.com/slackapi/slack-cli/internal/iostreams"
@@ -58,7 +57,7 @@ func Test_Project_InitCommand(t *testing.T) {
5857
Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) {
5958
setupProjectInitCommandMocks(t, ctx, cm, cf)
6059
// Do not link an existing app
61-
cm.IO.On("ConfirmPrompt", mock.Anything, app.LinkAppConfirmPromptText, mock.Anything).Return(false, nil)
60+
cm.IO.On("ConfirmPrompt", mock.Anything, linkAppConfirmPromptText, mock.Anything).Return(false, nil)
6261
},
6362
ExpectedStdoutOutputs: []string{
6463
"Project Initialization", // Assert section header
@@ -78,7 +77,7 @@ func Test_Project_InitCommand(t *testing.T) {
7877
t,
7978
"ConfirmPrompt",
8079
mock.Anything,
81-
app.LinkAppConfirmPromptText,
80+
linkAppConfirmPromptText,
8281
mock.Anything,
8382
)
8483
// Assert Trace
@@ -109,7 +108,7 @@ func Test_Project_InitCommand(t *testing.T) {
109108
// Default setup
110109
setupProjectInitCommandMocks(t, ctx, cm, cf)
111110
// Link an existing app
112-
cm.IO.On("ConfirmPrompt", mock.Anything, app.LinkAppConfirmPromptText, mock.Anything).Return(true, nil)
111+
cm.IO.On("ConfirmPrompt", mock.Anything, linkAppConfirmPromptText, mock.Anything).Return(true, nil)
113112
// Mock prompt for team
114113
cm.IO.On("SelectPrompt",
115114
mock.Anything,
@@ -156,7 +155,7 @@ func Test_Project_InitCommand(t *testing.T) {
156155
// Assert prompt to add existing apps was called
157156
cm.IO.AssertCalled(t, "ConfirmPrompt",
158157
mock.Anything,
159-
app.LinkAppConfirmPromptText,
158+
linkAppConfirmPromptText,
160159
mock.Anything,
161160
)
162161
// Assert prompt for team

0 commit comments

Comments
 (0)