librarian 0.0.25 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG.md +21 -0
  3. data/README.md +6 -1
  4. data/lib/librarian/action/persist_resolution_mixin.rb +51 -0
  5. data/lib/librarian/action/resolve.rb +3 -38
  6. data/lib/librarian/action/update.rb +4 -38
  7. data/lib/librarian/chef/dsl.rb +1 -0
  8. data/lib/librarian/chef/source.rb +1 -0
  9. data/lib/librarian/chef/source/github.rb +27 -0
  10. data/lib/librarian/chef/source/site.rb +51 -51
  11. data/lib/librarian/cli.rb +31 -23
  12. data/lib/librarian/cli/manifest_presenter.rb +36 -22
  13. data/lib/librarian/dependency.rb +60 -0
  14. data/lib/librarian/environment.rb +13 -1
  15. data/lib/librarian/linter/source_linter.rb +55 -0
  16. data/lib/librarian/lockfile/parser.rb +39 -16
  17. data/lib/librarian/manifest.rb +8 -0
  18. data/lib/librarian/manifest_set.rb +5 -7
  19. data/lib/librarian/mock/source/mock.rb +4 -21
  20. data/lib/librarian/resolution.rb +1 -1
  21. data/lib/librarian/resolver.rb +15 -12
  22. data/lib/librarian/resolver/implementation.rb +166 -75
  23. data/lib/librarian/source/basic_api.rb +45 -0
  24. data/lib/librarian/source/git.rb +4 -22
  25. data/lib/librarian/source/git/repository.rb +1 -1
  26. data/lib/librarian/source/local.rb +0 -7
  27. data/lib/librarian/source/path.rb +4 -22
  28. data/lib/librarian/version.rb +1 -1
  29. data/librarian.gemspec +3 -3
  30. data/spec/functional/chef/source/site_spec.rb +150 -100
  31. data/spec/functional/source/git/repository_spec.rb +2 -1
  32. data/spec/{functional → integration}/chef/source/git_spec.rb +12 -3
  33. data/spec/integration/chef/source/site_spec.rb +217 -0
  34. data/spec/support/cli_macro.rb +4 -12
  35. data/spec/support/method_patch_macro.rb +30 -0
  36. data/spec/unit/config/database_spec.rb +8 -0
  37. data/spec/unit/dependency_spec.rb +176 -0
  38. data/spec/unit/environment_spec.rb +76 -7
  39. data/spec/unit/resolver_spec.rb +2 -2
  40. metadata +52 -46
@@ -105,7 +105,7 @@ module Librarian
105
105
  def remote_branch_names
106
106
  remotes = remote_names.sort_by(&:length).reverse
107
107
 
108
- command = %W(branch -r)
108
+ command = %W(branch -r --no-color)
109
109
  names = run!(command, :chdir => true).strip.lines.map(&:strip).to_a
110
110
  names.each{|n| n.gsub!(/\s*->.*$/, "")}
111
111
  names.reject!{|n| n =~ /\/HEAD$/}
@@ -16,13 +16,6 @@ module Librarian
16
16
  [manifest].compact
17
17
  end
18
18
 
19
- def manifest(name, version, dependencies)
20
- manifest = Manifest.new(self, name)
21
- manifest.version = version
22
- manifest.dependencies = dependencies
23
- manifest
24
- end
25
-
26
19
  def manifest_search_paths(name)
27
20
  @manifest_search_paths ||= { }
28
21
  @manifest_search_paths[name] ||= begin
@@ -1,32 +1,14 @@
1
+ require 'librarian/source/basic_api'
1
2
  require 'librarian/source/local'
2
3
 
3
4
  module Librarian
4
5
  module Source
5
6
  class Path
6
-
7
+ include BasicApi
7
8
  include Local
8
9
 
9
- class << self
10
-
11
- LOCK_NAME = 'PATH'
12
-
13
- def lock_name
14
- LOCK_NAME
15
- end
16
-
17
- def from_lock_options(environment, options)
18
- new(environment, options[:remote], options.reject{|k, v| k == :remote})
19
- end
20
-
21
- def from_spec_args(environment, path, options)
22
- recognized_options = []
23
- unrecognized_options = options.keys - recognized_options
24
- unrecognized_options.empty? or raise Error, "unrecognized options: #{unrecognized_options.join(", ")}"
25
-
26
- new(environment, path, options)
27
- end
28
-
29
- end
10
+ lock_name 'PATH'
11
+ spec_options []
30
12
 
