gitdocs 0.5.0.pre6 → 0.5.0.pre7
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.
- checksums.yaml +8 -8
- data/.gitignore +1 -0
- data/.haml-lint.yml +3 -0
- data/.jslint.yml +84 -0
- data/.rubocop.yml +13 -0
- data/CHANGELOG +11 -0
- data/README.md +6 -2
- data/Rakefile +22 -3
- data/gitdocs.gemspec +36 -29
- data/lib/gitdocs.rb +5 -2
- data/lib/gitdocs/cli.rb +31 -8
- data/lib/gitdocs/configuration.rb +95 -49
- data/lib/gitdocs/manager.rb +36 -28
- data/lib/gitdocs/migration/001_create_shares.rb +2 -0
- data/lib/gitdocs/migration/002_add_remote_branch.rb +2 -0
- data/lib/gitdocs/migration/003_create_configs.rb +2 -0
- data/lib/gitdocs/migration/004_add_index_for_path.rb +4 -0
- data/lib/gitdocs/migration/005_add_start_web_frontend.rb +2 -0
- data/lib/gitdocs/migration/006_add_web_port_to_config.rb +2 -0
- data/lib/gitdocs/migration/007_add_sync_type.rb +11 -0
- data/lib/gitdocs/notifier.rb +89 -6
- data/lib/gitdocs/public/img/file.png +0 -0
- data/lib/gitdocs/public/img/folder.png +0 -0
- data/lib/gitdocs/public/js/app.js +26 -11
- data/lib/gitdocs/public/js/edit.js +3 -3
- data/lib/gitdocs/public/js/settings.js +8 -5
- data/lib/gitdocs/public/js/util.js +21 -20
- data/lib/gitdocs/rendering.rb +14 -9
- data/lib/gitdocs/repository.rb +180 -216
- data/lib/gitdocs/repository/path.rb +166 -0
- data/lib/gitdocs/runner.rb +22 -65
- data/lib/gitdocs/search.rb +35 -0
- data/lib/gitdocs/server.rb +123 -86
- data/lib/gitdocs/version.rb +1 -1
- data/lib/gitdocs/views/_header.haml +6 -6
- data/lib/gitdocs/views/app.haml +17 -17
- data/lib/gitdocs/views/dir.haml +10 -10
- data/lib/gitdocs/views/edit.haml +8 -9
- data/lib/gitdocs/views/file.haml +1 -1
- data/lib/gitdocs/views/home.haml +4 -4
- data/lib/gitdocs/views/revisions.haml +6 -6
- data/lib/gitdocs/views/search.haml +6 -6
- data/lib/gitdocs/views/settings.haml +23 -16
- data/test/.rubocop.yml +13 -0
- data/test/integration/browse_test.rb +149 -0
- data/test/integration/full_sync_test.rb +3 -11
- data/test/integration/share_management_test.rb +59 -10
- data/test/integration/status_test.rb +2 -0
- data/test/integration/test_helper.rb +40 -7
- data/test/unit/configuration_test.rb +82 -0
- data/test/unit/notifier_test.rb +165 -0
- data/test/unit/repository_path_test.rb +368 -0
- data/test/{repository_test.rb → unit/repository_test.rb} +426 -245
- data/test/unit/runner_test.rb +122 -0
- data/test/unit/search_test.rb +52 -0
- data/test/{test_helper.rb → unit/test_helper.rb} +5 -0
- metadata +138 -41
- data/lib/gitdocs/docfile.rb +0 -23
- data/test/configuration_test.rb +0 -41
- data/test/notifier_test.rb +0 -68
- data/test/runner_test.rb +0 -123
@@ -0,0 +1,368 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require File.expand_path('../test_helper', __FILE__)
|
3
|
+
|
4
|
+
describe Gitdocs::Repository::Path do
|
5
|
+
let(:path) { Gitdocs::Repository::Path.new(repository, relative_path) }
|
6
|
+
let(:repository) { stub(root: local_repo_path) }
|
7
|
+
let(:local_repo_path) { 'tmp/unit/local' }
|
8
|
+
|
9
|
+
let(:relative_path) { 'directory/file' }
|
10
|
+
|
11
|
+
before do
|
12
|
+
FileUtils.rm_rf('tmp/unit')
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#write' do
|
16
|
+
subject { path.write('foobar', :message) }
|
17
|
+
before { repository.expects(:write_commit_message).with(:message) }
|
18
|
+
|
19
|
+
describe 'directory missing' do
|
20
|
+
before { subject }
|
21
|
+
it { local_file_content.must_equal "foobar\n" }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'directory exists' do
|
25
|
+
before do
|
26
|
+
mkdir('directory')
|
27
|
+
subject
|
28
|
+
end
|
29
|
+
it { local_file_content.must_equal "foobar\n" }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'file exists' do
|
33
|
+
before do
|
34
|
+
write('directory/file', 'deadbeef')
|
35
|
+
subject
|
36
|
+
end
|
37
|
+
it { local_file_content.must_equal "foobar\n" }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#touch' do
|
42
|
+
subject { path.touch }
|
43
|
+
|
44
|
+
describe 'when directory does not exist' do
|
45
|
+
before { subject }
|
46
|
+
it { local_file_content.must_equal '' }
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'when directory already exists' do
|
50
|
+
before do
|
51
|
+
mkdir('directory')
|
52
|
+
subject
|
53
|
+
end
|
54
|
+
it { local_file_content.must_equal '' }
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'when file already exists' do
|
58
|
+
before do
|
59
|
+
write('directory/file', 'test')
|
60
|
+
subject
|
61
|
+
end
|
62
|
+
it { local_file_content.must_equal 'test' }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#mkdir' do
|
67
|
+
subject { path.mkdir }
|
68
|
+
|
69
|
+
describe 'directory does not exist' do
|
70
|
+
before { subject }
|
71
|
+
it { File.directory?(File.join(local_repo_path, 'directory', 'file')) }
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'directory does exist' do
|
75
|
+
before do
|
76
|
+
mkdir('directory/file')
|
77
|
+
subject
|
78
|
+
end
|
79
|
+
it { File.directory?(File.join(local_repo_path, 'directory', 'file')) }
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'already exists as a file' do
|
83
|
+
before { write('directory/file', 'foobar') }
|
84
|
+
it { assert_raises(Errno::EEXIST) { subject } }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#remove' do
|
89
|
+
subject { path.remove }
|
90
|
+
|
91
|
+
describe 'missing' do
|
92
|
+
it { subject.must_be_nil }
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'directory' do
|
96
|
+
before { mkdir('directory/file') }
|
97
|
+
it { subject.must_be_nil }
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'file' do
|
101
|
+
before do
|
102
|
+
write('directory/file', 'foobar')
|
103
|
+
subject
|
104
|
+
end
|
105
|
+
it { local_file_exist?.must_equal false }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#text?' do
|
110
|
+
subject { path.text? }
|
111
|
+
|
112
|
+
describe 'missing' do
|
113
|
+
it { subject.must_equal false }
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'directory' do
|
117
|
+
before { mkdir('directory/file') }
|
118
|
+
it { subject.must_equal false }
|
119
|
+
end
|
120
|
+
|
121
|
+
describe 'not a text file' do
|
122
|
+
let(:relative_path) { 'directory/file.png' }
|
123
|
+
it { subject.must_equal false }
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'empty file' do
|
127
|
+
before { write('directory/file', '') }
|
128
|
+
it { subject.must_equal true }
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'text file' do
|
132
|
+
before { write('directory/file', 'foobar') }
|
133
|
+
it { subject.must_equal true }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#meta' do
|
138
|
+
subject { path.meta }
|
139
|
+
before do
|
140
|
+
repository.stubs(:last_commit_for).with(relative_path).returns(commit)
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'when missing' do
|
144
|
+
let(:commit) { nil }
|
145
|
+
it { assert_raises(RuntimeError) { subject } }
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'on a 'do
|
149
|
+
let(:commit) { stub(author: { name: :name, time: :time }) }
|
150
|
+
before do
|
151
|
+
write('directory0/file0', '')
|
152
|
+
write('directory/file1', 'foo')
|
153
|
+
write('directory/file2', 'bar')
|
154
|
+
end
|
155
|
+
|
156
|
+
describe 'file size 0' do
|
157
|
+
let(:relative_path) { 'directory0/file0' }
|
158
|
+
it { subject[:author].must_equal :name }
|
159
|
+
it { subject[:size].must_equal(-1) }
|
160
|
+
it { subject[:modified].must_equal :time }
|
161
|
+
end
|
162
|
+
|
163
|
+
describe 'file non-zero size' do
|
164
|
+
let(:relative_path) { 'directory/file1' }
|
165
|
+
it { subject[:author].must_equal :name }
|
166
|
+
it { subject[:size].must_equal(3) }
|
167
|
+
it { subject[:modified].must_equal :time }
|
168
|
+
end
|
169
|
+
|
170
|
+
describe 'directory size 0' do
|
171
|
+
let(:relative_path) { 'directory0' }
|
172
|
+
it { subject[:author].must_equal :name }
|
173
|
+
it { subject[:size].must_equal(-1) }
|
174
|
+
it { subject[:modified].must_equal :time }
|
175
|
+
end
|
176
|
+
|
177
|
+
describe 'directory non-zero size' do
|
178
|
+
let(:relative_path) { 'directory' }
|
179
|
+
it { subject[:author].must_equal :name }
|
180
|
+
it { subject[:size].must_equal(6) }
|
181
|
+
it { subject[:modified].must_equal :time }
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe '#exist?' do
|
187
|
+
subject { path.exist? }
|
188
|
+
|
189
|
+
describe 'missing' do
|
190
|
+
it { subject.must_equal false }
|
191
|
+
end
|
192
|
+
|
193
|
+
describe 'directory' do
|
194
|
+
before { mkdir('directory/file') }
|
195
|
+
it { subject.must_equal true }
|
196
|
+
end
|
197
|
+
|
198
|
+
describe 'file' do
|
199
|
+
before { write('directory/file', 'foobar') }
|
200
|
+
it { subject.must_equal true }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '#directory?' do
|
205
|
+
subject { path.directory? }
|
206
|
+
|
207
|
+
describe 'missing' do
|
208
|
+
it { subject.must_equal false }
|
209
|
+
end
|
210
|
+
|
211
|
+
describe 'directory' do
|
212
|
+
before { mkdir('directory/file') }
|
213
|
+
it { subject.must_equal true }
|
214
|
+
end
|
215
|
+
|
216
|
+
describe 'file' do
|
217
|
+
before { write('directory/file', 'foobar') }
|
218
|
+
it { subject.must_equal false }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe '#absolute_path' do
|
223
|
+
subject { path.absolute_path(ref) }
|
224
|
+
|
225
|
+
describe 'no revision' do
|
226
|
+
let(:ref) { nil }
|
227
|
+
it { subject.must_equal absolute_local_path }
|
228
|
+
end
|
229
|
+
|
230
|
+
describe 'with revision' do
|
231
|
+
let(:ref) { :ref }
|
232
|
+
before { repository.stubs(:blob_at).with(relative_path, :ref).returns(blob) }
|
233
|
+
|
234
|
+
describe 'no blob' do
|
235
|
+
let(:blob) { nil }
|
236
|
+
it { File.read(subject).must_equal "\n" }
|
237
|
+
end
|
238
|
+
|
239
|
+
describe 'has blob' do
|
240
|
+
let(:blob) { stub(text: 'beef') }
|
241
|
+
it { File.read(subject).must_equal "beef\n" }
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe '#readme_path' do
|
247
|
+
subject { path.readme_path }
|
248
|
+
|
249
|
+
describe 'no directory' do
|
250
|
+
it { subject.must_be_nil }
|
251
|
+
end
|
252
|
+
|
253
|
+
describe 'no README' do
|
254
|
+
before { mkdir('directory/file') }
|
255
|
+
it { subject.must_be_nil }
|
256
|
+
end
|
257
|
+
|
258
|
+
describe 'with README.md' do
|
259
|
+
before { write('directory/file/README.md', 'foobar') }
|
260
|
+
it { subject.must_equal absolute_local_path('README.md') }
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe '#file_listing' do
|
265
|
+
subject { path.file_listing }
|
266
|
+
|
267
|
+
describe 'missing' do
|
268
|
+
it { subject.must_be_nil }
|
269
|
+
end
|
270
|
+
|
271
|
+
describe 'file' do
|
272
|
+
before { write('directory/file', 'foobar') }
|
273
|
+
it { subject.must_be_nil }
|
274
|
+
end
|
275
|
+
|
276
|
+
describe 'directory' do
|
277
|
+
before do
|
278
|
+
write('directory/file/.hidden', 'beef')
|
279
|
+
mkdir('directory/file/dir1')
|
280
|
+
write('directory/file/file1', 'foo')
|
281
|
+
write('directory/file/file2', 'bar')
|
282
|
+
|
283
|
+
# Paths which should not be included
|
284
|
+
write('directory/file/.git', 'test')
|
285
|
+
write('directory/file/.gitignore', 'test')
|
286
|
+
write('directory/file/.gitmessage~', 'test')
|
287
|
+
end
|
288
|
+
|
289
|
+
it { subject.size.must_equal 4 }
|
290
|
+
it { subject.map(&:name).must_equal %w(dir1 file1 file2 .hidden) }
|
291
|
+
it { subject.map(&:is_directory).must_equal [true, false, false, false] }
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe '#content' do
|
296
|
+
subject { path.content }
|
297
|
+
|
298
|
+
describe 'missing' do
|
299
|
+
it { subject.must_be_nil }
|
300
|
+
end
|
301
|
+
|
302
|
+
describe 'directory' do
|
303
|
+
before { mkdir('directory/file') }
|
304
|
+
it { subject.must_be_nil }
|
305
|
+
end
|
306
|
+
|
307
|
+
describe 'file' do
|
308
|
+
before { write('directory/file', 'foobar') }
|
309
|
+
it { subject.must_equal 'foobar' }
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
describe '#revisions' do
|
314
|
+
subject { path.revisions }
|
315
|
+
|
316
|
+
before do
|
317
|
+
repository.stubs(:commits_for).returns([
|
318
|
+
stub(oid: '1234567890', message: "short1\nlong", author: { name: :name1, time: :time1 }),
|
319
|
+
stub(oid: '0987654321', message: "short2\nlong", author: { name: :name2, time: :time2 })
|
320
|
+
])
|
321
|
+
end
|
322
|
+
it { subject.size.must_equal(2) }
|
323
|
+
it { subject[0].must_equal(commit: '1234567', subject: 'short1', author: :name1, date: :time1) }
|
324
|
+
it { subject[1].must_equal(commit: '0987654', subject: 'short2', author: :name2, date: :time2) }
|
325
|
+
end
|
326
|
+
|
327
|
+
describe '#revert' do
|
328
|
+
subject { path.revert('ref') }
|
329
|
+
before { repository.expects(:blob_at).with(relative_path, 'ref').returns(blob) }
|
330
|
+
|
331
|
+
describe 'blob missing' do
|
332
|
+
let(:blob) { nil }
|
333
|
+
it { subject.must_equal(nil) }
|
334
|
+
end
|
335
|
+
|
336
|
+
describe 'blob present' do
|
337
|
+
let(:blob) { stub(text: 'deadbeef') }
|
338
|
+
before { path.expects(:write).with('deadbeef', "Reverting '#{relative_path}' to ref") }
|
339
|
+
it { subject }
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
#############################################################################
|
344
|
+
|
345
|
+
private
|
346
|
+
|
347
|
+
def write(filename, content)
|
348
|
+
mkdir(File.dirname(filename))
|
349
|
+
File.write(File.join(local_repo_path, filename), content)
|
350
|
+
end
|
351
|
+
|
352
|
+
def mkdir(*path)
|
353
|
+
FileUtils.mkdir_p(File.join(local_repo_path, *path))
|
354
|
+
end
|
355
|
+
|
356
|
+
def local_file_exist?
|
357
|
+
File.exist?(File.join(local_repo_path, relative_path))
|
358
|
+
end
|
359
|
+
|
360
|
+
def local_file_content
|
361
|
+
return nil unless local_file_exist?
|
362
|
+
File.read(File.join(local_repo_path, relative_path))
|
363
|
+
end
|
364
|
+
|
365
|
+
def absolute_local_path(*path_elements)
|
366
|
+
File.join(File.absolute_path(local_repo_path), relative_path, *path_elements)
|
367
|
+
end
|
368
|
+
end
|
@@ -48,11 +48,13 @@ describe Gitdocs::Repository do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
describe 'with a share that is a repository' do
|
51
|
-
let(:path_or_share)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
let(:path_or_share) do
|
52
|
+
stub(
|
53
|
+
path: local_repo_path,
|
54
|
+
remote_name: 'remote',
|
55
|
+
branch_name: 'branch'
|
56
|
+
)
|
57
|
+
end
|
56
58
|
it { subject.must_be_kind_of Gitdocs::Repository }
|
57
59
|
it { subject.valid?.must_equal true }
|
58
60
|
it { subject.invalid_reason.must_be_nil }
|
@@ -80,59 +82,6 @@ describe Gitdocs::Repository do
|
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
83
|
-
describe '.search' do
|
84
|
-
subject { Gitdocs::Repository.search('term', repositories) }
|
85
|
-
|
86
|
-
let(:repositories) { Array.new(4, stub(root: 'root')) }
|
87
|
-
before do
|
88
|
-
repositories[0].expects(:search).with('term').returns(:result1)
|
89
|
-
repositories[1].expects(:search).with('term').returns(:result2)
|
90
|
-
repositories[2].expects(:search).with('term').returns(:result3)
|
91
|
-
repositories[3].expects(:search).with('term').returns([])
|
92
|
-
end
|
93
|
-
|
94
|
-
it do
|
95
|
-
subject.must_equal({
|
96
|
-
Gitdocs::Repository::RepoDescriptor.new('root', 1) => :result3,
|
97
|
-
Gitdocs::Repository::RepoDescriptor.new('root', 2) => :result2,
|
98
|
-
Gitdocs::Repository::RepoDescriptor.new('root', 3) => :result1
|
99
|
-
})
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe '#search' do
|
104
|
-
subject { repository.search(term) }
|
105
|
-
|
106
|
-
describe 'empty term' do
|
107
|
-
let(:term) { '' }
|
108
|
-
it { subject.must_equal [] }
|
109
|
-
end
|
110
|
-
|
111
|
-
describe 'nothing found' do
|
112
|
-
let(:term) { 'foo' }
|
113
|
-
before do
|
114
|
-
write_and_commit('file1', 'bar', 'commit', author1)
|
115
|
-
write_and_commit('file2', 'beef', 'commit', author1)
|
116
|
-
end
|
117
|
-
it { subject.must_equal [] }
|
118
|
-
end
|
119
|
-
|
120
|
-
describe 'term found' do
|
121
|
-
let(:term) { 'foo' }
|
122
|
-
before do
|
123
|
-
write_and_commit('file1', 'foo', 'commit', author1)
|
124
|
-
write_and_commit('file2', 'beef', 'commit', author1)
|
125
|
-
write_and_commit('file3', 'foobar', 'commit', author1)
|
126
|
-
end
|
127
|
-
it do
|
128
|
-
subject.must_equal([
|
129
|
-
Gitdocs::Repository::SearchResult.new('file1', 'foo'),
|
130
|
-
Gitdocs::Repository::SearchResult.new('file3', 'foobar')
|
131
|
-
])
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
85
|
describe '#root' do
|
137
86
|
subject { repository.root }
|
138
87
|
|
@@ -185,158 +134,394 @@ describe Gitdocs::Repository do
|
|
185
134
|
end
|
186
135
|
end
|
187
136
|
|
188
|
-
describe '#
|
189
|
-
subject { repository.
|
137
|
+
describe '#dirty?' do
|
138
|
+
subject { repository.dirty? }
|
190
139
|
|
191
|
-
let(:path_or_share)
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
140
|
+
let(:path_or_share) do
|
141
|
+
stub(
|
142
|
+
path: local_repo_path,
|
143
|
+
remote_name: 'origin',
|
144
|
+
branch_name: 'master'
|
145
|
+
)
|
146
|
+
end
|
196
147
|
|
197
148
|
describe 'when invalid' do
|
198
149
|
let(:path_or_share) { 'tmp/unit/missing' }
|
199
|
-
it { subject.
|
150
|
+
it { subject.must_equal false }
|
200
151
|
end
|
201
152
|
|
202
|
-
describe 'when
|
203
|
-
|
153
|
+
describe 'when no existing commits' do
|
154
|
+
describe 'and no new files' do
|
155
|
+
it { subject.must_equal false }
|
156
|
+
end
|
157
|
+
|
158
|
+
describe 'and new files' do
|
159
|
+
before { write('file1', 'foobar') }
|
160
|
+
it { subject.must_equal true }
|
161
|
+
end
|
162
|
+
|
163
|
+
describe 'and new empty directory' do
|
164
|
+
before { mkdir('directory') }
|
165
|
+
it { subject.must_equal true }
|
166
|
+
end
|
204
167
|
end
|
205
168
|
|
206
|
-
describe '
|
207
|
-
before {
|
169
|
+
describe 'when commits exist' do
|
170
|
+
before { write_and_commit('file1', 'foobar', 'initial commit', author1) }
|
208
171
|
|
209
|
-
describe '
|
210
|
-
|
211
|
-
Grit::Repo.any_instance.stubs(:remote_fetch)
|
212
|
-
.raises(Grit::Git::CommandFailed.new('', 1, 'fetch error output'))
|
213
|
-
end
|
214
|
-
it { subject.must_equal 'fetch error output' }
|
172
|
+
describe 'and no changes' do
|
173
|
+
it { subject.must_equal false }
|
215
174
|
end
|
216
175
|
|
217
|
-
describe '
|
218
|
-
|
176
|
+
describe 'add empty directory' do
|
177
|
+
before { mkdir('directory') }
|
178
|
+
it { subject.must_equal false }
|
219
179
|
end
|
220
180
|
|
221
|
-
describe '
|
222
|
-
before {
|
223
|
-
it { subject.must_equal
|
224
|
-
it { subject ; commit_count(local_repo).must_equal 1 }
|
181
|
+
describe 'add file' do
|
182
|
+
before { write('file2', 'foobar') }
|
183
|
+
it { subject.must_equal true }
|
225
184
|
end
|
226
185
|
|
227
|
-
describe '
|
228
|
-
before
|
229
|
-
|
230
|
-
|
231
|
-
'file2', 'deadbeef',
|
232
|
-
'second commit',
|
233
|
-
'author@example.com', 'A U Thor'
|
234
|
-
)
|
235
|
-
end
|
186
|
+
describe 'modify existing file' do
|
187
|
+
before { write('file1', 'deadbeef') }
|
188
|
+
it { subject.must_equal true }
|
189
|
+
end
|
236
190
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
end
|
191
|
+
describe 'delete file' do
|
192
|
+
before { rm_rf('file1') }
|
193
|
+
it { subject.must_equal true }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
244
197
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
198
|
+
describe '#need_sync' do
|
199
|
+
subject { repository.need_sync? }
|
200
|
+
|
201
|
+
let(:path_or_share) do
|
202
|
+
stub(
|
203
|
+
path: local_repo_path,
|
204
|
+
remote_name: 'origin',
|
205
|
+
branch_name: 'master'
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
describe 'when invalid' do
|
210
|
+
let(:path_or_share) { 'tmp/unit/missing' }
|
211
|
+
it { subject.must_equal false }
|
212
|
+
end
|
213
|
+
|
214
|
+
describe 'when no remotes' do
|
215
|
+
it { subject.must_equal false }
|
216
|
+
end
|
217
|
+
|
218
|
+
describe 'when no remote commits' do
|
219
|
+
before { create_local_repo_with_remote }
|
220
|
+
|
221
|
+
describe 'no local commits' do
|
222
|
+
it { subject.must_equal false }
|
223
|
+
end
|
224
|
+
|
225
|
+
describe 'local commits' do
|
226
|
+
before { write_and_commit('file1', 'beef', 'conflict commit', author1) }
|
227
|
+
it { subject.must_equal true }
|
250
228
|
end
|
251
229
|
end
|
252
230
|
|
253
|
-
describe '
|
231
|
+
describe 'when remote commits' do
|
254
232
|
before { create_local_repo_with_remote_with_commit }
|
255
233
|
|
256
|
-
describe '
|
257
|
-
it { subject.must_equal
|
234
|
+
describe 'no local commits' do
|
235
|
+
it { subject.must_equal false }
|
236
|
+
end
|
237
|
+
|
238
|
+
describe 'new local commit' do
|
239
|
+
before { write_and_commit('file2', 'beef', 'conflict commit', author1) }
|
240
|
+
it { subject.must_equal true }
|
258
241
|
end
|
259
242
|
|
260
|
-
describe '
|
243
|
+
describe 'new remote commit' do
|
261
244
|
before do
|
262
245
|
bare_commit(
|
263
246
|
remote_repo,
|
264
|
-
'
|
247
|
+
'file3', 'dead',
|
265
248
|
'second commit',
|
266
249
|
'author@example.com', 'A U Thor'
|
267
250
|
)
|
268
|
-
|
251
|
+
repository.fetch
|
269
252
|
end
|
270
253
|
|
271
|
-
it { subject.must_equal
|
272
|
-
it { subject ; commit_count(local_repo).must_equal 2 }
|
273
|
-
it { subject ; local_file_count.must_equal 3 }
|
274
|
-
it { subject ; local_file_content('file1 (f6ea049 original)').must_equal 'foobar' }
|
275
|
-
it { subject ; local_file_content('file1 (18ed963)').must_equal 'beef' }
|
276
|
-
it { subject ; local_file_content('file1 (7bfce5c)').must_equal 'dead' }
|
254
|
+
it { subject.must_equal true }
|
277
255
|
end
|
278
256
|
|
279
|
-
describe '
|
257
|
+
describe 'new local and remote commit' do
|
280
258
|
before do
|
281
259
|
bare_commit(
|
282
260
|
remote_repo,
|
283
|
-
'
|
284
|
-
'second commit',
|
285
|
-
'author@example.com', 'A U Thor'
|
286
|
-
)
|
287
|
-
bare_commit(
|
288
|
-
remote_repo,
|
289
|
-
'file2', 'foo',
|
261
|
+
'file3', 'dead',
|
290
262
|
'second commit',
|
291
263
|
'author@example.com', 'A U Thor'
|
292
264
|
)
|
293
|
-
|
265
|
+
repository.fetch
|
266
|
+
write_and_commit('file4', 'beef', 'conflict commit', author1)
|
294
267
|
end
|
295
268
|
|
296
|
-
it { subject.must_equal
|
297
|
-
it { subject ; commit_count(local_repo).must_equal 2 }
|
298
|
-
it { subject ; local_file_count.must_equal 3 }
|
299
|
-
it { subject ; local_file_content('file1 (f6ea049 original)').must_equal 'foobar' }
|
300
|
-
it { subject ; local_file_content('file1 (18ed963)').must_equal 'beef' }
|
301
|
-
it { subject ; local_file_content('file2').must_equal 'foo' }
|
269
|
+
it { subject.must_equal true }
|
302
270
|
end
|
271
|
+
end
|
272
|
+
end
|
303
273
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
274
|
+
describe '#grep' do
|
275
|
+
subject { repository.grep('foo') { |file, context| @grep_result << "#{file} #{context}" } }
|
276
|
+
|
277
|
+
before { @grep_result = [] }
|
278
|
+
|
279
|
+
describe 'timeout' do
|
280
|
+
before do
|
281
|
+
Grit::Repo.any_instance.stubs(:remote_fetch)
|
282
|
+
.raises(Grit::Git::GitTimeout.new)
|
283
|
+
end
|
284
|
+
it { subject ; @grep_result.must_equal([]) }
|
285
|
+
it { subject.must_equal '' }
|
286
|
+
end
|
287
|
+
|
288
|
+
describe 'command failure' do
|
289
|
+
before do
|
290
|
+
Grit::Repo.any_instance.stubs(:remote_fetch)
|
291
|
+
.raises(Grit::Git::CommandFailed.new('', 1, 'grep error output'))
|
292
|
+
end
|
293
|
+
it { subject ; @grep_result.must_equal([]) }
|
294
|
+
it { subject.must_equal '' }
|
295
|
+
end
|
296
|
+
|
297
|
+
describe 'success' do
|
298
|
+
before do
|
299
|
+
write_and_commit('file1', 'foo', 'commit', author1)
|
300
|
+
write_and_commit('file2', 'beef', 'commit', author1)
|
301
|
+
write_and_commit('file3', 'foobar', 'commit', author1)
|
302
|
+
write_and_commit('file4', "foo\ndead\nbeef\nfoobar", 'commit', author1)
|
303
|
+
end
|
304
|
+
it { subject ; @grep_result.must_equal(['file1 foo', 'file3 foobar', 'file4 foo', 'file4 foobar']) }
|
305
|
+
it { subject.must_equal("file1:foo\nfile3:foobar\nfile4:foo\nfile4:foobar\n") }
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
describe '#fetch' do
|
310
|
+
subject { repository.fetch }
|
311
|
+
|
312
|
+
describe 'when invalid' do
|
313
|
+
let(:path_or_share) { 'tmp/unit/missing' }
|
314
|
+
it { subject.must_be_nil }
|
315
|
+
end
|
316
|
+
|
317
|
+
describe 'when no remote' do
|
318
|
+
it { subject.must_equal :no_remote }
|
319
|
+
end
|
320
|
+
|
321
|
+
describe 'with remote' do
|
322
|
+
before { create_local_repo_with_remote }
|
323
|
+
|
324
|
+
describe 'and times out' do
|
325
|
+
before do
|
326
|
+
Grit::Repo.any_instance.stubs(:remote_fetch)
|
327
|
+
.raises(Grit::Git::GitTimeout.new)
|
328
|
+
end
|
329
|
+
it { subject.must_equal "Fetch timed out for #{File.absolute_path(local_repo_path)}" }
|
330
|
+
end
|
331
|
+
|
332
|
+
describe 'and command fails' do
|
333
|
+
before do
|
334
|
+
Grit::Repo.any_instance.stubs(:remote_fetch)
|
335
|
+
.raises(Grit::Git::CommandFailed.new('', 1, 'fetch error output'))
|
336
|
+
end
|
337
|
+
it { subject.must_equal 'fetch error output' }
|
308
338
|
end
|
309
339
|
|
310
|
-
describe '
|
340
|
+
describe 'and success' do
|
311
341
|
before do
|
312
342
|
bare_commit(
|
313
343
|
remote_repo,
|
314
|
-
'
|
315
|
-
'
|
316
|
-
'author@example.com', 'A U Thor'
|
344
|
+
'file1', 'deadbeef',
|
345
|
+
'commit', 'author@example.com', 'A U Thor'
|
317
346
|
)
|
318
347
|
end
|
319
348
|
it { subject.must_equal :ok }
|
320
|
-
|
321
|
-
|
349
|
+
|
350
|
+
describe 'side effects' do
|
351
|
+
before { subject }
|
352
|
+
it { local_repo_remote_branch.tip.oid.wont_be_nil }
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
describe '#merge' do
|
359
|
+
subject { repository.merge }
|
360
|
+
|
361
|
+
let(:path_or_share) do
|
362
|
+
stub(
|
363
|
+
path: local_repo_path,
|
364
|
+
remote_name: 'origin',
|
365
|
+
branch_name: 'master'
|
366
|
+
)
|
367
|
+
end
|
368
|
+
|
369
|
+
describe 'when invalid' do
|
370
|
+
let(:path_or_share) { 'tmp/unit/missing' }
|
371
|
+
it { subject.must_be_nil }
|
372
|
+
end
|
373
|
+
|
374
|
+
describe 'when no remote' do
|
375
|
+
it { subject.must_equal :no_remote }
|
376
|
+
end
|
377
|
+
|
378
|
+
describe 'has remote but nothing to merge' do
|
379
|
+
before { create_local_repo_with_remote }
|
380
|
+
it { subject.must_equal :ok }
|
381
|
+
end
|
382
|
+
|
383
|
+
describe 'has remote and times out' do
|
384
|
+
before do
|
385
|
+
create_local_repo_with_remote
|
386
|
+
bare_commit(
|
387
|
+
remote_repo,
|
388
|
+
'file1', 'deadbeef',
|
389
|
+
'commit', 'author@example.com', 'A U Thor'
|
390
|
+
)
|
391
|
+
repository.fetch
|
392
|
+
|
393
|
+
Grit::Git.any_instance.stubs(:merge)
|
394
|
+
.raises(Grit::Git::GitTimeout.new)
|
395
|
+
end
|
396
|
+
it { subject.must_equal "Merge timed out for #{File.absolute_path(local_repo_path)}" }
|
397
|
+
end
|
398
|
+
|
399
|
+
describe 'and fails, but does not conflict' do
|
400
|
+
before do
|
401
|
+
create_local_repo_with_remote
|
402
|
+
bare_commit(
|
403
|
+
remote_repo,
|
404
|
+
'file1', 'deadbeef',
|
405
|
+
'commit', 'author@example.com', 'A U Thor'
|
406
|
+
)
|
407
|
+
repository.fetch
|
408
|
+
|
409
|
+
Grit::Git.any_instance.stubs(:merge)
|
410
|
+
.raises(Grit::Git::CommandFailed.new('', 1, 'merge error output'))
|
411
|
+
end
|
412
|
+
it { subject.must_equal 'merge error output' }
|
413
|
+
end
|
414
|
+
|
415
|
+
describe 'and there is a conflict' do
|
416
|
+
before do
|
417
|
+
create_local_repo_with_remote_with_commit
|
418
|
+
bare_commit(
|
419
|
+
remote_repo,
|
420
|
+
'file1', 'dead',
|
421
|
+
'second commit',
|
422
|
+
'author@example.com', 'A U Thor'
|
423
|
+
)
|
424
|
+
write_and_commit('file1', 'beef', 'conflict commit', author1)
|
425
|
+
repository.fetch
|
426
|
+
end
|
427
|
+
|
428
|
+
it { subject.must_equal ['file1'] }
|
429
|
+
|
430
|
+
describe 'side effects' do
|
431
|
+
before { subject }
|
432
|
+
it { commit_count(local_repo).must_equal 2 }
|
433
|
+
it { local_file_count.must_equal 3 }
|
434
|
+
it { local_file_content('file1 (f6ea049 original)').must_equal 'foobar' }
|
435
|
+
it { local_file_content('file1 (18ed963)').must_equal 'beef' }
|
436
|
+
it { local_file_content('file1 (7bfce5c)').must_equal 'dead' }
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
describe 'and there is a conflict, with additional files' do
|
441
|
+
before do
|
442
|
+
create_local_repo_with_remote_with_commit
|
443
|
+
bare_commit(
|
444
|
+
remote_repo,
|
445
|
+
'file1', 'dead',
|
446
|
+
'second commit',
|
447
|
+
'author@example.com', 'A U Thor'
|
448
|
+
)
|
449
|
+
bare_commit(
|
450
|
+
remote_repo,
|
451
|
+
'file2', 'foo',
|
452
|
+
'second commit',
|
453
|
+
'author@example.com', 'A U Thor'
|
454
|
+
)
|
455
|
+
write_and_commit('file1', 'beef', 'conflict commit', author1)
|
456
|
+
repository.fetch
|
457
|
+
end
|
458
|
+
|
459
|
+
it { subject.must_equal ['file1'] }
|
460
|
+
|
461
|
+
describe 'side effects' do
|
462
|
+
before { subject }
|
463
|
+
it { commit_count(local_repo).must_equal 2 }
|
464
|
+
it { local_file_count.must_equal 3 }
|
465
|
+
it { local_file_content('file1 (f6ea049 original)').must_equal 'foobar' }
|
466
|
+
it { local_file_content('file1 (18ed963)').must_equal 'beef' }
|
467
|
+
it { local_file_content('file2').must_equal 'foo' }
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
describe 'and there are non-conflicted local commits' do
|
472
|
+
before do
|
473
|
+
create_local_repo_with_remote_with_commit
|
474
|
+
write_and_commit('file1', 'beef', 'conflict commit', author1)
|
475
|
+
repository.fetch
|
476
|
+
end
|
477
|
+
it { subject.must_equal :ok }
|
478
|
+
|
479
|
+
describe 'side effects' do
|
480
|
+
before { subject }
|
481
|
+
it { local_file_count.must_equal 1 }
|
482
|
+
it { commit_count(local_repo).must_equal 2 }
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe 'when new remote commits are merged' do
|
487
|
+
before do
|
488
|
+
create_local_repo_with_remote_with_commit
|
489
|
+
bare_commit(
|
490
|
+
remote_repo,
|
491
|
+
'file2', 'deadbeef',
|
492
|
+
'second commit',
|
493
|
+
'author@example.com', 'A U Thor'
|
494
|
+
)
|
495
|
+
repository.fetch
|
496
|
+
end
|
497
|
+
it { subject.must_equal :ok }
|
498
|
+
|
499
|
+
describe 'side effects' do
|
500
|
+
before { subject }
|
501
|
+
it { local_file_exist?('file2').must_equal true }
|
502
|
+
it { commit_count(local_repo).must_equal 2 }
|
322
503
|
end
|
323
504
|
end
|
324
505
|
end
|
325
506
|
|
326
507
|
describe '#commit' do
|
327
|
-
subject { repository.commit
|
508
|
+
subject { repository.commit }
|
328
509
|
|
329
|
-
let(:path_or_share)
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
510
|
+
let(:path_or_share) do
|
511
|
+
stub(
|
512
|
+
path: local_repo_path,
|
513
|
+
remote_name: 'origin',
|
514
|
+
branch_name: 'master'
|
515
|
+
)
|
516
|
+
end
|
334
517
|
|
335
518
|
describe 'when invalid' do
|
336
519
|
let(:path_or_share) { 'tmp/unit/missing' }
|
337
520
|
it { subject.must_be_nil }
|
338
521
|
end
|
339
522
|
|
523
|
+
# TODO: should test the paths which use the message file
|
524
|
+
|
340
525
|
describe 'no previous commits' do
|
341
526
|
describe 'nothing to commit' do
|
342
527
|
it { subject.must_equal false }
|
@@ -348,10 +533,14 @@ describe Gitdocs::Repository do
|
|
348
533
|
mkdir('directory')
|
349
534
|
end
|
350
535
|
it { subject.must_equal true }
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
536
|
+
|
537
|
+
describe 'side effects' do
|
538
|
+
before { subject }
|
539
|
+
it { local_file_exist?('directory/.gitignore').must_equal true }
|
540
|
+
it { commit_count(local_repo).must_equal 1 }
|
541
|
+
it { head_commit(local_repo).message.must_equal "Auto-commit from gitdocs\n" }
|
542
|
+
it { local_repo_clean?.must_equal true }
|
543
|
+
end
|
355
544
|
end
|
356
545
|
end
|
357
546
|
|
@@ -368,15 +557,19 @@ describe Gitdocs::Repository do
|
|
368
557
|
describe 'changes to commit' do
|
369
558
|
before do
|
370
559
|
write('file1', 'foobar')
|
371
|
-
|
560
|
+
rm_rf('file2')
|
372
561
|
write('file3', 'foobar')
|
373
562
|
mkdir('directory')
|
374
563
|
end
|
375
564
|
it { subject.must_equal true }
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
565
|
+
|
566
|
+
describe 'side effects' do
|
567
|
+
before { subject }
|
568
|
+
it { local_file_exist?('directory/.gitignore').must_equal true }
|
569
|
+
it { commit_count(local_repo).must_equal 3 }
|
570
|
+
it { head_commit(local_repo).message.must_equal "Auto-commit from gitdocs\n" }
|
571
|
+
it { local_repo_clean?.must_equal true }
|
572
|
+
end
|
380
573
|
end
|
381
574
|
end
|
382
575
|
end
|
@@ -384,11 +577,13 @@ describe Gitdocs::Repository do
|
|
384
577
|
describe '#push' do
|
385
578
|
subject { repository.push }
|
386
579
|
|
387
|
-
let(:path_or_share)
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
580
|
+
let(:path_or_share) do
|
581
|
+
stub(
|
582
|
+
path: local_repo_path,
|
583
|
+
remote_name: 'origin',
|
584
|
+
branch_name: 'master'
|
585
|
+
)
|
586
|
+
end
|
392
587
|
|
393
588
|
describe 'when invalid' do
|
394
589
|
let(:path_or_share) { 'tmp/unit/missing' }
|
@@ -404,7 +599,11 @@ describe Gitdocs::Repository do
|
|
404
599
|
|
405
600
|
describe 'and no local commits' do
|
406
601
|
it { subject.must_equal :nothing }
|
407
|
-
|
602
|
+
|
603
|
+
describe 'side effects' do
|
604
|
+
before { subject }
|
605
|
+
it { commit_count(remote_repo).must_equal 0 }
|
606
|
+
end
|
408
607
|
end
|
409
608
|
|
410
609
|
describe 'and a local commit' do
|
@@ -421,7 +620,11 @@ describe Gitdocs::Repository do
|
|
421
620
|
|
422
621
|
describe 'and the push succeeds' do
|
423
622
|
it { subject.must_equal :ok }
|
424
|
-
|
623
|
+
|
624
|
+
describe 'side effects' do
|
625
|
+
before { subject }
|
626
|
+
it { commit_count(remote_repo).must_equal 1 }
|
627
|
+
end
|
425
628
|
end
|
426
629
|
end
|
427
630
|
end
|
@@ -431,7 +634,11 @@ describe Gitdocs::Repository do
|
|
431
634
|
|
432
635
|
describe 'and no local commits' do
|
433
636
|
it { subject.must_equal :nothing }
|
434
|
-
|
637
|
+
|
638
|
+
describe 'side effects' do
|
639
|
+
before { subject }
|
640
|
+
it { commit_count(remote_repo).must_equal 1 }
|
641
|
+
end
|
435
642
|
end
|
436
643
|
|
437
644
|
describe 'and a local commit' do
|
@@ -449,13 +656,21 @@ describe Gitdocs::Repository do
|
|
449
656
|
describe 'and the push conflicts' do
|
450
657
|
before { bare_commit(remote_repo, 'file2', 'dead', 'commit', 'A U Thor', 'author@example.com') }
|
451
658
|
|
452
|
-
it { subject ; commit_count(remote_repo).must_equal 2 }
|
453
659
|
it { subject.must_equal :conflict }
|
660
|
+
|
661
|
+
describe 'side effects' do
|
662
|
+
before { subject }
|
663
|
+
it { commit_count(remote_repo).must_equal 2 }
|
664
|
+
end
|
454
665
|
end
|
455
666
|
|
456
667
|
describe 'and the push succeeds' do
|
457
668
|
it { subject.must_equal :ok }
|
458
|
-
|
669
|
+
|
670
|
+
describe 'side effects' do
|
671
|
+
before { subject }
|
672
|
+
it { commit_count(remote_repo).must_equal 2 }
|
673
|
+
end
|
459
674
|
end
|
460
675
|
end
|
461
676
|
end
|
@@ -479,12 +694,12 @@ describe Gitdocs::Repository do
|
|
479
694
|
|
480
695
|
describe 'all' do
|
481
696
|
let(:last_oid) { nil }
|
482
|
-
it { subject.must_equal(
|
697
|
+
it { subject.must_equal(author1 => 3, author2 => 1) }
|
483
698
|
end
|
484
699
|
|
485
700
|
describe 'some' do
|
486
701
|
let(:last_oid) { @intermediate_oid }
|
487
|
-
it { subject.must_equal(
|
702
|
+
it { subject.must_equal(author1 => 2, author2 => 1) }
|
488
703
|
end
|
489
704
|
|
490
705
|
describe 'missing oid' do
|
@@ -494,110 +709,67 @@ describe Gitdocs::Repository do
|
|
494
709
|
end
|
495
710
|
end
|
496
711
|
|
497
|
-
describe '#
|
498
|
-
subject { repository.
|
712
|
+
describe '#write_commit_message' do
|
713
|
+
subject { repository.write_commit_message(commit_message) }
|
714
|
+
before { subject }
|
499
715
|
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
write_and_commit('directory/file2', 'bar', 'commit2', author2)
|
504
|
-
write_and_commit('directory/file2', 'beef', 'commit3', author2)
|
505
|
-
end
|
506
|
-
|
507
|
-
describe 'on a missing file' do
|
508
|
-
let(:file_name) { 'missing_file' }
|
509
|
-
it { assert_raises(RuntimeError) { subject } }
|
716
|
+
describe 'with missing message' do
|
717
|
+
let(:commit_message) { nil }
|
718
|
+
it { local_file_exist?('.gitmessage~').must_equal(false) }
|
510
719
|
end
|
511
720
|
|
512
|
-
describe '
|
513
|
-
|
514
|
-
|
515
|
-
it { subject[:author].must_equal 'Art T. Fish' }
|
516
|
-
it { subject[:size].must_equal -1 }
|
517
|
-
it { subject[:modified].wont_be_nil }
|
518
|
-
end
|
519
|
-
|
520
|
-
describe 'of non-zero size' do
|
521
|
-
let(:file_name) { 'directory/file1' }
|
522
|
-
it { subject[:author].must_equal 'Art T. Fish' }
|
523
|
-
it { subject[:size].must_equal 3 }
|
524
|
-
it { subject[:modified].wont_be_nil }
|
525
|
-
end
|
721
|
+
describe 'with empty message' do
|
722
|
+
let(:commit_message) { '' }
|
723
|
+
it { local_file_exist?('.gitmessage~').must_equal(false) }
|
526
724
|
end
|
527
725
|
|
528
|
-
describe '
|
529
|
-
|
530
|
-
|
531
|
-
it { subject[:author].must_equal 'Art T. Fish' }
|
532
|
-
it { subject[:size].must_equal -1 }
|
533
|
-
it { subject[:modified].wont_be_nil }
|
534
|
-
end
|
535
|
-
|
536
|
-
describe 'of non-zero size' do
|
537
|
-
let(:file_name) { 'directory' }
|
538
|
-
it { subject[:author].must_equal 'A U Thor' }
|
539
|
-
it { subject[:size].must_equal 7 }
|
540
|
-
it { subject[:modified].wont_be_nil }
|
541
|
-
end
|
726
|
+
describe 'with valid message' do
|
727
|
+
let(:commit_message) { 'foobar' }
|
728
|
+
it { local_file_content('.gitmessage~').must_equal('foobar') }
|
542
729
|
end
|
543
730
|
end
|
544
731
|
|
545
|
-
describe '#
|
546
|
-
subject { repository.
|
732
|
+
describe '#commits_for' do
|
733
|
+
subject { repository.commits_for('directory/file', 2) }
|
547
734
|
|
548
735
|
before do
|
549
736
|
write_and_commit('directory0/file0', '', 'initial commit', author1)
|
550
|
-
|
551
|
-
@commit2 = write_and_commit('directory/
|
552
|
-
@commit3 = write_and_commit('directory/
|
737
|
+
write_and_commit('directory/file', 'foo', 'commit1', author1)
|
738
|
+
@commit2 = write_and_commit('directory/file', 'bar', 'commit2', author2)
|
739
|
+
@commit3 = write_and_commit('directory/file', 'beef', 'commit3', author2)
|
553
740
|
end
|
554
741
|
|
555
|
-
it { subject.
|
556
|
-
it { subject.map { |x| x[:author] }.must_equal ['A U Thor', 'A U Thor', 'Art T. Fish'] }
|
557
|
-
it { subject.map { |x| x[:commit] }.must_equal [@commit3[0, 7], @commit2[0, 7], @commit1[0, 7]] }
|
558
|
-
it { subject.map { |x| x[:subject] }.must_equal ['commit3', 'commit2', 'commit1'] }
|
742
|
+
it { subject.map(&:oid).must_equal([@commit3, @commit2]) }
|
559
743
|
end
|
560
744
|
|
561
|
-
describe '#
|
562
|
-
subject { repository.
|
745
|
+
describe '#last_commit_for' do
|
746
|
+
subject { repository.last_commit_for('directory/file') }
|
563
747
|
|
564
748
|
before do
|
565
|
-
write_and_commit('
|
566
|
-
write_and_commit('directory/
|
567
|
-
write_and_commit('directory/
|
568
|
-
@commit = write_and_commit('directory/file2', 'beef', 'commit3', author2)
|
749
|
+
write_and_commit('directory/file', 'foo', 'commit1', author1)
|
750
|
+
write_and_commit('directory/file', 'bar', 'commit2', author2)
|
751
|
+
@commit3 = write_and_commit('directory/file', 'beef', 'commit3', author2)
|
569
752
|
end
|
570
753
|
|
571
|
-
it { subject.must_equal
|
572
|
-
it { File.read(subject).must_equal "beef\n" }
|
754
|
+
it { subject.oid.must_equal(@commit3) }
|
573
755
|
end
|
574
756
|
|
575
|
-
describe '#
|
576
|
-
subject { repository.
|
577
|
-
|
578
|
-
let(:file_name) { File.join(local_repo_path, 'directory', 'file2') }
|
757
|
+
describe '#blob_at' do
|
758
|
+
subject { repository.blob_at('directory/file', @commit) }
|
579
759
|
|
580
760
|
before do
|
581
|
-
|
582
|
-
write_and_commit('directory/
|
583
|
-
|
584
|
-
write_and_commit('directory/file2', 'beef', 'commit3', author2)
|
585
|
-
end
|
586
|
-
|
587
|
-
describe 'file does not include the revision' do
|
588
|
-
let(:ref) { @commit0 }
|
589
|
-
it { subject ; local_file_content('directory', 'file2').must_equal 'beef' }
|
761
|
+
write_and_commit('directory/file', 'foo', 'commit1', author1)
|
762
|
+
@commit = write_and_commit('directory/file', 'bar', 'commit2', author2)
|
763
|
+
write_and_commit('directory/file', 'beef', 'commit3', author2)
|
590
764
|
end
|
591
765
|
|
592
|
-
|
593
|
-
let(:ref) { @commit2 }
|
594
|
-
it { subject ; local_file_content('directory', 'file2').must_equal "bar\n" }
|
595
|
-
end
|
766
|
+
it { subject.text.must_equal('bar') }
|
596
767
|
end
|
597
768
|
|
598
769
|
##############################################################################
|
599
770
|
|
600
771
|
private
|
772
|
+
|
601
773
|
def create_local_repo_with_remote
|
602
774
|
FileUtils.rm_rf(local_repo_path)
|
603
775
|
repo = Rugged::Repository.clone_at(remote_repo.path, local_repo_path)
|
@@ -627,6 +799,10 @@ describe Gitdocs::Repository do
|
|
627
799
|
File.write(File.join(local_repo_path, filename), content)
|
628
800
|
end
|
629
801
|
|
802
|
+
def rm_rf(filename)
|
803
|
+
FileUtils.rm_rf(File.join(local_repo_path, filename))
|
804
|
+
end
|
805
|
+
|
630
806
|
def write_and_commit(filename, content, commit_msg, author)
|
631
807
|
mkdir(File.dirname(filename))
|
632
808
|
File.write(File.join(local_repo_path, filename), content)
|
@@ -634,7 +810,7 @@ describe Gitdocs::Repository do
|
|
634
810
|
`cd #{local_repo_path} ; git rev-parse HEAD`.strip
|
635
811
|
end
|
636
812
|
|
637
|
-
def bare_commit(repo, filename, content, message, email, name)
|
813
|
+
def bare_commit(repo, filename, content, message, email, name) # rubocop:disable ParameterLists
|
638
814
|
index = Rugged::Index.new
|
639
815
|
index.add(
|
640
816
|
path: filename,
|
@@ -642,14 +818,15 @@ describe Gitdocs::Repository do
|
|
642
818
|
mode: 0100644
|
643
819
|
)
|
644
820
|
|
645
|
-
Rugged::Commit.create(
|
821
|
+
Rugged::Commit.create(
|
822
|
+
remote_repo,
|
646
823
|
tree: index.write_tree(repo),
|
647
824
|
author: { email: email, name: name, time: Time.now },
|
648
825
|
committer: { email: email, name: name, time: Time.now },
|
649
826
|
message: message,
|
650
|
-
parents: repo.empty? ? [] : [
|
827
|
+
parents: repo.empty? ? [] : [repo.head.target].compact,
|
651
828
|
update_ref: 'HEAD'
|
652
|
-
|
829
|
+
)
|
653
830
|
end
|
654
831
|
|
655
832
|
def commit_count(repo)
|
@@ -680,6 +857,10 @@ describe Gitdocs::Repository do
|
|
680
857
|
files.count
|
681
858
|
end
|
682
859
|
|
860
|
+
def local_repo_remote_branch
|
861
|
+
Rugged::Branch.lookup(local_repo, 'origin/master', :remote)
|
862
|
+
end
|
863
|
+
|
683
864
|
def local_repo_clean?
|
684
865
|
local_repo.diff_workdir(local_repo.head.target, include_untracked: true).deltas.empty?
|
685
866
|
end
|