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

Detect unwatched gemfile #28

Merged
merged 5 commits into from
Dec 11, 2014
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 .rspec
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
--color
--require spec_helper
--format doc
7 changes: 3 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ rvm:
matrix:
allow_failures:
- rvm: rbx

notifications:
recipients:
- remy@rymai.me
branches:
only:
- master
17 changes: 13 additions & 4 deletions Guardfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@ guard :bundler do
watch(%r{^.+\.gemspec$})
end

guard :rspec do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { 'spec' }
guard :rspec, cmd: "bundle exec rspec" do
require "ostruct"

rspec = OpenStruct.new
rspec.spec_dir = "spec"
rspec.spec = ->(m) { "#{rspec.spec_dir}/#{m}_spec.rb" }
rspec.spec_helper = "#{rspec.spec_dir}/spec_helper.rb"
rspec.spec_files = %r{^#{rspec.spec_dir}/.+_spec\.rb$}
rspec.lib_files = %r{^lib/(.+)\.rb$}

watch(rspec.spec_files)
watch(rspec.lib_files) { |m| rspec.spec.(m[1]) }
watch(rspec.spec_helper) { rspec.spec_dir }
end
2 changes: 1 addition & 1 deletion guard-bundler.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Gem::Specification.new do |s|
s.required_ruby_version = '>= 1.9.2'

s.add_dependency 'guard', '~> 2.2'
s.add_dependency 'guard-compat', '~> 1.0'
s.add_dependency 'guard-compat', '~> 1.1'
s.add_dependency 'bundler', '~> 1.0'

s.files = Dir.glob('{lib}/**/*') + %w[LICENSE README.md]
Expand Down
12 changes: 9 additions & 3 deletions lib/guard/bundler/templates/Guardfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
guard :bundler do
watch('Gemfile')
# Uncomment next line if your Gemfile contains the `gemspec' command.
# watch(/^.+\.gemspec/)
require 'guard/bundler'
require 'guard/bundler/verify'
helper = Guard::Bundler::Verify.new

files = ['Gemfile']
files += Dir['*.gemspec'] if files.any? { |f| helper.uses_gemspec?(f) }

# Assume files are symlinked from somewhere
files.each { |file| watch(helper.real_path(file)) }
end
54 changes: 54 additions & 0 deletions lib/guard/bundler/verify.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require 'pathname'

module Guard
class Bundler < Plugin
class Verify
if Gem.win_platform?
SYMLINK_NEEDED = <<-EOS
Error: Guard will not detect changes to your Gemfile!

Solution: move the Gemfile to a watched directory and symlink it, so that
'Gemfile' is symlinked e.g. to config/Gemfile.

(See: https://github.com/guard/guard/wiki/Optimizing-for-large-projects)

EOS
else
SYMLINK_NEEDED = <<-EOS
Error: Guard will not detect changes to your Gemfile!

Solution: move the Gemfile to a watched directory and symlink it back.

Example:

$ mkdir config
$ git mv Gemfile config # use just 'mv' if this doesn't work
$ ln -s config/Gemfile .

and add config to the `directories` statement in your Guardfile.

(See: https://github.com/guard/guard/wiki/Optimizing-for-large-projects)
EOS
end

def verify!(file)
watchdirs = Guard::Compat.watched_directories

gemfile = Pathname.new(file)
config_dir = gemfile.realpath.dirname
return if watchdirs.include?(config_dir)

Compat::UI.error SYMLINK_NEEDED
end

def real_path(file)
verify!(file)
Pathname.new(file).realpath.relative_path_from(Pathname.pwd).to_s
end

def uses_gemspec?(file)
IO.read(file).lines.map(&:strip).grep(/^gemspec$/).any?
end
end
end
end
74 changes: 74 additions & 0 deletions spec/guard/bundler/template_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
require "guard/compat/test/template"

require "guard/bundler"

# This is included by the template
require "guard/bundler/verify"

module Guard
RSpec.describe Bundler do
describe "template" do
subject { Compat::Test::Template.new(described_class) }

let(:helper) { instance_double(Bundler::Verify) }

before do
allow(Bundler::Verify).to receive(:new).and_return(helper)
allow(helper).to receive(:uses_gemspec?).and_return(true)

allow(helper).to receive(:real_path).with('Gemfile').
and_return('Gemfile')

allow(Dir).to receive(:[]).and_return(%w(guard-foo.gemspec))

allow(helper).to receive(:real_path).with('guard-foo.gemspec').
and_return('guard-foo.gemspec')
end

context "when gemspec is used" do
before do
allow(helper).to receive(:uses_gemspec?).with('Gemfile').
and_return(true)
end

it "watches the gemspec" do
expect(subject.changed('config/guard-foo.gemspec')).
to eq(%w(config/guard-foo.gemspec))
end
end

context "when gemspec is not used" do
before do
allow(helper).to receive(:uses_gemspec?).with('Gemfile').
and_return(false)
end

it "does not watch the gemspec" do
expect(subject.changed('guard-foo.gemspec')).to eq(%w())
end
end

context "when Gemfile is not a symlink" do
before do
expect(helper).to receive(:real_path).with('Gemfile').
and_return('Gemfile')
end

it "watches Gemfile" do
expect(subject.changed('Gemfile')).to eq(%w(Gemfile))
end
end

context "with a symlinked Gemfile" do
before do
expect(helper).to receive(:real_path).with('Gemfile').
and_return('config/Gemfile')
end

it "watches the real Gemfile" do
expect(subject.changed('config/Gemfile')).to eq(%w(config/Gemfile))
end
end
end
end
end
78 changes: 78 additions & 0 deletions spec/guard/bundler/verify_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
require "guard/bundler/verify"

RSpec.describe Guard::Bundler::Verify do
describe '#uses_gemspec?' do
context "when gemspec is used" do
before do
allow(IO).to receive(:read).with('foo').and_return("\n\n gemspec \n")
end

it "detects used gemspec" do
expect(subject.uses_gemspec?('foo')).to be_truthy
end
end

context "when gemspec is not used" do
before do
allow(IO).to receive(:read).with('foo').and_return("gem 'rspec'\n")
end

it "does not detects gemspec usage" do
expect(subject.uses_gemspec?('foo')).to be_falsey
end
end
end

describe '#real_path' do
context "when Gemfile is not watched" do
before do
allow(Guard::Compat).to receive(:watched_directories).and_return(['/foo'])
end

it 'shows error' do
expect(Guard::Compat::UI).to receive(:error).
with(/Guard will not detect changes/)
subject.real_path('Gemfile')
end
end

context "when Gemfile is watched along with whole project" do
before do
allow(Guard::Compat).to receive(:watched_directories).
and_return([Pathname.pwd])
end

it 'shows no error' do
expect(Guard::Compat::UI).to_not receive(:error)
subject.real_path('Gemfile')
end

it 'returns relative path to file' do
expect(subject.real_path('Gemfile')).to eq('Gemfile')
end
end

context "when subdir is watched" do
before do
allow(Guard::Compat).to receive(:watched_directories).
and_return([Pathname.pwd + 'foo'])
end

context "when Gemfile is symlinked" do
before do
allow_any_instance_of(Pathname).to receive(:realpath).
and_return(Pathname.pwd + 'foo/Gemfile')
end

it "returns the relative real path" do
expect(subject.real_path('Gemfile')).to eq('foo/Gemfile')
end

it 'shows no error' do
expect(Guard::Compat::UI).to_not receive(:error)
subject.real_path('Gemfile')
end
end
end
end
end