31
13
  attr_accessor :environment
32
14
  private :environment=
@@ -1,3 +1,3 @@
1
1
  module Librarian
2
- VERSION = "0.0.25"
2
+ VERSION = "0.0.26"
3
3
  end
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "librarian"
5
- s.version = "0.0.25"
5
+ s.version = "0.0.26"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Jay Feldblum"]
9
- s.date = "2012-10-12"
9
+ s.date = "2012-12-30"
10
10
  s.description = "Librarian"
11
11
  s.email = ["y_feldblum@yahoo.com"]
12
12
  s.executables = ["librarian-chef", "librarian-mock"]
13
- s.files = [".gitignore", ".rspec", ".travis.yml", "CHANGELOG.md", "Gemfile", "MIT-LICENSE", "README.md", "Rakefile", "bin/librarian-chef", "bin/librarian-mock", "lib/librarian.rb", "lib/librarian/action.rb", "lib/librarian/action/base.rb", "lib/librarian/action/clean.rb", "lib/librarian/action/ensure.rb", "lib/librarian/action/install.rb", "lib/librarian/action/resolve.rb", "lib/librarian/action/update.rb", "lib/librarian/chef.rb", "lib/librarian/chef/cli.rb", "lib/librarian/chef/dsl.rb", "lib/librarian/chef/environment.rb", "lib/librarian/chef/extension.rb", "lib/librarian/chef/integration/knife.rb", "lib/librarian/chef/manifest_reader.rb", "lib/librarian/chef/source.rb", "lib/librarian/chef/source/git.rb", "lib/librarian/chef/source/local.rb", "lib/librarian/chef/source/path.rb", "lib/librarian/chef/source/site.rb", "lib/librarian/chef/templates/Cheffile", "lib/librarian/cli.rb", "lib/librarian/cli/manifest_presenter.rb", "lib/librarian/config.rb", "lib/librarian/config/database.rb", "lib/librarian/config/file_source.rb", "lib/librarian/config/hash_source.rb", "lib/librarian/config/source.rb", "lib/librarian/dependency.rb", "lib/librarian/dsl.rb", "lib/librarian/dsl/receiver.rb", "lib/librarian/dsl/target.rb", "lib/librarian/environment.rb", "lib/librarian/error.rb", "lib/librarian/helpers.rb", "lib/librarian/lockfile.rb", "lib/librarian/lockfile/compiler.rb", "lib/librarian/lockfile/parser.rb", "lib/librarian/logger.rb", "lib/librarian/manifest.rb", "lib/librarian/manifest_set.rb", "lib/librarian/mock.rb", "lib/librarian/mock/cli.rb", "lib/librarian/mock/dsl.rb", "lib/librarian/mock/environment.rb", "lib/librarian/mock/extension.rb", "lib/librarian/mock/source.rb", "lib/librarian/mock/source/mock.rb", "lib/librarian/mock/source/mock/registry.rb", "lib/librarian/resolution.rb", "lib/librarian/resolver.rb", "lib/librarian/resolver/implementation.rb", "lib/librarian/source.rb", "lib/librarian/source/git.rb", "lib/librarian/source/git/repository.rb", "lib/librarian/source/local.rb", "lib/librarian/source/path.rb", "lib/librarian/spec.rb", "lib/librarian/spec_change_set.rb", "lib/librarian/specfile.rb", "lib/librarian/support/abstract_method.rb", "lib/librarian/ui.rb", "lib/librarian/version.rb", "librarian.gemspec", "spec/functional/chef/cli_spec.rb", "spec/functional/chef/source/git_spec.rb", "spec/functional/chef/source/site_spec.rb", "spec/functional/source/git/repository_spec.rb", "spec/support/cli_macro.rb", "spec/support/with_env_macro.rb", "spec/unit/action/base_spec.rb", "spec/unit/action/clean_spec.rb", "spec/unit/action/ensure_spec.rb", "spec/unit/action/install_spec.rb", "spec/unit/config/database_spec.rb", "spec/unit/dependency_spec.rb", "spec/unit/dsl_spec.rb", "spec/unit/environment_spec.rb", "spec/unit/lockfile/parser_spec.rb", "spec/unit/lockfile_spec.rb", "spec/unit/manifest_set_spec.rb", "spec/unit/manifest_spec.rb", "spec/unit/mock/source/mock_spec.rb", "spec/unit/resolver_spec.rb", "spec/unit/source/git_spec.rb", "spec/unit/spec_change_set_spec.rb"]
13
+ s.files = [".gitignore", ".rspec", ".travis.yml", "CHANGELOG.md", "Gemfile", "MIT-LICENSE", "README.md", "Rakefile", "bin/librarian-chef", "bin/librarian-mock", "lib/librarian.rb", "lib/librarian/action.rb", "lib/librarian/action/base.rb", "lib/librarian/action/clean.rb", "lib/librarian/action/ensure.rb", "lib/librarian/action/install.rb", "lib/librarian/action/persist_resolution_mixin.rb", "lib/librarian/action/resolve.rb", "lib/librarian/action/update.rb", "lib/librarian/chef.rb", "lib/librarian/chef/cli.rb", "lib/librarian/chef/dsl.rb", "lib/librarian/chef/environment.rb", "lib/librarian/chef/extension.rb", "lib/librarian/chef/integration/knife.rb", "lib/librarian/chef/manifest_reader.rb", "lib/librarian/chef/source.rb", "lib/librarian/chef/source/git.rb", "lib/librarian/chef/source/github.rb", "lib/librarian/chef/source/local.rb", "lib/librarian/chef/source/path.rb", "lib/librarian/chef/source/site.rb", "lib/librarian/chef/templates/Cheffile", "lib/librarian/cli.rb", "lib/librarian/cli/manifest_presenter.rb", "lib/librarian/config.rb", "lib/librarian/config/database.rb", "lib/librarian/config/file_source.rb", "lib/librarian/config/hash_source.rb", "lib/librarian/config/source.rb", "lib/librarian/dependency.rb", "lib/librarian/dsl.rb", "lib/librarian/dsl/receiver.rb", "lib/librarian/dsl/target.rb", "lib/librarian/environment.rb", "lib/librarian/error.rb", "lib/librarian/helpers.rb", "lib/librarian/linter/source_linter.rb", "lib/librarian/lockfile.rb", "lib/librarian/lockfile/compiler.rb", "lib/librarian/lockfile/parser.rb", "lib/librarian/logger.rb", "lib/librarian/manifest.rb", "lib/librarian/manifest_set.rb", "lib/librarian/mock.rb", "lib/librarian/mock/cli.rb", "lib/librarian/mock/dsl.rb", "lib/librarian/mock/environment.rb", "lib/librarian/mock/extension.rb", "lib/librarian/mock/source.rb", "lib/librarian/mock/source/mock.rb", "lib/librarian/mock/source/mock/registry.rb", "lib/librarian/resolution.rb", "lib/librarian/resolver.rb", "lib/librarian/resolver/implementation.rb", "lib/librarian/source.rb", "lib/librarian/source/basic_api.rb", "lib/librarian/source/git.rb", "lib/librarian/source/git/repository.rb", "lib/librarian/source/local.rb", "lib/librarian/source/path.rb", "lib/librarian/spec.rb", "lib/librarian/spec_change_set.rb", "lib/librarian/specfile.rb", "lib/librarian/support/abstract_method.rb", "lib/librarian/ui.rb", "lib/librarian/version.rb", "librarian.gemspec", "spec/functional/chef/cli_spec.rb", "spec/functional/chef/source/site_spec.rb", "spec/functional/source/git/repository_spec.rb", "spec/integration/chef/source/git_spec.rb", "spec/integration/chef/source/site_spec.rb", "spec/support/cli_macro.rb", "spec/support/method_patch_macro.rb", "spec/support/with_env_macro.rb", "spec/unit/action/base_spec.rb", "spec/unit/action/clean_spec.rb", "spec/unit/action/ensure_spec.rb", "spec/unit/action/install_spec.rb", "spec/unit/config/database_spec.rb", "spec/unit/dependency_spec.rb", "spec/unit/dsl_spec.rb", "spec/unit/environment_spec.rb", "spec/unit/lockfile/parser_spec.rb", "spec/unit/lockfile_spec.rb", "spec/unit/manifest_set_spec.rb", "spec/unit/manifest_spec.rb", "spec/unit/mock/source/mock_spec.rb", "spec/unit/resolver_spec.rb", "spec/unit/source/git_spec.rb", "spec/unit/spec_change_set_spec.rb"]
14
14
  s.homepage = ""
