-
Notifications
You must be signed in to change notification settings - Fork 24
feat: add 'app settings' command to open app settings webpage for a selected app #92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #92 +/- ##
==========================================
+ Coverage 63.18% 63.31% +0.12%
==========================================
Files 210 211 +1
Lines 22195 22276 +81
==========================================
+ Hits 14025 14104 +79
Misses 7085 7085
- Partials 1085 1087 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
mwbrooks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ Amazing work @zimeg 🎉
🧪 Manual testing is looking great and you've got very high test coverage on this command 📈
📝 I left a few minor suggestions that you can take, leave, or riff with. I've also left a lengthy suggestion to follow-up with a 2nd PR that attempts to introduce a best better practice for our global xyzFunc swaps.
| {Command: "install", Meaning: "Install a production app to a team"}, | ||
| {Command: "link", Meaning: "Link an existing app to the project"}, | ||
| {Command: "list", Meaning: "List all teams with the app installed"}, | ||
| {Command: "app settings", Meaning: "Open app settings in a web browser"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: Foreseeing a future of alphabetically ordered examples prefixed with app 🔮
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As much as I appreicate alphabetics I was thinking these examples were ordered with expected steps in mind?
To me this tells an interesting story:
installlinklistsettingsuninstalldelete
Which is almost in alphabetics I realize now! So perhaps following "install" with "delete" isn't so wild 👾
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahhhh, that's alright as well. For now, the order flows well and it's easy to see where unlink & update would land.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When unlink lands we should revisit this. Background thoughts are now nudging me towards preferring the more standard order 😳
| ErrAppExists = "app_add_exists" | ||
| ErrAppFlagRequired = "app_flag_required" | ||
| ErrAppFound = "app_found" | ||
| ErrAppHosted = "app_hosted" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: I can see this being a useful error for us in the future!
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| var settingsAppSelectPromptFunc = prompts.AppSelectPrompt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: [Non-Blocker] I'd like us to use this new command as a way to nudge out best practices for maintainability and testability. While we use the xyzFunc pattern for testability, it always feels like a hack.
I think the better approach would be dependency injection: NewSettingsCommand(clients, prompts.AppSelectPrompt).
But, how do we design this to scale for all commands and xyzFunc workarounds?
Maybe we use clients? This would remove the global swap-a-roo and isolate it to the instance of clients.
// clients.go
clients.AppSelectPrompt = prompts.AppSelectPrompt
// clients_mock.go
clients.AppSelectPrompt = appSelectMock.AppSelectPrompt
I think this is out-of-scope of this PR, but perhaps we can follow-up with some approach in a future PR? We can take some time to see if it helps address other xyzFunc use-cases as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mwbrooks I'm so interested in this as well 🧠 ✨
I considered mocking the calls used in AppSelectPrompt to avoid this pattern altogether, but found that this adds so much overhead and perhaps mixes concerns...
Using clients might be a decent approach! It seems like we're settling on patterns of having identical function signatures within a command:
RunE: func(cmd *cobra.Command, args []string) error {
return appSettingsCommandRunE(clients, cmd, args)
},But we've discussed avoiding clients for sake of more obvious usage of packages and dependencies. I'm wondering if within the command handler clients might be alright to keep, but for all other code following it should be avoided?
I'll hold off on making changes here so we can keep these patterns consistent for now, but I want to know what you think and I'm happy to follow up with changes we do decide on 🤖
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally agree, good call on not adding more complexity in this PR. Let's discuss it offline to figure out what we want to try out!
| parsed, err := url.Parse(host) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| parsed.Host = "api." + parsed.Host | ||
| settingsURL := fmt.Sprintf("%s/apps/%s", parsed.String(), app.App.AppID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: Very nice work 👏🏻
| Secondary: []string{ | ||
| settingsURL, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: What do you think about adding output explaining the action being taken (opening the web browser)?
| Secondary: []string{ | |
| settingsURL, | |
| }, | |
| Secondary: []string{ | |
| "Opening default web browser:", | |
| settingsURL, | |
| }, |
☝🏻 You might have better wording than that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 I might have preference against this since erroring cases might cause confusion that the standalone link saves?
The balance of text also feels lopsided but I don't think this is significant reason against this:
🏠 App Settings
Opening default web browser:
https://api.slack.com/apps/A08SPJ83H4L
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 It does make me think --no-browser might be a flag to later support with the default behavior though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me. Also --no-browser would be an appropriate future flag, since activity --browser already exists to open the activity in the browser.
| })) | ||
| clients.Browser().OpenURL(settingsURL) | ||
|
|
||
| clients.IO.PrintTrace(ctx, slacktrace.AppSettingsSuccess, settingsURL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: heh, you read my mind to add settingsURL 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setups of PrintTrace continue to impress me! 👾
I'm hoping soon we can equip all commands with at least a simple "start" and "success" with follow ups in @slack/cli-test but for now I'm also so glad we can print a success message with additional detail 📚 ✨
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like a reasonable PR to add a "start" and "success" to each command and land the equivalent definitions in @slack/cli-test.
| }, | ||
| ExpectedError: slackerror.New(slackerror.ErrAppHosted), | ||
| }, | ||
| "requires an existing application": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: Nice, I tested this manually and I'm happy to see you already added a test!
Co-authored-by: Michael Brooks <[email protected]>
Co-authored-by: Michael Brooks <[email protected]>
|
@mwbrooks I am so excited for this to land in the next release! 🚀 ✨ Thanks for helping refine this to a better place as always. I left a few responses about perhaps much larger changes that this PR poked at, but for now I will merge this. Follow up for particular flag options is also interesting to me, but also might be outside the scope of a first iteration. |
Summary
This PR adds the
app settingscommand to open app settings for a selected app.Preview
demo.mov
Reviewers
Hello please feel free to test this with various apps, perhaps a:
devinstancesFor the most adventurous, the
--appflag can be attempted too.Notes
--forceflag can be used to attempt this opening.Requirements