94

Is possible have a git branch dependency, inside mygem.gemspec?

I'm thinking something similar to the following:

gem.add_runtime_dependency 'oauth2', :git => 'git@github.com:lgs/oauth2.git'

... but it doesn't work.

Nakilon
  • 34,866
  • 14
  • 107
  • 142
Luca G. Soave
  • 12,271
  • 12
  • 58
  • 109
  • I have this same issue, except that I want a path dependency, not a git dependency. Isn't there a way to get around this somehow? Maybe by sticking some hackish Ruby code in the gemspec somewhere? – Ajedi32 Jan 06 '14 at 14:46

5 Answers5

48

This is not possible, and likely never will be because it would be rather heavy-handed for RubyGems to allow gem developers to require that users have a specific version control system installed to access a gem. Gems should be self-contained with a minimal number of dependencies so that people can use them in as wide an array of application as possible.

If you want to do this for your own internal projects, my suggestion would be to use Bundler which supports this quite well.

Teo Klestrup Röijezon
  • 5,097
  • 3
  • 29
  • 37
gtd
  • 16,956
  • 6
  • 49
  • 65
  • 26
    ... yes, but how can I do it ? – Luca G. Soave Jun 27 '11 at 22:08
  • I bundle a gem (omniauth) which actually re-bundle many others, like faraday and oauth2, which are both pointing to an old faraday (0.6.1). I was trying to decouple that nested dependency ... – Luca G. Soave Jun 27 '11 at 22:13
  • 6
    You do it just like you suggested, but in the Gemfile. If there is no explicit oauth2 requirement, add it ("gem 'oauth2', :git => '....'"), and bundle install. – gtd Jun 27 '11 at 22:18
  • Oh, also, you need to use a proper url, not the ssh syntax. eg. git://github.com/rails/exception_notification – gtd Jun 27 '11 at 22:20
  • Great it works! I was lost, thanks for clarifying, I really appreciate. – Luca G. Soave Jun 27 '11 at 22:44
  • 33
    But what if your gem is to be later included in another gem (eg. foobar_gem)? When foobar_gem wants to resolve dependencies in your gem, won't it look exclusively in the gemspec file? – eremzeit May 03 '12 at 22:29
  • 7
    Did you ever find a solution to this I have exactly the same problem? – msaspence Feb 27 '13 at 08:27
  • 2
    @eremzeit Because Bundler looks at your `Gemfile` and the dependency `.gemspec` files, adding a local or git reference to a Gem in your `Gemfile` will tell bundler where to find it, even if it's referenced in another gem. You just need to make sure you have compatible version specs. – jwadsack Nov 22 '14 at 17:24
  • 14
    @eremzeit & msaspence - since you have so many upvotes, I feel compelled to respond. There is no solution to this because _you're doing it wrong_. It's fine to depend on a git repo for a single application using Bundler, it is completely wrong for a released gem to depend on GitHub or any other source code repository. If you are releasing a gem, all its dependencies must also be released as gems. To make a formal package such as a gem rely on unreleased source code is to put the cart before the horse. **Please do not attempt to do this**. – gtd Dec 26 '14 at 19:25
  • 31
    @gtd Creating a gem and releasing a gem on rubygems are two separate things. Its possible that a private unpublished gem has private dependencies of its own. That seems fine to me. RubyGems doesn't seem to cater to this use case, but I'm not convinced this is doing it wrong. There's just not much to support it. Am I wrong? – Stephen Crosby May 04 '16 at 20:46
  • 3
    @StephenCrosby when I said RubyGems I was referring to the package manager, not to rubygems.org, private gems are still published (to a private server). Again, I don't know how I can make this any more clear: if you want to pull in arbitrary branches out of version control, **use Bundler, it supports this workflow**. Doing so in RubyGems completely subverts the point of having formal release numbers and dependencies declared since there is no permanence to a source repo branch. Furthermore I'm not sure what people are hoping to gain by this, but I assure you it will not be maintainable. – gtd May 07 '16 at 02:16
  • 2
    @StephenCrosby I was in that exact situation with my private gems hosted on Github. I was developing gem B which depended on private gem A. I was able to get everything happy by adding `gem 'A', git: 'git@github.com:myorganization/A.git'` to gem B's Gemfile, *not* its .gemspec – Matt Feb 01 '17 at 18:30
  • 1
    @Matt This is what I do too. Bundler supports 'gitted' gems and Rubygems gemspecs do not. Bundler doesn't look at the Gemfiles inside gem dependencies. It uses the gemspec which does not support 'gitted' gems. This means if you care about controlling the versions of your 'gitted' gems, you have to name all your 'gitted' application dependencies at the highest level (in your application's Gemfile). You get no help from Bundler or Rubygems in controlling transitive, 'gitted' gem dependencies from within dependent gems. – Stephen Crosby Feb 02 '17 at 19:19
  • Guys, for some reason adding gem to B's Gemfile does not work for me. The A gem does not even show up in `bundle install`. What do I miss? – Nakilon Oct 26 '17 at 12:20
  • It just ignores the Gemfile -- I see that by adding `fail` at the top of it and that nothing happens. – Nakilon Oct 26 '17 at 12:26