15
15
  s.require_paths = ["lib"]
16
16
  s.rubyforge_project = "librarian"
@@ -4,9 +4,8 @@ require 'webmock'
4
4
 
5
5
  require 'librarian'
6
6
  require 'librarian/helpers'
7
- require 'librarian/action/resolve'
8
- require 'librarian/action/install'
9
7
  require 'librarian/chef'
8
+ require 'librarian/linter/source_linter'
10
9
 
11
10
  module Librarian
12
11
  module Chef
@@ -20,7 +19,8 @@ module Librarian
20
19
  project_path = project_path.dirname until project_path.join("Rakefile").exist?
21
20
  project_path
22
21
  end
23
- let(:tmp_path) { project_path.join("tmp/spec/chef/site-source") }
22
+ let(:tmp_path) { project_path.join("tmp/spec/functional/chef/source/site") }
23
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
24
24
  let(:sample_path) { tmp_path.join("sample") }
25
25
  let(:sample_metadata) do
26
26
  Helpers.strip_heredoc(<<-METADATA)
@@ -73,141 +73,191 @@ module Librarian
73
73
  WebMock.reset!
74
74
  end
75
75
 
76
- context "a single dependency with a site source" do
76
+ let(:repo_path) { tmp_path.join("methods") }
77
+ before { repo_path.mkpath }
77
78
 
