Skip to content

Commit d791e6d

Browse files
committed
show error if Gemfile is not watched
1 parent 35bd3d1 commit d791e6d

File tree

4 files changed

+215
-3
lines changed

4 files changed

+215
-3
lines changed
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
guard :bundler do
2-
watch('Gemfile')
3-
# Uncomment next line if your Gemfile contains the `gemspec' command.
4-
# watch(/^.+\.gemspec/)
2+
require 'guard/bundler'
3+
require 'guard/bundler/verify'
4+
helper = Guard::Bundler::Verify.new
5+
6+
files = ['Gemfile']
7+
files += Dir['*.gemspec'] if files.any? { |f| helper.uses_gemspec?(f) }
8+
9+
# Assume files are symlinked from somewhere
10+
files.each { |file| watch(helper.real_path(file)) }
511
end

lib/guard/bundler/verify.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
require 'pathname'
2+
3+
module Guard
4+
class Bundler < Plugin
5+
class Verify
6+
if Gem.win_platform?
7+
SYMLINK_NEEDED = <<-EOS
8+
Error: Guard will not detect changes to your Gemfile!
9+
10+
Solution: move the Gemfile to a watched directory and symlink it, so that
11+
'Gemfile' is symlinked e.g. to config/Gemfile.
12+
13+
(See: https://github.com/guard/guard/wiki/Optimizing-for-large-projects)
14+
15+
EOS
16+
else
17+
SYMLINK_NEEDED = <<-EOS
18+
Error: Guard will not detect changes to your Gemfile!
19+
20+
Solution: move the Gemfile to a watched directory and symlink it back.
21+
22+
Example:
23+
24+
$ mkdir config
25+
$ git mv Gemfile config # use just 'mv' if this doesn't work
26+
$ ln -s config/Gemfile .
27+
28+
and add config to the `directories` statement in your Guardfile.
29+
30+
(See: https://github.com/guard/guard/wiki/Optimizing-for-large-projects)
31+
EOS
32+
end
33+
34+
def verify!(file)
35+
watchdirs = Guard::Compat.watched_directories
36+
37+
gemfile = Pathname.new(file)
38+
config_dir = gemfile.realpath.dirname
39+
return if watchdirs.include?(config_dir)
40+
41+
Compat::UI.error SYMLINK_NEEDED
42+
end
43+
44+
def real_path(file)
45+
verify!(file)
46+
Pathname.new(file).realpath.relative_path_from(Pathname.pwd).to_s
47+
end
48+
49+
def uses_gemspec?(file)
50+
IO.read(file).lines.map(&:strip).grep(/^gemspec$/).any?
51+
end
52+
end
53+
end
54+
end
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
require "guard/compat/test/template"
2+
3+
require "guard/bundler"
4+
5+
# This is included by the template
6+
require "guard/bundler/verify"
7+
8+
module Guard
9+
RSpec.describe Bundler do
10+
describe "template" do
11+
subject { Compat::Test::Template.new(described_class) }
12+
13+
let(:helper) { instance_double(Bundler::Verify) }
14+
15+
before do
16+
allow(Bundler::Verify).to receive(:new).and_return(helper)
17+
allow(helper).to receive(:uses_gemspec?).and_return(true)
18+
19+
allow(helper).to receive(:real_path).with('Gemfile').
20+
and_return('Gemfile')
21+
22+
allow(Dir).to receive(:[]).and_return(%w(guard-foo.gemspec))
23+
24+
allow(helper).to receive(:real_path).with('guard-foo.gemspec').
25+
and_return('guard-foo.gemspec')
26+
end
27+
28+
context "when gemspec is used" do
29+
before do
30+
allow(helper).to receive(:uses_gemspec?).with('Gemfile').
31+
and_return(true)
32+
end
33+
34+
it "watches the gemspec" do
35+
expect(subject.changed('config/guard-foo.gemspec')).
36+
to eq(%w(config/guard-foo.gemspec))
37+
end
38+
end
39+
40+
context "when gemspec is not used" do
41+
before do
42+
allow(helper).to receive(:uses_gemspec?).with('Gemfile').
43+
and_return(false)
44+
end
45+
46+
it "does not watch the gemspec" do
47+
expect(subject.changed('guard-foo.gemspec')).to eq(%w())
48+
end
49+
end
50+
51+
context "when Gemfile is not a symlink" do
52+
before do
53+
expect(helper).to receive(:real_path).with('Gemfile').
54+
and_return('Gemfile')
55+
end
56+
57+
it "watches Gemfile" do
58+
expect(subject.changed('Gemfile')).to eq(%w(Gemfile))
59+
end
60+
end
61+
62+
context "with a symlinked Gemfile" do
63+
before do
64+
expect(helper).to receive(:real_path).with('Gemfile').
65+
and_return('config/Gemfile')
66+
end
67+
68+
it "watches the real Gemfile" do
69+
expect(subject.changed('config/Gemfile')).to eq(%w(config/Gemfile))
70+
end
71+
end
72+
end
73+
end
74+
end

spec/guard/bundler/verify_spec.rb

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
require "guard/bundler/verify"
2+
3+
RSpec.describe Guard::Bundler::Verify do
4+
describe '#uses_gemspec?' do
5+
context "when gemspec is used" do
6+
before do
7+
allow(IO).to receive(:read).with('foo').and_return("\n\n gemspec \n")
8+
end
9+
10+
it "detects used gemspec" do
11+
expect(subject.uses_gemspec?('foo')).to be_truthy
12+
end
13+
end
14+
15+
context "when gemspec is not used" do
16+
before do
17+
allow(IO).to receive(:read).with('foo').and_return("gem 'rspec'\n")
18+
end
19+
20+
it "does not detects gemspec usage" do
21+
expect(subject.uses_gemspec?('foo')).to be_falsey
22+
end
23+
end
24+
end
25+
26+
describe '#real_path' do
27+
context "when Gemfile is not watched" do
28+
before do
29+
allow(Guard::Compat).to receive(:watched_directories).and_return(['/foo'])
30+
end
31+
32+
it 'shows error' do
33+
expect(Guard::Compat::UI).to receive(:error).
34+
with(/Guard will not detect changes/)
35+
subject.real_path('Gemfile')
36+
end
37+
end
38+
39+
context "when Gemfile is watched along with whole project" do
40+
before do
41+
allow(Guard::Compat).to receive(:watched_directories).
42+
and_return([Pathname.pwd])
43+
end
44+
45+
it 'shows no error' do
46+
expect(Guard::Compat::UI).to_not receive(:error)
47+
subject.real_path('Gemfile')
48+
end
49+
50+
it 'returns relative path to file' do
51+
expect(subject.real_path('Gemfile')).to eq('Gemfile')
52+
end
53+
end
54+
55+
context "when subdir is watched" do
56+
before do
57+
allow(Guard::Compat).to receive(:watched_directories).
58+
and_return([Pathname.pwd + 'foo'])
59+
end
60+
61+
context "when Gemfile is symlinked" do
62+
before do
63+
allow_any_instance_of(Pathname).to receive(:realpath).
64+
and_return(Pathname.pwd + 'foo/Gemfile')
65+
end
66+
67+
it "returns the relative real path" do
68+
expect(subject.real_path('Gemfile')).to eq('foo/Gemfile')
69+
end
70+
71+
it 'shows no error' do
72+
expect(Guard::Compat::UI).to_not receive(:error)
73+
subject.real_path('Gemfile')
74+
end
75+
end
76+
end
77+
end
78+
end

0 commit comments

Comments
 (0)