dotty 0.0.1
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/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +110 -0
- data/Rakefile +2 -0
- data/bin/dotty +5 -0
- data/dotty.gemspec +27 -0
- data/lib/dotty/app.rb +150 -0
- data/lib/dotty/helpers.rb +19 -0
- data/lib/dotty/profile.rb +57 -0
- data/lib/dotty/repository.rb +141 -0
- data/lib/dotty/repository_actions.rb +110 -0
- data/lib/dotty/version.rb +3 -0
- data/lib/dotty.rb +18 -0
- data/spec/app_spec.rb +328 -0
- data/spec/profile_spec.rb +188 -0
- data/spec/repository_actions_spec.rb +204 -0
- data/spec/repository_spec.rb +303 -0
- data/spec/spec_helper.rb +62 -0
- data/spec/support/shared_contexts.rb +61 -0
- data/templates/README.md +41 -0
- metadata +124 -0
data/spec/app_spec.rb
ADDED
@@ -0,0 +1,328 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
|
4
|
+
describe Dotty::App do
|
5
|
+
describe "#add" do
|
6
|
+
it "should invoke Dotty::Repository.add" do
|
7
|
+
name = 'repo'
|
8
|
+
url = 'url'
|
9
|
+
Dotty::Repository.stub!(:add_existing_repository)
|
10
|
+
Dotty::Repository.should_receive(:add_existing_repository).with(name, url)
|
11
|
+
subject.add(name, url)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#create" do
|
16
|
+
it "should invoke Dotty::Repository.create" do
|
17
|
+
Dotty::Repository.stub!(:create_repository).and_return(Dotty::Repository.new('name', 'url'))
|
18
|
+
Dotty::Repository.should_receive(:create_repository).with('name', 'url')
|
19
|
+
suppress_output do
|
20
|
+
subject.invoke :create, %w(name url)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should copy the README.md to the repo dir" do
|
25
|
+
suppress_output do
|
26
|
+
subject.invoke :create, %w(name url)
|
27
|
+
end
|
28
|
+
File.file?(File.join Dotty::Repository.list.first.local_path, 'README.md').should be_true
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should create a dotfiles/ directory" do
|
32
|
+
suppress_output do
|
33
|
+
subject.invoke :create, %w(name url)
|
34
|
+
end
|
35
|
+
File.directory?(File.join Dotty::Repository.list.first.local_path, 'dotfiles').should be_true
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#remove" do
|
41
|
+
it "should invoke #destroy on the Repository instance with the given name" do
|
42
|
+
repo = Dotty::Repository.new('name', 'url')
|
43
|
+
repo.stub!(:destroy)
|
44
|
+
repo.should_receive(:destroy)
|
45
|
+
Dotty::Repository.repositories = [repo]
|
46
|
+
suppress_output do
|
47
|
+
subject.invoke :remove, %w(name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#update" do
|
53
|
+
include_context "two in memory repositories"
|
54
|
+
|
55
|
+
before do
|
56
|
+
subject.send(:actions).stub!(:update)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should invoke update action with the specified repo" do
|
60
|
+
subject.send(:actions).should_receive(:update).with(@repo1).once
|
61
|
+
suppress_output do
|
62
|
+
subject.update 'repo1name'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should invoke update action for all repos if no repo is specified" do
|
67
|
+
subject.send(:actions).should_receive(:update).with(@repo1).once
|
68
|
+
subject.send(:actions).should_receive(:update).with(@repo2).once
|
69
|
+
suppress_output do
|
70
|
+
subject.update
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#bootstrap" do
|
76
|
+
include_context "two in memory repositories"
|
77
|
+
|
78
|
+
before do
|
79
|
+
subject.send(:actions).stub!(:bootstrap)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should invoke bootstrap action with the specified repo" do
|
83
|
+
subject.send(:actions).should_receive(:bootstrap).with(@repo1).once
|
84
|
+
suppress_output do
|
85
|
+
subject.bootstrap 'repo1name'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should invoke bootstrap action for all repos if no repo is specified" do
|
90
|
+
subject.send(:actions).should_receive(:bootstrap).with(@repo1).once
|
91
|
+
subject.send(:actions).should_receive(:bootstrap).with(@repo2).once
|
92
|
+
suppress_output do
|
93
|
+
subject.bootstrap
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#implode" do
|
99
|
+
include_context "two in memory repositories"
|
100
|
+
|
101
|
+
before do
|
102
|
+
subject.send(:actions).stub!(:implode)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should invoke implode action with the specified repo" do
|
106
|
+
subject.send(:actions).should_receive(:implode).with(@repo1).once
|
107
|
+
suppress_output do
|
108
|
+
subject.implode 'repo1name'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should invoke implode action for all repos if no repo is specified" do
|
113
|
+
subject.send(:actions).should_receive(:implode).with(@repo1).once
|
114
|
+
subject.send(:actions).should_receive(:implode).with(@repo2).once
|
115
|
+
suppress_output do
|
116
|
+
subject.implode
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "#update_submodules" do
|
122
|
+
# TODO add these when I figure out how to make multiple should_receive + thor work
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#execute" do
|
126
|
+
include_context "two in memory repositories"
|
127
|
+
|
128
|
+
it "should run the given command inside the the specified repository's directory" do
|
129
|
+
subject.stub(:run) do
|
130
|
+
subject.destination_root.should == @repo1.local_path
|
131
|
+
end
|
132
|
+
subject.should_receive(:run).once.with('ls')
|
133
|
+
suppress_output do
|
134
|
+
subject.execute @repo1.name, 'ls'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should run the given command in each repositories directroy if no repository is specified" do
|
139
|
+
paths = [@repo1.local_path, @repo2.local_path]
|
140
|
+
i = 0
|
141
|
+
subject.stub(:run) do
|
142
|
+
subject.destination_root.should == paths[i]
|
143
|
+
i += 1
|
144
|
+
end
|
145
|
+
subject.should_receive(:run).twice.with('ls')
|
146
|
+
suppress_output do
|
147
|
+
subject.execute 'ls'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "#import_repos" do
|
153
|
+
it "should invoke Dotty::Repository.import" do
|
154
|
+
Dotty::Repository.stub!(:import)
|
155
|
+
Dotty::Repository.should_receive(:import).with('location')
|
156
|
+
suppress_output do
|
157
|
+
subject.import_repos('location')
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "#find_repo!" do
|
163
|
+
include_context "two in memory repositories"
|
164
|
+
|
165
|
+
it "should return the correct repo instance if it exists" do
|
166
|
+
subject.send(:find_repo!, 'repo1name').should == @repo1
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should raise an exception when the given repository does not exist" do
|
170
|
+
expect {
|
171
|
+
subject.send(:find_repo!, 'nonexistant')
|
172
|
+
}.to raise_error Dotty::RepositoryNotFoundError, "The specified repository does not exist"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "#actions" do
|
177
|
+
it "should return an instance of Dotty::RepositoryActions" do
|
178
|
+
subject.send(:actions).should be_kind_of Dotty::RepositoryActions
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should cache it" do
|
182
|
+
app = subject
|
183
|
+
app.send(:actions).should == app.send(:actions)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe "#for_specified_or_all_repos" do
|
188
|
+
include_context "two in memory repositories"
|
189
|
+
|
190
|
+
it "should yield the two registered repos" do
|
191
|
+
subject.should_receive(:for_specified_or_all_repos).and_yield(Dotty::Repository.list)
|
192
|
+
subject.send(:for_specified_or_all_repos) { |r| }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe "#create_profile" do
|
197
|
+
it "should invoke Profile.create" do
|
198
|
+
Dotty::Profile.stub(:create)
|
199
|
+
Dotty::Profile.should_receive(:create).once.with('name')
|
200
|
+
suppress_output do
|
201
|
+
subject.create_profile 'name'
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "#remove_profile" do
|
207
|
+
it "should invoke Profile.remove" do
|
208
|
+
Dotty::Profile.stub(:remove)
|
209
|
+
Dotty::Profile.should_receive(:remove).once.with('my_repo')
|
210
|
+
suppress_output do
|
211
|
+
subject.remove_profile 'my_repo'
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "#profiles" do
|
217
|
+
include_context "profile data"
|
218
|
+
it "should list existing proiles" do
|
219
|
+
output = capture :stdout do
|
220
|
+
subject.invoke :profiles
|
221
|
+
end
|
222
|
+
output.should == "\e[34mDOTTY PROFILES\n\e[0m\n \e[32m* my_profile\e[0m\n other_profile\n"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "#profile" do
|
227
|
+
include_context "profile data"
|
228
|
+
|
229
|
+
it "should print the current profile if no profile name is given" do
|
230
|
+
output = capture :stdout do
|
231
|
+
subject.invoke :profile
|
232
|
+
end
|
233
|
+
output.gsub!(/\e\[\d+\w/, '') # Remove colors and shit
|
234
|
+
output.should == "Current dotty profile: my_profile\n"
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should change Profile.current_profile when given a valid profile name" do
|
238
|
+
suppress_output do
|
239
|
+
subject.invoke :profile, %w(other_profile)
|
240
|
+
end
|
241
|
+
Dotty::Profile.current_profile.should == 'other_profile'
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should invoke Profile.write_yaml" do
|
245
|
+
Dotty::Profile.should_receive(:write_yaml)
|
246
|
+
suppress_output do
|
247
|
+
subject.invoke :profile, %w(other_profile)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should call Profile.find!" do
|
252
|
+
Dotty::Profile.should_receive(:find!).with('other_profile')
|
253
|
+
suppress_output do
|
254
|
+
subject.invoke :profile, %w(other_profile)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should invoke implode then bootstrap" do
|
259
|
+
subject.should_receive(:implode).once.ordered
|
260
|
+
subject.should_receive(:bootstrap).once.ordered
|
261
|
+
suppress_output do
|
262
|
+
subject.profile 'other_profile'
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "#list" do
|
269
|
+
|
270
|
+
context "with some repositories" do
|
271
|
+
include_context "profile data"
|
272
|
+
|
273
|
+
before do
|
274
|
+
Dotty::Repository.list.each do |repo|
|
275
|
+
%x(git init #{repo.local_path})
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should display a list of repositories" do
|
280
|
+
output = capture(:stdout) do
|
281
|
+
subject.list
|
282
|
+
end
|
283
|
+
output.gsub!(/\e\[\d+\w/, '') # Remove colors and shit
|
284
|
+
output.should == <<-EXPECTED_OUTPUT
|
285
|
+
Installed dotty repositories for profile 'my_profile'
|
286
|
+
|
287
|
+
my_repo git://github.com/me/my_repo
|
288
|
+
other_repo git://github.com/me/other_repo
|
289
|
+
|
290
|
+
EXPECTED_OUTPUT
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should display git changes" do
|
294
|
+
%x(cd #{Dotty::Repository.list.first.local_path} && touch newfile)
|
295
|
+
Dotty::Repository.list.first.stub!(:unpushed_changes?).and_return(true)
|
296
|
+
output = capture(:stdout) do
|
297
|
+
subject.list
|
298
|
+
end
|
299
|
+
output.gsub!(/\e\[\d+\w/, '') # Remove colors and shit
|
300
|
+
output.should == <<-EXPECTED_OUTPUT
|
301
|
+
Installed dotty repositories for profile 'my_profile'
|
302
|
+
|
303
|
+
my_repo git://github.com/me/my_repo [1 uncomitted changes] [unpushed commits]
|
304
|
+
other_repo git://github.com/me/other_repo
|
305
|
+
|
306
|
+
EXPECTED_OUTPUT
|
307
|
+
end
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should display a message if there are no repositories" do
|
312
|
+
Dotty::Repository.repositories = []
|
313
|
+
output = capture(:stdout) do
|
314
|
+
subject.list
|
315
|
+
end
|
316
|
+
output.gsub!(/\e\[\d+\w/, '') # Remove colors and shit
|
317
|
+
output.should == <<-EXPECTED_OUTPUT
|
318
|
+
Installed dotty repositories for profile 'default'
|
319
|
+
|
320
|
+
No repositories here. Use 'create', 'add' or 'import_repos' to get going.
|
321
|
+
|
322
|
+
EXPECTED_OUTPUT
|
323
|
+
|
324
|
+
end
|
325
|
+
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Dotty::Profile do
|
4
|
+
|
5
|
+
describe ".create" do
|
6
|
+
it "should add the profile to profile_data" do
|
7
|
+
Dotty::Profile.create 'name'
|
8
|
+
Dotty::Profile.profile_data['profiles'].should have_key 'name'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should invoke .write_yaml" do
|
12
|
+
Dotty::Profile.stub!(:write_yaml)
|
13
|
+
Dotty::Profile.should_receive(:write_yaml)
|
14
|
+
Dotty::Profile.create 'name'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".remove" do
|
19
|
+
include_context "profile data"
|
20
|
+
|
21
|
+
it "should remove the profile from profile_data" do
|
22
|
+
Dotty::Profile.remove 'my_profile'
|
23
|
+
Dotty::Profile.profile_data['profiles'].should_not have_key 'my_profile'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should invoke .write_yaml" do
|
27
|
+
Dotty::Profile.should_receive(:write_yaml)
|
28
|
+
Dotty::Profile.remove 'my_profile'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should set current_profile to the first existing profile" do
|
32
|
+
Dotty::Profile.current_profile = 'my_profile'
|
33
|
+
Dotty::Profile.remove 'my_profile'
|
34
|
+
Dotty::Profile.current_profile.should == 'other_profile'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe ".profile_data" do
|
39
|
+
it "should return data by calling .read_yaml the first time" do
|
40
|
+
Dotty::Profile.should_receive(:read_yaml).once.and_return(:test)
|
41
|
+
Dotty::Profile.profile_data.should == :test
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should use cached data when available" do
|
45
|
+
Dotty::Profile.stub!(:read_yaml).and_return(:test)
|
46
|
+
Dotty::Profile.profile_data # cache data
|
47
|
+
Dotty::Profile.should_not_receive(:read_yaml)
|
48
|
+
Dotty::Profile.profile_data.should == :test
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe ".current_profile" do
|
53
|
+
it "should return 'default' if no data is set and there are no profiles" do
|
54
|
+
Dotty::Profile.instance_variable_set '@profile_data', {}
|
55
|
+
Dotty::Profile.current_profile.should == 'default'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should use the value from @profile_data if its set and @current_profile isnt" do
|
59
|
+
Dotty::Profile.instance_variable_set('@profile_data', { 'current_profile' => 'myprofile' })
|
60
|
+
Dotty::Profile.current_profile.should == 'myprofile'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should use @current_profile when its set" do
|
64
|
+
Dotty::Profile.instance_variable_set('@profile_data', { 'current_profile' => 'myprofile' })
|
65
|
+
Dotty::Profile.instance_variable_set('@current_profile', 'banana')
|
66
|
+
Dotty::Profile.current_profile.should == 'banana'
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with profiles" do
|
70
|
+
include_context "profile data"
|
71
|
+
it "should use the first repo when profile_data does not have a current_profile set" do
|
72
|
+
Dotty::Profile.profile_data['current_profile'] = nil
|
73
|
+
Dotty::Profile.current_profile.should == 'my_profile'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe ".current_profile_data" do
|
79
|
+
include_context "profile data"
|
80
|
+
|
81
|
+
it "should return the profile's section in profile_data" do
|
82
|
+
Dotty::Profile.stub!(:profile_data).and_return(@profile_data)
|
83
|
+
Dotty::Profile.current_profile_data.should == {
|
84
|
+
'repositories' => {
|
85
|
+
'my_repo' => {
|
86
|
+
'url' => 'git://github.com/me/my_repo'
|
87
|
+
},
|
88
|
+
'other_repo' => {
|
89
|
+
'url' => 'git://github.com/me/other_repo'
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return empty hash when there is no profile data" do
|
96
|
+
FileUtils.rm Dotty::Profile::YAML_PATH
|
97
|
+
Dotty::Profile.current_profile_data.should == {}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe ".read_yaml" do
|
102
|
+
include_context "profile data"
|
103
|
+
|
104
|
+
it "should return the data structure defined in the yaml" do
|
105
|
+
Dotty::Profile.read_yaml.should == @profile_data
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should return false if there is no ~/.dotty/.profiles.yml" do
|
109
|
+
FileUtils.rm Dotty::Profile::YAML_PATH
|
110
|
+
Dotty::Profile.read_yaml.should == false
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
describe ".write_yaml" do
|
116
|
+
include_context "profile data"
|
117
|
+
|
118
|
+
it "should create the file when it doesnt exist" do
|
119
|
+
FileUtils.rm Dotty::Profile::YAML_PATH
|
120
|
+
Dotty::Profile.write_yaml
|
121
|
+
File.exist?(Dotty::Profile::YAML_PATH).should be_true
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should write data so that .read_yaml returns identical data" do
|
125
|
+
Dotty::Profile.instance_variable_set '@profile_data', @profile_data
|
126
|
+
Dotty::Profile.write_yaml
|
127
|
+
Dotty::Profile.read_yaml.should == @profile_data
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should write updated repository data" do
|
131
|
+
repo = Dotty::Repository.list.first
|
132
|
+
repo.name = 'newreponame'
|
133
|
+
Dotty::Profile.write_yaml
|
134
|
+
Dotty::Profile.read_yaml.should == {
|
135
|
+
"current_profile" => "my_profile",
|
136
|
+
"profiles" => {
|
137
|
+
"my_profile" => {
|
138
|
+
"repositories" =>{
|
139
|
+
"newreponame" => { "url"=>"git://github.com/me/my_repo" },
|
140
|
+
"other_repo" => { "url"=>"git://github.com/me/other_repo" }
|
141
|
+
}
|
142
|
+
},
|
143
|
+
"other_profile" => {
|
144
|
+
"repositories" => {
|
145
|
+
"my_repo" => { "url"=>"git://github.com/me/my_repo" },
|
146
|
+
"other_repo" => { "url"=>"git://github.com/me/other_repo"}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe ".find" do
|
155
|
+
include_context "profile data"
|
156
|
+
it "should raise an error if the given profile name does not exist" do
|
157
|
+
expect {
|
158
|
+
Dotty::Profile.find! 'non_existant_profile'
|
159
|
+
}.to raise_error(Dotty::Error, "Profile 'non_existant_profile' does not exist")
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should return the profile data if the profile exists" do
|
163
|
+
Dotty::Profile.find!('other_profile').should == {
|
164
|
+
'repositories' => {
|
165
|
+
'my_repo' => { 'url' => 'git://github.com/me/my_repo' },
|
166
|
+
'other_repo' => { 'url' => 'git://github.com/me/other_repo' }
|
167
|
+
}
|
168
|
+
}
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
#describe "#new" do
|
173
|
+
#it "should return an instance of Dotty::Profile" do
|
174
|
+
#profile = Dotty::Profile.new('name')
|
175
|
+
#profile.should be_instance_of Dotty::Profile
|
176
|
+
#end
|
177
|
+
#end
|
178
|
+
|
179
|
+
#describe "#name" do
|
180
|
+
#it "should return the given name" do
|
181
|
+
#profile = Dotty::Profile.new('name')
|
182
|
+
#profile.name.should == 'name'
|
183
|
+
#end
|
184
|
+
#end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
|