78
- context "resolving" do
79
- let(:repo_path) { tmp_path.join("repo/resolve") }
80
- before do
81
- repo_path.rmtree if repo_path.exist?
82
- repo_path.mkpath
83
- repo_path.join("cookbooks").mkpath
84
- cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
85
- #!/usr/bin/env ruby
86
- cookbook "sample", :site => #{api_url.inspect}
87
- CHEFFILE
88
- repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
89
- end
90
-
91
- context "the resolve" do
92
- it "should not raise an exception" do
93
- expect { Action::Resolve.new(env).run }.to_not raise_error
94
- end
79
+ describe "lint" do
80
+ it "lints" do
81
+ Librarian::Linter::SourceLinter.lint! described_class
82
+ end
83
+ end
84
+
85
+ describe "class methods" do
86
+
87
+ describe ".lock_name" do
88
+ specify { described_class.lock_name.should == "SITE" }
89
+ end
90
+
91
+ describe ".from_spec_args" do
92
+ it "gives the expected source" do
93
+ args = { }
94
+ source = described_class.from_spec_args(env, api_url, args)
95
+ source.uri.should == api_url
95
96
  end
96
97
 
97
- context "the results" do
98
- before { Action::Resolve.new(env).run }
98
+ it "raises on unexpected args" do
99
+ args = {:k => 3}
100
+ expect { described_class.from_spec_args(env, api_url, args) }.
101
+ to raise_error Librarian::Error, "unrecognized options: k"
102
+ end
103
+ end
99
104
 
100
- it "should create the lockfile" do
101
- repo_path.join("Cheffile.lock").should exist
102
- end
105
+ describe ".from_lock_options" do
106
+ it "gives the expected source" do
107
+ options = {:remote => api_url}
108
+ source = described_class.from_lock_options(env, options)
109
+ source.uri.should == api_url
110
+ end
103
111
 
104
- it "should not attempt to install the cookbok" do
105
- repo_path.join("cookbooks/sample").should_not exist
106
- end
112
+ it "roundtrips" do
113
+ options = {:remote => api_url}
114
+ source = described_class.from_lock_options(env, options)
115
+ source.to_lock_options.should == options
107
116
  end
108
117
  end
109
118
 
110
- context "intalling" do
111
- let(:repo_path) { tmp_path.join("repo/install") }
112
- before do
113
- repo_path.rmtree if repo_path.exist?
114
- repo_path.mkpath
115
- repo_path.join("cookbooks").mkpath
116
- cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
117
- #!/usr/bin/env ruby
118
- cookbook "sample", :site => #{api_url.inspect}
119
- CHEFFILE
120
- repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
119
+ end
121
120
 
