{"id":18103159,"url":"https://github.com/manageiq/bundler-inject","last_synced_at":"2025-04-05T00:06:35.740Z","repository":{"id":34258308,"uuid":"162640423","full_name":"ManageIQ/bundler-inject","owner":"ManageIQ","description":"A bundler plugin that allows extension of a project with personal and overridden gems","archived":false,"fork":false,"pushed_at":"2025-01-23T20:43:23.000Z","size":140,"stargazers_count":23,"open_issues_count":5,"forks_count":8,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-05T00:06:30.528Z","etag":null,"topics":["bundler","bundler-plugin","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ManageIQ.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-20T23:05:11.000Z","updated_at":"2025-03-15T10:57:14.000Z","dependencies_parsed_at":"2024-10-31T22:10:49.833Z","dependency_job_id":"c5c89286-d543-44e3-b155-0768f6cefe9f","html_url":"https://github.com/ManageIQ/bundler-inject","commit_stats":{"total_commits":87,"total_committers":14,"mean_commits":6.214285714285714,"dds":"0.47126436781609193","last_synced_commit":"45f743ce13648c3a6def294cc8136172996ea0c0"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManageIQ%2Fbundler-inject","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManageIQ%2Fbundler-inject/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManageIQ%2Fbundler-inject/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManageIQ%2Fbundler-inject/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ManageIQ","download_url":"https://codeload.github.com/ManageIQ/bundler-inject/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247266563,"owners_count":20910836,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bundler","bundler-plugin","ruby"],"created_at":"2024-10-31T22:10:41.395Z","updated_at":"2025-04-05T00:06:35.716Z","avatar_url":"https://github.com/ManageIQ.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bundler-inject\n\n[![Gem Version](https://badge.fury.io/rb/bundler-inject.svg)](http://badge.fury.io/rb/bundler-inject)\n[![CI](https://github.com/ManageIQ/bundler-inject/actions/workflows/ci.yaml/badge.svg)](https://github.com/ManageIQ/bundler-inject/actions/workflows/ci.yaml)\n[![Code Climate](https://codeclimate.com/github/ManageIQ/bundler-inject.svg)](https://codeclimate.com/github/ManageIQ/bundler-inject)\n[![Test Coverage](https://codeclimate.com/github/ManageIQ/bundler-inject/badges/coverage.svg)](https://codeclimate.com/github/ManageIQ/bundler-inject/coverage)\n\n**bundler-inject** is a [bundler plugin](https://bundler.io/guides/bundler_plugins.html)\nthat allows a developer to extend a project with their own personal gems and/or\noverride existing gems, without having to modify the Gemfile, thus avoiding\naccidental modification of git history.\n\n## Installation\n\nAdd these lines to your application's `Gemfile`:\n\n```ruby\nplugin 'bundler-inject'\nrequire File.join(Bundler::Plugin.index.load_paths(\"bundler-inject\")[0], \"bundler-inject\") rescue nil\n```\n\nAdditionally, commit a `bundler.d/.gitkeep` file, and add `/bundler.d` to your\n`.gitignore` file. This will be one of the locations developers can place their\noverrides.\n\n## Usage\n\nOnce the above lines are in the Gemfile, subsequent bundle commands will attempt\nto evaluate extra gemfiles from two locations if they are present.\n\n- global - `~/.bundler.d/*.rb`\n- project - `$PROJECT_DIR/bundler.d/*.rb`\n\nFor example, a developer may prefer the `pry` gem over `irb`, but can't use it\nbecause the project Gemfile doesn't have `pry` in it. Instead of modifying the\nGemfile and hoping they don't commit the changes, they can create a\n`bundler.d/developer.rb` file with the contents set to `gem \"pry\"`. From then on\nthe developer can use `pry`, even though the project didn't state it explicitly.\n\nSince this example developer likely *always* wants to use `pry`, it would be\npreferable to specify this as a global choice in a `~/.bundler.d/developer.rb`\nfile instead.\n\n### override_gem\n\n`override_gem` is an extra DSL command that allows overriding existing gems from\nthe Gemfile. A useful example of this is if you are making a change to a\ndependent gem, and temporarily want to override the existing `gem` definition\nwith, a git or path reference.\n\nFor example, there is a project with a Gemfile with `gem \"foo\"` in it. We want\nto fix a bug in foo, and we intend to make a pull request to upstream, but in\nthe interim we want to test our foo change with the project. Instead of\nmodifying the Gemfile and hoping we don't commit the changes, we can create a\n`bundler.d/developer.rb` with the contents set to\n`override_gem \"foo\", :git =\u003e \"https://github.com/me/foo.git\"`. bundler-inject\nwill output a warning to the screen to make us aware we are overriding, and\nthen it will use the new definition.\n\n`override_gem` will raise an exception if the specified gem does not exist in\nthe original Gemfile.\n\n### ensure_gem\n\n`ensure_gem` is an extra DSL command similar to `override_gem`, and primarily\nmeant for the global override file.\n\nOne issue with the global file is that it specifies a new gem with `gem`, but\nthat gem already exists in the project you will get a nasty warning. Conversely,\nif it specifies an override with `override_gem`, but the gem does not exist in\nthe project you will get an exception. To deal with these issues, you can use\n`ensure_gem` in your global file.\n\n`ensure_gem` works by checking if the gem is already in the dependency list, and\ncomparing the options specified. If the dependency does not exist, it uses `gem`,\notherwise if the options or version specified are significantly different, it\nwill use `override_gem`, otherwise it will just do nothing, deferring to the\noriginal declaration.\n\n## Configuration\n\n### Disabling warnings\n\nTo disable warnings that are output to the console when `override_gem` or\n`ensure_gem` is in use, you can update a bundler setting:\n\n```console\n$ bundle config bundler_inject.disable_warn_override_gem true\n```\n\nor use an environment variable:\n\n```console\n$ export BUNDLE_BUNDLER_INJECT__DISABLE_WARN_OVERRIDE_GEM=true\n```\n\nThere is a fallback for those that will check the `RAILS_ENV` environment\nvariable, and will disable the warning when in `\"production\"`.\n\n### Specifying gem source directories\n\nMany developers checkout gems into a single directory for enhancement.\nInstead of specifying the full path of gems every time, specify a gem path\nto locate these directories. This can be defined with a bundler setting:\n\n```console\n$ bundle config bundler_inject.gem_path ~/src:~/gem_src\n```\n\nor use an environment variable:\n\n```console\n$ export BUNDLE_BUNDLER_INJECT__GEM_PATH=~/src:~/gem_src\n```\n\nAn override will find a gem in either of these two directories or in the directory\nwhere the Gemfile override is located.\n\n```Gemfile\n# located in ~/src/ansi\noverride_gem \"ansi\"\n# located in $PWD/mime_override\noverride_gem \"mime/type\", path: \"mime_override\"\n```\n\n## What is this sorcery?\n\nWhile this is technically a bundler plugin, bundler-inject does not use the\nexpected plugin hooks/sources/commands. To understand how this works and why\nthese were not used, it's useful to understand how bundler passes over your\nGemfile.\n\nFor `bundle install`/`bundle update`, bundler makes two passes over the Gemfile.\n\nOn the first pass, bundler executes your Gemfile in a `Bundler::Plugin::DSL`\ncontext. This class is a special subclass of `Bundler::Dsl`, where nearly all of\nthe usual DSL methods like `gem` and `gemspec` are a no-op, and the `plugin` DSL\nmethod does it's thing. So, after the first pass, bundler sees only your plugin\ngems, and will then install them into `.bundle/plugin`.\n\nOn the second pass, bundler executes your Gemfile in a `Bundler::Dsl` context,\nwhere the usual DSL methods like `gem` and `gemspec` do their thing, and the\n`plugin` DSL method is instead a no-op. This is the pass most people think of.\n\nOn the very first install of the plugin, between the two passes, bundler will\nload your plugin to see what kind of features it has, whether hooks, sources, or\ncommands, and will store this information in the `.bundle/plugin/index` file.\nIt would seem that since the plugin code is loaded this would be an opportune\ntime to do what we need, but unfortunately this only happens on initial install.\nOn subsequent `bundle update` calls, bundler sees that the index file exists,\nand doesn't need to load the plugin, since all of the information is in the\nindex.\n\nComplicating the matter further, for `bundle check`/`bundle exec`, bundler makes\nonly one pass over the Gemfile in a `Bundler::Dsl` context.\n\nOne immediate question on your mind may be, why not just define a fake hook or\nsource, and then put the code in there. Unfortunately, the problem is that any\nof hooks, sources, or commands that will trigger the load of the plugin occur\nafter the Gemfile has already been passed over, preventing us from adding to the\nDSL, as well as loading extra gemfiles.\n\nAs such, the earliest we can possibly trigger our plugin load in all cases is\nimmediately after we declare the plugin in the Gemfile. This is why we need that\nmagic line after the plugin line in the Gemfile.\n\nOnce we have the ability to trigger a load of our plugin, whether direct via the\nmagic line, or automatically on first plugin installation, then the plugin can\nmanipulate the Bundler::Dsl to add the `override_gem` method and trigger the\neval of extra gemfiles.\n\n## Development\n\nDevelopment of bundler plugins can be a little strange, with a few gotchas.\n\n1. bundler installs your gem into the .bundle/plugin directory of the target\n   project.\n2. `plugin \"bundler-inject\", :path =\u003e \"/path/to/bundler-inject\"` doesn't work\n   as expected since bundler needs to \"install\" your gem into .bundle/plugin,\n   and thus doesn't know how. To get around this, use\n   `:git =\u003e File.expand_path(\"/path/to/bundler-inject\")`.\n3. If you are using :git (which also applies to :path with the workaround\n   above), bundler will only consider committed code. Therefore, you *must*\n   commit your code in a temporary commit if you want it to be picked up.\n4. bundler plugins are copied to .bundle/plugin only on first install, and then\n   updated only if a change is detected. Unless you have a `:ref` or a changing\n   version number, bundler will think your gem hasn't changed and will not\n   update it, even if you commit something. To force bundler to pull in your\n   changes, you will have to `rm -rf .bundle/plugin`.\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/ManageIQ/bundler-inject.\n\n## License\n\nThis project is available as open source under the terms of the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanageiq%2Fbundler-inject","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanageiq%2Fbundler-inject","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanageiq%2Fbundler-inject/lists"}