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

Plugin framework #51

Merged
merged 14 commits into from
Jul 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/coverage/
/doc/
/pkg/
/vendor/
/spec/reports/
/tmp/
.DS_Store
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ rvm:
script:
- rake install
- 3scale help
- 3scale copy help
- 3scale import help
- 3scale help copy
- 3scale help import
Binary file removed 3scale_toolbox-0.1.1.gem
Binary file not shown.
7 changes: 4 additions & 3 deletions 3scale_toolbox.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Gem::Specification.new do |spec|
spec.name = '3scale_toolbox'
spec.version = ThreeScaleToolbox::VERSION
spec.licenses = ['MIT']
spec.authors = ['Michal Cichra']
spec.email = ['[email protected]']
spec.authors = ['Michal Cichra', 'Eguzki Astiz Lezaun']
spec.email = ['[email protected]', '[email protected]']

spec.summary = %q{3scale CLI Toolbox.}
spec.description = %q{3scale CLI tools to manage your API from the terminal.}
Expand All @@ -23,5 +23,6 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'rake', '~> 10.0'
spec.required_ruby_version = '>= 2.1'

spec.add_dependency '3scale-api', '~> 0.1.2'
spec.add_dependency '3scale-api', '~> 0.1'
spec.add_dependency 'cri', '~> 2.10'
end
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ After checking out the repo, run `bin/setup` to install dependencies. You can al

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Plugins

As of 3scale Toolbox 0.5.0, 3scale Toolbox will load plugins installed in gems or $LOAD_PATH. Plugins are discovered via Gem::find_files then loaded.
Install, uninstall and update plugins using tools like [RubyGems](https://guides.rubygems.org/rubygems-basics/) and/or [Bundler](https://bundler.io/).

[Make your own plugin](docs/plugins.md)

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/3scale/3scale_toolbox.
Expand Down
133 changes: 133 additions & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Developing 3scale Toolbox CLI plugins

3scale Toolbox CLI is based on [cri](https://github.com/ddfreyne/cri) library for building command line tools.
Plugin system also uses [cri](https://github.com/ddfreyne/cri) to leverage easy to develop, flexible and extensible plugin system.

3scale Toolbox will load plugins installed in gems or $LOAD_PATH. Plugins are discovered via *Gem::find_files*, then loaded.
Plugins must be named ‘3scale_toolbox_plugin’ (.rb, .so, etc) and placed at the root of your gem’s #require_path.

Plugins may add commands to *3scale* CLI or may add *subcommands* to any existing command.
Subcommands may be added to main commands or other subcommands as children.

Nothing better than few examples to illustrate .

Let's create a plugin to add a main `simple hello world` command.

```
$ cat lib/3scale_toolbox_plugin.rb
require '3scale_toolbox/cli'

module FooCommand
extend ThreeScaleToolbox::Command

def self.command
Cri::Command.define do
name 'foo'
usage 'foo [options]'
summary '3scale foo'
description '3scale foo command'
flag :h, :help, 'show help for this command' do |_, cmd|
puts cmd.help
exit 0
end
run do |opts, args, _|
puts "foo done"
end
end
end
end
ThreeScaleToolbox::CLI.add_command(FooCommand)

$ RUBYOPT=-Ilib 3scale foo
Hello World
```
Few things worth to highlight.
- Your module must be extended by *ThreeScaleToolbox::Command* module. It allows your command to be added to CLI command tree.
- Must implement `command` module function and return instance of `Cri::Command` from [cri](https://github.com/ddfreyne/cri)
- Add your command to `3scale` CLI command tree by calling `ThreeScaleToolbox::CLI.add_command`

Your plugin help is also available using builtin *help* command

```
$ RUBYOPT=-Ilib 3scale help foo
NAME
foo - foo command

USAGE
3scale foo [options]

DESCRIPTION
This command does a lot of stuff.

OPTIONS
-h --help show help for this command

OPTIONS FOR 3SCALE
-v --version Prints the version of this command
```

Let's create a plugin to add a `simple hello world` subcommand for the builtin *copy* command.

```
$ cat lib/3scale_toolbox_plugin.rb
require '3scale_toolbox/base_command'
require '3scale_toolbox/commands/copy_command'

module FooCommand
extend ThreeScaleToolbox::Command

def self.command
Cri::Command.define do
name 'foo'
usage 'foo [options]'
summary '3scale copy foo'
description '3scale copy foo subcommand'
flag :h, :help, 'show help for this command' do |_, cmd|
puts cmd.help
exit 0
end
run do |opts, args, _|
puts "foo done"
end
end
end
end

ThreeScaleToolbox::Commands::CopyCommand.add_subcommand(FooCommand)

$ RUBYOPT=-Ilib 3scale copy foo
foo done
```

Few things worth to highlight.
- Your module must be extended by *ThreeScaleToolbox::Command* module. It allows your command to be added to CLI command tree.
- Must implement `command` module function and return instance of `Cri::Command` from [cri](https://github.com/ddfreyne/cri)
- Add your subcommand to `3scale` CLI command tree by calling parent command's module's `add_subcommand` method.

Checking `copy` command help, it can be verified the new subcommand `foo` is added.

```
$ RUBYOPT=-Ilib 3scale help copy
NAME
copy - 3scale CLI copy

USAGE
3scale copy <command> [options]

DESCRIPTION
3scale CLI copy tools to manage your API from the terminal.

SUBCOMMANDS
foo 3scale copy foo
service 3scale CLI copy service

OPTIONS
-h --help show help for this command

OPTIONS FOR 3SCALE
-v --version Prints the version of this command
```

Now, package your plugin as a [gem](https://guides.rubygems.org/make-your-own-gem/) and let us know about it.

Choose a reason for hiding this comment

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

I think this part is the most fragile. Gems have a flat namespace where you basically would need to name your plugin as 3scale_toolbox-myplugin to avoid polluting this global shared namespace. I'd advocate having the code installed in something such as /usr/share/3scale_toolbox/plugins (or .local/share...) or having a config file setting to specify it.

At the very least, here we should suggest using a specific prefix for the gem names, and possibly enforce it when looking up plugin code.

Update: I see we are using a specific path to look up plugins, but I guess that is still not enforcing things like the above, and it is not clear how to install such plugins from this doc.

Copy link
Contributor

Choose a reason for hiding this comment

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

That is a common practice in Ruby ecosystem. https://guides.rubygems.org/name-your-gem/

We just require gems to have 3scale_toolbox_plugin.rb to be automatically loaded by the 3scale executable.

I don't really see any need to enforce any rules. People are free to do whatever they want to do.
It is common practice to name extensions prefixed with the gem name. Also it is common practice to namespace all your code with the correct namespace according to your gem name.


## Existing Plugins
12 changes: 3 additions & 9 deletions exe/3scale
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
#!/usr/bin/env ruby

require '3scale_toolbox'
require '3scale_toolbox/cli'

options, argv = ThreeScaleToolbox::CLI.parse
args = ARGV.clone

unless options.command
puts 'Available subcommands: '
puts ThreeScaleToolbox::CLI.subcommands
puts
ThreeScaleToolbox::CLI.print_help!
end

exec options.command.full_path, *ARGV
ThreeScaleToolbox::CLI.run args
Loading