Bundler.with_clean_env does not find a JavaScript Runtime - heroku

I try to create a simple heroku app which clones a git repository, invokes bundle install, a rake dist task and then uploads the created files to a GitHub repository. The build task of the cloned repository uses Rake Pipeline, which uses the execjs gem for building the binary.
I've created a sample app located at https://github.com/pangratz/github-uploader-test, which illustrates the problem. The directory structure of the application is the following:
/upload.rb
/project
Rakefile
Assetfile
Gemfile
Gemfile.lock
The app itself is a simple sinatra app with a get '/' route, which looks like this:
upload.rb
get '/' do
Dir.chdir "project" do
Bundler.with_clean_env do
system "bundle install"
system "bundle exec rake dist"
end
end
end
For demonstration purpose, the project folder simulates the cloned git repository. It contains a Rakefile, Assetfile, Gemfile and Gemfile.lock.
project/Rakefile
desc "Build"
task :dist do
Rake::Pipeline::Project.new("Assetfile").invoke
end
project/Assetfile
require "rake-pipeline-web-filters"
require "json"
require "uglifier"
require "execjs"
puts ExecJS.eval "'red yellow blue'.split(' ')"
project/Gemfile
source "http://rubygems.org"
gem "rake-pipeline", :git => "https://github.com/livingsocial/rake-pipeline.git"
gem "rake-pipeline-web-filters", :git => "https://github.com/wycats/rake-pipeline-web-filters.git"
gem "colored"
gem "uglifier", :git => "https://github.com/lautis/uglifier.git"
group :development do
gem "rack"
gem "rest-client"
gem "github_api"
gem "ember-docs", :git => "https://github.com/emberjs/docs-generator.git"
gem "kicker"
end
The invocation of bundle install seems to work. The problem is that rake dist is failing with the error Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes..
The heroku app itself is created with the option --stack cedar.
I've also created a route '/test' which uses Execjs and this does not fail. So it seems
that there is a problem with the Bundler.with_clean_env and not finding the installed JavaScript Runtime ...
upload.rb
get '/test' do
puts ExecJS.eval "'red yellow blue'.split(' ')"
end

You could also try setting ENV['BUNDLE_GEMFILE']=/path/to/project/Gemfile. That should ensure that install and exec find the correct Gemfile.

I've opened an issue on Heroku and I could solve the issue. The problem was that the Dir.chdir("project") in combination with the Bundler.with_clean_env resulted in an invalid PATH which is needed to locate the JavaScript Runtime. Long story short, here is the working solution:
get '/' do
Dir.chdir "project" do
Bundler.with_clean_env do
ENV["PATH"] = "/app/bin:#{ENV['PATH']}"
system "bundle install --without WATWAT"
system "bundle exec rake dist"
end
end
end
A note on the solution: the --without WATWAT is needed because Heroku installs your app with bundle install --without development. Since the --without is remembered for successive calls, and the gems of development group are needed in the Assetfile, this option has to be overwritten. Using --without '' somehow doesn't work so I'm using the nonexistent group WATWAT to include all groups in the Gemfile.

Related

How to work with gemspec add_runtime_dependency and `bundle install`

I have a codebase which has a gemspec file like:
require "rubygems"
::Gem::Specification.new do |specification|
specification.add_development_dependency "yard", "~> 0.9"
specification.add_runtime_dependency "dry-validation", "~> 0.13"
end
bundle install will install both dependency types. So I want to just install the runtime dependencies for my CI scripts. I see bundle install --with <group> exists, but I don't have groups. Run interactively, the returned specification has an empty result returned from .groups. I would love to rationalize these two worlds. Must I explicitly add a group for each gem dependency? Does add_runtime_dependency and add_development_dependency even make a difference?
from bundler's documentation
Because we have the gemspec method call in our Gemfile, Bundler will automatically add this gem to a group called “development” which then we can reference any time we want to load these gems with the following line:
Bundler.require(:default, :development)
in your case, if you wish to install all rubygems that are not for development, then try
bundle install --without development
for future bundler version, you can configure it locally (or globally)
bundle config set --local without 'development'
to make it all work, verify that you have a Gemfile in your project, which will look like
# frozen_string_literal: true
source 'https://rubygems.org'
gemspec