15

EDIT

According to a commenter, this is no longer true. Prior information retained for historical context.

Duplicating the reference to a gem in Gemfile and .gemspec now appears to raise a warning message in Bundler, so this answer would appear to be no longer true.

Outdated info

This article by Yehuda Katz cleared up similar confusion for me. It says that, for use in development only, it's best to add the git stuff into the gemfile, but that bundler will still use the dependency/version info from the gemspec (seems magical to me, but I trust Yehuda).

heartpunk
  • 2,235
  • 1
  • 21
  • 26
  • 4
    What's so magical about that? Bundler reads only from the Gemfile—except that if you put `gemspec` in there, it also reads from the gemspec. So when you run `bundle install`, I assume (but haven't tested) that what happens is that Bundler installs the gem specified in the Gemfile. Since Bundler has already installed it, that gem is available for the gem to `require`, regardless of the fact that it didn't come from a gem repository. No magic, just Bundler working as usual. – Marnen Laibow-Koser Jan 26 '14 at 00:16
  • 2
    Duplicating the reference to a gem in Gemfile and .gemspec now appears to raise a warning message in Bundler, so this answer would appear to be no longer true... – Andy Jones Dec 02 '15 at 10:34
7

I just was trying to figure this problem out as well. And I just came up with the following solution (which I'm not sure if your publishing your gem or have rights to redistribute that oauth2 gem).

In your gem that requires oauth2 gem run this.

git submodule add git@github.com:lgs/oauth2.git lib/oauth2

If you require a different branch than the default

cd lib/oauth2 && git checkout <branchname_or_ref>
cd .. && git add lib/oauth2
git commit -m "adding outh2 submodule"

In your gemspec add this above your require version line

$:.push File.expand_path('../lib/oauth2/lib', __FILE__)

Also you'll need to add all of the oauth2 gem's runtime dependencies to your gemspec. I haven't figured out a way around this yet.

This is what I did, and it works for us because our gem is required via git so I'm not sure if this would work for a rubygems published gem.

lightswitch05
  • 9,058
  • 7
  • 52
  • 75
kwbock
  • 647
  • 5
  • 13
  • Adding the dependency as a submodule is the correct solution if you've authored both gems and both are in active development. – Benjineer Jul 30 '16 at 10:20
  • Importantly if you do this, you may need to use: `gem 'my_gem', git: 'git@github.com:me/myrepo', submodules: true` in your host application if you are installing from github. – Joe Edgar Jul 07 '20 at 23:59
2

I found a work-around pretty straight forward:

Say your are in a project P and you want to use the self made gem tools which itself uses an OS gem oauth2.

If you made a patch within oauth2 and need that patch in your gem tools, you won't be able to fix this issue in the gem according to the accepted answer.

However, you can speficy the version you want within your projet P's Gemfile, and this will be the version used by tools on runtime:

gem 'oauth2', github: 'lgs/oauth2'

Here is a real life example of mine.

Ulysse BN
  • 10,116
  • 7
  • 54
  • 82
1

I was facing similar issue and here is what I found. You cannot add git branch directly for some other gem, However you can acheive this another way. You can define a private gem with repository link and branch name in gemfile of you custom gem i.e

gem 'gem_name', '>=0.1.1', git: 'repository_link ', branch: 'brnach_name'

and run bundle install

Now you can mention it in gemspec file, no need to add version as it will already pick from Gemfile.lock

spec.add_runtime_dependency 'sms_service'

Note: Make sure you keep gemspec at the bottom in Gemfile. So, it will first install necessary gems and than add them as dependency to your gem.

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'sms_service', '>=0.1.1', git: 'repository link', branch: 'branch_name'

gemspec
Touqeer
  • 583
  • 1
  • 4
  • 19
  • It did not work for me :( – kimerseen Jan 05 '22 at 02:17
  • This can work locally, but for anyone installing it via rubygems.org it probably won't know to fetch the branch. – lulalala Sep 04 '22 at 07:05
  • Adding 'gemspec' helps by running Gemfile then gemspec.. but defining the gem the second time aka `spec.add_runtime..` (above) just caused the wrong gem version to load. Takeaway.. reference the branch u need in Gemfile.. and make sure to add gemspec to bottom of Gemfile. – Evolve Mar 29 '23 at 14:06