122
- Action::Resolve.new(env).run
121
+ describe "instance methods" do
122
+ let(:source) { described_class.new(env, api_url) }
123
+
124
+ describe "#manifests" do
125
+ it "gives a list of all manifests" do
126
+ manifests = source.manifests("sample")
127
+ manifests.should have(1).item
128
+ manifest = manifests.first
129
+ manifest.source.should be source
130
+ manifest.version.should == Manifest::Version.new("0.6.5")
131
+ manifest.dependencies.should be_empty
123
132
  end
133
+ end
124
134
 
125
- context "the install" do
126
- it "should not raise an exception" do
127
- expect { Action::Install.new(env).run }.to_not raise_error
128
- end
135
+ describe "#fetch_version" do
136
+ it "fetches the version based on extra" do
137
+ extra = "#{api_url}/cookbooks/sample/versions/0_6_5"
138
+ source.fetch_version("sample", extra).should == "0.6.5"
129
139
  end
140
+ end
130
141
 
131
- context "the results" do
132
- before { Action::Install.new(env).run }
142
+ describe "#fetch_dependencies" do
143
+ it "fetches the dependencies based on extra" do
144
+ extra = "#{api_url}/cookbooks/sample/versions/0_6_5"
145
+ source.fetch_dependencies("sample", "0.6.5", extra).should == [ ]
146
+ end
147
+ end
133
148
 
134
- it "should create the lockfile" do
135
- repo_path.join("Cheffile.lock").should exist
136
- end
149
+ describe "#pinned?" do
150
+ it "returns false" do
151
+ source.should_not be_pinned
152
+ end
153
+ end
137
154
 
138
- it "should create a directory for the cookbook" do
139
- repo_path.join("cookbooks/sample").should exist
140
- end
155
+ describe "#unpin!" do
156
+ it "is a no-op" do
157
+ source.unpin!
158
+ end
159
+ end
160
+
161
+ describe "#install!" do
162
+ before { env.install_path.mkpath }
141
163
 
142
- it "should copy the cookbook files into the cookbook directory" do
143
- repo_path.join("cookbooks/sample/metadata.rb").should exist
164
+ context "directly" do
165
+ it "installs the manifest" do
166
+ manifest = Manifest.new(source, "sample")
167
+ manifest.version = "0.6.5"
168
+ source.install!(manifest)
169
+ text = env.install_path.join("sample/metadata.rb").read
170
+ text.should == sample_metadata
144
171
  end
145
172
  end
146
- end
147
173
 
148
- context "resolving and separately installing" do
149
- let(:repo_path) { tmp_path.join("repo/resolve-install") }
150
- before do
151
- repo_path.rmtree if repo_path.exist?
152
- repo_path.mkpath
153
- repo_path.join("cookbooks").mkpath
154
- cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
155
- #!/usr/bin/env ruby
156
- cookbook "sample", :site => #{api_url.inspect}
157
- CHEFFILE
158
- repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
159
-
160
- Action::Resolve.new(env).run
161
- repo_path.join("tmp").rmtree if repo_path.join("tmp").exist?
162
- end
163
-
164
- context "the install" do
165
- it "should not raise an exception" do
166
- expect { Action::Install.new(env).run }.to_not raise_error
174
+ context "indirectly" do
175
+ it "installs the manifest" do
176
+ manifest = source.manifests("sample").first
177
+ source.install!(manifest)
178
+ text = env.install_path.join("sample/metadata.rb").read
179
+ text.should == sample_metadata
167
180
  end
168
181
  end
182
+ end
169
183
 
170
- context "the results" do
171
- before { Action::Install.new(env).run }
184
+ describe "#to_spec_args" do
185
+ it "gives the expected spec args" do
186
+ source.to_spec_args.should == [api_url, { }]
187
+ end
188
+ end
172
189
 
173
- it "should create a directory for the cookbook" do
174
- repo_path.join("cookbooks/sample").should exist
175
- end
190
+ describe "#to_lock_options" do
191
+ it "gives the expected lock options" do
192
+ source.to_lock_options.should == {:remote => api_url}
193
+ end
176
194
 
177
- it "should copy the cookbook files into the cookbook directory" do
178
- repo_path.join("cookbooks/sample/metadata.rb").should exist
179
- end
195
+ it "roundtrips" do
196
+ options = source.to_lock_options
197
+ described_class.from_lock_options(env, options).should == source
180
198
  end
181
199
  end
182
200
 
183
201
  end
184
202
 
185
- context "when the repo path has a space" do
203
+ describe "following http redirects" do
204
+ let(:source) { described_class.new(env, api_url) }
186
205
 
