librarian 0.0.12 → 0.0.13

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.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.0.13
2
+
3
+ * \#36 Fixes an issue where, if a dependency has a git source (the upstream), and the upstream is updated,
4
+ then attempting to update that dependency in the local resolution would not update that dependency so
5
+ long as that git source were cached (@databus23).
6
+
7
+ * More immediate detection of, and better error messages for, cases of blank dependency or manifest names
8
+ or cases of names that are otherwise insensible, such as names that are untrimmed.
9
+
1
10
  ## 0.0.12
2
11
 
3
12
  * Fixes an issue where, if a dependency has a git source with a ref, re-resolving may fail.
data/README.md CHANGED
@@ -12,7 +12,7 @@ The mock source is in-process and in-memory and does not touch the filesystem or
12
12
  Librarian::Chef
13
13
  ---------------
14
14
 
15
- An adapter for Librarian applying to Chef cookbooks in a Chef Repository.
15
+ An adapter for Librarian applying to Chef cookbooks in a Chef Repository. When used with Chef, Librarian is really for pulling in the 50 or so finished third-party cookbooks that you're using, not the 1 or 2 cookbooks you're actively working on.
16
16
 
17
17
  ## Install librarian:
18
18
 
@@ -24,6 +24,7 @@ __Make sure your cookbooks directory is gitignored__
24
24
  $ cd ~/path/to/chef-repo
25
25
  $ git rm -r cookbooks # if the directory is present
26
26
  $ echo cookbooks >> .gitignore
27
+ $ echo tmp >> .gitignore
27
28
 
28
29
  Note that librarian *takes over* your cookbooks directory
29
30
  and manages it for you based on your Cheffile. Your
@@ -40,7 +41,7 @@ __Add dependencies and their sources to Cheffile__
40
41
  $ cat Cheffile
41
42
  site 'http://community.opscode.com/api/v1'
42
43
  cookbook 'ntp'
43
- cookbook 'timezone'
44
+ cookbook 'timezone', '0.0.1'
44
45
  cookbook 'rvm',
45
46
  :git => 'https://github.com/fnichol/chef-rvm',
46
47
  :ref => 'v0.7.1'
@@ -59,7 +60,7 @@ __Update your cheffile with new/changed/removed constraints/sources/dependencies
59
60
  $ cat Cheffile
60
61
  site 'http://community.opscode.com/api/v1'
61
62
  cookbook 'ntp'
62
- cookbook 'timezone'
63
+ cookbook 'timezone', '0.0.1'
63
64
  cookbook 'rvm',
64
65
  :git => 'https://github.com/fnichol/chef-rvm',
65
66
  :ref => 'v0.7.1'
@@ -17,6 +17,8 @@ module Librarian
17
17
  spec = specfile.read(previous_resolution.sources)
18
18
  spec_changes = spec_change_set(spec, previous_resolution)
19
19
  raise Error, "Cannot update when the specfile has been changed." unless spec_changes.same?
20
+ unpinnable_sources = previous_resolution.sources - partial_manifests.map(&:source)
21
+ unpinnable_sources.each(&:unpin!)
20
22
  resolution = resolver.resolve(spec, partial_manifests)
21
23
  unless resolution.correct?
22
24
  raise Error, "Could not resolve the dependencies."
@@ -54,6 +54,13 @@ module Librarian
54
54
  {:remote => uri}
55
55
  end
56
56
 
57
+ def pinned?
58
+ false
59
+ end
60
+
61
+ def unpin!
62
+ end
63
+
57
64
  def cache!(dependencies)
58
65
  cache_path.mkpath
59
66
  dependencies.each do |dependency|
@@ -5,6 +5,8 @@ site 'http://community.opscode.com/api/v1'
5
5
 
6
6
  # cookbook 'chef-client'
7
7
 
8
+ # cookbook 'apache2', '>= 1.0.0'
9
+
8
10
  # cookbook 'rvm',
9
11
  # :git => 'https://github.com/fnichol/chef-rvm'
10
12
 
@@ -10,12 +10,16 @@ module Librarian
10
10
 
11
11
  include Helpers::Debug
12
12
 
13
- attr_reader :name, :requirement, :source
13
+ attr_accessor :name, :requirement, :source
14
+ private :name=, :requirement=, :source=
14
15
 
15
16
  def initialize(name, requirement, source)
16
- @name = name
17
- @requirement = Requirement.create(requirement)
18
- @source = source
17
+ assert_name_valid! name
18
+
19
+ self.name = name
20
+ self.requirement = Requirement.create(requirement)
21
+ self.source = source
22
+
19
23
  @manifests = nil
