clc-promote 0.4.3 → 0.4.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5639da39cb5c09225b1f84de02e315c550483433
4
- data.tar.gz: a5c506c785f6495178c4c94100980ff7336fca49
3
+ metadata.gz: 674a20f898ac27d30598579081401a13f660e374
4
+ data.tar.gz: 55dd1f8a1927e4ff519e40bc33762abd56d40680
5
5
  SHA512:
6
- metadata.gz: 90a38c6dcabf0a36451cf90e3c14e1de96de0edd631fc3eb5b7bf861e99fa06abf11eb2ce41191f706449472f03cb53f7841af7a4940a46ece02bb6f2bc50289
7
- data.tar.gz: 500302a8fbb0809c1cf21c46c95655f4fdfdf6d5165a7a2a9a6e573b2fc1a1c6a44f8d6d15f6fe051c673ff66dcbf14ef465a4ff9ffb41a5c3076db85a9e369c
6
+ metadata.gz: dd0d30a5d62a51f14c8f30398971ac4cc4be3252c0152817e4ee71aaa66224bf481d2936fd537bfeadd28cbe0a2e990b181604d6b5aa72011140fd7c32d0c090
7
+ data.tar.gz: 1d1462b21bddf6cb3ed0bb5bd05929f79732e70b8ef782600b72c018e2d7f9c6cb5bb12dca81bbb8a02b8db4d7edac92aaca47c11ea04fd21ed449136f1766fc
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.bundle
10
+ *.so
11
+ *.o
12
+ *.a
13
+ mkmf.log
14
+ *.gem
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:test)
5
+
6
+ task :default => [:test]
@@ -0,0 +1,24 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/lib')
2
+ require 'promote/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'clc-promote'
6
+ s.version = Promote::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.extra_rdoc_files = ['README.md']
9
+ s.summary = 'Provides versioning and promotion logic for chef artifacts.'
10
+ s.description = s.summary
11
+ s.authors = ['CenturyLink Cloud']
12
+ s.email = 'matt.wrock@CenturyLinkCloud.com'
13
+ s.homepage = 'https://github.com/tier3/DevOps/gems/clc-promote'
14
+
15
+ s.require_path = 'lib'
16
+ s.files = `git ls-files -z`.split("\x0")
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ s.add_runtime_dependency 'clc-git', '~> 1.2', '>= 1.2.8'
20
+ s.add_runtime_dependency 'berkshelf', '~> 3.1', '>= 3.1.4'
21
+
22
+ s.add_development_dependency 'rspec', '~> 3.0', '>= 3.0.0'
23
+ s.add_development_dependency 'rake', '~> 10.3', '>= 10.3.2'
24
+ end
@@ -0,0 +1,79 @@
1
+ require 'forwardable'
2
+ require "berkshelf/downloader"
3
+ require "kitchen/provisioner/chef_zero"
4
+ require "promote"
5
+
6
+ module Kitchen
7
+
8
+ module Provisioner
9
+
10
+ class Environment < ChefZero
11
+
12
+ def create_sandbox
13
+ super
14
+ prepare_environment_dependencies
15
+ create_node
16
+ end
17
+
18
+ private
19
+
20
+ def create_node
21
+ node_file = File.join(instance.busser[:test_base_path], "nodes/#{instance.suite.name}.json")
22
+ if File.exist?(node_file)
23
+ node = JSON.parse(File.read(node_file))
24
+ node[:run_list] = config[:run_list]
25
+ File.open(node_file, 'w') do |out|
26
+ out << JSON.pretty_generate(node)
27
+ end
28
+ end
29
+ end
30
+
31
+ def prepare_environment_dependencies
32
+ if !config[:client_rb].has_key?(:environment)
33
+ info("No environment specified to lock")
34
+ return
35
+ end
36
+
37
+ environment = config[:client_rb][:environment]
38
+ repo = File.dirname(config[:environments_path])
39
+ promote_config = Promote::Config.new(:repo_root => repo)
40
+ env_file = Promote::EnvironmentFile.new(environment, promote_config)
41
+
42
+ info("comparing current cookbook versions to those in #{environment}")
43
+ Kitchen.mutex.synchronize do
44
+ berks_path = File.join(config[:kitchen_root], 'Berksfile')
45
+ ::Berkshelf.set_format :null
46
+ berks = ::Berkshelf::Berksfile.from_file(berks_path)
47
+ downloader = ::Berkshelf::Downloader.new(berks)
48
+ berks.install
49
+ my_deps = berks.list
50
+
51
+ my_deps.each do | dep |
52
+ next if dep.location.respond_to?(:relative_path)
53
+ env_version = env_file.cookbook_versions[dep.name]
54
+
55
+ if !env_version.nil? && dep.locked_version.to_s != env_version
56
+ if dep.name == File.basename(config[:kitchen_root])
57
+ raise "cookbook '#{dep.name}' is outdated. Expected v#{env_version} from #{environment}"
58
+ end
59
+
60
+ info("replacing v#{dep.locked_version} of #{dep.name} with #{env_version}")
61
+ downloader.download(dep.name, env_version) do |stash|
62
+ FileUtils.copy_entry(stash, File.join(tmpbooks_dir, dep.name))
63
+ end
64
+ end
65
+ end
66
+
67
+ # we do this because the vendoring converts metadayta.rb to json
68
+ # any subsequent berks command on the vendored cookbook will fail
69
+ FileUtils.rm_rf Dir.glob("#{tmpbooks_dir}/**/Berksfile*")
70
+ end
71
+ end
72
+
73
+ def tmpbooks_dir
74
+ File.join(sandbox_path, "cookbooks")
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ module Promote
2
+ VERSION = '0.4.4'
3
+ end
@@ -0,0 +1,104 @@
1
+ require 'kitchen'
2
+ require 'kitchen/configurable'
3
+ require 'kitchen/provisioner/environment'
4
+
5
+ describe Kitchen::Provisioner::Environment do
6
+ let(:logged_output) { StringIO.new }
7
+ let(:logger) { Logger.new(logged_output) }
8
+ let(:config) do
9
+ { :test_base_path => "/b", :kitchen_root => "/cookbook_4", :log_level => :info, :sudo => true, :client_rb => client_rb_config, :environments_path => '/env/path' }
10
+ end
11
+ let(:suite) do
12
+ double('suite', :name => "fries")
13
+ end
14
+ let(:transport) do
15
+ double('transport', :sudo => config[:sudo], :shell => "bourne")
16
+ end
17
+ let(:instance) do
18
+ double('instance', :name => "coolbeans", :logger => logger, :suite => suite, :transport => transport, :busser => {:test_base_path => 'base_path'})
19
+ end
20
+ let(:downloader) { double('downloader') }
21
+ let(:fake_berks) { double('berksfile', :install => nil, :update => nil, :list => [
22
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1'), :location => nil),
23
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2'), :location => nil),
24
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'), :location => nil)
25
+ ]) }
26
+ let(:client_rb_config) { {:environment => 'environment'} }
27
+ let (:env_file) { double('env', :cookbook_versions => {
28
+ 'cookbook_2' => '1.1.1',
29
+ 'cookbook_3' => '2.2.2',
30
+ 'cookbook_4' => '3.3.3'
31
+ })}
32
+
33
+ subject { Kitchen::Provisioner::Environment.new(config).finalize_config!(instance) }
34
+
35
+ before {
36
+ allow(FileUtils).to receive(:rm_rf)
37
+ allow(FileUtils).to receive(:copy_entry)
38
+ allow(Berkshelf::Berksfile).to receive(:from_file).and_return(fake_berks)
39
+ allow(Promote::EnvironmentFile).to receive(:new).and_return(env_file)
40
+ allow(Berkshelf::Downloader).to receive(:new).and_return(downloader)
41
+ }
42
+
43
+ context "when no environment specified" do
44
+ let(:client_rb_config) { {} }
45
+
46
+ it "does not get berks dependencies" do
47
+ expect(fake_berks).not_to receive(:list)
48
+ subject.create_sandbox
49
+ end
50
+ end
51
+
52
+ context "wnem local cookbooks are outdated" do
53
+ let (:env_file) { double('env', :cookbook_versions => {
54
+ 'cookbook_2' => '2.2.2',
55
+ 'cookbook_3' => '2.2.2',
56
+ 'cookbook_4' => '3.3.3'
57
+ })}
58
+
59
+ it "downloads the outdated cookbooks" do
60
+ expect(downloader).to receive(:download).with('cookbook_2', '2.2.2')
61
+ subject.create_sandbox
62
+ end
63
+ end
64
+
65
+ context "when environment file is missing a dependency" do
66
+ let (:env_file) { double('env', :cookbook_versions => {
67
+ 'cookbook_2' => '2.2.2',
68
+ 'cookbook_4' => '3.3.3'
69
+ })}
70
+
71
+ it "downloads only the outdated cookbook" do
72
+ expect(downloader).to receive(:download).with('cookbook_2', '2.2.2')
73
+ subject.create_sandbox
74
+ end
75
+ end
76
+
77
+ context "when cookbook under test is outdated" do
78
+ let (:env_file) { double('env', :cookbook_versions => {
79
+ 'cookbook_2' => '1.1.1',
80
+ 'cookbook_3' => '2.2.2',
81
+ 'cookbook_4' => '4.4.4'
82
+ })}
83
+
84
+ it "downloads only the outdated cookbooks" do
85
+ expect{subject.create_sandbox}.to raise_error(/4\.4\.4/)
86
+ end
87
+ end
88
+
89
+ context "when outdated cookbook is from a local source" do
90
+ let(:fake_berks) { double('berksfile', :install => nil, :update => nil, :list => [
91
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1'), :location => nil),
92
+ double('Dependency',
93
+ :name => 'cookbook_3',
94
+ :locked_version => Semverse::Version.new('1.1.1'),
95
+ :location => double('location', :relative_path => '../cookbook')),
96
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'), :location => nil)
97
+ ]) }
98
+
99
+ it "downloads only the outdated cookbooks" do
100
+ expect(downloader).not_to receive(:download)
101
+ subject.create_sandbox
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,92 @@
1
+ require 'promote'
2
+
3
+ describe Promote::Config do
4
+ let(:opts) {{
5
+ :repo_root => "root",
6
+ :cookbook_directory => "cookbooks",
7
+ :environment_directory => "environments",
8
+ :data_bag_directory => "data_bags",
9
+ :temp_directory => "temp",
10
+ :node_name => "user",
11
+ :client_key => "key",
12
+ :chef_server_url => "url"}}
13
+ subject { Promote::Config.new(opts) }
14
+
15
+ it "assigns options to node_name attribute" do
16
+ expect(subject.node_name).to eq(opts[:node_name])
17
+ end
18
+ it "assigns options to client_key attribute" do
19
+ expect(subject.client_key).to eq(opts[:client_key])
20
+ end
21
+ it "assigns options to chef_server_url attribute" do
22
+ expect(subject.chef_server_url).to eq(opts[:chef_server_url])
23
+ end
24
+ it "assigns options to repo_root attribute" do
25
+ expect(subject.repo_root).to eq(opts[:repo_root])
26
+ end
27
+ it "assigns options to cookbook_directory attribute" do
28
+ expect(subject.cookbook_directory).to eq(opts[:cookbook_directory])
29
+ end
30
+ it "assigns options to data_bag_directory attribute" do
31
+ expect(subject.data_bag_directory).to eq(opts[:data_bag_directory])
32
+ end
33
+ it "assigns options to environment_directory attribute" do
34
+ expect(subject.environment_directory).to eq(opts[:environment_directory])
35
+ end
36
+ it "assigns options to temp_directory attribute" do
37
+ expect(subject.temp_directory).to eq(opts[:temp_directory])
38
+ end
39
+ it "can correctly convert to a hash" do
40
+ hash = subject.to_hash
41
+ expect(hash[:repo_root]).to eq(opts[:repo_root])
42
+ end
43
+
44
+ context "directories are not in options" do
45
+ let(:opts) {{
46
+ :node_name => "user",
47
+ :client_key => "key",
48
+ :chef_server_url => "url"}}
49
+ subject { Promote::Config.new(opts) }
50
+
51
+ it "assigns repo_root to pwd" do
52
+ expect(subject.repo_root).to eq(Dir.pwd)
53
+ end
54
+ it "assigns cookbook_directory to cookbooks off root" do
55
+ expect(subject.cookbook_directory).to eq(File.join(subject.repo_root, "cookbooks"))
56
+ end
57
+ it "assigns data_bag_directory to data_bags off root" do
58
+ expect(subject.data_bag_directory).to eq(File.join(subject.repo_root, "data_bags"))
59
+ end
60
+ it "assigns environment_directory to environments off root" do
61
+ expect(subject.environment_directory).to eq(File.join(subject.repo_root, "environments"))
62
+ end
63
+ it "assigns temp_directory to tmp" do
64
+ expect(subject.temp_directory).to eq("/tmp/promote")
65
+ end
66
+ end
67
+
68
+ context "directories are not in options but repo root is" do
69
+ let(:opts) {{
70
+ :repo_root => "root",
71
+ :node_name => "user",
72
+ :client_key => "key",
73
+ :chef_server_url => "url"}}
74
+ subject { Promote::Config.new(opts) }
75
+
76
+ it "assigns repo_root to pwd" do
77
+ expect(subject.repo_root).to eq(opts[:repo_root])
78
+ end
79
+ it "assigns cookbook_directory to cookbooks off root" do
80
+ expect(subject.cookbook_directory).to eq(File.join(subject.repo_root, "cookbooks"))
81
+ end
82
+ it "assigns data_bag_directory to data_bags off root" do
83
+ expect(subject.data_bag_directory).to eq(File.join(subject.repo_root, "data_bags"))
84
+ end
85
+ it "assigns environment_directory to environments off root" do
86
+ expect(subject.environment_directory).to eq(File.join(subject.repo_root, "environments"))
87
+ end
88
+ it "assigns temp_directory to tmp" do
89
+ expect(subject.temp_directory).to eq("/tmp/promote")
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,250 @@
1
+ require 'promote'
2
+
3
+ describe Promote::Cookbook do
4
+ let(:cookbook_dir) {'/tmp/promote_test_cookbooks/stubs'}
5
+ let(:config) { Promote::Config.new({
6
+ :cookbook_directory => cookbook_dir})
7
+ }
8
+ let(:fake_berks) { double('berksfile', :list => nil, :install => nil, :update => nil) }
9
+
10
+ before(:all) {
11
+ cb_dir = '/tmp/promote_test_cookbooks'
12
+ FileUtils.rm_rf(cb_dir) if Dir.exist?(cb_dir)
13
+ Dir.mkdir(cb_dir)
14
+ FileUtils.cp_r(File.join(File.dirname(File.dirname(__FILE__)), 'stubs'), cb_dir)
15
+ }
16
+
17
+ subject { Promote::Cookbook.new('cookbook_1', config) }
18
+
19
+ describe "dependencies" do
20
+ before {
21
+ allow(Berkshelf::Berksfile).to receive(:from_file).and_return(fake_berks)
22
+ allow(fake_berks).to receive(:list).and_return([
23
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
24
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
25
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
26
+ ])
27
+ }
28
+
29
+ it "returns dependencies from lockfile" do
30
+ expect(subject.dependencies.keys.count).to be 3
31
+ expect(subject.dependencies['cookbook_2'].to_s).to eq '1.1.1'
32
+ expect(subject.dependencies['cookbook_3'].to_s).to eq '2.2.2'
33
+ expect(subject.dependencies['cookbook_4'].to_s).to eq '3.3.3'
34
+ end
35
+ end
36
+
37
+ describe "metadata_dependencies" do
38
+
39
+ it "returns dependencies from metadata.rb" do
40
+ expect(subject.metadata_dependencies.keys.count).to be 1
41
+ expect(subject.metadata_dependencies['cookbook_2'].to_s).to eq '= 1.1.1'
42
+ end
43
+ end
44
+
45
+ describe "path" do
46
+
47
+ it "returns the correct path of the cookbook" do
48
+ expect(subject.path).to eq(File.join(cookbook_dir, 'cookbook_1'))
49
+ end
50
+ end
51
+
52
+ describe "version" do
53
+
54
+ it "reads the current version" do
55
+ expect(subject.version.to_s).to eq('1.0.0')
56
+ end
57
+
58
+ it "writes changed version to metadata.rb" do
59
+ subject.version = Semverse::Version.new('2.2.2')
60
+ expect(Promote::Cookbook.new('cookbook_1', config).version.to_s).to eq '2.2.2'
61
+ end
62
+
63
+ it "returns the new version after a version has changed" do
64
+ subject.version = Semverse::Version.new('2.2.2')
65
+ expect(subject.version.to_s).to eq('2.2.2')
66
+ end
67
+ end
68
+
69
+ describe "stamp_commit" do
70
+ it "writes the sha1 to the end of the metadata file" do
71
+ subject.stamp_commit('commit_1')
72
+ expect(subject.raw_metadata).to end_with "\n#sha1 'commit_1'"
73
+ end
74
+
75
+ it "does not write the sha1 m ore than once" do
76
+ subject.stamp_commit('commit_1')
77
+ subject.stamp_commit('commit_2')
78
+ expect(subject.raw_metadata).not_to include "commit_1"
79
+ end
80
+ end
81
+
82
+ describe "sync_berksfile" do
83
+ before {
84
+ allow(File).to receive(:exist?).with(/Berksfile$/).and_return(true)
85
+ allow(File).to receive(:exist?).with(/Berksfile.lock/).and_return(true)
86
+ }
87
+
88
+ it "Installs berks dependencies" do
89
+ dummy = double('berksfile')
90
+ expect(Berkshelf::Berksfile).to receive(:from_file).with(
91
+ File.join(subject.path, "Berksfile")).and_return(dummy)
92
+ expect(dummy).to receive(:install)
93
+
94
+ subject.sync_berksfile
95
+ end
96
+
97
+ it "Updates berks dependencies when asked to update" do
98
+ dummy = double('berksfile')
99
+ expect(Berkshelf::Berksfile).to receive(:from_file).with(
100
+ File.join(subject.path, "Berksfile")).and_return(dummy)
101
+ expect(dummy).to receive(:update)
102
+
103
+ subject.sync_berksfile(true)
104
+ end
105
+
106
+ context "update berksfile with no lock file" do
107
+ before {
108
+ allow(File).to receive(:exist?).with(/Berksfile.lock/).and_return(false)
109
+ }
110
+
111
+ it "Installs berks dependencies instead of update" do
112
+ dummy = double('berksfile')
113
+ expect(Berkshelf::Berksfile).to receive(:from_file).with(
114
+ File.join(subject.path, "Berksfile")).and_return(dummy)
115
+ expect(dummy).to receive(:install)
116
+
117
+ subject.sync_berksfile(true)
118
+ end
119
+ end
120
+ end
121
+
122
+ describe "dependencies_changed_after_update?" do
123
+ before {
124
+ allow(File).to receive(:exist?).and_return(true)
125
+ allow(Berkshelf::Berksfile).to receive(:from_file).and_return(fake_berks)
126
+ allow(fake_berks).to receive(:list).and_return([
127
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
128
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
129
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
130
+ ])
131
+ }
132
+
133
+ it "performs a berks update" do
134
+ expect(fake_berks).to receive(:update)
135
+ subject.dependencies_changed_after_update?
136
+ end
137
+
138
+ context "there is no change" do
139
+
140
+ before {
141
+ allow(fake_berks).to receive(:list).and_return(
142
+ [
143
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
144
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
145
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
146
+ ],
147
+ [
148
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
149
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
150
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
151
+ ]
152
+ )
153
+ }
154
+
155
+ it "returns false" do
156
+ expect(subject.dependencies_changed_after_update?).to be false
157
+ end
158
+ end
159
+
160
+ context "there is a version change" do
161
+
162
+ before {
163
+ allow(Berkshelf::Berksfile).to receive(:from_file).and_return(fake_berks)
164
+ allow(fake_berks).to receive(:list).and_return(
165
+ [
166
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
167
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
168
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
169
+ ],
170
+ [
171
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
172
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.3')),
173
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
174
+ ]
175
+ )
176
+ }
177
+
178
+ it "returns true" do
179
+ expect(subject.dependencies_changed_after_update?).to be true
180
+ end
181
+ end
182
+
183
+ context "a dependency is removed" do
184
+
185
+ before {
186
+ allow(Berkshelf::Berksfile).to receive(:from_file).and_return(fake_berks)
187
+ allow(fake_berks).to receive(:list).and_return(
188
+ [
189
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
190
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
191
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
192
+ ],
193
+ [
194
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
195
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
196
+ ]
197
+ )
198
+ }
199
+
200
+ it "returns true" do
201
+ expect(subject.dependencies_changed_after_update?).to be true
202
+ end
203
+ end
204
+
205
+ context "a dependency is added" do
206
+
207
+ before {
208
+ allow(Berkshelf::Berksfile).to receive(:from_file).and_return(fake_berks)
209
+ allow(fake_berks).to receive(:list).and_return(
210
+ [
211
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
212
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
213
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3'))
214
+ ],
215
+ [
216
+ double('Dependency', :name => 'cookbook_2', :locked_version => Semverse::Version.new('1.1.1')),
217
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
218
+ double('Dependency', :name => 'cookbook_4', :locked_version => Semverse::Version.new('3.3.3')),
219
+ double('Dependency', :name => 'cookbook_5', :locked_version => Semverse::Version.new('3.3.3'))
220
+ ]
221
+ )
222
+ }
223
+
224
+ it "returns true" do
225
+ expect(subject.dependencies_changed_after_update?).to be true
226
+ end
227
+ end
228
+
229
+ context "the cookbook under test has changed" do
230
+
231
+ before {
232
+ allow(Berkshelf::Berksfile).to receive(:from_file).and_return(fake_berks)
233
+ allow(fake_berks).to receive(:list).and_return(
234
+ [
235
+ double('Dependency', :name => 'cookbook_1', :locked_version => Semverse::Version.new('1.1.1')),
236
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
237
+ ],
238
+ [
239
+ double('Dependency', :name => 'cookbook_1', :locked_version => Semverse::Version.new('1.1.2')),
240
+ double('Dependency', :name => 'cookbook_3', :locked_version => Semverse::Version.new('2.2.2')),
241
+ ]
242
+ )
243
+ }
244
+
245
+ it "returns false" do
246
+ expect(subject.dependencies_changed_after_update?).to be false
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,59 @@
1
+ require 'promote'
2
+
3
+ describe Promote::Promoter do
4
+ context "Promote one environment to another" do
5
+ let(:config) { Promote::Config.new({
6
+ :node_name => 'user',
7
+ :cookbook_directory => '/cookbooks',
8
+ :client_key => 'key',
9
+ :chef_server_url => 'https://some.chef.server'}) }
10
+ let(:fake_file){double('file')}
11
+ let(:env1) do
12
+ <<-EOS
13
+ {
14
+ "name": "QA1",
15
+ "chef_type": "environment",
16
+ "json_class": "Chef::Environment",
17
+ "cookbook_versions": {
18
+ "build-essential": "2.0.0",
19
+ "newrelic": "2.0.0",
20
+ "platform_haproxy": "2.0.0"
21
+ }
22
+ }
23
+ EOS
24
+ end
25
+
26
+ let(:env2) do
27
+ <<-EOS
28
+ {
29
+ "name": "QA1",
30
+ "chef_type": "environment",
31
+ "json_class": "Chef::Environment",
32
+ "cookbook_versions": {
33
+ "build-essential": "1.0.0",
34
+ "platform_haproxy": "1.0.0"
35
+ }
36
+ }
37
+ EOS
38
+ end
39
+
40
+ before {
41
+ allow(File).to receive(:read).with(/env1\.json$/).and_return(env1)
42
+ allow(File).to receive(:read).with(/env2\.json$/).and_return(env2)
43
+ allow(File).to receive(:open).with(/env2\.json$/, "w").and_yield(fake_file)
44
+ }
45
+
46
+ subject { Promote::Promoter.new(config) }
47
+
48
+ it "copies the cookbook constraints" do
49
+ expect(fake_file).to receive(:<<).with(an_instance_of(String)) do |arg|
50
+ parsed = JSON.parse(arg)
51
+ expect(parsed['cookbook_versions'].length).to eq(3)
52
+ expect(parsed['cookbook_versions']['build-essential']).to eq('2.0.0')
53
+ expect(parsed['cookbook_versions']['newrelic']).to eq('2.0.0')
54
+ expect(parsed['cookbook_versions']['platform_haproxy']).to eq('2.0.0')
55
+ end
56
+ subject.promote_to("env1", "env2")
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,208 @@
1
+ require 'promote'
2
+ require_relative '../support/dummy_metadata'
3
+
4
+ describe Promote::Uploader do
5
+ let(:knife_config) {{ :cookbook_path => "path"}}
6
+ let(:temp_dir) { "/tmp/berks" }
7
+ let(:config) { Promote::Config.new({
8
+ :node_name => 'user',
9
+ :cookbook_directory => '/cookbooks',
10
+ :client_key => 'key',
11
+ :temp_directory => temp_dir,
12
+ :chef_server_url => 'https://some.chef.server'}) }
13
+
14
+ subject { Promote::Uploader.new(config) }
15
+
16
+ context "upload cookbooks" do
17
+ let(:env_name) { "QA1" }
18
+ let(:metadata) { PromoteSpecs::DummyMetadata.new({'version' => "1.1.1"}) }
19
+ let(:environment) do
20
+ <<-EOS
21
+ {
22
+ "name": "#{env_name}",
23
+ "chef_type": "environment",
24
+ "json_class": "Chef::Environment",
25
+ "cookbook_versions": {
26
+ "int_cookbook1": "1.1.1",
27
+ "int_cookbook3": "1.1.1",
28
+ "cookbook3": "3.3.3"
29
+ }
30
+ }
31
+ EOS
32
+ end
33
+ let(:berks_cookbooks) {[
34
+ "/berks/cookbook1-1.1.1",
35
+ "/berks/cookbook1-1.1.2",
36
+ "/berks/cookbook2-2.2.2",
37
+ "/berks/cookbook3-3.3.3",
38
+ "/berks/cookbook4-3.3.3",
39
+ ]}
40
+ let(:internal_cookbooks) {[
41
+ "/cookbooks/int_cookbook1",
42
+ "/cookbooks/int_cookbook2",
43
+ "/cookbooks/int_cookbook3",
44
+ ]}
45
+ let(:server_cookbooks){{
46
+ "cookbook1" => {"versions" => [{"version" => "1.1.1"}]},
47
+ "cookbook2" => {"versions" => [{"version" => "1.1.1"}]},
48
+ "int_cookbook1" => {"versions" => [{"version" => "1.1.1"}]},
49
+ "int_cookbook2" => {"versions" => [{"version" => "2.2.2"}]}
50
+ }}
51
+ let(:rest){double('rest')}
52
+ let(:knife) { instance_double('CookbookUpload', :run => nil) }
53
+ before {
54
+ allow(File).to receive(:read).with(File.join(config.environment_directory, "#{env_name}.json")).and_return(environment)
55
+ allow(File).to receive(:read).with(/metadata\.json$/).and_return('')
56
+ allow(Chef::REST).to receive(:new).and_return(rest)
57
+ allow(rest).to receive(:get_rest).and_return(server_cookbooks)
58
+ allow(Chef::Cookbook::Metadata).to receive(:new).and_return(metadata)
59
+ allow(Chef::Knife::CookbookUpload).to receive(:new).and_return(knife)
60
+ allow(Dir).to receive(:glob).with(File.expand_path("~/.berkshelf/cookbooks/*")).and_return(berks_cookbooks)
61
+ allow(Dir).to receive(:glob).with(File.join(config.cookbook_directory, "*")).and_return(internal_cookbooks)
62
+ allow(Dir).to receive(:mkdir)
63
+ allow(Dir).to receive(:exist?).and_return(false)
64
+ allow(knife).to receive(:config).and_return(knife_config)
65
+ allow(FileUtils).to receive(:copy_entry)
66
+ allow(File).to receive(:exist?).with(/metadata\.rb$/).and_return(true)
67
+ }
68
+
69
+ it "copies updated cookbooks to temp directory" do
70
+ expect(FileUtils).not_to receive(:copy_entry).with("/berks/cookbook1-1.1.1", File.join(config.temp_directory, "cookbook1"))
71
+ expect(FileUtils).not_to receive(:copy_entry).with("/berks/cookbook1-1.1.2", File.join(config.temp_directory, "cookbook1"))
72
+ expect(FileUtils).not_to receive(:copy_entry).with("/berks/cookbook4-3.3.3", File.join(config.temp_directory, "cookbook4"))
73
+ expect(FileUtils).not_to receive(:copy_entry).with("/berks/cookbook2-2.2.2", File.join(config.temp_directory, "cookbook2"))
74
+ expect(FileUtils).to receive(:copy_entry).with("/berks/cookbook3-3.3.3", File.join(config.temp_directory, "cookbook3"))
75
+ expect(FileUtils).not_to receive(:copy_entry).with("/cookbooks/int_cookbook2", File.join(config.temp_directory, "int_cookbook2"))
76
+ expect(FileUtils).not_to receive(:copy_entry).with("/cookbooks/int_cookbook1", File.join(config.temp_directory, "int_cookbook1"))
77
+ expect(FileUtils).to receive(:copy_entry).with("/cookbooks/int_cookbook3", File.join(config.temp_directory, "int_cookbook3"))
78
+ subject.upload_cookbooks(env_name)
79
+ end
80
+ it "uploads cookbooks to chef server" do
81
+ expect(knife).to receive(:run)
82
+
83
+ subject.upload_cookbooks(env_name)
84
+ end
85
+ it "Creates temp directory" do
86
+ expect(Dir).to receive(:mkdir).with(config.temp_directory)
87
+
88
+ subject.upload_cookbooks(env_name)
89
+ end
90
+ it "uploads cookbooks from config temp path" do
91
+ subject.upload_cookbooks(env_name)
92
+ expect(knife.config[:cookbook_path]).to eq(config.temp_directory)
93
+ end
94
+ it "uploads all cookbooks" do
95
+ subject.upload_cookbooks(env_name)
96
+ expect(knife.config[:all]).to eq(true)
97
+ end
98
+ it "freezes all cookbooks" do
99
+ subject.upload_cookbooks(env_name)
100
+ expect(knife.config[:freeze]).to eq(true)
101
+ end
102
+
103
+ context "no environment is given" do
104
+ it "copies updated cookbooks and does not filter by environment" do
105
+ expect(FileUtils).not_to receive(:copy_entry).with("/berks/cookbook1-1.1.1", File.join(config.temp_directory, "cookbook1"))
106
+ expect(FileUtils).to receive(:copy_entry).with("/berks/cookbook1-1.1.2", File.join(config.temp_directory, "cookbook1"))
107
+ expect(FileUtils).to receive(:copy_entry).with("/berks/cookbook4-3.3.3", File.join(config.temp_directory, "cookbook4"))
108
+ expect(FileUtils).to receive(:copy_entry).with("/berks/cookbook2-2.2.2", File.join(config.temp_directory, "cookbook2"))
109
+ expect(FileUtils).to receive(:copy_entry).with("/berks/cookbook3-3.3.3", File.join(config.temp_directory, "cookbook3"))
110
+ expect(FileUtils).to receive(:copy_entry).with("/cookbooks/int_cookbook2", File.join(config.temp_directory, "int_cookbook2"))
111
+ expect(FileUtils).not_to receive(:copy_entry).with("/cookbooks/int_cookbook1", File.join(config.temp_directory, "int_cookbook1"))
112
+ expect(FileUtils).to receive(:copy_entry).with("/cookbooks/int_cookbook3", File.join(config.temp_directory, "int_cookbook3"))
113
+ subject.upload_cookbooks
114
+ end
115
+ end
116
+
117
+ context "temp directory already exists" do
118
+ before {allow(Dir).to receive(:exist?).and_return(true)}
119
+
120
+ it "deletes temp directory" do
121
+ expect(FileUtils).to receive(:rm_rf).with(config.temp_directory)
122
+ subject.upload_cookbooks(env_name)
123
+ end
124
+ end
125
+
126
+ context "no metadata.rb file exists for cookbook" do
127
+ before {allow(File).to receive(:exist?).with(/rb$/).and_return(false)}
128
+
129
+ it "loads json instead of ruby file" do
130
+ expect(metadata).to receive(:from_json).at_least(1).times
131
+ expect(metadata).not_to receive(:from_file)
132
+ subject.upload_cookbooks(env_name)
133
+ end
134
+ end
135
+
136
+ context "nothing to upload" do
137
+ let(:berks_cookbooks) {[]}
138
+ let(:internal_cookbooks) {[]}
139
+
140
+ it "does not call knife" do
141
+ expect(Chef::Knife::CookbookUpload).not_to receive(:new)
142
+
143
+ subject.upload_cookbooks(env_name)
144
+ end
145
+ end
146
+
147
+ context "config missing node_name" do
148
+ let(:config) { Promote::Config.new({
149
+ :client_key => 'key',
150
+ :chef_server_url => 'https://some.chef.server'}) }
151
+
152
+ it "raises error that node_name is missing" do
153
+ expect{subject.upload_cookbooks(env_name)}.to raise_error(/node_name/)
154
+ end
155
+ end
156
+
157
+ context "config missing client_key" do
158
+ let(:config) { Promote::Config.new({
159
+ :node_name => 'user',
160
+ :chef_server_url => 'https://some.chef.server'}) }
161
+
162
+ it "raises error that client_key is missing" do
163
+ expect{subject.upload_cookbooks(env_name)}.to raise_error(/client_key/)
164
+ end
165
+ end
166
+
167
+ context "config missing chef_server_url" do
168
+ let(:config) { Promote::Config.new({
169
+ :node_name => 'user',
170
+ :client_key => 'key'}) }
171
+
172
+ it "raises error that chef_server_url is missing" do
173
+ expect{subject.upload_cookbooks(env_name)}.to raise_error(/chef_server_url/)
174
+ end
175
+ end
176
+ end
177
+
178
+ context "upload json artifacts" do
179
+ context "upload an environment" do
180
+ let(:env_name) { "my_test" }
181
+
182
+ it "uploads the environment" do
183
+ expect(Chef::ChefFS::FileSystem).to receive(:copy_to).with(an_instance_of(Chef::ChefFS::FilePattern), anything(), anything(), anything(), anything()) do |arg|
184
+ expect(arg.pattern).to eq(File.join("/environments", "#{env_name}.json"))
185
+ end
186
+ subject.upload_environment(env_name)
187
+ end
188
+ end
189
+
190
+ context "upload all environments" do
191
+ it "uploads the environment" do
192
+ expect(Chef::ChefFS::FileSystem).to receive(:copy_to).with(an_instance_of(Chef::ChefFS::FilePattern), anything(), anything(), anything(), anything()) do |arg|
193
+ expect(arg.pattern).to eq(File.join("/environments/*.json"))
194
+ end
195
+ subject.upload_environments
196
+ end
197
+ end
198
+
199
+ context "upload data_bags" do
200
+ it "uploads the data_bags" do
201
+ expect(Chef::ChefFS::FileSystem).to receive(:copy_to).with(an_instance_of(Chef::ChefFS::FilePattern), anything(), anything(), anything(), anything()) do |arg|
202
+ expect(arg.pattern).to eq("/data_bags/**/*.json")
203
+ end
204
+ subject.upload_data_bags
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,291 @@
1
+ require 'promote'
2
+ require_relative '../support/dummy_log'
3
+
4
+ describe Promote::Versioner do
5
+ before(:all) {
6
+ cb_dir = '/tmp/promote_test_cookbooks'
7
+ FileUtils.rm_rf(cb_dir) if Dir.exist?(cb_dir)
8
+ Dir.mkdir(cb_dir)
9
+ FileUtils.cp_r(File.join(File.dirname(File.dirname(__FILE__)), 'stubs'), cb_dir)
10
+ }
11
+
12
+ let(:cookbook_dir) {'/tmp/promote_test_cookbooks/stubs'}
13
+ let(:test_cookbook) {'cookbook_1'}
14
+ let(:config) {Promote::Config.new(:cookbook_directory => cookbook_dir)}
15
+ let(:fake_file) { double('file') }
16
+
17
+ let(:artifact_file) { "" }
18
+ let(:fake_berks) { double('berksfile', :install => nil) }
19
+ before {
20
+ allow(Berkshelf::Berksfile).to receive(:from_file).and_return(fake_berks)
21
+ allow_any_instance_of(Promote::GitRepo).to receive(:git).and_return(Git::Base.new)
22
+ allow_any_instance_of(Git::Base).to receive(:tags).and_return([
23
+ double("tag", :name => '1.0', :sha => 'abc'),
24
+ double("tag", :name => '1.1', :sha => 'def'),
25
+ double("tag", :name => '1.2', :sha => 'ghi')
26
+ ])
27
+ allow_any_instance_of(Git::Base).to receive(:log).with(10000).and_return(
28
+ PromoteSpecs::DummyLog.new([
29
+ {:msg => 'blah', :sha => 'aaa'},
30
+ {:msg => 'CI:bumping', :sha => 'bbb'},
31
+ {:msg => 'blah', :sha => 'ccc'}
32
+ ]))
33
+ config = Promote::Config.new
34
+ }
35
+
36
+ subject { Promote::Versioner.new(config) }
37
+
38
+ context 'version_cookbook' do
39
+ context 'when versioning a new cookbook version' do
40
+ it "writes the new version and sha to the file" do
41
+ subject.version_cookbook(test_cookbook)
42
+ expect(Promote::Cookbook.new(test_cookbook, config).version.to_s).to eq('1.2.2')
43
+ end
44
+
45
+ it "adds the new version and sha to the cookbook" do
46
+ subject.version_cookbook(test_cookbook)
47
+ expect(Promote::Cookbook.new(test_cookbook, config).raw_metadata).to end_with("#sha1 'aaa'")
48
+ end
49
+ end
50
+
51
+ context 'when versioning a cookbook with no changes' do
52
+ it "does not write to metadata rb" do
53
+ expect(subject.version_cookbook(test_cookbook)).to be nil
54
+ end
55
+ end
56
+ end
57
+
58
+ context 'version_cookbooks' do
59
+ let(:cookbooks) {[
60
+ File.join(subject.config.cookbook_directory, "cookbook1"),
61
+ File.join(subject.config.cookbook_directory, "cookbook2"),
62
+ File.join(subject.config.cookbook_directory, "cookbook3")
63
+ ]}
64
+ before {
65
+ allow(subject).to receive(:version_cookbook)
66
+ allow(Dir).to receive(:glob).with(
67
+ File.join(subject.config.cookbook_directory, "*")).and_return(cookbooks)
68
+ }
69
+
70
+ it "versions each cookbook" do
71
+ cookbooks.each do |cookbook|
72
+ expect(subject).to receive(:version_cookbook).with(File.basename(cookbook))
73
+ end
74
+ subject.version_cookbooks
75
+ end
76
+ end
77
+
78
+ context 'version_environment' do
79
+ before {
80
+ regex = File.join(config.environment_directory,'test.json')
81
+ allow(File).to receive(:read).with(regex).and_return(artifact_file)
82
+ allow(File).to receive(:open).with(regex, "w").and_yield(fake_file)
83
+ }
84
+
85
+ context 'when versioning a new environment with no version' do
86
+ let(:artifact_file) do
87
+ <<-EOS
88
+ {
89
+ "name": "QA1",
90
+ "chef_type": "environment",
91
+ "json_class": "Chef::Environment",
92
+ "override_attributes": {
93
+ "environment_parent": "QA"
94
+ }
95
+ }
96
+ EOS
97
+ end
98
+
99
+ it "writes the new version and sha to the file" do
100
+ parsed = JSON.parse(artifact_file)
101
+ parsed['override_attributes']['version'] = '1.2.2'
102
+ parsed['override_attributes']['sha1'] = 'aaa'
103
+ expect(fake_file).to receive(:<<).with(JSON.pretty_generate(parsed))
104
+ subject.version_environment('test')
105
+ end
106
+ end
107
+
108
+ context 'when versioning a new environment with old version' do
109
+
110
+ let(:artifact_file) do
111
+ <<-EOS
112
+ {
113
+ "name": "QA1",
114
+ "chef_type": "environment",
115
+ "json_class": "Chef::Environment",
116
+ "override_attributes": {
117
+ "environment_parent": "QA",
118
+ "version": "1.0.0",
119
+ "sha1": "ccc"
120
+ }
121
+ }
122
+ EOS
123
+ end
124
+
125
+ it "writes the new version and sha to the file" do
126
+ parsed = JSON.parse(artifact_file)
127
+ parsed['override_attributes']['version'] = '1.2.2'
128
+ parsed['override_attributes']['sha1'] = 'aaa'
129
+ expect(fake_file).to receive(:<<).with(JSON.pretty_generate(parsed))
130
+ subject.version_environment('test')
131
+ end
132
+ end
133
+
134
+ context 'when commiting an environment with no changes' do
135
+ let(:artifact_file) do
136
+ <<-EOS
137
+ {
138
+ "name": "QA1",
139
+ "chef_type": "environment",
140
+ "json_class": "Chef::Environment",
141
+ "override_attributes": {
142
+ "environment_parent": "QA",
143
+ "version": "1.2.2",
144
+ "sha1": "aaa"
145
+ }
146
+ }
147
+ EOS
148
+ end
149
+
150
+ it "does not write to the file" do
151
+ expect(fake_file).not_to receive(:<<)
152
+ subject.version_environment('test')
153
+ end
154
+ end
155
+ end
156
+
157
+ context 'version_environments' do
158
+ let(:environments) {%w{dir/environment1.json dir/environment2.json dir/environment3.json}}
159
+ before {
160
+ allow(subject).to receive(:version_environment)
161
+ allow(Dir).to receive(:glob).with(
162
+ File.join(subject.config.environment_directory, "*.json")).and_return(environments)
163
+ }
164
+
165
+ it "versions each environment" do
166
+ environments.each do |environment|
167
+ expect(subject).to receive(:version_environment).with(
168
+ File.basename(environment ,File.extname(environment)))
169
+ end
170
+ subject.version_environments
171
+ end
172
+ end
173
+
174
+ context 'constrain_environment' do
175
+ before {
176
+ regex = File.join(config.environment_directory,'test.json')
177
+ allow(File).to receive(:read).with(regex).and_return(artifact_file)
178
+ allow(File).to receive(:open).with(regex, "w").and_yield(fake_file)
179
+ }
180
+
181
+ let(:artifact_file) do
182
+ <<-EOS
183
+ {
184
+ "name": "QA1",
185
+ "chef_type": "environment",
186
+ "json_class": "Chef::Environment"
187
+ }
188
+ EOS
189
+ end
190
+ before {
191
+ allow(File).to receive(:exist?).with(/Berksfile$/).and_return(true)
192
+ allow(fake_berks).to receive(:list).and_return([
193
+ double('Dependency', :name => 'cookbook1', :locked_version => Semverse::Version.new('1.1.1')),
194
+ double('Dependency', :name => 'cookbook2', :locked_version => Semverse::Version.new('2.2.2')),
195
+ double('Dependency', :name => 'cookbook3', :locked_version => Semverse::Version.new('3.3.3'))
196
+ ])
197
+ }
198
+ it "writes the cookbook constraints to the file" do
199
+ expect(fake_file).to receive(:<<).with(an_instance_of(String)) do |arg|
200
+ parsed = JSON.parse(arg)
201
+ expect(parsed['cookbook_versions']['cookbook1']).to eq('1.1.1')
202
+ expect(parsed['cookbook_versions']['cookbook2']).to eq('2.2.2')
203
+ expect(parsed['cookbook_versions']['cookbook3']).to eq('3.3.3')
204
+ end
205
+ subject.constrain_environment('test', 'test_cookbook')
206
+ end
207
+ end
208
+
209
+ context 'is_dirty' do
210
+ before {
211
+ regex = File.join(config.environment_directory,'test.json')
212
+ allow(File).to receive(:read).with(regex).and_return(artifact_file)
213
+ allow(File).to receive(:open).with(regex, "w").and_yield(fake_file)
214
+ allow(File).to receive(:read).with(/new.json/).and_return(
215
+ <<-EOS
216
+ {
217
+ "name": "test",
218
+ "chef_type": "environment",
219
+ "json_class": "Chef::Environment",
220
+ "cookbook_versions": {
221
+ "cookbook1": "1.1.1",
222
+ "cookbook2": "2.2.2",
223
+ "cookbook3": "3.3.3"
224
+ }
225
+ }
226
+ EOS
227
+ )
228
+ }
229
+
230
+ context "cookbook is dirty" do
231
+
232
+ let(:artifact_file) do
233
+ <<-EOS
234
+ {
235
+ "name": "QA1",
236
+ "chef_type": "environment",
237
+ "json_class": "Chef::Environment",
238
+ "cookbook_versions": {
239
+ "cookbook1": "1.1.1",
240
+ "cookbook2": "1.1.1",
241
+ "cookbook3": "3.3.3"
242
+ }
243
+ }
244
+ EOS
245
+ end
246
+
247
+ it "returns dirty" do
248
+ expect(subject.is_dirty('new', 'test', 'cookbook2')).to be(true)
249
+ end
250
+ end
251
+ context "cookbook is not dirty" do
252
+ let(:artifact_file) do
253
+ <<-EOS
254
+ {
255
+ "name": "QA1",
256
+ "chef_type": "environment",
257
+ "json_class": "Chef::Environment",
258
+ "cookbook_versions": {
259
+ "cookbook1": "1.1.1",
260
+ "cookbook2": "2.2.2",
261
+ "cookbook3": "3.3.3"
262
+ }
263
+ }
264
+ EOS
265
+ end
266
+
267
+ it "returns clean" do
268
+ expect(subject.is_dirty('new', 'test', 'cookbook2')).to be(false)
269
+ end
270
+ end
271
+ context "cookbook is new to environment" do
272
+ let(:artifact_file) do
273
+ <<-EOS
274
+ {
275
+ "name": "QA1",
276
+ "chef_type": "environment",
277
+ "json_class": "Chef::Environment",
278
+ "cookbook_versions": {
279
+ "cookbook1": "1.1.1",
280
+ "cookbook3": "3.3.3"
281
+ }
282
+ }
283
+ EOS
284
+ end
285
+
286
+ it "returns dirty" do
287
+ expect(subject.is_dirty('new', 'test', 'cookbook2')).to be(true)
288
+ end
289
+ end
290
+ end
291
+ end
@@ -0,0 +1,3 @@
1
+ source "https://api.berkshelf.com"
2
+
3
+ metadata
@@ -0,0 +1,9 @@
1
+ name 'cookbook_1'
2
+ maintainer 'CenturyLink Cloud'
3
+ maintainer_email 'your.mama@clc.io'
4
+ license 'all_rights'
5
+ description 'Transfers files via scp'
6
+ long_description 'Transfers files via scp'
7
+ version '1.0.0'
8
+
9
+ depends "cookbook_2", '1.1.1'
@@ -0,0 +1,47 @@
1
+ require 'git'
2
+
3
+ module PromoteSpecs
4
+
5
+ class DummyLog < Git::Log
6
+ include Enumerable
7
+
8
+ def initialize(commits)
9
+ @commits = commits
10
+ @author = nil
11
+ @grep = nil
12
+ @object = nil
13
+ @path = nil
14
+ @since = nil
15
+ @skip = nil
16
+ @until = nil
17
+ @between = nil
18
+ end
19
+
20
+ def size
21
+ run_log.size rescue nil
22
+ end
23
+
24
+ def first
25
+ run_log.first rescue nil
26
+ end
27
+
28
+ private
29
+
30
+ def run_log
31
+ filtered = @commits.select { |c| @grep.nil? ? true : c[:msg] == @grep }
32
+ filtered.map { |c| DummyCommit.new(c[:sha]) }
33
+ ensure
34
+ @grep = nil
35
+ end
36
+
37
+ end
38
+
39
+ class DummyCommit
40
+ def initialize(sha)
41
+ @sha=sha
42
+ end
43
+
44
+ attr_accessor :sha
45
+ end
46
+
47
+ end
@@ -0,0 +1,20 @@
1
+ module PromoteSpecs
2
+
3
+ class DummyMetadata < Chef::Cookbook::Metadata
4
+ def initialize(hash = nil)
5
+ @hash = hash
6
+ end
7
+
8
+ def from_file(file_path)
9
+ @name = File.basename(File.dirname(file_path))
10
+ idx = @name.rindex('-')
11
+ if !idx.nil?
12
+ @version = @name[idx+1,@name.length-idx]
13
+ @name = @name[0,idx]
14
+ else
15
+ from_hash(@hash) unless @hash.nil?
16
+ end
17
+ end
18
+ end
19
+
20
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clc-promote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - CenturyLink Cloud
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-18 00:00:00.000000000 Z
11
+ date: 2014-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clc-git
@@ -97,8 +97,12 @@ extensions: []
97
97
  extra_rdoc_files:
