treet 0.8.2 → 0.10.2
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 +0 -1
- data/.travis.yml +4 -0
- data/Gemfile +0 -2
- data/Guardfile +19 -0
- data/lib/treet/farm.rb +13 -10
- data/lib/treet/gitfarm.rb +28 -0
- data/lib/treet/gitrepo.rb +180 -0
- data/lib/treet/hash.rb +11 -5
- data/lib/treet/repo.rb +40 -28
- data/lib/treet/version.rb +1 -1
- data/lib/treet.rb +9 -4
- data/spec/json/four.json +8 -0
- data/spec/lib/repo_spec.rb +115 -7
- data/spec/lib/{farm_spec.rb → test_farm.rb} +21 -18
- data/spec/lib/test_gitfarm.rb +63 -0
- data/spec/lib/test_gitrepo.rb +346 -0
- data/spec/test_helper.rb +25 -0
- data/treet.gemspec +7 -5
- metadata +66 -23
@@ -1,22 +1,17 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
require "
|
2
|
+
require "test_helper"
|
3
3
|
|
4
4
|
describe "Repository Farm" do
|
5
5
|
it "should export as array of hashes with an xref value" do
|
6
6
|
farm = Treet::Farm.new(:root => "#{File.dirname(__FILE__)}/../repos/farm1", :xref => 'test')
|
7
|
-
farm.
|
7
|
+
farm.repos.count.must_equal 2
|
8
|
+
farm.export.must_equal [
|
8
9
|
{
|
9
10
|
'name' => {
|
10
11
|
'full' => 'John Bigbooté'
|
11
|
-
},
|
12
|
-
'xref' => {
|
13
|
-
'test' => 'one'
|
14
12
|
}
|
15
13
|
},
|
16
14
|
{
|
17
|
-
'xref' => {
|
18
|
-
'test' => 'two'
|
19
|
-
},
|
20
15
|
'name' => {
|
21
16
|
'full' => 'John Smallberries',
|
22
17
|
'first' => 'John',
|
@@ -39,26 +34,34 @@ describe "Repository Farm" do
|
|
39
34
|
it "planting should create a directory of UUID-labeled repos" do
|
40
35
|
farm = Treet::Farm.plant(:json => "#{File.dirname(__FILE__)}/../json/master.json", :root => Dir.mktmpdir)
|
41
36
|
|
42
|
-
Dir.glob("#{farm.root}/*").count.
|
43
|
-
Dir.glob("#{farm.root}/*/emails/*").count.
|
44
|
-
Dir.glob("#{farm.root}/*/addresses/*").count.
|
37
|
+
Dir.glob("#{farm.root}/*").count.must_equal 3
|
38
|
+
Dir.glob("#{farm.root}/*/emails/*").count.must_equal 5
|
39
|
+
Dir.glob("#{farm.root}/*/addresses/*").count.must_equal 1
|
45
40
|
|
46
41
|
FileUtils.rm_rf(farm.root)
|
47
42
|
end
|
48
43
|
|
49
|
-
it "should be retrievable by repo label/xref" do
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
44
|
+
# it "should be retrievable by repo label/xref" do
|
45
|
+
# farm = Treet::Farm.new(:root => "#{File.dirname(__FILE__)}/../repos/farm1", :xref => 'test')
|
46
|
+
# farm['two'].root.must_equal "#{File.dirname(__FILE__)}/../repos/farm1/two"
|
47
|
+
# farm['two'].to_hash['xref'].must_equal {'test' => 'two'}
|
48
|
+
# end
|
54
49
|
|
55
50
|
it "should take additions" do
|
56
51
|
farm = Treet::Farm.plant(:json => "#{File.dirname(__FILE__)}/../json/master.json", :root => Dir.mktmpdir)
|
52
|
+
farm.repos.count.must_equal 3
|
57
53
|
|
58
54
|
bob_hash = load_json("bob1")
|
59
55
|
repo = farm.add(bob_hash)
|
60
|
-
repo.root.
|
61
|
-
Dir.glob("#{farm.root}/*").count.
|
56
|
+
repo.root.must_match /#{farm.root}/
|
57
|
+
Dir.glob("#{farm.root}/*").count.must_equal 4
|
58
|
+
|
59
|
+
farm.repos.count.must_equal 4
|
60
|
+
|
61
|
+
# now try with a predefined ID
|
62
|
+
repo = farm.add(bob_hash, :id => '12345')
|
63
|
+
repo.root.must_equal "#{farm.root}/12345"
|
64
|
+
Dir.glob("#{farm.root}/*").count.must_equal 5
|
62
65
|
|
63
66
|
FileUtils.rm_rf(farm.root)
|
64
67
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "test_helper"
|
3
|
+
require "pp"
|
4
|
+
|
5
|
+
describe Treet::Gitfarm do
|
6
|
+
def self.empty_gitfarm
|
7
|
+
f = Treet::Gitfarm.new(
|
8
|
+
:root => Dir.mktmpdir('farm', $topdir),
|
9
|
+
:xref => 'testapp',
|
10
|
+
:author => {:name => 'Bob', :email => 'bob@example.com'}
|
11
|
+
)
|
12
|
+
# puts "MADE AN EMPTY FARM OF #{f.repotype}"
|
13
|
+
f
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "a directory of labeled git repos" do
|
17
|
+
def self.plantfarm
|
18
|
+
@farm ||= Treet::Gitfarm.plant(
|
19
|
+
:json => jsonfile('master'),
|
20
|
+
:root => Dir.mktmpdir('farm', $topdir),
|
21
|
+
:author => {:name => 'Bob', :email => 'bob@example.com'},
|
22
|
+
:xref => 'myapp'
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:farm) { self.class.plantfarm }
|
27
|
+
|
28
|
+
it "should be populated" do
|
29
|
+
farm.repos.count.must_equal 3
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should all be gitified" do
|
33
|
+
farm.repos.each do |id, repo|
|
34
|
+
repo.head.wont_be_nil
|
35
|
+
repo.tags.must_be_empty
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "new repo in empty farm" do
|
41
|
+
def self.dofarm
|
42
|
+
@farm ||= begin
|
43
|
+
farm = empty_gitfarm
|
44
|
+
farm.add(load_json('bob1'), :tag => "app1")
|
45
|
+
farm
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:farm) { self.class.dofarm }
|
50
|
+
|
51
|
+
it "is the only repo" do
|
52
|
+
farm.repos.count.must_equal 1
|
53
|
+
end
|
54
|
+
|
55
|
+
it "can be tagged" do
|
56
|
+
farm.must_be_instance_of Treet::Gitfarm
|
57
|
+
bob = farm.repos.values.first
|
58
|
+
bob.wont_be_nil
|
59
|
+
bob.must_be_instance_of Treet::Gitrepo
|
60
|
+
bob.tags.first.name.must_equal 'refs/tags/app1'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,346 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "test_helper"
|
3
|
+
require "pp"
|
4
|
+
|
5
|
+
# convert a hash to a gitrepo
|
6
|
+
# convert a plain repo to a gitrepo
|
7
|
+
# convert a gitrepo to a plain repo
|
8
|
+
# initialize a treet git from an existing gitrepo (with a treet::repo structure)
|
9
|
+
# patch a gitrepo (with commit) - verify commit structure
|
10
|
+
# pulling past snapshots
|
11
|
+
|
12
|
+
describe Treet::Gitrepo do
|
13
|
+
def self.make_gitrepo(filename, opts = {})
|
14
|
+
thash = Treet::Hash.new(load_json(filename))
|
15
|
+
trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
|
16
|
+
Treet::Gitrepo.new(trepo.root, opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def make_gitrepo(filename, opts = {})
|
20
|
+
self.class.make_gitrepo(filename, opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
def hashalike(h1, h2)
|
24
|
+
Treet::Hash.diff(h1, h2).empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "creation" do
|
28
|
+
it "must have an author" do
|
29
|
+
->{ make_gitrepo('one') }.must_raise(ArgumentError, "xxx")
|
30
|
+
end
|
31
|
+
|
32
|
+
# TODO: must have an existing & non-empty directory tree
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "a minimal non-empty untagged gitrepo" do
|
36
|
+
def self.make_johnb
|
37
|
+
@memo ||= begin
|
38
|
+
data = {
|
39
|
+
"name" => {
|
40
|
+
"full" => "John Bigbooté"
|
41
|
+
}
|
42
|
+
}
|
43
|
+
thash = Treet::Hash.new(data)
|
44
|
+
trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
|
45
|
+
Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:johnb) { self.class.make_johnb }
|
50
|
+
|
51
|
+
it "should have exactly one commit" do
|
52
|
+
johnb.head.wont_be_nil
|
53
|
+
johnb.refs.count.must_equal 1
|
54
|
+
johnb.refs.first.target.must_equal johnb.head.target
|
55
|
+
r = Rugged::Repository.new(johnb.root)
|
56
|
+
r.lookup(johnb.head.target).parents.must_be_empty
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should have a single entry" do
|
60
|
+
johnb.index.count.must_equal 1
|
61
|
+
johnb.entries.must_equal ['name']
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should fetch data content" do
|
65
|
+
johnb.to_hash.must_equal load_json('one')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should have no tags" do
|
69
|
+
johnb.tags.must_be_empty
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should fail on unknown tag lookups" do
|
73
|
+
->{johnb.to_hash(:tag => 'nosuchtag')}.must_raise ArgumentError
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should have no branches" do
|
77
|
+
johnb.branches.must_be_empty
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return commit SHA for version label" do
|
81
|
+
johnb.version.must_equal johnb.head.target
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return nil for unknown tag versions" do
|
85
|
+
johnb.version(:tag => 'nosuchtag').must_be_nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
describe "a patched gitrepo" do
|
91
|
+
def self.patch_johnb
|
92
|
+
@memo ||= begin
|
93
|
+
data = {
|
94
|
+
"name" => {
|
95
|
+
"full" => "John Bigbooté"
|
96
|
+
}
|
97
|
+
}
|
98
|
+
thash = Treet::Hash.new(data)
|
99
|
+
trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
|
100
|
+
r = Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
|
101
|
+
r.patch([
|
102
|
+
[
|
103
|
+
"+",
|
104
|
+
"org.name",
|
105
|
+
"Bigcorp"
|
106
|
+
]
|
107
|
+
])
|
108
|
+
r
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
let(:repo) { self.class.patch_johnb }
|
113
|
+
|
114
|
+
it "should have correct git index" do
|
115
|
+
repo.index.count.must_equal 2
|
116
|
+
repo.entries.must_include 'name'
|
117
|
+
repo.entries.must_include 'org'
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should hashify correctly" do
|
121
|
+
expectation = load_json('one').merge({'org' => {'name' => 'Bigcorp'}})
|
122
|
+
repo.to_hash.must_equal expectation
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should have 2 commits" do
|
126
|
+
r = Rugged::Repository.new(repo.root)
|
127
|
+
latest_commit = r.head.target
|
128
|
+
r.lookup(latest_commit).parents.count.must_equal 1
|
129
|
+
previous_commit = r.lookup(latest_commit).parents.first
|
130
|
+
previous_commit.parents.must_be_empty
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should have no tags" do
|
134
|
+
repo.tags.must_be_empty
|
135
|
+
end
|
136
|
+
|
137
|
+
# it "should be able to reverse-engineer the patch from the git history" do
|
138
|
+
# skip
|
139
|
+
# # rugged has a `Rugged::Commit#diff-tree` on the roadmap (see `USAGE.rb`), not yet implemented
|
140
|
+
# end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "patched with a delete" do
|
144
|
+
let(:repo) do
|
145
|
+
r = make_gitrepo('two', :author => {:name => 'Bob', :email => 'bob@example.com'})
|
146
|
+
r.patch([
|
147
|
+
[
|
148
|
+
"-",
|
149
|
+
"emails[]",
|
150
|
+
{ "label" => "home", "email" => "johns@lectroid.com" }
|
151
|
+
]
|
152
|
+
])
|
153
|
+
r
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should have correct git index" do
|
157
|
+
repo.index.count.must_equal 2
|
158
|
+
repo.entries.must_include 'name'
|
159
|
+
repo.entries.grep(/emails/).wont_be_empty
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should hashify correctly" do
|
163
|
+
# should reflect the deletion in current state
|
164
|
+
expectation = load_json('two')
|
165
|
+
expectation['emails'].delete_if {|v| v['label'] == 'home'}
|
166
|
+
repo.to_hash.must_equal expectation
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should have 2 commits" do
|
170
|
+
r = Rugged::Repository.new(repo.root)
|
171
|
+
latest_commit = r.head.target
|
172
|
+
r.lookup(latest_commit).parents.count.must_equal 1
|
173
|
+
previous_commit = r.lookup(latest_commit).parents.first
|
174
|
+
previous_commit.parents.must_be_empty
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should show the original state in the previous commit" do
|
178
|
+
r = Rugged::Repository.new(repo.root)
|
179
|
+
latest_commit = r.head.target
|
180
|
+
r.lookup(latest_commit).parents.count.must_equal 1
|
181
|
+
previous_commit = r.lookup(latest_commit).parents.first
|
182
|
+
assert hashalike(repo.to_hash(:commit => previous_commit.oid), load_json('two'))
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "a tagged & patched repo" do
|
187
|
+
def self.makerepo
|
188
|
+
@cache ||= begin
|
189
|
+
r = make_gitrepo('two',
|
190
|
+
:author => {:name => 'Bob', :email => 'bob@example.com'},
|
191
|
+
:xrefkey => 'app1',
|
192
|
+
:xref => 'APP1_ID'
|
193
|
+
)
|
194
|
+
r.tag('app1')
|
195
|
+
r.patch([
|
196
|
+
[
|
197
|
+
"-",
|
198
|
+
"emails[]",
|
199
|
+
{ "label" => "home", "email" => "johns@lectroid.com" }
|
200
|
+
],
|
201
|
+
[
|
202
|
+
"+",
|
203
|
+
"name.first",
|
204
|
+
"Ralph"
|
205
|
+
]
|
206
|
+
])
|
207
|
+
r
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
let(:repo) { self.class.makerepo }
|
212
|
+
|
213
|
+
it "should correctly commit the existing updated git artifacts" do
|
214
|
+
repo.to_hash(:commit => repo.head.target)['name']['first'].must_equal 'Ralph'
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should not have an index entry for the removed item" do
|
218
|
+
repo.entries.must_include 'name'
|
219
|
+
repo.entries.grep(/^emails/).wont_be_empty
|
220
|
+
repo.index.count.must_equal 2
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should have tag not pointing to HEAD" do
|
224
|
+
repo.tags.count.must_equal 1
|
225
|
+
repo.tags.first.name.must_equal "refs/tags/app1"
|
226
|
+
repo.tags.first.target.wont_equal repo.head.target
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should have the original image for the tag" do
|
230
|
+
refute hashalike(repo.to_hash, repo.to_hash(:tag => 'app1'))
|
231
|
+
assert hashalike(repo.to_hash(:tag => 'app1'), load_json('two'))
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should have no branches" do
|
235
|
+
repo.branches.must_be_empty
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should track version label by tag" do
|
239
|
+
repo.version.must_equal repo.head.target
|
240
|
+
repo.version(:tag => 'app1').must_equal repo.tags.first.target
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "a tagged repo" do
|
245
|
+
let(:repo) do
|
246
|
+
r = make_gitrepo('two', :author => {:name => 'Bob', :email => 'bob@example.com'})
|
247
|
+
r.tag('source1')
|
248
|
+
r
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should have tags" do
|
252
|
+
repo.tags.count.must_equal 1
|
253
|
+
repo.tags.first.name.must_equal "refs/tags/source1"
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should have no branches" do
|
257
|
+
repo.branches.must_be_empty
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should retrieve same image for default and by tag" do
|
261
|
+
assert hashalike(repo.to_hash(:tag => 'source1'), load_json('two'))
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should point the tag at the commit" do
|
265
|
+
repo.tags.first.target.must_equal repo.head.target
|
266
|
+
repo.version.must_equal repo.version(:tag => 'source1')
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
describe "a multiply-patched gitrepo" do
|
271
|
+
def self.makerepo
|
272
|
+
@cache ||= begin
|
273
|
+
r = make_gitrepo('two', :author => {:name => 'Bob', :email => 'bob@example.com'})
|
274
|
+
r.tag('app1')
|
275
|
+
r.tag('app2')
|
276
|
+
image1 = r.to_hash
|
277
|
+
r.patch([
|
278
|
+
[
|
279
|
+
"+",
|
280
|
+
"org.name",
|
281
|
+
"BigCorp"
|
282
|
+
]
|
283
|
+
])
|
284
|
+
r.tag('app2')
|
285
|
+
image2 = r.to_hash
|
286
|
+
r.patch([
|
287
|
+
[
|
288
|
+
"-",
|
289
|
+
"org.name",
|
290
|
+
"BigCorp"
|
291
|
+
]
|
292
|
+
])
|
293
|
+
r.tag('app3')
|
294
|
+
image3 = r.to_hash
|
295
|
+
r.patch([
|
296
|
+
[
|
297
|
+
"-",
|
298
|
+
"emails[]",
|
299
|
+
{ "label" => "home", "email" => "johns@lectroid.com" }
|
300
|
+
]
|
301
|
+
])
|
302
|
+
r.tag('app4')
|
303
|
+
image4 = r.to_hash
|
304
|
+
|
305
|
+
{
|
306
|
+
:repo => r,
|
307
|
+
:image1 => image1,
|
308
|
+
:image2 => image2,
|
309
|
+
:image3 => image3,
|
310
|
+
:image4 => image4
|
311
|
+
}
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
let(:repo) { self.class.makerepo }
|
316
|
+
|
317
|
+
it "should remember all the tags" do
|
318
|
+
repo[:repo].tags.count.must_equal 4
|
319
|
+
end
|
320
|
+
|
321
|
+
it "should fetch different images by tag" do
|
322
|
+
assert hashalike(repo[:repo].to_hash(:tag => 'app1'), repo[:image1])
|
323
|
+
assert hashalike(repo[:repo].to_hash(:tag => 'app2'), repo[:image2])
|
324
|
+
assert hashalike(repo[:repo].to_hash(:tag => 'app3'), repo[:image3])
|
325
|
+
assert hashalike(repo[:repo].to_hash(:tag => 'app4'), repo[:image4])
|
326
|
+
assert hashalike(repo[:repo].to_hash, repo[:image4])
|
327
|
+
end
|
328
|
+
|
329
|
+
it "should have different version labels for each tag" do
|
330
|
+
versions = ['app1', 'app2', 'app3', 'app4'].map {|s| repo[:repo].version(:tag => s)}
|
331
|
+
versions.uniq.count.must_equal 4
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
describe "a branched gitrepo" do
|
336
|
+
let(:repo) do
|
337
|
+
r = make_gitrepo('one', :author => {:name => 'Bob', :email => 'bob@example.com'})
|
338
|
+
r.branch('mybranch')
|
339
|
+
r
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should show a branch" do
|
343
|
+
repo.branches.must_equal ['refs/heads/mybranch']
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
data/spec/test_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
|
3
|
+
require File.expand_path('../../lib/treet', __FILE__)
|
4
|
+
|
5
|
+
require "tmpdir"
|
6
|
+
require "fileutils"
|
7
|
+
|
8
|
+
$topdir ||= Dir.mktmpdir("treet-tests-")
|
9
|
+
|
10
|
+
def jsonfile(filename)
|
11
|
+
"#{File.dirname(__FILE__)}/json/#{filename}.json"
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_json(filename)
|
15
|
+
JSON.load(File.open(jsonfile(filename)))
|
16
|
+
end
|
17
|
+
|
18
|
+
MiniTest::Unit.after_tests do
|
19
|
+
$stderr.puts "Erasing #{$topdir}"
|
20
|
+
FileUtils.rm_rf $topdir
|
21
|
+
$topdir = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# MUST PUT THIS AT *END* OF FILE OR CLEANUP WILL HAPPEN BEFORE TESTS ARE RUN!
|
25
|
+
require 'minitest/autorun'
|
data/treet.gemspec
CHANGED
@@ -15,10 +15,12 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Treet::VERSION
|
17
17
|
|
18
|
-
gem.add_dependency '
|
18
|
+
gem.add_dependency 'thor'
|
19
|
+
gem.add_dependency 'rugged', "~> 0.17.0.b6"
|
19
20
|
|
20
|
-
gem.add_development_dependency "rake"
|
21
|
-
gem.add_development_dependency "rspec"
|
22
|
-
gem.add_development_dependency "guard-rspec"
|
23
|
-
gem.add_development_dependency "
|
21
|
+
gem.add_development_dependency "rake"
|
22
|
+
gem.add_development_dependency "rspec"
|
23
|
+
gem.add_development_dependency "guard-rspec"
|
24
|
+
gem.add_development_dependency "guard-minitest"
|
25
|
+
gem.add_development_dependency "ruby_gntp"
|
24
26
|
end
|