20
24
  end
21
25
 
@@ -50,5 +54,9 @@ module Librarian
50
54
  source.environment
51
55
  end
52
56
 
57
+ def assert_name_valid!(name)
58
+ raise ArgumentError, "name (#{name.inspect}) must be sensible" unless name =~ /^\S.*\S$/
59
+ end
60
+
53
61
  end
54
62
  end
@@ -12,14 +12,18 @@ module Librarian
12
12
  include Support::AbstractMethod
13
13
  include Helpers::Debug
14
14
 
15
- attr_reader :source, :name
15
+ attr_accessor :source, :name
16
+ private :source=, :name=
16
17
 
17
18
  abstract_method :fetch_version!, :fetch_dependencies!
18
19
  abstract_method :install!
19
20
 
20
21
  def initialize(source, name)
21
- @source = source
22
- @name = name
22
+ assert_name_valid! name
23
+
24
+ self.source = source
25
+ self.name = name
26
+
23
27
  @fetched_version = nil
24
28
  @defined_version = nil
25
29
  @fetched_dependencies = nil
@@ -84,5 +88,9 @@ module Librarian
84
88
  dependencies.sort_by{|d| d.name}
85
89
  end
86
90
 
91
+ def assert_name_valid!(name)
92
+ raise ArgumentError, "name (#{name.inspect}) must be sensible" unless name =~ /^\S.*\S$/
93
+ end
94
+
87
95
  end
88
96
  end
@@ -65,6 +65,14 @@ module Librarian
65
65
  options
66
66
  end
67
67
 
68
+ def pinned?
69
+ !!sha
70
+ end
71
+
72
+ def unpin!
73
+ @sha = nil
74
+ end
75
+
68
76
  def cache!(dependencies)
69
77
  unless repository.git?
70
78
  repository.path.rmtree if repository.path.exist?
@@ -73,7 +81,9 @@ module Librarian
73
81
  end
74
82
  unless sha == repository.current_commit_hash
75
83
  repository.fetch!(:tags => true)
76
- repository.checkout!(sha || ref)
84
+ repository.fetch!
85
+ repository.merge_all_remote_branches!
86
+ repository.reset_hard! repository.hash_from(sha || ref)
77
87
  @sha ||= repository.current_commit_hash
78
88
  end
79
89
  end
@@ -47,6 +47,13 @@ module Librarian
47
47
  end
48
48
  end
49
49
 
50
+ def reset_hard!(reference)
51
+ within do
52
+ command = "reset --hard #{reference}"
53
+ run!(command, false)
54
+ end
55
+ end
56
+
50
57
  def fetch!(options = { })
51
58
  within do
52
59
  command = "fetch"
@@ -55,6 +62,13 @@ module Librarian
55
62
  end
56
63
  end
57
64
 
65
+ def merge!(reference)
66
+ within do
67
+ command = "merge #{reference}"
68
+ run!(command)
69
+ end
70
+ end
71
+
58
72
  def hash_from(reference)
59
73
  within do
60
74
  command = "rev-parse #{reference}"
@@ -69,10 +83,26 @@ module Librarian
69
83
  end
70
84
  end
71
85
 
86
+ def merge_all_remote_branches!
87
+ remote_branches.each do |branch|
88
+ checkout!(branch.slice(%r{[^/]+$}))
89
+ merge! branch
90
+ end
91
+ end
92
+
93
+ def remote_branches
94
+ within do
95
+ command ="branch -r --no-color"
96
+ run!(command, false).split("\n ").reject do |r|
97
+ r.include? '->' #delete pointers like origin/HEAD -> origin/master
98
+ end.collect {|r|r.strip}
99
+ end
100
+ end
72
101
  private
73
102
 
74
- def run!(text)
75
- text = "git #{text} --quiet"
103
+ def run!(text, quiet = true)
104
+ text = "git #{text}"
105
+ text << " --quiet" if quiet
76
106
  debug { "Running `#{text}` in #{relative_path_to(Dir.pwd)}" }
77
107
  out = Open3.popen3(text) do |i, o, e, t|
78
108
  raise StandardError, e.read unless (t ? t.value : $?).success?
@@ -43,6 +43,13 @@ module Librarian
43
43
  {:remote => path}
44
44
  end
45
45
 
46
+ def pinned?
47
+ false
48
+ end
49
+
50
+ def unpin!
51
+ end
52
+
46
53
  def cache!(dependencies)
47
54
  end
48
55
 
@@ -1,10 +1,12 @@
1
1
  module Librarian
2
2
  class Spec
