Skip to content
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

Customized slash command registration #11890

Closed
wants to merge 15 commits into from

Conversation

ethervoid
Copy link
Contributor

@ethervoid ethervoid commented Aug 15, 2019

Summary

This PR includes two new methods in the plugin helpers:

  • RegisterCommand: This new method allows the plugin creators to register a new command and attach a callback that is executed when the command is launched by a user
  • ExecuteCommand: This method complements the previous one. This method parses the arguments, generates a new CommandArgs data object and calls the callback that is linked with the received trigger

I'd love to get those bonus points but I've left out the Cobra part by now because I've been struggling with Go and I didn't want to add more complexity to the PR right now :)

I've made the proper modifications to the demo-plugin using these new methods. You can see it here

Ticket Link

Fixes #11843

Related Pull Requests

mattermost/mattermost-plugin-demo#57

These two new methods help the plugin creators to:
- reduce the boilerplate in the parameters and trigger extraction.
- define a callback for a command in the RegisterCommand that would be
executed when the trigger is fired
@ethervoid
Copy link
Contributor Author

@lieut-data Could you please review this PR. I think this is the required changes for the issue but maybe I've misunderstood it or something so I prefer to validate it :)

One question I have. If a command is registered twice, the API.RegisterCommand method doesn't complain and I'm overriding the callback for that command. Is that the expected behavior?

@lieut-data lieut-data requested review from lieut-data and crspeller and removed request for lieut-data August 15, 2019 18:26
Copy link
Member

@lieut-data lieut-data left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, @ethervoid! A few small comments.

plugin/helpers.go Outdated Show resolved Hide resolved
plugin/helpers.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
@ethervoid
Copy link
Contributor Author

@lieut-data changes made and I've also included the OriginalArgs inside the new plugin.CommandArgs struct for two reasons:

  • Reduce the callback parameters
  • Now we can pass just one pointer to one object in order to retrieve things like UserId, ChannelId and so on that comes in the OriginalArgs

What do you think?

plugin/helpers.go Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
@ethervoid
Copy link
Contributor Author

@hanzei Changes done and I've also added more test cases

Copy link
Contributor

@hanzei hanzei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

plugin/helpers_commands.go Outdated Show resolved Hide resolved
@hanzei hanzei requested a review from lieut-data August 16, 2019 11:03
Copy link
Member

@lieut-data lieut-data left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ethervoid! Just a few minor comments -- this is looking great!

plugin/helpers.go Outdated Show resolved Hide resolved
// func (p *Plugin) ExecuteCommand(c *Context, args *model.CommandArgs) {
// return p.Helpers.ExecuteCommand(c, args)
// }
// Returns (&model.CommandResponse{}, nil) if for some reason the callback doesn't exist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it makes sense to describe all the return values here -- this is basically just duplicating the code, and it's very likely to get out of date. Propose removing all the Returns ... comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen in the other comments and I just follow a bit the idea. Is ok for me to remove them

plugin/helpers_commands.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
plugin/helpers_commands.go Outdated Show resolved Hide resolved
Copy link
Member

@crspeller crspeller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation looks good once Jesse's comments are addressed.

However I have to wonder about the usefulness of this. The only operative code is a small block where we parse out the "trigger" from the "args" which is a trivial piece of code that most plugins have already written. I could see this being useful if it provided a full interface like cobra that dealt with all the trivialities of setting up a good CLI, keeping in mind we would really like to support full auto-completion in the future.

Thoughts @lieut-data @ethervoid ?

Co-Authored-By: Jesse Hallam <jesse.hallam@gmail.com>
@lieut-data
Copy link
Member

lieut-data commented Aug 16, 2019

@crspeller, agreed that, by itself, this isn't "ground breaking" new functionality, and easily done by plugins themselves.

This is part of the overall epic to expand the plugin helpers and reduce the "boilerplate" that makes it hard to write new plugins. I see this block of code repeated across all of our plugins and, imo, needlessly distracting from the intent and making it just a little bit harder to "get started".

