Skip to content

Add bundler before/after eval hooks for plugins#6961

Open
ccutrer wants to merge 1 commit intoruby:masterfrom
ccutrer:bundler-plugin-eval-hooks
Open

Add bundler before/after eval hooks for plugins#6961
ccutrer wants to merge 1 commit intoruby:masterfrom
ccutrer:bundler-plugin-eval-hooks

Conversation

@ccutrer
Copy link
Contributor

@ccutrer ccutrer commented Sep 14, 2023

What was the end-user or developer problem that led to this PR?

My plugin would have a much cleaner implementation if it could hook both before and after the Gemfile is evaluated (the former to easily add additional DSL methods, the latter to do verification that the new methods were properly used).

What is your fix for the problem, implemented in this PR?

Add the hooks and call them from Definition.build (not Dsl#evaluate or Dsl#eval_gemfile, so as not to interfere with the plugin-parsing pass of the Gemfile).

Make sure the following tasks are checked

@ccutrer ccutrer mentioned this pull request Sep 14, 2023
@ccutrer ccutrer force-pushed the bundler-plugin-eval-hooks branch from 1883e8f to 5626626 Compare October 11, 2023 15:53
@binford2k
Copy link

This hook would GREATLY help our situation. In the Puppet ecosystem, modules are tested via a Gemfile that declares all the ruby code required to run the tests. One of the requirements is puppet which may now be provided by:

  • a gem named openvox
  • a gem named puppet from ruby gems
  • a gem named puppet from a private authenticated gem server

Each gem is very nearly equivalent and the real difference comes from transitive dependencies. But in order to test that a module works on all three implementations, we need to allow the site operator to select which implementation to install and use.

It's infeasible to require every author of every module to add boilerplate code to their Gemfile to select a gem to install.

My https://github.com/overlookinfra/bundler-alias plugin now handles all but one case, and that would be enabled by this contribution.

Copy link
Contributor

@Edouard-chin Edouard-chin left a comment

Choose a reason for hiding this comment

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

Having a hook to extend the DSL is also something I'm looking for. I was about to propose a patch but saw this PR.

For the maintainers that will review this PR, having an official way to extend the dsl would allow Rubist to more easily build tooling, and implement Bundler features that could make it upstream if they are popular in the community.
Right now, it's possible but your Gemfile would look like this:

plugin 'foo'

if Plugin.installed?(:foo)
  Plugin.send(:load_plugins, :foo)

  my_cool_new_dsl_method
end

raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file?

Dsl.evaluate(gemfile, lockfile, unlock)
Plugin.hook(Plugin::Events::GEM_BEFORE_EVAL, gemfile, lockfile, unlock)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the hook should be in the dsl file. If the intent is to let plugin extend the dsl, then we should pass the dsl class to the hook.
So the plugin would be able to do something like:

Bundler::Plugin::API.hook(Plugin::Events) do |dsl|
  dsl.define_method(:overrides!) {}
end

We'd also need to passthrough method_missing

def method_missing(name, *args)
in the DSL plugin, otherwise users won't be able to use ours custom dsl methods.
If a user accidentaly call a methods that doesn't exist (either in the vanilla Bundler dsl or our custom plugins) it will be caught afterwards when Bundler evaluates the DSL from the DSL class
def method_missing(name, *args)
raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile"
end

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.

4 participants