3
3
 
4
- attr_reader :source, :dependencies
4
+ attr_accessor :source, :dependencies
5
+ private :source=, :dependencies=
5
6
 
6
7
  def initialize(source, dependencies)
7
- @source, @dependencies = source, dependencies
8
+ self.source = source
9
+ self.dependencies = dependencies
8
10
  end
9
11
 
10
12
  end
@@ -1,3 +1,3 @@
1
1
  module Librarian
2
- VERSION = "0.0.12"
2
+ VERSION = "0.0.13"
3
3
  end
@@ -6,6 +6,7 @@ require 'librarian/helpers'
6
6
  require 'librarian/error'
7
7
  require 'librarian/action/resolve'
8
8
  require 'librarian/action/install'
9
+ require 'librarian/action/update'
9
10
  require 'librarian/chef'
10
11
 
11
12
  module Librarian
@@ -337,6 +338,94 @@ module Librarian
337
338
  end
338
339
  end
339
340
 
341
+ context "when upstream updates" do
342
+ let(:git_path) { tmp_path.join("upstream-updates-repo") }
343
+ let(:repo_path) { tmp_path.join("repo/resolve-with-upstream-updates") }
344
+
345
+ let(:sample_metadata) do
346
+ Helpers.strip_heredoc(<<-METADATA)
347
+ version "0.6.5"
348
+ METADATA
349
+ end
350
+ before do
351
+
352
+ # set up the git repo as normal, but let's also set up a release-stable branch
353
+ # from which our Cheffile will only pull stable releases
354
+ git_path.rmtree if git_path.exist?
355
+ git_path.mkpath
356
+ git_path.join("metadata.rb").open("w+b"){|f| f.write(sample_metadata)}
357
+
358
+ Dir.chdir(git_path) do
359
+ `git init`
360
+ `git add metadata.rb`
361
+ `git commit -m "Initial Commit."`
362
+ `git checkout -b some-branch --quiet`
363
+ `echo 'hi' > some-file`
364
+ `git add some-file`
365
+ `git commit -m 'Some File.'`
366
+ `git checkout master --quiet`
367
+ end
368
+
369
+ # set up the chef repo as normal, except the Cheffile points to the release-stable
370
+ # branch - we expect when the upstream copy of that branch is changed, then we can
371
+ # fetch & merge those changes when we update
372
+ repo_path.rmtree if repo_path.exist?
373
+ repo_path.mkpath
374
+ repo_path.join("cookbooks").mkpath
375
+ cheffile = Helpers.strip_heredoc(<<-CHEFFILE)
376
+ cookbook "sample",
377
+ :git => #{git_path.to_s.inspect},
378
+ :ref => "some-branch"
379
+ CHEFFILE
380
+ repo_path.join("Cheffile").open("wb") { |f| f.write(cheffile) }
381
+ Action::Resolve.new(env).run
382
+
383
+ # change the upstream copy of that branch: we expect to be able to pull the latest
384
+ # when we re-resolve
385
+ Dir.chdir(git_path) do
386
+ `git checkout some-branch --quiet`
387
+ `echo 'ho' > some-other-file`
388
+ `git add some-other-file`
389
+ `git commit -m 'Some Other File.'`
390
+ `git checkout master --quiet`
391
+ end
392
+ end
393
+
394
+ let(:metadata_file) { repo_path.join("cookbooks/sample/metadata.rb") }
395
+ let(:old_code_file) { repo_path.join("cookbooks/sample/some-file") }
396
+ let(:new_code_file) { repo_path.join("cookbooks/sample/some-other-file") }
397
+
398
+ context "when updating not a cookbook from that source" do
399
+ before do
400
+ Action::Update.new(env).run
401
+ end
402
+
403
+ it "should pull the tip from upstream" do
404
+ Action::Install.new(env).run
405
+
406
+ metadata_file.should exist #sanity
407
+ old_code_file.should exist #sanity
408
+
409
+ new_code_file.should_not exist # the assertion
410
+ end
411
+ end
412
+
413
+ context "when updating a cookbook from that source" do
414
+ before do
415
+ Action::Update.new(env, :names => %w(sample)).run
416
+ end
417
+
418
+ it "should pull the tip from upstream" do
419
+ Action::Install.new(env).run
420
+
421
+ metadata_file.should exist #sanity
422
+ old_code_file.should exist #sanity
423
+
424
+ new_code_file.should exist # the assertion
425
+ end
426
+ end
427
+ end
428
+
340
429
  end
341
430
  end
342
431
  end
