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.
Files changed (51) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +38 -0
  8. data/Rakefile +1 -0
  9. data/bin/head-chef +5 -0
  10. data/features/commands/diff.feature +74 -0
  11. data/features/commands/list.feature +20 -0
  12. data/features/commands/sync.feature +67 -0
  13. data/features/step_definitions/berkshelf_steps.rb +40 -0
  14. data/features/step_definitions/chef_server_steps.rb +81 -0
  15. data/features/step_definitions/git_steps.rb +3 -0
  16. data/features/support/env.rb +40 -0
  17. data/head_chef.gemspec +36 -0
  18. data/lib/head_chef/cli.rb +28 -0
  19. data/lib/head_chef/cookbook.rb +115 -0
  20. data/lib/head_chef/cookbook_diff.rb +80 -0
  21. data/lib/head_chef/tasks/diff.rb +42 -0
  22. data/lib/head_chef/tasks/env.rb +48 -0
  23. data/lib/head_chef/tasks/list.rb +17 -0
  24. data/lib/head_chef/tasks/sync.rb +38 -0
  25. data/lib/head_chef/tasks.rb +3 -0
  26. data/lib/head_chef/ui.rb +23 -0
  27. data/lib/head_chef/version.rb +3 -0
  28. data/lib/head_chef.rb +63 -0
  29. data/spec/cookbook_diff_spec.rb +77 -0
  30. data/spec/cookbook_spec.rb +60 -0
  31. data/spec/diff_spec.rb +38 -0
  32. data/spec/env_spec.rb +94 -0
  33. data/spec/fixtures/Berksfiles/default +3 -0
  34. data/spec/fixtures/Berksfiles/template.erb +5 -0
  35. data/spec/fixtures/cookbooks/test_cookbook/metadata.rb +2 -0
  36. data/spec/fixtures/cookbooks/test_cookbook/recipes/default.rb +8 -0
  37. data/spec/fixtures/cookbooks/test_cookbook_file_content_conflict/metadata.rb +2 -0
  38. data/spec/fixtures/cookbooks/test_cookbook_file_content_conflict/recipes/default.rb +10 -0
  39. data/spec/fixtures/cookbooks/test_cookbook_file_list_conflict/chefignore +2 -0
  40. data/spec/fixtures/cookbooks/test_cookbook_file_list_conflict/metadata.rb +2 -0
  41. data/spec/fixtures/cookbooks/test_cookbook_file_list_conflict/recipes/default.rb +10 -0
  42. data/spec/fixtures/cookbooks/test_cookbook_file_list_conflict/recipes/not_default.rb +1 -0
  43. data/spec/fixtures/dot_chef/head_chef.pem +27 -0
  44. data/spec/fixtures/dot_chef/knife.rb +4 -0
  45. data/spec/head_chef_spec.rb +79 -0
  46. data/spec/list_spec.rb +26 -0
  47. data/spec/spec_helper.rb +15 -0
  48. data/spec/support/chef_server.rb +100 -0
  49. data/spec/support/path_helpers.rb +38 -0
  50. data/spec/sync_spec.rb +86 -0
  51. 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
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rb"].sort.each do |path|
2
+ require_relative "tasks/#{File.basename(path, '.rb')}"
3
+ end
@@ -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)
@@ -0,0 +1,3 @@
1
+ module HeadChef
2
+ VERSION = '0.1.0'
3
+ end
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,3 @@
1
+ site :opscode
2
+
3
+ cookbook 'java'
@@ -0,0 +1,5 @@
1
+ site :opscode
2
+
3
+ <% @cookbooks.each do |cookbook| %>
4
+ <%= "cookbook '#{cookbook[0]}', '#{cookbook[1]}', #{cookbook[2]}" %>
5
+ <% end %>
@@ -0,0 +1,2 @@
1
+ name 'test_cookbook'
2
+ version '0.1.0'
@@ -0,0 +1,8 @@
1
+ #
2
+ # Cookbook Name:: test_cookbook
3
+ # Recipe:: default
4
+ #
5
+ # Copyright 2013, YOUR_COMPANY_NAME
6
+ #
7
+ # All rights reserved - Do Not Redistribute
8
+ #
@@ -0,0 +1,2 @@
1
+ name 'test_cookbook'
2
+ version '0.1.0'
@@ -0,0 +1,10 @@
1
+ #
2
+ # Cookbook Name:: test_cookbook
3
+ # Recipe:: default
4
+ #
5
+ # Copyright 2013, YOUR_COMPANY_NAME
6
+ #
7
+ # All rights reserved - Do Not Redistribute
8
+ #
9
+ #
10
+ ### DIFFERENT CONTENT
@@ -0,0 +1,2 @@
1
+ chefignore
2
+ recipes/default.rb
@@ -0,0 +1,2 @@
1
+ name 'test_cookbook'
2
+ version '0.1.0'
@@ -0,0 +1,10 @@
1
+ #
2
+ # Cookbook Name:: test_cookbook
3
+ # Recipe:: default
4
+ #
5
+ # Copyright 2013, YOUR_COMPANY_NAME
6
+ #
7
+ # All rights reserved - Do Not Redistribute
8
+ #
9
+ #
10
+ ### DIFFERENT CONTENT