soloist 0.9.7 → 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
data/soloist.gemspec CHANGED
@@ -6,11 +6,11 @@ Gem::Specification.new do |s|
6
6
  s.name = "soloist"
7
7
  s.version = Soloist::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Matthew Kocher"]
10
- s.email = ["kocher@gmail.com"]
9
+ s.authors = ["Matthew Kocher", "Doc Ritezel"]
10
+ s.email = ["kocher@gmail.com", "ritezel@gmail.com"]
11
11
  s.homepage = "http://github.com/mkocher/soloist"
12
- s.summary = %q{Soloist is a simple way of running chef-solo}
13
- s.description = %q{Soloist is an easy way of running chef solo, but it's not doing much.}
12
+ s.summary = "Soloist is a simple way of running chef-solo"
13
+ s.description = "Makes running chef-solo easy."
14
14
 
15
15
  s.rubyforge_project = "soloist"
16
16
 
@@ -20,4 +20,14 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
 
22
22
  s.add_dependency "chef"
23
- end
23
+ s.add_dependency "librarian"
24
+ s.add_dependency "thor"
25
+ s.add_dependency "hashie"
26
+
27
+ s.add_development_dependency "rspec"
28
+ s.add_development_dependency "guard-rspec"
29
+ s.add_development_dependency "guard-bundler"
30
+ s.add_development_dependency "rb-fsevent"
31
+ s.add_development_dependency "terminal-notifier-guard"
32
+ s.add_development_dependency "gem-release"
33
+ end
@@ -0,0 +1,133 @@
1
+ require "spec_helper"
2
+
3
+ describe Soloist::CLI do
4
+ let(:cli) { Soloist::CLI.new }
5
+ let(:base_path) { Dir.mktmpdir }
6
+ let(:soloistrc_path) { File.expand_path("soloistrc", base_path) }
7
+
8
+ before { FileUtils.mkdir_p(base_path) }
9
+
10
+ describe "#chef" do
11
+ context "when the soloistrc file does not exist" do
12
+ it "raises an error" do
13
+ expect do
14
+ begin
15
+ Dir.chdir(base_path) { cli.chef }
16
+ rescue Soloist::NotFound => e
17
+ e.message.should == "Could not find soloistrc or .soloistrc"
18
+ raise
19
+ end
20
+ end.to raise_error(Soloist::NotFound)
21
+ end
22
+ end
23
+
24
+ context "when the soloistrc file exists" do
25
+ before do
26
+ File.open(soloistrc_path, "w") do |file|
27
+ file.write(YAML.dump("recipes" => ["stinky::feet"]))
28
+ end
29
+ end
30
+
31
+ it "runs the proper recipes" do
32
+ cli.stub(:exec)
33
+ Dir.chdir(base_path) { cli.chef }
34
+ cli.config.royal_crown.recipes.should =~ ["stinky::feet"]
35
+ end
36
+
37
+ context "when the Cheffile does not exist" do
38
+ it "runs chef" do
39
+ cli.should_receive(:exec)
40
+ Dir.chdir(base_path) { cli.chef }
41
+ end
42
+
43
+ it "does not run librarian" do
44
+ cli.stub(:exec)
45
+ Librarian::Chef::Cli.should_not_receive(:with_environment)
46
+ Dir.chdir(base_path) { cli.chef }
47
+ end
48
+ end
49
+
50
+ context "when the Cheffile exists" do
51
+ let(:cli_instance) { double(:cli_instance) }
52
+
53
+ before do
54
+ FileUtils.touch(File.expand_path("Cheffile", base_path))
55
+ cli.stub(:exec)
56
+ end
57
+
58
+ it "runs librarian" do
59
+ Librarian::Chef::Cli.should_receive(:with_environment).and_yield
60
+ Librarian::Chef::Cli.should_receive(:new).and_return(cli_instance)
61
+ cli_instance.should_receive(:install)
62
+ Dir.chdir(base_path) { cli.chef }
63
+ end
64
+
65
+ it "runs chef" do
66
+ cli.should_receive(:exec)
67
+ Dir.chdir(base_path) { cli.chef }
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#DO_IT_LIVE" do
74
+ context "when the soloistrc does not exist" do
75
+ it "raises an error" do
76
+ expect do
77
+ Dir.chdir(base_path) { cli.DO_IT_LIVE("pineapple::wut") }
78
+ end.to raise_error(Soloist::NotFound)
79
+ end
80
+ end
81
+
82
+ context "when the soloistrc file exists" do
83
+ before do
84
+ File.open(soloistrc_path, "w") do |file|
85
+ file.write(YAML.dump("recipes" => ["pineapple::wutcake"]))
86
+ end
87
+ end
88
+
89
+ it "sets a recipe to run" do
90
+ Dir.chdir(base_path) do
91
+ cli.should_receive(:chef)
92
+ cli.DO_IT_LIVE("angst::teenage", "ennui::default")
93
+ cli.config.royal_crown.recipes.should =~ ["angst::teenage", "ennui::default"]
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "#ensure_chef_cache_path" do
100
+ context "when the cache path does not exist" do
101
+ before { File.stub(:directory? => false) }
102
+
103
+ it "creates the cache path" do
104
+ cli.should_receive(:system).with("sudo mkdir -p /var/chef/cache")
105
+ cli.ensure_chef_cache_path
106
+ end
107
+ end
108
+
109
+ context "when the cache path exists" do
110
+ before { File.stub(:directory? => true) }
111
+
112
+ it "does not create the cache path" do
113
+ cli.should_not_receive(:system)
114
+ cli.ensure_chef_cache_path
115
+ end
116
+ end
117
+ end
118
+
119
+ describe "#chef_solo" do
120
+ before do
121
+ ENV["AUTREYISM"] = "pathological-yodeling"
122
+ FileUtils.touch(File.expand_path("soloistrc", base_path))
123
+ end
124
+
125
+ it "receives the outside environment" do
126
+ cli.stub(:chef_solo).and_return('echo $AUTREYISM')
127
+ cli.should_receive(:exec) do |chef_solo|
128
+ `#{chef_solo}`.chomp.should == "pathological-yodeling"
129
+ end
130
+ Dir.chdir(base_path) { cli.chef }
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,107 @@
1
+ require "spec_helper"
2
+
3
+ describe Soloist::Config do
4
+ let(:soloist_rc) { Soloist::RoyalCrown.new(:path => "/tmp/soloist/soloistrc") }
5
+ let(:config) { Soloist::Config.new(soloist_rc) }
6
+
7
+ describe "#as_solo_rb" do
8
+ context "without extra cookbook paths" do
9
+ it "can generate solo.rb" do
10
+ config.as_solo_rb.should == 'cookbook_path ["/tmp/soloist/cookbooks"]'
11
+ end
12
+ end
13
+
14
+ context "with a cookbook path" do
15
+ before { soloist_rc.cookbook_paths = ["/opt/holla/at/yo/soloist"] }
16
+
17
+ it "can have multiple cookbook paths" do
18
+ config.as_solo_rb.should == 'cookbook_path ["/tmp/soloist/cookbooks", "/opt/holla/at/yo/soloist"]'
19
+ end
20
+
21
+ it "removes duplicate cookbook paths" do
22
+ expect do
23
+ soloist_rc.cookbook_paths << "/opt/holla/at/yo/soloist"
24
+ end.not_to change { config.as_solo_rb }
25
+ end
26
+ end
27
+
28
+ context "with relative paths" do
29
+ let(:pwd) { File.expand_path(".") }
30
+
31
+ before { soloist_rc.cookbook_paths << "./meth/cookbooks" }
32
+
33
+ it "can have multiple cookbook paths" do
34
+ config.as_solo_rb.should == 'cookbook_path ["/tmp/soloist/cookbooks", "/tmp/soloist/meth/cookbooks"]'
35
+ end
36
+ end
37
+
38
+ context "with unixisms in the cookbook path" do
39
+ let(:home) { File.expand_path("~") }
40
+
41
+ before { soloist_rc.cookbook_paths << "~/yo/homes" }
42
+
43
+ it "expands paths" do
44
+ config.as_solo_rb.should include "#{home}/yo/homes"
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "#as_json" do
50
+ context "with recipes" do
51
+ before { soloist_rc.recipes = ["waffles"] }
52
+
53
+ it "can generate json" do
54
+ config.as_json["recipes"].should include "waffles"
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#compiled_rc" do
60
+ let(:switch) { {"OX_TONGUES" => {"FINE" => {"recipes" => ["hobo_fist"]}}} }
61
+
62
+ before do
63
+ soloist_rc.env_variable_switches = switch
64
+ end
65
+
66
+ context "when a switch is active" do
67
+ before { ENV.stub(:[]).and_return("FINE") }
68
+
69
+ it "merges the environment variable switch" do
70
+ config.compiled_rc.recipes.should include "hobo_fist"
71
+ end
72
+ end
73
+
74
+ context "when a switch is inactive" do
75
+ before { ENV.stub(:[]).and_return("WHAT_NO_EW") }
76
+
77
+ it "outputs an empty list" do
78
+ config.compiled_rc.recipes.should be_empty
79
+ end
80
+ end
81
+
82
+ context "when switches are nested" do
83
+ let(:inner) { {"GOAT" => {"TASTY" => {"node_attributes" => {"bbq" => "satan"}}}} }
84
+ let(:outer) { {"recipes" => ["stinkditch"], "env_variable_switches" => inner} }
85
+
86
+ before { ENV.stub(:[]).and_return("TASTY") }
87
+
88
+ context "when the inner switch is active" do
89
+ let(:switch) { {"HORSE" => {"TASTY" => outer }} }
90
+
91
+ it "evalutes all switches" do
92
+ config.compiled_rc.node_attributes.bbq.should == "satan"
93
+ config.compiled_rc.recipes.should == ["stinkditch"]
94
+ end
95
+ end
96
+
97
+ context "when the outer switch is inactive" do
98
+ let(:switch) { {"HORSE" => {"GROSS" => outer }} }
99
+
100
+ it "does not evaluate deeper" do
101
+ config.compiled_rc.recipes.should be_empty
102
+ config.compiled_rc.node_attributes.should be_empty
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ describe Soloist::RoyalCrown do
4
+ let(:contents) { { "recipes" => ["broken_vim"] } }
5
+ let(:tempfile) do
6
+ Tempfile.new("soloist-royalcrown").tap do |file|
7
+ file.write(YAML.dump(contents))
8
+ file.close
9
+ end
10
+ end
11
+
12
+ let(:royal_crown) { Soloist::RoyalCrown.from_file(tempfile.path) }
13
+
14
+ describe ".from_file" do
15
+ context "when the rc file is empty" do
16
+ let(:tempfile) do
17
+ Tempfile.new("soloist-royalcrown").tap do |file|
18
+ file.close
19
+ end
20
+ end
21
+
22
+ it "loads an empty file" do
23
+ expect { royal_crown }.not_to raise_error
24
+ end
25
+ end
26
+
27
+ it "loads from a yaml file" do
28
+ royal_crown.recipes.should =~ ["broken_vim"]
29
+ end
30
+
31
+ it "defaults nil fields to an empty primitive" do
32
+ royal_crown.node_attributes.should == {}
33
+ end
34
+ end
35
+
36
+ describe "#save" do
37
+ it "writes the values to a file" do
38
+ royal_crown.recipes = ["hot_rats", "tissue_paper"]
39
+ royal_crown.save
40
+ royal_crown = Soloist::RoyalCrown.from_file(tempfile.path)
41
+ royal_crown.recipes.should =~ ["hot_rats", "tissue_paper"]
42
+ end
43
+ end
44
+
45
+ describe "#to_yaml" do
46
+ it "skips the path attribute" do
47
+ royal_crown.to_yaml.keys.should_not include "path"
48
+ end
49
+
50
+ it "nils out fields that have not been set" do
51
+ royal_crown.to_yaml["node_attributes"].should be_nil
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ describe Soloist::Spotlight do
4
+ let(:tempdir) { Dir.mktmpdir }
5
+ let(:shallow_path) { File.expand_path("beans/roger", tempdir) }
6
+ let(:spotlight) { Soloist::Spotlight.new(shallow_path) }
7
+
8
+ before { FileUtils.mkdir_p(shallow_path) }
9
+
10
+ describe "#find" do
11
+ context "with non-existent files" do
12
+ it "raises an error with three files" do
13
+ expect do
14
+ begin
15
+ spotlight.find!("larry", "moe", "curly")
16
+ rescue Soloist::NotFound => e
17
+ e.message.should == "Could not find larry, moe or curly"
18
+ raise
19
+ end
20
+ end.to raise_error(Soloist::NotFound)
21
+ end
22
+
23
+ it "raises an error with two files" do
24
+ expect do
25
+ begin
26
+ spotlight.find!("lulz", "wut")
27
+ rescue Soloist::NotFound => e
28
+ e.message.should == "Could not find lulz or wut"
29
+ raise
30
+ end
31
+ end.to raise_error(Soloist::NotFound)
32
+ end
33
+
34
+ it "raises an error with one file" do
35
+ expect do
36
+ begin
37
+ spotlight.find!("whatever.dude")
38
+ rescue Soloist::NotFound => e
39
+ e.message.should == "Could not find whatever.dude"
40
+ raise
41
+ end
42
+ end.to raise_error(Soloist::NotFound)
43
+ end
44
+ end
45
+
46
+ context "when the file exists" do
47
+ let(:file_path) { File.expand_path("soloistrc", shallow_path) }
48
+
49
+ before { FileUtils.touch(file_path) }
50
+
51
+ it "finds a soloistrc in the current directory" do
52
+ spotlight.find("soloistrc").to_s.should == tempdir + "/beans/roger/soloistrc"
53
+ end
54
+
55
+ context "inside a deeper directory" do
56
+ let(:deep_path) { File.expand_path("meat/hi", shallow_path) }
57
+ let(:spotlight) { Soloist::Spotlight.new(deep_path) }
58
+
59
+ before { FileUtils.mkdir_p(deep_path) }
60
+
61
+ it "finds a soloistrc upwards" do
62
+ spotlight.find("soloistrc").to_s.should == file_path
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,6 @@
1
- require 'rspec'
2
- require File.dirname(__FILE__) + '/../lib/soloist'
1
+ $: << File.expand_path("../../lib", __FILE__)
3
2
 
4
- def mock_gem(name, dependencies=[])
5
- mock_dependencies = dependencies.map { |depenency| mock(:name => depenency) }
6
- mock_gemspec = mock("#{name} gemspec", :dependencies => mock_dependencies)
7
- Gem::Specification.stub(:find_by_name).with(name).and_return(mock_gemspec)
8
- Gem.stub(:searcher).and_return(mock({:find => mock_gemspec}))
9
- end
3
+ require "soloist"
4
+ require "tempfile"
5
+ require "json"
6
+ require "tmpdir"
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: soloist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
5
- prerelease:
4
+ version: 1.0.0.pre
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Matthew Kocher
9
+ - Doc Ritezel
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2012-09-29 00:00:00.000000000 Z
13
+ date: 2012-11-12 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: chef
@@ -27,34 +28,182 @@ dependencies:
27
28
  - - ! '>='
28
29
  - !ruby/object:Gem::Version
29
30
  version: '0'
30
- description: Soloist is an easy way of running chef solo, but it's not doing much.
31
+ - !ruby/object:Gem::Dependency
32
+ name: librarian
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: thor
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: hashie
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: rspec
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: guard-rspec
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-bundler
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: rb-fsevent
129
+ requirement: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ type: :development
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ - !ruby/object:Gem::Dependency
144
+ name: terminal-notifier-guard
145
+ requirement: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ type: :development
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: gem-release
161
+ requirement: !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ! '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ! '>='
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ description: Makes running chef-solo easy.
31
176
  email:
32
177
  - kocher@gmail.com
178
+ - ritezel@gmail.com
33
179
  executables:
34
180
  - soloist
35
181
  extensions: []
36
182
  extra_rdoc_files: []
37
183
  files:
38
184
  - .gitignore
185
+ - .rspec
39
186
  - .rvmrc
40
187
  - .travis.yml
41
188
  - Gemfile
42
189
  - Gemfile.lock
190
+ - Guardfile
43
191
  - MIT-LICENSE
44
192
  - README.markdown
45
- - Rakefile
46
193
  - bin/soloist
47
194
  - lib/soloist.rb
48
- - lib/soloist/chef_config_generator.rb
49
- - lib/soloist/cookbook_gem_linker.rb
50
- - lib/soloist/util.rb
195
+ - lib/soloist/cli.rb
196
+ - lib/soloist/config.rb
197
+ - lib/soloist/royal_crown.rb
198
+ - lib/soloist/spotlight.rb
51
199
  - lib/soloist/version.rb
200
+ - script/ci.sh
52
201
  - soloist.gemspec
53
- - spec/chef_config_generator_spec.rb
54
- - spec/cookbook_gem_linker_spec.rb
55
- - spec/pivotal_workstation_cookbook.rb
202
+ - spec/lib/soloist/cli_spec.rb
203
+ - spec/lib/soloist/config_spec.rb
204
+ - spec/lib/soloist/royal_crown_spec.rb
205
+ - spec/lib/soloist/spotlight_spec.rb
56
206
  - spec/spec_helper.rb
57
- - spec/util_spec.rb
58
207
  homepage: http://github.com/mkocher/soloist
59
208
  licenses: []
60
209
  post_install_message:
@@ -70,9 +219,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
70
219
  required_rubygems_version: !ruby/object:Gem::Requirement
71
220
  none: false
72
221
  requirements:
73
- - - ! '>='
222
+ - - ! '>'
74
223
  - !ruby/object:Gem::Version
75
- version: '0'
224
+ version: 1.3.1
76
225
  requirements: []
77
226
  rubyforge_project: soloist
78
227
  rubygems_version: 1.8.24
@@ -80,8 +229,8 @@ signing_key:
80
229
  specification_version: 3
81
230
  summary: Soloist is a simple way of running chef-solo
82
231
  test_files:
83
- - spec/chef_config_generator_spec.rb
84
- - spec/cookbook_gem_linker_spec.rb
85
- - spec/pivotal_workstation_cookbook.rb
232
+ - spec/lib/soloist/cli_spec.rb
233
+ - spec/lib/soloist/config_spec.rb
234
+ - spec/lib/soloist/royal_crown_spec.rb
235
+ - spec/lib/soloist/spotlight_spec.rb
86
236
  - spec/spec_helper.rb
87
- - spec/util_spec.rb
data/Rakefile DELETED
@@ -1,10 +0,0 @@
1
- require 'bundler'
2
- Bundler::GemHelper.install_tasks
3
-
4
- task :default => [:spec]
5
- task :test => [:spec]
6
-
7
- desc "Run the test suite"
8
- task :spec do
9
- exec "rspec spec/"
10
- end