soloist 0.9.7 → 1.0.0.pre

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.
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