98
98
  - README.md
99
99
  files:
100
+ - ".gitignore"
100
101
  - README.md
102
+ - Rakefile
103
+ - clc-promote.gemspec
101
104
  - lib/chef/knife/promote.rb
105
+ - lib/kitchen/provisioner/environment.rb
102
106
  - lib/promote.rb
103
107
  - lib/promote/config.rb
104
108
  - lib/promote/cookbook.rb
@@ -108,7 +112,18 @@ files:
108
112
  - lib/promote/rake_tasks.rb
109
113
  - lib/promote/uploader.rb
110
114
  - lib/promote/utils.rb
115
+ - lib/promote/version.rb
111
116
  - lib/promote/versioner.rb
117
+ - spec/unit/kitchen/provisioner/environment_spec.rb
118
+ - spec/unit/promote/config_spec.rb
119
+ - spec/unit/promote/cookbook_spec.rb
120
+ - spec/unit/promote/promoter_spec.rb
121
+ - spec/unit/promote/uploader_spec.rb
122
+ - spec/unit/promote/versioner_spec.rb
123
+ - spec/unit/stubs/cookbook_1/Berksfile
124
+ - spec/unit/stubs/cookbook_1/metadata.rb
125
+ - spec/unit/support/dummy_log.rb
126
+ - spec/unit/support/dummy_metadata.rb
112
127
  homepage: https://github.com/tier3/DevOps/gems/clc-promote
113
128
  licenses: []
114
129
  metadata: {}
@@ -132,5 +147,15 @@ rubygems_version: 2.4.1
132
147
  signing_key:
133
148
  specification_version: 4
134
149
  summary: Provides versioning and promotion logic for chef artifacts.
135
- test_files: []
150
+ test_files:
151
+ - spec/unit/kitchen/provisioner/environment_spec.rb
152
+ - spec/unit/promote/config_spec.rb
153
+ - spec/unit/promote/cookbook_spec.rb
154
+ - spec/unit/promote/promoter_spec.rb
155
+ - spec/unit/promote/uploader_spec.rb
156
+ - spec/unit/promote/versioner_spec.rb
157
+ - spec/unit/stubs/cookbook_1/Berksfile
158
+ - spec/unit/stubs/cookbook_1/metadata.rb
159
+ - spec/unit/support/dummy_log.rb
160
+ - spec/unit/support/dummy_metadata.rb
136
161
  has_rdoc: