clc-promote 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
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: