knife-cookbook-utils 0.1.0 → 0.2.0

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.
@@ -1,8 +1,8 @@
1
- require 'rlet'
1
+ require 'knife-cookbook-utils/rlet'
2
2
 
3
3
  module KnifeCookbookUtils
4
4
  class CookbookKeep < Chef::Knife
5
- include Let
5
+ include KnifeCookbookUtils::Let
6
6
 
7
7
  banner "knife cookbook keep NUM (options)"
8
8
 
@@ -1,9 +1,8 @@
1
- require 'rlet'
2
- require 'ap'
1
+ require 'knife-cookbook-utils/rlet'
3
2
 
4
3
  module KnifeCookbookUtils
5
4
  class CookbookMissingDeps < Chef::Knife
6
- include Let
5
+ include KnifeCookbookUtils::Let
7
6
 
8
7
  banner "knife cookbook missing deps (options)"
9
8
 
@@ -14,7 +13,7 @@ module KnifeCookbookUtils
14
13
  # A map of all cookbooks and versions
15
14
  let(:all_cookbooks) do
16
15
  Hash.new.tap do |cookbooks|
17
- rest.get("cookbooks/?num_versions=all").each do |cookbook, info|
16
+ raw_cookbook_listing.each do |cookbook, info|
18
17
  info['versions'].each do |version_info|
19
18
  # We cannot use Hash.new to initialize a new hash, since it will try to
20
19
  # add a new key while iterating
@@ -30,8 +29,7 @@ module KnifeCookbookUtils
30
29
  all_cookbooks.each do |cookbook_name, versions|
31
30
  versions.each do |cookbook_version, cookbook_url|
32
31
  Chef::Log.info("Checking deps for #{cookbook_name} #{cookbook_version}")
33
- cookbook = rest.get("cookbooks/#{cookbook_name}/#{cookbook_version}")
34
- cookbook.manifest['metadata']['dependencies'].each do |dep_cookbook_name, dep_constraint|
32
+ dependencies_for_cookbook_version(cookbook_name, cookbook_version).each do |dep_cookbook_name, dep_constraint|
35
33
  _constraint = Chef::VersionConstraint.new(dep_constraint)
36
34
  available_versions = (all_cookbooks[dep_cookbook_name] || {}).keys.flatten
37
35
  next if available_versions.any? { |c| _constraint.include?(c) }
@@ -44,6 +42,15 @@ module KnifeCookbookUtils
44
42
  end
45
43
  end
46
44
 
45
+ let(:raw_cookbook_listing) { rest.get("cookbooks/?num_versions=all") }
46
+
47
+ def dependencies_for_cookbook_version(name, version)
48
+ rest.
49
+ get("cookbooks/#{name}/#{version}").
50
+ manifest['metadata']['dependencies']
51
+ end
52
+
53
+
47
54
  def run
48
55
  puts "Missing dependencies:" if missing_deps.any?
49
56
  missing_deps.each do |cookbook, missing_deps|