187
- let(:repo_path) { tmp_path.join("repo/with extra spaces/resolve") }
206
+ def redirect_to(url)
207
+ {:status => 302, :headers => {"Location" => url}}
208
+ end
188
209
 
189
- before do
190
- repo_path.rmtree if repo_path.exist?
191
- repo_path.mkpath
192
- repo_path.join("cookbooks").mkpath
210
+ context "with a sequence of http redirects" do
211
+ before do
212
+ stub_request(:get, "#{api_url}/cookbooks/sample").
213
+ to_return redirect_to "#{api_url}/cookbooks/sample-1"
214
+ stub_request(:get, "#{api_url}/cookbooks/sample-1").
215
+ to_return redirect_to "#{api_url}/cookbooks/sample-2"
216
+ stub_request(:get, "#{api_url}/cookbooks/sample-2").
217
+ to_return(:body => JSON.dump(sample_index_data))
218
+ end
193
219
 
194
- cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
195
- #!/usr/bin/env ruby
196
- cookbook "sample", :site => #{api_url.inspect}
197
- CHEFFILE
198
- repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
220
+ it "follows a sequence of redirects" do
221
+ manifest = source.manifests("sample").first
222
+ manifest.version.to_s.should == "0.6.5"
223
+ end
199
224
  end
200
225
 
201
- after do
202
- repo_path.rmtree
203
- end
226
+ context "with too many http redirects" do
227
+ before do
228
+ stub_request(:get, "#{api_url}/cookbooks/sample").
229
+ to_return redirect_to "#{api_url}/cookbooks/sample-1"
230
+ (1 .. 11).each do |i|
231
+ stub_request(:get, "#{api_url}/cookbooks/sample-#{i}").
232
+ to_return redirect_to "#{api_url}/cookbooks/sample-#{i + 1}"
233
+ end
234
+ stub_request(:get, "#{api_url}/cookbooks/sample-12").
235
+ to_return(:body => JSON.dump(sample_index_data))
236
+ end
204
237
 
205
- context "the resolution" do
206
- it "should not raise an exception" do
207
- expect { Action::Resolve.new(env).run }.to_not raise_error
238
+ it "raises, warning of too many redirects" do
239
+ expect { source.manifests("sample").first }.
240
+ to raise_error Librarian::Error, /because too many redirects!/
208
241
  end
209
242
  end
210
243
 
244
+ context "with a redirect cycle" do
245
+ before do
246
+ stub_request(:get, "#{api_url}/cookbooks/sample").
247
+ to_return redirect_to "#{api_url}/cookbooks/sample-1"
248
+ (1 .. 8).each do |i|
249
+ stub_request(:get, "#{api_url}/cookbooks/sample-#{i}").
250
+ to_return redirect_to "#{api_url}/cookbooks/sample-#{i + 1}"
251
+ end
252
+ stub_request(:get, "#{api_url}/cookbooks/sample-9").
253
+ to_return redirect_to "#{api_url}/cookbooks/sample-6"
254
+ end
255
+
256
+ it "raises, warning of a redirect cycle" do
257
+ expect { source.manifests("sample").first }.
258
+ to raise_error Librarian::Error, /because redirect cycle!/
259
+ end
260
+ end
211
261
  end
212
262
 
213
263
  end
@@ -15,7 +15,8 @@ describe Librarian::Source::Git::Repository do
15
15
  project_path = project_path.dirname until project_path.join("Rakefile").exist?
16
16
  project_path
17
17
  end
18
- let(:tmp_path) { project_path + "tmp/spec/unit/source/git/repository-spec" }
18
+ let(:tmp_path) { project_path + "tmp/spec/functional/source/git/repository" }
19
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
19
20
  let(:git_source_path) { tmp_path + SecureRandom.hex(16) }
20
21
  let(:branch) { "the-branch" }
21
22
  let(:tag) { "the-tag" }
@@ -19,7 +19,8 @@ module Librarian
19
19
  project_path = project_path.dirname until project_path.join("Rakefile").exist?
20
20
  project_path
21
21
  end
22
- let(:tmp_path) { project_path.join("tmp/spec/chef/git-source") }
22
+ let(:tmp_path) { project_path.join("tmp/spec/integration/chef/source/git") }
23
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
23
24
 
24
25
  let(:cookbooks_path) { tmp_path.join("cookbooks") }