I also see this as a stepping stone towards a cobra-like interface for command handling. While @ethervoid couldn't tackle that part of linked issue in this ticket, I'm expecting to split it out to a separate help-wanted ticket.

Thoughts?

@ethervoid
Copy link
Contributor Author

@lieut-data changes made (waiting for the response of other people to remove the Return comments)

About what @crspeller said. I agree with it but as @lieut-data said, we can split this issue into two so this one covers the base and the new one covers the changes made to introduce cobra.

@@ -29,8 +33,22 @@ type Helpers interface {
//
// Minimum server version: 5.6
KVSetWithExpiryJSON(key string, value interface{}, expireInSeconds int64) error

// RegisterCommand registers the given command and callback for the ExecuteCommand helper.
RegisterCommand(command *model.Command, callback CommandCallback) error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed the common convention for callbacks in Golang is usually referred to as Handlers, I would recommend renaming this to
RegisterCommand(command *model.Command, handler CommandHandler) error unless there is a good reason not to.

Few examples:
https://github.com/golang/gofrontend/blob/master/libgo/go/net/http/server.go#L1996
https://github.com/golang/go/blob/master/src/syscall/js/func.go#L59

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good for me. I'm a Golang noob :)

@crspeller
Copy link
Member

@lieut-data @ethervoid But how would we extend this to have that advanced functionality? Using cobra or not? It seems like we would have to add a new helper, adding to the confusion of how to create slash commands. If this where extendable and we had a plan, I would be ok with doing it in stages.

return nil, nil
}

return callback.(CommandCallback)(c, commandArgs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since p.CommandCallbacks is exposed, is it worth either making it private or asserting the callback is of type (CommandCallback) for better error handling?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I can't create some accessors to the property for example

import model "github.com/mattermost/mattermost-server/model"
import plugin "github.com/mattermost/mattermost-server/plugin"
import (
io "io"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

were these done automatically through the linter? do we have to alias these?

@lieut-data lieut-data self-assigned this Aug 20, 2019
@ethervoid
Copy link
Contributor Author

@crspeller Sorry for answering that later but I've been out for some days. That said, I can include the Cobra part because it looks like it's mandatory for this change. It's going to take a while because I'm not sure enough how to include Cobra here but I can talk with someone from the Toolkit team

@lieut-data
Copy link
Member

@ethervoid, thanks for being willing to push on this. When you have time, I'd be happy to sit down and talk through this in more detail!

@lieut-data lieut-data removed their assignment Aug 30, 2019
@mattermod
Copy link
Contributor

This issue has been automatically labelled "stale" because it hasn't had recent activity.
A core team member will check in on the status of the PR to help with questions.
Thank you for your contribution!

/cc @jasonblais @hanzei

@hanzei hanzei added Work In Progress Not yet ready for review and removed 2: Dev Review Requires review by a developer Lifecycle/1:stale labels Sep 14, 2019
@mattermod
Copy link
Contributor

This issue has been automatically labelled "stale" because it hasn't had recent activity.
A core team member will check in on the status of the PR to help with questions.
Thank you for your contribution!

/cc @jasonblais @hanzei

@hanzei
Copy link
Contributor

hanzei commented Sep 29, 2019

Hey @ethervoid,

Just wanted to check if we can help you in any way with the cobra changes?

@ethervoid
Copy link
Contributor Author

@hanzei Hi! I'm going to be out for about 1 month until then i'm not going to be able to take a look at It :(. If you need to tackle It ASAP i'm going to suggest yo release It from me. if not, as soon as i come back ill be glad to continue with It :)

@hanzei
Copy link
Contributor

hanzei commented Sep 29, 2019

Hi @ethervoid, thanks for the heads up! There is no rush on this ticket, so we can keep this open. Looking forward to you continue your work 👍

@lieut-data
Copy link
Member

I synched up with @ethervoid offline, and while we'll keep this PR around for reference, he won't be continuing with this effort right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Customized slash command registration
7 participants