@@ -0,0 +1,30 @@
1
+ require "librarian/dependency"
2
+
3
+ describe Librarian::Dependency do
4
+
5
+ describe "validations" do
6
+
7
+ context "when the name is blank" do
8
+ it "raises" do
9
+ expect { described_class.new("", [], nil) }.
10
+ to raise_error(ArgumentError, %{name ("") must be sensible})
11
+ end
12
+ end
13
+
14
+ context "when the name has leading whitespace" do
15
+ it "raises" do
16
+ expect { described_class.new(" the-name", [], nil) }.
17
+ to raise_error(ArgumentError, %{name (" the-name") must be sensible})
18
+ end
19
+ end
20
+
21
+ context "when the name has trailing whitespace" do
22
+ it "raises" do
23
+ expect { described_class.new("the-name ", [], nil) }.
24
+ to raise_error(ArgumentError, %{name ("the-name ") must be sensible})
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -8,6 +8,17 @@ module Librarian
8
8
 
9
9
  let(:env) { Environment.new }
10
10
 
11
+ context "a single source and a single dependency with a blank name" do
12
+ it "should not not run with a blank name" do
13
+ expect do
14
+ env.dsl do
15
+ src 'source-1'
16
+ dep ''
17
+ end
18
+ end.to raise_error(ArgumentError, %{name ("") must be sensible})
19
+ end
20
+ end
21
+
11
22
  context "a single dependency but no applicable source" do
12
23
 
13
24
  it "should not run without any sources" do
@@ -0,0 +1,30 @@
1
+ require "librarian/manifest"
2
+
3
+ describe Librarian::Manifest do
4
+
5
+ describe "validations" do
6
+
7
+ context "when the name is blank" do
8
+ it "raises" do
9
+ expect { described_class.new(nil, "") }.
10
+ to raise_error(ArgumentError, %{name ("") must be sensible})
11
+ end
12
+ end
13
+
14
+ context "when the name has leading whitespace" do
15
+ it "raises" do
16
+ expect { described_class.new(nil, " the-name") }.
17
+ to raise_error(ArgumentError, %{name (" the-name") must be sensible})
18
+ end
19
+ end
20
+
21
+ context "when the name has trailing whitespace" do
22
+ it "raises" do
23
+ expect { described_class.new(nil, "the-name ") }.
24
+ to raise_error(ArgumentError, %{name ("the-name ") must be sensible})
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: librarian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-18 00:00:00.000000000Z
12
+ date: 2012-02-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
16
- requirement: &34503640 !ruby/object:Gem::Requirement
16
+ requirement: &16739740 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *34503640
24
+ version_requirements: *16739740
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &34503220 !ruby/object:Gem::Requirement
27
+ requirement: &16753740 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *34503220
35
+ version_requirements: *16753740
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &34502800 !ruby/object:Gem::Requirement
38
+ requirement: &16751920 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *34502800
46
+ version_requirements: *16751920
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: cucumber
49
- requirement: &34502380 !ruby/object:Gem::Requirement
49
+ requirement: &16749300 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *34502380
57
+ version_requirements: *16749300
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: aruba
60
- requirement: &34501960 !ruby/object:Gem::Requirement
60
+ requirement: &16748440 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *34501960
68
+ version_requirements: *16748440
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: webmock
71
- requirement: &34501540 !ruby/object:Gem::Requirement
71
+ requirement: &16754860 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *34501540
79
+ version_requirements: *16754860
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: chef
82
- requirement: &34501040 !ruby/object:Gem::Requirement
82
+ requirement: &17524920 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0.10'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *34501040
90
+ version_requirements: *17524920
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: highline
93
- requirement: &34500620 !ruby/object:Gem::Requirement
93
+ requirement: &17522700 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0'
99
99
  type: :runtime
100
100
  prerelease: false
101
- version_requirements: *34500620
101
+ version_requirements: *17522700
102
102
  description: Librarian
103
103
  email:
104
104
  - y_feldblum@yahoo.com
@@ -188,9 +188,11 @@ files:
188
188
  - spec/unit/action/clean_spec.rb
189
189
  - spec/unit/action/ensure_spec.rb
190
190
  - spec/unit/action/install_spec.rb
191
+ - spec/unit/dependency_spec.rb
191
192
  - spec/unit/dsl_spec.rb
192
193
  - spec/unit/environment_spec.rb
193
194
  - spec/unit/lockfile_spec.rb
195
+ - spec/unit/manifest_spec.rb
194
196
  - spec/unit/mock/source/mock.rb
195
197
  - spec/unit/resolver_spec.rb
196
198
  - spec/unit/spec_change_set_spec.rb