25
26
 
@@ -49,7 +50,7 @@ module Librarian
49
50
  METADATA
50
51
  end
51
52
 
52
- before :all do
53
+ before do
53
54
  sample_path.rmtree if sample_path.exist?
54
55
  sample_path.mkpath
55
56
  sample_path.join("metadata.rb").open("wb") { |f| f.write(sample_metadata) }
@@ -217,7 +218,7 @@ module Librarian
217
218
  METADATA
218
219
  end
219
220
 
220
- before :all do
221
+ before do
221
222
  git_path.rmtree if git_path.exist?
222
223
  git_path.mkpath
223
224
  sample_path.mkpath
@@ -304,6 +305,14 @@ module Librarian
304
305
  let(:git_path) { tmp_path.join("big-git-repo") }
305
306
  let(:repo_path) { tmp_path.join("repo/resolve") }
306
307
  before do
308
+ git_path.rmtree if git_path.exist?
309
+ git_path.mkpath
310
+ Dir.chdir(git_path) do
311
+ `git init`
312
+ `touch not-a-metadata`
313
+ `git add .`
314
+ `git commit -m "Initial commit."`
315
+ end
307
316
  repo_path.rmtree if repo_path.exist?
308
317
  repo_path.mkpath
309
318
  repo_path.join("cookbooks").mkpath