Install *gem file with bundle

I try to develop a gem. I include it in my rails application through Gemfile with :path option for testing purpose, but there are some errors that appear when I build it and release to rubygems that does not appear when gem included from local path. How can I install gem from *gem file (made with rake build command) in rails or any bundle driven application for testing?
This will give you the best help: http://guides.rubygems.org/make-your-own-gem/
But in summary you need to build your gem from the .gemspec then using irb require your gem to test it out.
Example:
gem build hola.gemspec
% irb
require 'hola'
=> true

Bundler does not install from stash private repo, but reports that it does

My bundle file doesn't appear to be pulling down a gem from a private repository properly.
Inside of my Gemfile, I have:
group :internal do
gem 'private', git: 'ssh://git#internalserver.org:<port>/gems/private.git'
end
This runs, and verbose logging produces:
Updating ssh://git#internalserver.org:<port>/gems/private.git
Cloning into '/Users/<username>/.rvm/gems/ruby-2.0.0-p247/bundler/gems/private-ddec73caf50f'...
done.
When I navigate to /Users/<username>/.rvm/gems/ruby-2.0.0-p247/bundler/gems/, I see the correct repository cloned properly, with a gemspec with the correct name.
When bundler is finished running, gem list does not show the private gem. It produces an error when I attempt to require it.
I tried deleting the Gemfile.lock file in the repository and rerunning, and that did not work. All of the public gems in the Gemfile install correctly.
Relevant version numbers / software:
Bundler version 1.3.5
rvm 1.23.14
ruby 2.0.0p247
Atlassan Stash
Git gems are a Bundler-specific extension to Rubygems. The gem command does not know about these, so they're not listed by gem list. You can run bundle show to see the list of gems that are recognised by Bundler, which will include git gems.
To require the gem, you'll need to be sure that the load path is set up correctly by Bundler. There are three ways to do this:
Call require 'bundler/setup' in your app. This is typical for Rails apps. More on Bundler.setup
Call bundle exec <command> to run the command. This is more common when running commands from a gem, such as rake or rspec. More on bundle exec
Create binstubs for commands that you run frequently.
See http://bundler.io/v1.5/git.html for more information on git gems.

Gemfile - separating Production gems from Development gems

So I know that in a Gemfile I can do something like this:
group :development, :test do
gem 'gem1'
gem 'gem2'
end
What I am looking to accomplish is something like this:
group :production do
gem 'gem1'
gem 'gem2'
end
group :development, :test do
gem 'gem1', :path => '/Documents/Code/gem1/'
gem 'gem2', :path => '/Documents/Code/gem2/'
end
So our application uses 2 gems that we also develop locally. In order to improve time while developing on our local machines, we want to be able to point our dev environments to the local copies of the gems - this way it picks up all changes without needing to restart our rails server. Otherwise we would have to rebuild the gem, re-install the gem, and restart rails with every development change in the gem.
However, doing this gives me the following error:
You cannot specify the same gem twice coming from different sources. You specified that gem1 (>= 0) should come from an unspecfied source and source at /Documents/Code/gem1
I have tried even running something like bundle install --without production and I get the same error.
Does anyone know if it IS possible to do what I would like to do?
Thanks!
i think that there is a supported way to do it and some hacks to work around it.
supported way:
use bundle config with the local option as described here: http://bundler.io/v1.3/man/bundle-config.1.html
hacky way:
use env vars and execute bundler before using in production: http://www.cowboycoded.com/2010/08/10/using-2-sources-for-a-gem-in-different-environments-with-bundler/
there is a feature-request for this problem on github with several related issues and lots of comments: https://github.com/carlhuda/bundler/issues/396
the github issue phoet linked to is resolved, and is consistent with the supported way.
I dug around through the docs, you'll need to set the config variable and updated your gemfile to reference the branch as well.
e.g.
edit your Gemfile:
gem <gem_name>, git: <git_url>, branch: <branch>
on command line:
bundle config local.<gem_name> <local_path_to_gem>
I solved this by creating a new Gemfile that's identical to the original except for the target gem's source. Then, in config/boot.rb, I used:
require 'rails'
if Rails.env.development?
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../DevGemfile', __FILE__)
else
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../ProdGemfile', __FILE__)
end