@@ -0,0 +1,71 @@
1
+
2
+ # Author's Note: I was asked to embed this. Since this is not entirely my project, I agreed.
3
+ # My preference is to have this in a gem (or better yet, in the standard library). See: rlet gem
4
+
5
+ module KnifeCookbookUtils
6
+ # This is ActiveSupport::Concern, taken from
7
+ # https://github.com/rails/rails/blob/6794e92b204572d75a07bd6413bdae6ae22d5a82/activesupport/lib/active_support/concern.rb
8
+ #
9
+ # If ActiveSupport::Concern is loaded, it will use that instead
10
+ #
11
+ # Rails license:
12
+ # https://github.com/rails/rails/blob/6794e92b204572d75a07bd6413bdae6ae22d5a82/activesupport/MIT-LICENSE
13
+ module RLet
14
+ module Concern
15
+ def self.extended(base) #:nodoc:
16
+ base.instance_variable_set("@_dependencies", [])
17
+ end
18
+
19
+ def append_features(base)
20
+ if base.instance_variable_defined?("@_dependencies")
21
+ base.instance_variable_get("@_dependencies") << self
22
+ return false
23
+ else
24
+ return false if base < self
25
+ @_dependencies.each { |dep| base.send(:include, dep) }
26
+ super
27
+ base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
28
+ base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
29
+ end
30
+ end
31
+
32
+ def included(base = nil, &block)
33
+ if base.nil?
34
+ @_included_block = block
35
+ else
36
+ super
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ Concern = if defined?(ActiveSupport) and defined?(ActiveSupport::Concern)
43
+ ActiveSupport::Concern
44
+ else
45
+ RLet::Concern
46
+ end
47
+
48
+ module Let
49
+ extend Concern
50
+
51
+ module ClassMethods
52
+ def let(name, &block)
53
+ define_method(name) do
54
+ __memoized[name] ||= instance_eval(&block)
55
+ end
56
+ end
57
+ end
58
+
59
+ # Implementation based on Rspec let()
60
+ # https://github.com/rspec/rspec-core/blob/07be957b7f69447bf59ffe3ede9530436e6267ee/lib/rspec/core/let.rb
61
+ # License of RSpec:
62
+ # https://github.com/rspec/rspec-core/blob/07be957b7f69447bf59ffe3ede9530436e6267ee/License.txt
63
+
64
+ private
65
+
66
+ def __memoized # :nodoc:
67
+ @__memoized ||= {}
68
+ end
69
+ end
70
+ end
71
+
@@ -1,3 +1,3 @@
1
1
  module KnifeCookbookUtils
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,205 @@
1
+ require 'spec_helper'
2
+ require 'chef/knife/cookbook-keep'
3
+
4
+ describe KnifeCookbookUtils::CookbookKeep do
5
+
6
+ let(:command) do
7
+ KnifeCookbookUtils::CookbookKeep.new.
8
+ tap(&with_cookbook_listing).
9
+ tap(&with_num_to_keep)
10
+ end
11
+
12
+ let(:with_num_to_keep) { with_stub.(:num_to_keep, num_to_keep) }
13
+ let(:with_cookbook_listing) { with_stub.(:raw_cookbook_listing, raw_cookbook_listing) }
14
+ let(:with_stub) { ->(stub_name, returns) { ->(x) { x.stub!(stub_name).and_return(returns) } } }
15
+ let(:version) { ->(v) { Chef::Version.new(v) } }
16
+
17
+ let(:num_to_keep) { 1 }
18
+ let(:raw_cookbook_listing) { fail 'Must define let(:raw_cookbook_listing' }
19
+ let(:cookbooks_with_one_version) do
20
+ {
21
+ "rbenv"=>{
22
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv",
23
+ "versions"=>[{"version"=>"1.4.1", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.1"}]},
24
+ "postgresql"=>{
25
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/postgresql",
26
+ "versions"=>[{"version"=>"3.0.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/postgresql/3.0.0"}]},
27
+ }
28
+ end
29
+
30
+ let(:cookbooks_with_two_versions) do
31
+ {
32
+ "rbenv"=>{
33
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv",
34
+ "versions"=>[
35
+ {"version"=>"1.4.1", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.1"},
36
+ {"version"=>"1.4.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.0"},
37
+ ]},
38
+ "postgresql"=>{
39
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/postgresql",
40
+ "versions"=>[{"version"=>"3.0.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/postgresql/3.0.0"}]},
41
+ }
42
+ end
43
+
44
+ let(:cookbooks_with_three_versions) do
45
+ {
46
+ "nginx"=>{
47
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv",
48
+ "versions"=>[
49
+ {"version"=>"1.7.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.7.0"},
50
+ {"version"=>"1.6.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.6.0"},
51
+ {"version"=>"1.4.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.0"},
52
+ ]},
53
+ "rbenv"=>{
54
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv",
55
+ "versions"=>[
56
+ {"version"=>"1.4.1", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.1"},
57
+ {"version"=>"1.4.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.0"},
58
+ ]},
59
+ "postgresql"=>{
60
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/postgresql",
61
+ "versions"=>[{"version"=>"3.0.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/postgresql/3.0.0"}]},
62
+ }
63
+ end
64
+
65
+ describe "#cookbooks_to_keep" do
66
+ subject { command.cookbooks_to_keep }
67
+
68
+ context "with only one cookbook version" do
69
+ let(:raw_cookbook_listing) { cookbooks_with_one_version }
70
+
71
+ context "when keeping latest version" do
72
+ let(:num_to_keep) { 1 }
73
+ it "should only keep latest version" do
74
+ should eql [ ['rbenv', version.('1.4.1')], ['postgresql', version.('3.0.0')] ]
75
+ end
76
+ end
77
+
78
+ context "when keeping latest 2 versions" do
79
+ let(:num_to_keep) { 2 }
80
+ it "should only keep latest version" do
81
+ should eql [ ['rbenv', version.('1.4.1')], ['postgresql', version.('3.0.0')] ]
82
+ end
83
+ end
84
+ end
85
+
86
+ context "with only two cookbook version" do
87
+ let(:raw_cookbook_listing) { cookbooks_with_two_versions }
88
+
89
+ context "when keeping latest version" do
90
+ let(:num_to_keep) { 1 }
91
+ it "should only keep latest version" do
92
+ should eql [ ['rbenv', version.('1.4.1')], ['postgresql', version.('3.0.0')] ]
93
+ end
94
+ end
95
+
96
+ context "when keeping latest 2 versions" do
97
+ let(:num_to_keep) { 2 }
98
+ it "should only keep latest 2 versions" do
99
+ should eql [ ['rbenv', version.('1.4.1')], ['rbenv', version.('1.4.0')], ['postgresql', version.('3.0.0')] ]
100
+ end
101
+ end
102
+ end
103
+
104
+ context "with only three cookbook version" do
105
+ let(:raw_cookbook_listing) { cookbooks_with_three_versions }
106
+
107
+ context "when keeping latest version" do
108
+ let(:num_to_keep) { 1 }
109
+ it "should only keep latest version" do
110
+ should eql [ ['nginx', version.('1.7.0') ], ['rbenv', version.('1.4.1')], ['postgresql', version.('3.0.0')] ]
111
+ end
112
+ end
113
+
114
+ context "when keeping latest 2 versions" do
115
+ let(:num_to_keep) { 2 }
116
+ it "should only keep latest 2 versions" do
117
+ should eql [
118
+ ['nginx', version.('1.7.0')],
119
+ ['nginx', version.('1.6.0')],
120
+ ['rbenv', version.('1.4.1')],
121
+ ['rbenv', version.('1.4.0')],
122
+ ['postgresql', version.('3.0.0')] ]
123
+ end
124
+ end
125
+
126
+ context "when keeping latest 3 versions" do
127
+ let(:num_to_keep) { 3 }
128
+ it "should only keep latest 3 versions" do
129
+ should eql [
130
+ ['nginx', version.('1.7.0')],
131
+ ['nginx', version.('1.6.0')],
132
+ ['nginx', version.('1.4.0')],
133
+ ['rbenv', version.('1.4.1')],
134
+ ['rbenv', version.('1.4.0')],
135
+ ['postgresql', version.('3.0.0')] ]
136
+ end
137
+ end
138
+ end # with only three cookbook versions
139
+ end # #cookbooks_to_keep
140
+
141
+ describe "#cookbooks_to_delete" do
142
+ subject { command.cookbooks_to_delete }
143
+
144
+ context "with only one cookbook version" do
145
+ let(:raw_cookbook_listing) { cookbooks_with_one_version }
146
+
147
+ context "when keeping latest version" do
148
+ let(:num_to_keep) { 1 }
149
+ it "should delete nothing" do
150
+ should eql [ ]
151
+ end
152
+ end
153
+
154
+ context "when keeping latest 2 versions" do
155
+ let(:num_to_keep) { 2 }
156
+ it "should delete nothing" do
157
+ should eql [ ]
158
+ end
159
+ end
160
+ end
161
+
162
+ context "with only two cookbook version" do
163
+ let(:raw_cookbook_listing) { cookbooks_with_two_versions }
164
+
165
+ context "when keeping latest version" do
166
+ let(:num_to_keep) { 1 }
167
+ it "should delete older versions" do
168
+ should eql [ ['rbenv', version.('1.4.0')] ]
169
+ end
170
+ end
171
+
172
+ context "when keeping latest 2 versions" do
173
+ let(:num_to_keep) { 2 }
174
+ it "should delete nothing" do
175
+ should eql [ ]
176
+ end
177
+ end
178
+ end
179
+
180
+ context "with only three cookbook version" do
181
+ let(:raw_cookbook_listing) { cookbooks_with_three_versions }
182
+
183
+ context "when keeping latest version" do
184
+ let(:num_to_keep) { 1 }
185
+ it "should delete older versions" do
186
+ should eql [ ['nginx', version.('1.6.0') ], ['nginx', version.('1.4.0')], ['rbenv', version.('1.4.0')] ]
187
+ end
188
+ end
189
+
190
+ context "when keeping latest 2 versions" do
191
+ let(:num_to_keep) { 2 }
192
+ it "should older versions" do
193
+ should eql [ ['nginx', version.('1.4.0')] ]
194
+ end
195
+ end
196
+
197
+ context "when keeping latest 3 versions" do
198
+ let(:num_to_keep) { 3 }
199
+ it "should delete nothing" do
200
+ should eql [ ]
201
+ end
202
+ end
203
+ end # with only three cookbook versions
204
+ end # #cookbooks_to_delete
205
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+ require 'chef/knife/cookbook-missing-deps'
3
+
4
+ describe KnifeCookbookUtils::CookbookMissingDeps do
5
+
6
+ let(:command) do
7
+ KnifeCookbookUtils::CookbookMissingDeps.new.
8
+ tap(&with_cookbook_listing).
9
+ tap(&with_dependency_check)
10
+ end
11
+
12
+ let(:with_cookbook_listing) { with_stub.(:raw_cookbook_listing, raw_cookbook_listing) }
13
+ let(:with_dependency_check) { ->(x) { x.stub(:dependencies_for_cookbook_version, &dependencies_for_cookbook_version)} }
14
+ let(:with_stub) { ->(stub_name, returns) { ->(x) { x.stub!(stub_name).and_return(returns) } } }
15
+
16
+ let(:dependencies_for_cookbook_version) { ->(name, version) { {} } }
17
+
18
+ let(:raw_cookbook_listing) do
19
+ {
20
+ "nginx"=>{
21
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv",
22
+ "versions"=>[
23
+ {"version"=>"1.7.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/nginx/1.7.0"},
24
+ {"version"=>"1.6.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/nginx/1.6.0"},
25
+ {"version"=>"1.4.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/nginx/1.4.0"},
26
+ ]},
27
+ "rbenv"=>{
28
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv",
29
+ "versions"=>[
30
+ {"version"=>"1.4.1", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.1"},
31
+ {"version"=>"1.4.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.0"},
32
+ ]},
33
+ "postgresql"=>{
34
+ "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/postgresql",
35
+ "versions"=>[{"version"=>"3.0.0", "url"=>"https://api.opscode.com/organizations/example-org/cookbooks/postgresql/3.0.0"}]},
36
+ }
37
+ end
38
+
39
+ describe "#all_cookbooks" do
40
+ subject { command.all_cookbooks }
41
+ let(:expected) do
42
+ {
43
+ "nginx" => {
44
+ "1.7.0" => "https://api.opscode.com/organizations/example-org/cookbooks/nginx/1.7.0",
45
+ "1.6.0" => "https://api.opscode.com/organizations/example-org/cookbooks/nginx/1.6.0",
46
+ "1.4.0" => "https://api.opscode.com/organizations/example-org/cookbooks/nginx/1.4.0", },
47
+ "rbenv" => {
48
+ "1.4.1" => "https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.1",
49
+ "1.4.0" => "https://api.opscode.com/organizations/example-org/cookbooks/rbenv/1.4.0" },
50
+ "postgresql" => {
51
+ "3.0.0" => "https://api.opscode.com/organizations/example-org/cookbooks/postgresql/3.0.0" }
52
+ }
53
+ end
54
+
55
+ it "should return a map of all cookbook and versions" do
56
+ should eql expected
57
+ end
58
+ end
59
+
60
+ describe "#missing_deps" do
61
+ subject { command.missing_deps }
62
+
63
+ context "without missing deps" do
64
+ it { should eql Hash.new }
65
+ end
66
+
67
+ context "with missing deps" do
68
+ let(:dependencies_for_cookbook_version) do
69
+ proc do |name, version|
70
+ if name == 'rbenv' and version == '1.4.1'
71
+ { 'ohai' => '>= 1.1' }
72
+ else
73
+ { }
74
+ end
75
+ end
76
+ end
77
+
78
+ let(:expected) { { ['rbenv', '1.4.1'] => [['ohai', '>= 1.1']] } }
79
+
80
+ it "should return a map of missing deps" do
81
+ should eql expected
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,14 @@
1
+ require 'chef/knife'
2
+
3
+ # variable_to_watch.tap(&WATCH)
4
+ WATCH = lambda { |o| ap o } unless defined?(WATCH)
5
+
6
+ # Autoload everything in support
7
+ Dir["spec/support/**/*.rb"].map { |f| f.gsub(%r{.rb$}, '') }.each { |f| require f }
8
+
9
+ RSpec.configure do |config|
10
+ config.filter_run :focus => true
11
+ config.run_all_when_everything_filtered = true
12
+ config.treat_symbols_as_metadata_keys_with_true_values = true
13
+ end
14
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-cookbook-utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-17 00:00:00.000000000 Z
12
+ date: 2013-06-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: chef
@@ -27,22 +27,6 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: 11.0.0
30
- - !ruby/object:Gem::Dependency
31
- name: rlet
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - '='
36
- - !ruby/object:Gem::Version
37
- version: 0.5.1
38
- type: :runtime
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - '='
44
- - !ruby/object:Gem::Version
45
- version: 0.5.1
46
30
  - !ruby/object:Gem::Dependency
47
31
  name: rspec
48
32
  requirement: !ruby/object:Gem::Requirement
@@ -72,7 +56,11 @@ files:
72
56
  - Rakefile
73
57
  - lib/chef/knife/cookbook-keep.rb
74
58
  - lib/chef/knife/cookbook-missing-deps.rb
59
+ - lib/knife-cookbook-utils/rlet.rb
75
60
  - lib/knife-cookbook-utils/version.rb
61
+ - spec/chef/knife/cookbook-keep_spec.rb
62
+ - spec/chef/knife/cookbook-missing-deps_spec.rb
63
+ - spec/spec_helper.rb
76
64
  homepage: http://www.opscode.com
77
65
  licenses:
78
66
  - Apache 2.0