@@ -0,0 +1,217 @@
1
+ require 'pathname'
2
+ require 'json'
3
+ require 'webmock'
4
+
5
+ require 'librarian'
6
+ require 'librarian/helpers'
7
+ require 'librarian/action/resolve'
8
+ require 'librarian/action/install'
9
+ require 'librarian/chef'
10
+
11
+ module Librarian
12
+ module Chef
13
+ module Source
14
+ describe Site do
15
+
16
+ include WebMock::API
17
+
18
+ let(:project_path) do
19
+ project_path = Pathname.new(__FILE__).expand_path
20
+ project_path = project_path.dirname until project_path.join("Rakefile").exist?
21
+ project_path
22
+ end
23
+ let(:tmp_path) { project_path.join("tmp/spec/integration/chef/source/site") }
24
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
25
+ let(:sample_path) { tmp_path.join("sample") }
26
+ let(:sample_metadata) do
27
+ Helpers.strip_heredoc(<<-METADATA)
28
+ version "0.6.5"
29
+ METADATA
30
+ end
31
+
32
+ let(:api_url) { "http://site.cookbooks.com" }
33
+
34
+ let(:sample_index_data) do
35
+ {
36
+ "name" => "sample",
37
+ "versions" => [
38
+ "#{api_url}/cookbooks/sample/versions/0_6_5"
39
+ ]
40
+ }
41
+ end
42
+ let(:sample_0_6_5_data) do
43
+ {
44
+ "version" => "0.6.5",
45
+ "file" => "#{api_url}/cookbooks/sample/versions/0_6_5/file.tar.gz"
46
+ }
47
+ end
48
+ let(:sample_0_6_5_package) do
49
+ s = StringIO.new
50
+ z = Zlib::GzipWriter.new(s, Zlib::NO_COMPRESSION)
51
+ t = Archive::Tar::Minitar::Output.new(z)
52
+ t.tar.add_file_simple("sample/metadata.rb", :mode => 0700,
53
+ :size => sample_metadata.bytesize){|io| io.write(sample_metadata)}
54
+ t.close
55
+ z.close unless z.closed?
56
+ s.string
57
+ end
58
+
59
+ # depends on repo_path being defined in each context
60
+ let(:env) { Environment.new(:project_path => repo_path) }
61
+
62
+ before do
63
+ stub_request(:get, "#{api_url}/cookbooks/sample").
64
+ to_return(:body => JSON.dump(sample_index_data))
65
+
66
+ stub_request(:get, "#{api_url}/cookbooks/sample/versions/0_6_5").
67
+ to_return(:body => JSON.dump(sample_0_6_5_data))
68
+
69
+ stub_request(:get, "#{api_url}/cookbooks/sample/versions/0_6_5/file.tar.gz").
70
+ to_return(:body => sample_0_6_5_package)
71
+ end
72
+
73
+ after do
74
+ WebMock.reset!
75
+ end
76
+
77
+ context "a single dependency with a site source" do
78
+
79
+ context "resolving" do
80
+ let(:repo_path) { tmp_path.join("repo/resolve") }
81
+ before do
82
+ repo_path.rmtree if repo_path.exist?
83
+ repo_path.mkpath
84
+ repo_path.join("cookbooks").mkpath
85
+ cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
86
+ #!/usr/bin/env ruby
87
+ cookbook "sample", :site => #{api_url.inspect}
88
+ CHEFFILE
89
+ repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
90
+ end
91
+
92
+ context "the resolve" do
93
+ it "should not raise an exception" do
94
+ expect { Action::Resolve.new(env).run }.to_not raise_error
95
+ end
96
+ end
97
+
98
+ context "the results" do
99
+ before { Action::Resolve.new(env).run }
100
+
101
+ it "should create the lockfile" do
102
+ repo_path.join("Cheffile.lock").should exist
103
+ end
104
+
105
+ it "should not attempt to install the cookbok" do
106
+ repo_path.join("cookbooks/sample").should_not exist
107
+ end
108
+ end
109
+ end
110
+
111
+ context "intalling" do
112
+ let(:repo_path) { tmp_path.join("repo/install") }
113
+ before do
114
+ repo_path.rmtree if repo_path.exist?
115
+ repo_path.mkpath
116
+ repo_path.join("cookbooks").mkpath
117
+ cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
118
+ #!/usr/bin/env ruby
119
+ cookbook "sample", :site => #{api_url.inspect}
120
+ CHEFFILE
121
+ repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
122
+
123
+ Action::Resolve.new(env).run
124
+ end
125
+
126
+ context "the install" do
127
+ it "should not raise an exception" do
128
+ expect { Action::Install.new(env).run }.to_not raise_error
129
+ end
130
+ end
131
+
132
+ context "the results" do
133
+ before { Action::Install.new(env).run }
134
+
135
+ it "should create the lockfile" do
136
+ repo_path.join("Cheffile.lock").should exist
137
+ end
138
+
139
+ it "should create a directory for the cookbook" do
140
+ repo_path.join("cookbooks/sample").should exist
141
+ end
142
+
143
+ it "should copy the cookbook files into the cookbook directory" do
144
+ repo_path.join("cookbooks/sample/metadata.rb").should exist
145
+ end
146
+ end
147
+ end
148
+
149
+ context "resolving and separately installing" do
150
+ let(:repo_path) { tmp_path.join("repo/resolve-install") }
151
+ before do
152
+ repo_path.rmtree if repo_path.exist?
153
+ repo_path.mkpath
154
+ repo_path.join("cookbooks").mkpath
155
+ cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
156
+ #!/usr/bin/env ruby
157
+ cookbook "sample", :site => #{api_url.inspect}
158
+ CHEFFILE
159
+ repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
160
+
161
+ Action::Resolve.new(env).run
162
+ repo_path.join("tmp").rmtree if repo_path.join("tmp").exist?
163
+ end
164
+
165
+ context "the install" do
166
+ it "should not raise an exception" do
167
+ expect { Action::Install.new(env).run }.to_not raise_error
168
+ end
169
+ end
170
+
171
+ context "the results" do
172
+ before { Action::Install.new(env).run }
173
+
174
+ it "should create a directory for the cookbook" do
175
+ repo_path.join("cookbooks/sample").should exist
176
+ end
177
+
178
+ it "should copy the cookbook files into the cookbook directory" do
179
+ repo_path.join("cookbooks/sample/metadata.rb").should exist
180
+ end
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+ context "when the repo path has a space" do
187
+
188
+ let(:repo_path) { tmp_path.join("repo/with extra spaces/resolve") }
189
+
190
+ before do
191
+ repo_path.rmtree if repo_path.exist?
192
+ repo_path.mkpath
193
+ repo_path.join("cookbooks").mkpath
194
+
195
+ cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
196
+ #!/usr/bin/env ruby
197
+ cookbook "sample", :site => #{api_url.inspect}
198
+ CHEFFILE
199
+ repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
200
+ end
201
+
202
+ after do
203
+ repo_path.rmtree
204
+ end
205
+
206
+ context "the resolution" do
207
+ it "should not raise an exception" do
208
+ expect { Action::Resolve.new(env).run }.to_not raise_error
209
+ end
210
+ end
211
+
212
+ end
213
+
214
+ end
215
+ end
216
+ end
217
+ end