How can Bundler/Gemfile be configured to use different gem sources during development?

I have a Sinatra application that requires another gem I'm developing locally. I'm having trouble configuring Bundler to use my local gem code during development but my vendored gem code in production.
Ideally I could do something like this, but Bundler doesn't allow you to specify the same gem twice:
# Doesn't work:
group :development do
gem 'awesome', :path => "~/code/awesome"
end
group :production do
gem 'awesome', :path => "vendor/gems/awesome-0.0.1"
end
In the meantime I've resorted to manually vendoring the gem & updating the gem source in the Gemfile every single time I deploy, which is quite a hassle. My workflow is this:
Point to my local gem during development (gem 'awesome', :path => "~/code/awesome")
When ready to deploy, unpack gem into vendor/gems
Update Gemfile to point to vendored gem (gem 'awesome', :path => "vendor/gems/awesome-0.0.1")
Run bundle install (to update Gemfile.lock)
Deploy code
Return to step 1.
What a hassle! I'd like to do something cleaner than simply writing Rake tasks to automate my current setup.
What's the best workflow for this scenario?
There is a new feature that allows to do that, by simply specyfing local.gem_name config option, like:
bundle config local.rack ~/path/to/local/rack
This only works if the gem has a git repo and branch specified in the Gemfile.
See thr Bundler docs for more details: http://bundler.io/v1.3/bundle_config.html
Apparently, you can use regular Ruby in your Gemfile. According to this article you can set an environment variable (or any other variable, I've found), to let you pick which version of a gem you want to use.
## based on an ENV variable
if ENV['RACK_ENV'] == "development"
gem 'awesome', :path => "~/code/awesome"
else
gem 'awesome', :path => "vendor/gems/awesome-0.0.1"
end
Maybe that'll work. If you need to vendor your in-progress gem maybe you could make a tiny little script that'll set the ENV, vendor it, and reset the ENV. Eh?
If you are using doccker to build your containers, you can always set the path as an environment variable in the dockerfile, and use this environment variable in Gemfile. Please find an example of Dockerfile and Gemfile below.
Dockerfile
ARG tenant
ENV mgm=3
ENV GEMBOX_URL='abc.com:9292'
WORKDIR /app
COPY Gemfile* ./
RUN bundle install --without development test
COPY . .
ENTRYPOINT ["entrypoint.sh"]
CMD ["crond", "-f"]
Gemfile
source 'https://rubygems.org/'
source ENV['GEMBOX_URL']
gem 'jwt'
gem 'activerecord-import'
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary-edge', '~> 0.12.5.0'
gem 'zgear', '~> 0.6.4.1', source: ENV['GEMBOX_URL']
gem "piston", '~> 1.3.1', source: ENV['GEMBOX_URL']
gem 'communication_connector', '~> 0.1.4', source: ENV['GEMBOX_URL']
gem 'health_check', source: ENV['GEMBOX_URL']
Here is a suggestion which I didn't get to fully work (used for a spree theme and I got problems with some stylesheets from the theme):
group :production do
gem 'gemname', '~> 0.1.6', :git => 'git://github.com/foouser/gemname.git'
end
group :development do
gem 'gemnamedev', :path => '~/path/gemname' # use local version
end
Duplicate your gemname.gemspec file and call it gemnamedev.gemspec, and change s.name inside it to "gemnamedev".

Resources