head_chef 0.1.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.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +1 -0
- data/bin/head-chef +5 -0
- data/features/commands/diff.feature +74 -0
- data/features/commands/list.feature +20 -0
- data/features/commands/sync.feature +67 -0
- data/features/step_definitions/berkshelf_steps.rb +40 -0
- data/features/step_definitions/chef_server_steps.rb +81 -0
- data/features/step_definitions/git_steps.rb +3 -0
- data/features/support/env.rb +40 -0
- data/head_chef.gemspec +36 -0
- data/lib/head_chef/cli.rb +28 -0
- data/lib/head_chef/cookbook.rb +115 -0
- data/lib/head_chef/cookbook_diff.rb +80 -0
- data/lib/head_chef/tasks/diff.rb +42 -0
- data/lib/head_chef/tasks/env.rb +48 -0
- data/lib/head_chef/tasks/list.rb +17 -0
- data/lib/head_chef/tasks/sync.rb +38 -0
- data/lib/head_chef/tasks.rb +3 -0
- data/lib/head_chef/ui.rb +23 -0
- data/lib/head_chef/version.rb +3 -0
- data/lib/head_chef.rb +63 -0
- data/spec/cookbook_diff_spec.rb +77 -0
- data/spec/cookbook_spec.rb +60 -0
- data/spec/diff_spec.rb +38 -0
- data/spec/env_spec.rb +94 -0
- data/spec/fixtures/Berksfiles/default +3 -0
- data/spec/fixtures/Berksfiles/template.erb +5 -0
- data/spec/fixtures/cookbooks/test_cookbook/metadata.rb +2 -0
- data/spec/fixtures/cookbooks/test_cookbook/recipes/default.rb +8 -0
- data/spec/fixtures/cookbooks/test_cookbook_file_content_conflict/metadata.rb +2 -0
- data/spec/fixtures/cookbooks/test_cookbook_file_content_conflict/recipes/default.rb +10 -0
- data/spec/fixtures/cookbooks/test_cookbook_file_list_conflict/chefignore +2 -0
- data/spec/fixtures/cookbooks/test_cookbook_file_list_conflict/metadata.rb +2 -0
- data/spec/fixtures/cookbooks/test_cookbook_file_list_conflict/recipes/default.rb +10 -0
- data/spec/fixtures/cookbooks/test_cookbook_file_list_conflict/recipes/not_default.rb +1 -0
- data/spec/fixtures/dot_chef/head_chef.pem +27 -0
- data/spec/fixtures/dot_chef/knife.rb +4 -0
- data/spec/head_chef_spec.rb +79 -0
- data/spec/list_spec.rb +26 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/chef_server.rb +100 -0
- data/spec/support/path_helpers.rb +38 -0
- data/spec/sync_spec.rb +86 -0
- metadata +319 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
module HeadChef
|
2
|
+
class CookbookDiff
|
3
|
+
attr_reader :diff_hash
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@diff_hash = { add: [],
|
7
|
+
update: [],
|
8
|
+
remove: [],
|
9
|
+
revert: [],
|
10
|
+
conflict: [] }
|
11
|
+
end
|
12
|
+
|
13
|
+
# @TODO: cleanup
|
14
|
+
# @TODO: switch statements
|
15
|
+
def add(cookbook)
|
16
|
+
# Removal is the only operation that does not require a diff, as no
|
17
|
+
# cookbook will be uploaded
|
18
|
+
if cookbook.chef_version && !cookbook.berkshelf_version
|
19
|
+
@diff_hash[:remove] << cookbook and return
|
20
|
+
end
|
21
|
+
|
22
|
+
unless cookbook.diff
|
23
|
+
@diff_hash[:conflict] << cookbook and return
|
24
|
+
end
|
25
|
+
|
26
|
+
if cookbook.berkshelf_version && !cookbook.chef_version
|
27
|
+
@diff_hash[:add] << cookbook and return
|
28
|
+
end
|
29
|
+
|
30
|
+
berkshelf_version = Semantic::Version.new(cookbook.berkshelf_version)
|
31
|
+
chef_version = Semantic::Version.new(cookbook.chef_version)
|
32
|
+
|
33
|
+
if berkshelf_version > chef_version
|
34
|
+
@diff_hash[:update] << cookbook and return
|
35
|
+
elsif berkshelf_version < chef_version
|
36
|
+
@diff_hash[:revert] << cookbook and return
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def conflicts
|
41
|
+
@diff_hash[:conflict]
|
42
|
+
end
|
43
|
+
|
44
|
+
def conflicts?
|
45
|
+
!@diff_hash[:conflict].empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def empty?
|
49
|
+
[:add, :update, :remove, :revert, :conflict].each do |method|
|
50
|
+
return false if !@diff_hash[method].empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def pretty_print
|
57
|
+
if self.empty?
|
58
|
+
HeadChef.ui.say("Berksfile and Chef environment are identical", :green)
|
59
|
+
return
|
60
|
+
end
|
61
|
+
|
62
|
+
colors = { add: :green,
|
63
|
+
update: :green,
|
64
|
+
remove: :red,
|
65
|
+
revert: :red,
|
66
|
+
conflict: :red }
|
67
|
+
|
68
|
+
[:add, :update, :remove, :revert, :conflict].each do |method|
|
69
|
+
color = colors[method]
|
70
|
+
|
71
|
+
unless @diff_hash[method].empty?
|
72
|
+
HeadChef.ui.say("#{method.to_s.upcase}:", color)
|
73
|
+
diff_hash[method].each do |cookbook|
|
74
|
+
HeadChef.ui.say(" #{cookbook.to_s}", color)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module HeadChef
|
2
|
+
class Diff
|
3
|
+
def self.diff(environment)
|
4
|
+
HeadChef.ui.info("Loading environment #{environment} from chef server...")
|
5
|
+
chef_environment = HeadChef.chef_server.environment.find(environment)
|
6
|
+
|
7
|
+
if chef_environment
|
8
|
+
chef_versions = chef_environment.cookbook_versions
|
9
|
+
else
|
10
|
+
HeadChef.ui.error("Environment #{environment} not found on chef server.")
|
11
|
+
Kernel.exit(1337)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Run berks install to populate cached cookbook list
|
15
|
+
# @NOTE: for now it is up to user to maintain Berksfile
|
16
|
+
HeadChef.ui.info('Loading cookbooks from berkshelf...')
|
17
|
+
cached_cookbooks = Berkshelf.ui.mute { HeadChef.berksfile.install }
|
18
|
+
|
19
|
+
HeadChef.ui.say('Calculating diff...', :cyan)
|
20
|
+
cookbook_diff = CookbookDiff.new
|
21
|
+
|
22
|
+
cached_cookbooks.each do |berkshelf_cookbook|
|
23
|
+
cookbook_name = berkshelf_cookbook.name.chomp("-#{berkshelf_cookbook.version}")
|
24
|
+
|
25
|
+
if chef_versions[cookbook_name]
|
26
|
+
chef_version = chef_versions[cookbook_name]
|
27
|
+
else
|
28
|
+
chef_version = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
cookbook_diff.add(Cookbook.new(cookbook_name, berkshelf_cookbook.version, chef_version))
|
32
|
+
chef_versions.delete(cookbook_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
chef_versions.each do |cookbook_name, cookbook_version|
|
36
|
+
cookbook_diff.add(Cookbook.new(cookbook_name, nil, cookbook_version))
|
37
|
+
end
|
38
|
+
|
39
|
+
cookbook_diff
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module HeadChef
|
2
|
+
class Env < Thor
|
3
|
+
class_option :environment,
|
4
|
+
aliases: '-e',
|
5
|
+
banner: '<environment>',
|
6
|
+
desc: 'Applies to the specified environment',
|
7
|
+
type: :string
|
8
|
+
|
9
|
+
desc 'diff', 'Shows cookbook diff between Berksfile and Chef <environment>'
|
10
|
+
long_desc <<-EOD
|
11
|
+
Shows cookbook version diff between Berksfile and Chef <environment>
|
12
|
+
|
13
|
+
By default, matches current git branch name against Chef environment.
|
14
|
+
EOD
|
15
|
+
def diff
|
16
|
+
environment = options[:environment] || HeadChef.current_branch
|
17
|
+
|
18
|
+
Diff.diff(environment).pretty_print
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'list', 'Lists cookbooks with versions from Chef <environment>.'
|
22
|
+
long_desc <<-EOD
|
23
|
+
Shows cookbook version diff between Berksfile and Chef <environment>
|
24
|
+
|
25
|
+
By default, matches current git branch name against Chef enviroment.
|
26
|
+
EOD
|
27
|
+
def list
|
28
|
+
environment = options[:environment] || HeadChef.current_branch
|
29
|
+
|
30
|
+
List.list(environment)
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'sync', 'Syncs Berksfile with Chef <environment>'
|
34
|
+
long_desc <<-EOD
|
35
|
+
Syncs Berksfile cookbook with Chef <environment>
|
36
|
+
|
37
|
+
By default, matches current git branch and against Chef enviroment. Chef
|
38
|
+
environment will be created if it does not exist.
|
39
|
+
EOD
|
40
|
+
option :force, banner: '', desc: 'Force upload of cookbooks to chef server'
|
41
|
+
def sync
|
42
|
+
environment = options[:environment] || HeadChef.current_branch
|
43
|
+
force = options[:force] ? true : false
|
44
|
+
|
45
|
+
Sync.sync(environment, force)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module HeadChef
|
2
|
+
class List
|
3
|
+
def self.list(environment)
|
4
|
+
chef_environment = HeadChef.chef_server.environment.find(environment)
|
5
|
+
|
6
|
+
unless chef_environment
|
7
|
+
HeadChef.ui.error "Environment #{environment} not found on chef server."
|
8
|
+
Kernel.exit(1337)
|
9
|
+
end
|
10
|
+
|
11
|
+
HeadChef.ui.say("COOKBOOKS:")
|
12
|
+
chef_environment.cookbook_versions.sort.each do |cookbook, version|
|
13
|
+
HeadChef.ui.say(" #{cookbook}: #{version}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module HeadChef
|
2
|
+
class Sync
|
3
|
+
def self.sync(environment, force)
|
4
|
+
# Check if environment exits, if not create it
|
5
|
+
# Perform first, if it fails no need to continue
|
6
|
+
unless HeadChef.chef_server.environment.find(environment)
|
7
|
+
HeadChef.chef_server.environment.create(name: environment)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Diff now performs all Berkshelf/lockfile dependency operations
|
11
|
+
HeadChef.ui.say("Determing side effects of sync with chef environment "\
|
12
|
+
"#{environment}...", :cyan)
|
13
|
+
cookbook_diff = HeadChef.ui.mute { Diff.diff(environment) }
|
14
|
+
|
15
|
+
unless force
|
16
|
+
if cookbook_diff.conflicts?
|
17
|
+
HeadChef.ui.error 'The following cookbooks are in conflict:'
|
18
|
+
cookbook_diff.conflicts.each do |cookbook|
|
19
|
+
HeadChef.ui.error "#{cookbook.name}: #{cookbook.berkshelf_version}"
|
20
|
+
end
|
21
|
+
HeadChef.ui.error 'Use --force to sync environment'
|
22
|
+
Kernel.exit(1337)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieve berksfile
|
27
|
+
berksfile = HeadChef.berksfile
|
28
|
+
|
29
|
+
HeadChef.ui.say('Uploading cookbooks to chef server...', :cyan)
|
30
|
+
berksfile.upload({force: force})
|
31
|
+
|
32
|
+
# Apply without lock options argument
|
33
|
+
HeadChef.ui.say("Applying Berksfile.lock cookbook version to " \
|
34
|
+
"environment #{environment}...", :cyan)
|
35
|
+
berksfile.apply(environment, {})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/head_chef/ui.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module HeadChef
|
2
|
+
module UI
|
3
|
+
def mute!
|
4
|
+
@mute = true
|
5
|
+
end
|
6
|
+
|
7
|
+
def unmute!
|
8
|
+
@mute = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def error(message, color = :red)
|
12
|
+
message = set_color(message, *color) if color
|
13
|
+
super(message)
|
14
|
+
end
|
15
|
+
|
16
|
+
def info(message, color = :cyan)
|
17
|
+
message = set_color(message, *color) if color
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Thor::Base.shell.send(:include, HeadChef::UI)
|
data/lib/head_chef.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# external requires
|
2
|
+
require 'berkshelf'
|
3
|
+
require 'ridley'
|
4
|
+
require 'grit'
|
5
|
+
require 'thor'
|
6
|
+
require 'semantic'
|
7
|
+
require 'pathname'
|
8
|
+
|
9
|
+
# internal requires
|
10
|
+
require_relative 'head_chef/tasks'
|
11
|
+
require_relative 'head_chef/cookbook'
|
12
|
+
require_relative 'head_chef/cookbook_diff'
|
13
|
+
require_relative 'head_chef/ui'
|
14
|
+
require_relative 'head_chef/version'
|
15
|
+
|
16
|
+
#@TODO: establish head_chef exit codes
|
17
|
+
#Create custom errors
|
18
|
+
module HeadChef
|
19
|
+
|
20
|
+
BERKSFILE_LOCATION = 'Berksfile'.freeze
|
21
|
+
BERKSFILE_COOKBOOK_DIR = '.head_chef'.freeze
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def root
|
25
|
+
@root ||= Pathname.new(File.expand_path('../', File.dirname(__FILE__)))
|
26
|
+
end
|
27
|
+
|
28
|
+
def ui
|
29
|
+
@ui ||= Thor::Base.shell.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def chef_server
|
33
|
+
@chef_server ||= Ridley.from_chef_config()
|
34
|
+
end
|
35
|
+
|
36
|
+
# @TODO: refactor?
|
37
|
+
# Is grit necessary to get current branch, is shell command sufficient?
|
38
|
+
# This can look up dir's until it finds .git dir
|
39
|
+
def master_cookbook
|
40
|
+
begin
|
41
|
+
@master_cookbook ||= Grit::Repo.new('.')
|
42
|
+
rescue Grit::InvalidGitRepositoryError
|
43
|
+
puts Dir.pwd
|
44
|
+
HeadChef.ui.error 'head_chef must be run in root of git repo'
|
45
|
+
Kernel.exit(1337)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def current_branch
|
50
|
+
master_cookbook.head.name
|
51
|
+
end
|
52
|
+
|
53
|
+
def berksfile
|
54
|
+
@berksfile ||= Berkshelf::Berksfile.from_file(BERKSFILE_LOCATION)
|
55
|
+
end
|
56
|
+
|
57
|
+
def cleanup
|
58
|
+
if Dir.exists?(BERKSFILE_COOKBOOK_DIR)
|
59
|
+
FileUtils.rm_rf(BERKSFILE_COOKBOOK_DIR)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HeadChef::CookbookDiff do
|
4
|
+
let(:empty_diff_hash) do
|
5
|
+
{ add: [],
|
6
|
+
update: [],
|
7
|
+
remove: [],
|
8
|
+
revert: [],
|
9
|
+
conflict: [] }
|
10
|
+
end
|
11
|
+
|
12
|
+
shared_examples_for 'correct add to CookbookDiff' do |cookbook, method|
|
13
|
+
it "appends #{cookbook.name} cookbook to :#{method} list" do
|
14
|
+
subject.add(cookbook)
|
15
|
+
expect(subject.diff_hash[method]).to include(cookbook)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'ClassMethods' do
|
20
|
+
describe '#new' do
|
21
|
+
it 'initializes hash' do
|
22
|
+
expect(subject.diff_hash).to eq(empty_diff_hash)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'InstanceMethods' do
|
28
|
+
describe '#add(HeadChef::Cookbook)' do
|
29
|
+
|
30
|
+
context 'with cookbook content conflict' do
|
31
|
+
before(:each) do
|
32
|
+
HeadChef::Cookbook.any_instance.stub(:diff).and_return(false)
|
33
|
+
end
|
34
|
+
|
35
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
36
|
+
HeadChef::Cookbook.new('add_test', '0.0.1', nil), :conflict
|
37
|
+
|
38
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
39
|
+
HeadChef::Cookbook.new('update_test', '0.0.2', '0.0.1'), :conflict
|
40
|
+
|
41
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
42
|
+
HeadChef::Cookbook.new('remove_test', nil, '0.0.1'), :remove
|
43
|
+
|
44
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
45
|
+
HeadChef::Cookbook.new('revert_test', '0.0.1', '0.0.2'), :conflict
|
46
|
+
|
47
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
48
|
+
HeadChef::Cookbook.new('conflict_test', '0.0.1', '0.0.1'), :conflict
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'without cookbook content conflict' do
|
52
|
+
before(:each) do
|
53
|
+
HeadChef::Cookbook.any_instance.stub(:diff).and_return(true)
|
54
|
+
end
|
55
|
+
|
56
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
57
|
+
HeadChef::Cookbook.new('add_test', '0.0.1', nil), :add
|
58
|
+
|
59
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
60
|
+
HeadChef::Cookbook.new('update_test', '0.0.2', '0.0.1'), :update
|
61
|
+
|
62
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
63
|
+
HeadChef::Cookbook.new('remove_test', nil, '0.0.1'), :remove
|
64
|
+
|
65
|
+
it_should_behave_like 'correct add to CookbookDiff',
|
66
|
+
HeadChef::Cookbook.new('revert_test', '0.0.1', '0.0.2'), :revert
|
67
|
+
|
68
|
+
it 'does nothing when berkshelf version == chef version' do
|
69
|
+
cookbook = HeadChef::Cookbook.new('conflict_test', '0.0.1', '0.0.1')
|
70
|
+
subject.add(cookbook)
|
71
|
+
expect(subject.diff_hash).to eq(empty_diff_hash)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HeadChef::Cookbook do
|
4
|
+
let(:cookbook_resource) { double('Ridley::CookbookResouce') }
|
5
|
+
let(:cached_cookbooks) { [] }
|
6
|
+
let(:cached_cookbook) { double('Berkshelf::CachedCookbook') }
|
7
|
+
|
8
|
+
subject { HeadChef::Cookbook.new('test', '0.0.1', '0.0.2') }
|
9
|
+
|
10
|
+
describe 'ClassMethods' do
|
11
|
+
describe '::new' do
|
12
|
+
it 'reads name' do
|
13
|
+
expect(subject.name).to eq('test')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'reads berkshelf version' do
|
17
|
+
expect(subject.berkshelf_version).to eq('0.0.1')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'reads chef version' do
|
21
|
+
expect(subject.chef_version).to eq('0.0.2')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'InstanceMethods' do
|
27
|
+
describe '#diff' do
|
28
|
+
before(:each) do
|
29
|
+
HeadChef.stub_chain(:chef_server, :cookbook).
|
30
|
+
and_return(cookbook_resource)
|
31
|
+
|
32
|
+
allow(cookbook_resource).to receive(:find).
|
33
|
+
with(subject.name, subject.berkshelf_version).
|
34
|
+
and_return(cookbook_resource)
|
35
|
+
allow(cookbook_resource).to receive(:manifest).and_return(Hashie::Mash.new)
|
36
|
+
|
37
|
+
HeadChef.stub_chain(:berksfile, :cached_cookbooks).
|
38
|
+
and_return(cached_cookbooks)
|
39
|
+
allow(cached_cookbooks).to receive(:find).and_return(cached_cookbook)
|
40
|
+
|
41
|
+
allow(cached_cookbook).to receive(:path)
|
42
|
+
allow(subject).to receive(:remove_ignored_files).and_return([])
|
43
|
+
end
|
44
|
+
|
45
|
+
after(:each) do
|
46
|
+
subject.diff
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'retrieves cookbook checksums from chef server' do
|
50
|
+
expect(cookbook_resource).to receive(:find).
|
51
|
+
with(subject.name, subject.berkshelf_version)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'loads cookbook from berkshelf cache' do
|
55
|
+
expect(cached_cookbooks).to receive(:find)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/spec/diff_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HeadChef::Diff do
|
4
|
+
describe 'ClassMethods' do
|
5
|
+
let(:berksfile) { double('Berkshelf::Berksfile') }
|
6
|
+
let(:chef_environment) { double('Hashie::Mash') }
|
7
|
+
let(:environment) { 'test_env' }
|
8
|
+
|
9
|
+
describe '::diff' do
|
10
|
+
before(:each) do
|
11
|
+
HeadChef.stub_chain(:chef_server, :environment, :find).
|
12
|
+
with(environment).
|
13
|
+
and_return(chef_environment)
|
14
|
+
|
15
|
+
allow(chef_environment).to receive(:cookbook_versions).and_return({})
|
16
|
+
|
17
|
+
allow(HeadChef).to receive(:berksfile).and_return(berksfile)
|
18
|
+
allow(berksfile).to receive(:install).and_return([])
|
19
|
+
end
|
20
|
+
|
21
|
+
after(:each) do
|
22
|
+
described_class.diff(environment)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'loads chef environment' do
|
26
|
+
expect(chef_environment).to receive(:cookbook_versions)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'calls Berksfile#install to load berkshelf cookbooks into cache' do
|
30
|
+
expect(berksfile).to receive(:install)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns CookbookDiff' do
|
34
|
+
expect(described_class.diff(environment)).to be_an_instance_of(HeadChef::CookbookDiff)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/env_spec.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HeadChef::Env do
|
4
|
+
let(:current_branch) { 'test_branch' }
|
5
|
+
let(:environment) { 'option_environment' }
|
6
|
+
|
7
|
+
shared_examples_for "HeadChef::Env command" do |klass, method, return_value|
|
8
|
+
|
9
|
+
context 'defaults' do
|
10
|
+
it 'uses branch name for environment' do
|
11
|
+
expect(klass).to receive(method) do |*args|
|
12
|
+
args[0].should eq(current_branch)
|
13
|
+
end.and_return(return_value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with --environment' do
|
18
|
+
it 'uses environment option value' do
|
19
|
+
subject.options[:environment] = environment
|
20
|
+
|
21
|
+
expect(klass).to receive(method) do |*args|
|
22
|
+
args[0].should eq(environment)
|
23
|
+
end.and_return(return_value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'commands' do
|
29
|
+
|
30
|
+
before(:each) do
|
31
|
+
allow(HeadChef).to receive(:current_branch).and_return(current_branch)
|
32
|
+
|
33
|
+
# Unfreeze Thor::CoreExt::HashWithIndifferentAccess
|
34
|
+
subject.options = subject.options.dup
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
describe '::diff' do
|
39
|
+
let(:cookbook_diff) { HeadChef::CookbookDiff.new }
|
40
|
+
|
41
|
+
after(:each) do
|
42
|
+
subject.diff
|
43
|
+
end
|
44
|
+
|
45
|
+
it_should_behave_like 'HeadChef::Env command',
|
46
|
+
HeadChef::Diff, :diff, HeadChef::CookbookDiff.new
|
47
|
+
|
48
|
+
context 'defaults' do
|
49
|
+
it 'outputs CookbookDiff' do
|
50
|
+
allow(HeadChef::Diff).to receive(:diff).
|
51
|
+
with(any_args).and_return(cookbook_diff)
|
52
|
+
|
53
|
+
expect(cookbook_diff).to receive(:pretty_print)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '::list' do
|
59
|
+
after(:each) do
|
60
|
+
subject.list
|
61
|
+
end
|
62
|
+
|
63
|
+
it_should_behave_like 'HeadChef::Env command',
|
64
|
+
HeadChef::List, :list, nil
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '::sync' do
|
68
|
+
after(:each) do
|
69
|
+
subject.sync
|
70
|
+
end
|
71
|
+
|
72
|
+
it_should_behave_like 'HeadChef::Env command',
|
73
|
+
HeadChef::Sync, :sync, nil
|
74
|
+
|
75
|
+
context 'defaults' do
|
76
|
+
it 'uses false for force option' do
|
77
|
+
expect(HeadChef::Sync).to receive(:sync) do |*args|
|
78
|
+
args[1].should eq(false)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'with --force' do
|
84
|
+
it 'sets force option to true' do
|
85
|
+
subject.options[:force] = true
|
86
|
+
|
87
|
+
expect(HeadChef::Sync).to receive(:sync) do |*args|
|
88
|
+
args[1].should eq(true)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
### DIFFERENT FILE
|