gitdocs 0.5.0.pre3 → 0.5.0.pre5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MWMzMjFmOGM0ZDE0OTBhMjVlNmIxYzIzNGZhODFhOGYyZDhiN2YyYw==
4
+ YzYxMWM5MTg3ZWYzMzllZDNhY2NiNDdlNTA2NmNmMWEyNTVjMzFkNQ==
5
5
  data.tar.gz: !binary |-
6
- NmFmYWFiOWE2M2Y0YTVkNDVlMThmY2UwZmNkNjNjZWM1YjE5NDVkMg==
6
+ Njc0MTAxYjFlODI1ZjE5NjdmZGE0YmNmODc2MmJkMDc4NWQ5MzY5Ng==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YmM0ODM5NWM2ODg0OTc3YWEyMTZmNWIyYWI3NDBmZjQxODg4OTdiNjFiYjU1
10
- OWRhZWNhNzljOWIzY2Q3MmNmZjYzNThiMTY5NWQ1NTJlYWMyN2RjZDliYTc2
11
- MDRhOTg0ZTlmYmRkYWM5MjA0Zjk1ODA1ZjE0NjBkZGYwMjEyZDI=
9
+ NDFkODRiMDJjMGU3MWNkZGY4NjdhZWQ4OTM3N2EyNjRiNjM5MjAwYmQ5NWQ1
10
+ MTBlZTA5NGFkNWU1ODM2MWJhYmY1NWI0NDg3ZmVhMGI1YTBjODY0MTE1YjQ4
11
+ Njc1YjIyN2ZjMjAyN2M3YjZiNWM1OGE2ZDViMmZjOTgxZjkwMTY=
12
12
  data.tar.gz: !binary |-
13
- ZjQxM2EwMDNhY2RkMGUwNjMzMTVmMmM4YWNkZTkwMGZhNDYzYTQzMGQyZjUw
14
- ZTdlMDg2NjgzZjU0NmNiZDA4ZmQwYWU3MWI3YjYxMDk4MzM5Y2I3MzU0ODI3
15
- M2E1ZGNhNTNhMDg1MGYwYjYzNjU3ZmE3NDFjYzk2YjgxZTZhNzY=
13
+ NzRjMzZmZDRhZjUzZDAyODNhMzRjNjFmNGRjZmViZmM5OTk1MzkzMWZmYzA2
14
+ ODMxMmNiY2U0NTVkOGEwODIyM2UxZTJkMTZiN2I2MWE0YzZkMjNjOTM4Mjkx
15
+ YjUzMzNjMTIzZmUzMzIzZGQ1ZDRkYjQ5OTQxODNiNzE0NTgyNzQ=
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ 0.5.0.pre5 (May 14th 2014)
2
+
3
+ * Cleanup behavior on empty commits
4
+ * Improve pre-commit working directory change
5
+ * More rugged / grit conversions
6
+ * Update remote check to rugged
7
+ * Re-write empty directory tagging to use Find
8
+
9
+ 0.5.0.pre4 (April 15th 2014)
10
+
11
+ * Fix a performance bug related to using Rugged for the "push" (@acant)
12
+
1
13
  0.5.0.pre3 (3/30/2014)
2
14
 
3
15
  * Eliminate sleep from sync integration test (@acant)
@@ -1,14 +1,14 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ require 'find'
2
3
 
3
4
  # Wrapper for accessing the shared git repositories.
4
- # Rugged, grit, or shell will be used in that order of preference depending
5
+ # Rugged or Grit will be used, in that order of preference, depending
5
6
  # upon the features which are available with each option.
6
7
  #
7
8
  # @note If a repository is invalid then query methods will return nil, and
8
9
  # command methods will raise exceptions.
9
10
  #
10
11
  class Gitdocs::Repository
11
- include ShellTools
12
12
  attr_reader :invalid_reason
13
13
 
14
14
  # Initialize the repository on the specified path. If the path is not valid
@@ -26,9 +26,10 @@ class Gitdocs::Repository
26
26
  @branch_name = path_or_share.branch_name
27
27
  end
28
28
 
29
- @rugged = Rugged::Repository.new(path)
30
- @grit = Grit::Repo.new(path)
31
- @invalid_reason = nil
29
+ @rugged = Rugged::Repository.new(path)
30
+ @grit = Grit::Repo.new(path)
31
+ Grit::Git.git_timeout = 120
32
+ @invalid_reason = nil
32
33
  rescue Rugged::OSError
33
34
  @invalid_reason = :directory_missing
34
35
  rescue Rugged::RepositoryError
@@ -129,6 +130,7 @@ class Gitdocs::Repository
129
130
  Rugged::Branch.each_name(@rugged, :local).sort
130
131
  end
131
132
 
133
+ # @return [nil] if there are no commits present
132
134
  # @return [String] oid of the HEAD of the working directory
133
135
  def current_oid
134
136
  @rugged.head.target
@@ -150,33 +152,45 @@ class Gitdocs::Repository
150
152
  return nil unless valid?
151
153
  return :no_remote unless has_remote?
152
154
 
153
- out, status = sh_with_code("cd #{root} ; git fetch --all 2>/dev/null && git merge #{@remote_name}/#{@branch_name} 2>/dev/null")
154
-
155
- if status.success?
156
- :ok
157
- elsif out[/CONFLICT/]
158
- # Find the conflicted files
159
- conflicted_files = sh('git ls-files -u --full-name -z').split("\0")
160
- .reduce(Hash.new { |h, k| h[k] = [] }) do|h, line|
161
- parts = line.split(/\t/)
162
- h[parts.last] << parts.first.split(/ /)
163
- h
164
- end
165
-
166
- # Mark the conflicted files
167
- conflicted_files.each do |conflict, ids|
168
- conflict_start, conflict_end = conflict.scan(/(.*?)(|\.[^\.]+)$/).first
169
- ids.each do |(mode, sha, id)|
170
- author = ' original' if id == '1'
171
- system("cd #{root} && git show :#{id}:#{conflict} > '#{conflict_start} (#{sha[0..6]}#{author})#{conflict_end}'")
172
- end
173
- system("cd #{root} && git rm --quiet #{conflict} >/dev/null 2>/dev/null") || fail
155
+ begin
156
+ @rugged.remotes.each { |x| @grit.remote_fetch(x.name) }
157
+ rescue Grit::Git::GitTimeout
158
+ return "Fetch timed out for #{root}"
159
+ rescue Grit::Git::CommandFailed => e
160
+ return e.err
161
+ end
162
+
163
+ return :ok if remote_branch.nil? || remote_branch.tip.oid == current_oid
164
+
165
+ @grit.git.merge({ raise: true, chdir: root }, "#{@remote_name}/#{@branch_name}")
166
+ :ok
167
+ rescue Grit::Git::GitTimeout
168
+ "Merged command timed out for #{root}"
169
+ rescue Grit::Git::CommandFailed => e
170
+ # HACK: The rugged in-memory index will not have been updated after the
171
+ # Grit merge command. Reload it before checking for conflicts.
172
+ @rugged.index.reload
173
+ return e.err unless @rugged.index.conflicts?
174
+
175
+ conflicted_paths = @rugged.index.map do |index_entry|
176
+ filename, extension = index_entry[:path].scan(/(.*?)(|\.[^\.]+)$/).first
177
+
178
+ author = ' original' if index_entry[:stage] == 1
179
+ short_oid = index_entry[:oid][0..6]
180
+ new_filename = "#{filename} (#{short_oid}#{author})#{extension}"
181
+ File.open(File.join(root, new_filename), 'wb') do |f|
182
+ f.write(Rugged::Blob.lookup(@rugged, index_entry[:oid]).content)
174
183
  end
175
184
 
176
- conflicted_files.keys
177
- else
178
- out # return the output on error
185
+ index_entry[:path]
179
186
  end
187
+
188
+ conflicted_paths.uniq!
189
+ conflicted_paths.each { |path| FileUtils.remove(File.join(root, path), force: true) }
190
+
191
+ # NOTE: leave the commit until the next push
192
+
193
+ conflicted_paths
180
194
  end
181
195
 
182
196
  # Commit and push the repository
@@ -191,19 +205,34 @@ class Gitdocs::Repository
191
205
  return :no_remote unless has_remote?
192
206
 
193
207
  #add and commit
194
- Dir.glob(File.join(root, '**', '*'))
195
- .select { |x| File.directory?(x) && Dir.glob("#{x}/*").empty? }
196
- .each { |x| FileUtils.touch(File.join(x, '.gitignore')) }
197
- Dir.chdir(root) do
198
- @rugged.index.add_all
199
- @rugged.index.update_all
208
+ Find.find(root).each do |path|
209
+ Find.prune if File.basename(path) == '.git'
210
+ if File.directory?(path) && Dir.entries(path).count == 2
211
+ FileUtils.touch(File.join(path, '.gitignore'))
212
+ end
213
+ end
214
+
215
+ # Check if there are uncommitted changes
216
+ dirty =
217
+ if current_oid.nil?
218
+ Dir.glob(File.join(root, '*')).any?
219
+ else
220
+ @rugged.diff_workdir(current_oid, include_untracked: true).deltas.any?
221
+ end
222
+
223
+ # Commit any changes in the working directory.
224
+ if dirty
225
+ Dir.chdir(root) do
226
+ @rugged.index.add_all
227
+ @rugged.index.update_all
228
+ end
229
+ @rugged.index.write
230
+ @grit.commit_index(message)
200
231
  end
201
- @rugged.index.write
202
- @grit.commit_index(message) if @rugged.index.count
203
232
 
204
- remote_branch = Rugged::Branch.lookup(@rugged, "#{@remote_name}/#{@branch_name}", :remote)
233
+ return :nothing if current_oid.nil?
205
234
 
206
- if last_synced_oid.nil? || remote_branch.nil? || remote_branch.tip.oid != @rugged.head.target
235
+ if last_synced_oid.nil? || remote_branch.nil? || remote_branch.tip.oid != current_oid
207
236
  begin
208
237
  @grit.git.push({ raise: true }, @remote_name, @branch_name)
209
238
  :ok
@@ -330,7 +359,18 @@ class Gitdocs::Repository
330
359
  private
331
360
 
332
361
  def has_remote?
333
- sh_string('git remote')
362
+ @rugged.remotes.any?
363
+ end
364
+
365
+ # HACK: This will return nil if there are no commits in the remote branch.
366
+ # It is not the response that I would expect but it mostly gets the job
367
+ # done. This should probably be reviewed when upgrading to the next version
368
+ # of Rugged.
369
+ #
370
+ # @return [nil] if the remote branch does not exist
371
+ # @return [Rugged::Remote]
372
+ def remote_branch
373
+ Rugged::Branch.lookup(@rugged, "#{@remote_name}/#{@branch_name}", :remote)
334
374
  end
335
375
 
336
376
  def head_walker
@@ -339,16 +379,4 @@ class Gitdocs::Repository
339
379
  walker.push(@rugged.head.target)
340
380
  walker
341
381
  end
342
-
343
- # sh_string("git config branch.`git branch | grep '^\*' | sed -e 's/\* //'`.remote", "origin")
344
- def sh_string(cmd, default = nil)
345
- val = sh("cd #{root} ; #{cmd}").strip rescue nil
346
- val.nil? || val.empty? ? default : val
347
- end
348
-
349
- # Run in shell, return both status and output
350
- # @see #sh
351
- def sh_with_code(cmd)
352
- ShellTools.sh_with_code(cmd, root)
353
- end
354
382
  end
@@ -1,3 +1,3 @@
1
1
  module Gitdocs
2
- VERSION = '0.5.0.pre3'
2
+ VERSION = '0.5.0.pre5'
3
3
  end
@@ -8,7 +8,7 @@ describe Gitdocs::Repository do
8
8
 
9
9
  before do
10
10
  FileUtils.rm_rf('tmp/unit')
11
- FileUtils.mkdir_p(local_repo_path)
11
+ mkdir
12
12
  repo = Rugged::Repository.init_at(local_repo_path)
13
13
  repo.config['user.email'] = 'afish@example.com'
14
14
  repo.config['user.name'] = 'Art T. Fish'
@@ -21,7 +21,6 @@ describe Gitdocs::Repository do
21
21
  let(:remote_repo) { Rugged::Repository.init_at('tmp/unit/remote', :bare) }
22
22
  let(:local_repo) { Rugged::Repository.new(local_repo_path) }
23
23
 
24
-
25
24
  describe 'initialize' do
26
25
  subject { repository }
27
26
 
@@ -118,7 +117,6 @@ describe Gitdocs::Repository do
118
117
  it { subject.must_equal [] }
119
118
  end
120
119
 
121
-
122
120
  describe 'term found' do
123
121
  let(:term) { 'foo' }
124
122
  before do
@@ -205,19 +203,55 @@ describe Gitdocs::Repository do
205
203
  it { subject.must_equal :no_remote }
206
204
  end
207
205
 
208
- describe 'when there is an error' do
209
- before do
210
- Rugged::Remote.add(
211
- Rugged::Repository.new(local_repo_path),
212
- 'origin',
213
- 'file:///bad/remote'
214
- )
206
+ describe 'with a valid remote with no initial commits' do
207
+ before { create_local_repo_with_remote }
208
+
209
+ describe 'when there is an error fetching' do
210
+ before do
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' }
215
+ end
216
+
217
+ describe 'when there are no local commits' do
218
+ it { subject.must_equal :ok }
219
+ end
220
+
221
+ describe 'when there is a local commit' do
222
+ before { write_and_commit('file1', 'beef', 'conflict commit', author1) }
223
+ it { subject.must_equal :ok }
224
+ it { subject ; commit_count(local_repo).must_equal 1 }
225
+ end
226
+
227
+ describe 'then new remote commits are fetched' do
228
+ before do
229
+ bare_commit(
230
+ remote_repo,
231
+ 'file2', 'deadbeef',
232
+ 'second commit',
233
+ 'author@example.com', 'A U Thor'
234
+ )
235
+ end
236
+
237
+ describe 'when there is an error merging' do
238
+ before do
239
+ Grit::Git.any_instance.stubs(:merge)
240
+ .raises(Grit::Git::CommandFailed.new('', 1, 'merge error output'))
241
+ end
242
+ it { subject.must_equal 'merge error output' }
243
+ end
244
+
245
+ describe ' and merged' do
246
+ it { subject.must_equal :ok }
247
+ it { subject ; local_file_exist?('file2').must_equal true }
248
+ it { subject ; commit_count(local_repo).must_equal 1 }
249
+ end
215
250
  end
216
- it { subject.must_equal "Fetching origin\n" }
217
251
  end
218
252
 
219
- describe 'with a valid remote' do
220
- before { create_local_repo_with_remote }
253
+ describe 'with a valid remote with commits' do
254
+ before { create_local_repo_with_remote_with_commit }
221
255
 
222
256
  describe 'when there is nothing to pull' do
223
257
  it { subject.must_equal :ok }
@@ -236,13 +270,19 @@ describe Gitdocs::Repository do
236
270
 
237
271
  it { subject.must_equal ['file1'] }
238
272
  it { subject ; commit_count(local_repo).must_equal 2 }
239
- it { subject ; local_repo_files.count.must_equal 3 }
240
- it { subject ; local_repo_files.must_include 'file1 (f6ea049 original)' }
241
- it { subject ; local_repo_files.must_include 'file1 (18ed963)' }
242
- it { subject ; local_repo_files.must_include 'file1 (7bfce5c)' }
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' }
243
277
  end
244
278
 
245
- describe 'when new commits are pulled and merged' do
279
+ describe 'when there is a non-conflicted local commit' do
280
+ before { write_and_commit('file1', 'beef', 'conflict commit', author1) }
281
+ it { subject.must_equal :ok }
282
+ it { subject ; commit_count(local_repo).must_equal 2 }
283
+ end
284
+
285
+ describe 'when new remote commits are pulled and merged' do
246
286
  before do
247
287
  bare_commit(
248
288
  remote_repo,
@@ -252,7 +292,7 @@ describe Gitdocs::Repository do
252
292
  )
253
293
  end
254
294
  it { subject.must_equal :ok }
255
- it { subject ; File.exists?(File.join(local_repo_path, 'file2')).must_equal true }
295
+ it { subject ; local_file_exist?('file2').must_equal true }
256
296
  it { subject ; commit_count(local_repo).must_equal 2 }
257
297
  end
258
298
  end
@@ -278,7 +318,7 @@ describe Gitdocs::Repository do
278
318
  it { subject.must_equal :no_remote }
279
319
  end
280
320
 
281
- describe 'remote exists' do
321
+ describe 'remote exists with no commits' do
282
322
  before { create_local_repo_with_remote }
283
323
 
284
324
  describe 'last sync is nil' do
@@ -292,6 +332,116 @@ describe Gitdocs::Repository do
292
332
  )
293
333
  end
294
334
  it { subject.must_equal :nothing }
335
+ it { subject ; commit_count(local_repo).must_equal 0 }
336
+ end
337
+
338
+ describe 'and there is a conflicted file to push' do
339
+ before do
340
+ bare_commit(remote_repo, 'file1', 'dead', 'commit', 'A U Thor', 'author@example.com')
341
+ write('file1', 'beef')
342
+ end
343
+ it { subject ; commit_count(local_repo).must_equal 1 }
344
+ it { subject ; commit_count(remote_repo).must_equal 1 }
345
+ it { subject.must_equal :nothing }
346
+ end
347
+
348
+ describe 'and there are empty directories to push' do
349
+ before do
350
+ mkdir('directory')
351
+ mkdir('.hidden_empty')
352
+ end
353
+ it { subject.must_equal :ok }
354
+ it { subject ; commit_count(local_repo).must_equal 1 }
355
+ it { subject ; commit_count(remote_repo).must_equal 1 }
356
+ it { subject ; head_commit(remote_repo).message.must_equal "message\n" }
357
+ it { subject ; head_tree_files(remote_repo).count.must_equal 2 }
358
+ it { subject ; head_tree_files(remote_repo).must_include 'directory' }
359
+ it { subject ; head_tree_files(remote_repo).must_include '.hidden_empty' }
360
+ it { subject ; Dir.glob("#{local_repo_path}/**/.gitignore", File::FNM_DOTMATCH).count.must_equal 2 }
361
+ end
362
+
363
+ describe 'and there is a directory with a hidden file' do
364
+ before do
365
+ mkdir('directory')
366
+ write('directory/.hidden', '')
367
+ end
368
+ it { subject.must_equal :ok }
369
+ it { subject ; local_file_exist?('directory', '.gitignore').must_equal false }
370
+ it { subject ; commit_count(local_repo).must_equal 1 }
371
+ it { subject ; commit_count(remote_repo).must_equal 1 }
372
+ it { subject ; head_commit(remote_repo).message.must_equal "message\n" }
373
+ it { subject ; head_tree_files(remote_repo).count.must_equal 1 }
374
+ it { subject ; head_tree_files(remote_repo).must_include 'directory' }
375
+ end
376
+
377
+ describe 'and there is a new file to push' do
378
+ before { write('file2', 'foobar') }
379
+ it { subject.must_equal :ok }
380
+ it { subject ; commit_count(local_repo).must_equal 1 }
381
+ it { subject ; commit_count(remote_repo).must_equal 1 }
382
+ it { subject ; head_commit(remote_repo).message.must_equal "message\n" }
383
+ it { subject ; head_tree_files(remote_repo).count.must_equal 1 }
384
+ it { subject ; head_tree_files(remote_repo).must_include 'file2' }
385
+ end
386
+ end
387
+
388
+ describe 'last sync is not nil' do
389
+ let(:last_oid) { 'oid' }
390
+
391
+ describe 'and this is an error on the push' do
392
+ before do
393
+ write('file2', 'foobar')
394
+
395
+ # Simulate an error occurring during the push
396
+ Grit::Git.any_instance.stubs(:push).raises(
397
+ Grit::Git::CommandFailed.new('', 1, 'error message')
398
+ )
399
+ end
400
+ it { subject.must_equal 'error message' }
401
+ end
402
+
403
+ describe 'and this is nothing to push' do
404
+ it { subject.must_equal :nothing }
405
+ it { subject ; commit_count(local_repo).must_equal 0 }
406
+ end
407
+
408
+ describe 'and there is a conflicted commit to push' do
409
+ before do
410
+ bare_commit(remote_repo, 'file1', 'dead', 'commit', 'A U Thor', 'author@example.com')
411
+ write('file1', 'beef')
412
+ end
413
+ it { subject ; commit_count(local_repo).must_equal 1 }
414
+ it { subject ; commit_count(remote_repo).must_equal 1 }
415
+ it { subject.must_equal :conflict }
416
+ end
417
+
418
+ describe 'and there is a commit to push' do
419
+ before { write('file2', 'foobar') }
420
+ it { subject.must_equal :ok }
421
+ it { subject ; commit_count(local_repo).must_equal 1 }
422
+ it { subject ; commit_count(remote_repo).must_equal 1 }
423
+ it { subject ; head_commit(remote_repo).message.must_equal "message\n" }
424
+ it { subject ; head_tree_files(remote_repo).count.must_equal 1 }
425
+ it { subject ; head_tree_files(remote_repo).must_include 'file2' }
426
+ end
427
+ end
428
+ end
429
+
430
+ describe 'remote exists' do
431
+ before { create_local_repo_with_remote_with_commit }
432
+
433
+ describe 'last sync is nil' do
434
+ let(:last_oid) { nil }
435
+
436
+ describe 'and there is an error on push' do
437
+ # Simulate an error occurring during the push
438
+ before do
439
+ Grit::Git.any_instance.stubs(:push).raises(
440
+ Grit::Git::CommandFailed.new('', 1, '')
441
+ )
442
+ end
443
+ it { subject.must_equal :nothing }
444
+ it { subject ; commit_count(local_repo).must_equal 1 }
295
445
  end
296
446
 
297
447
  describe 'and there is a conflicted file to push' do
@@ -304,9 +454,29 @@ describe Gitdocs::Repository do
304
454
  it { subject.must_equal :nothing }
305
455
  end
306
456
 
307
- describe 'and there is an empty directory to push' do
308
- before { FileUtils.mkdir_p(File.join(local_repo_path, 'directory')) }
457
+ describe 'and there are empty directories to push' do
458
+ before do
459
+ mkdir('directory')
460
+ mkdir('.hidden_empty')
461
+ end
462
+ it { subject.must_equal :ok }
463
+ it { subject ; commit_count(local_repo).must_equal 2 }
464
+ it { subject ; commit_count(remote_repo).must_equal 2 }
465
+ it { subject ; head_commit(remote_repo).message.must_equal "message\n" }
466
+ it { subject ; head_tree_files(remote_repo).count.must_equal 3 }
467
+ it { subject ; head_tree_files(remote_repo).must_include 'file1' }
468
+ it { subject ; head_tree_files(remote_repo).must_include 'directory' }
469
+ it { subject ; head_tree_files(remote_repo).must_include '.hidden_empty' }
470
+ it { subject ; Dir.glob("#{local_repo_path}/**/.gitignore", File::FNM_DOTMATCH).count.must_equal 2 }
471
+ end
472
+
473
+ describe 'and there is a directory with a hidden file' do
474
+ before do
475
+ mkdir('directory')
476
+ write('directory/.hidden', '')
477
+ end
309
478
  it { subject.must_equal :ok }
479
+ it { subject ; local_file_exist?('directory', '.gitignore').must_equal false }
310
480
  it { subject ; commit_count(local_repo).must_equal 2 }
311
481
  it { subject ; commit_count(remote_repo).must_equal 2 }
312
482
  it { subject ; head_commit(remote_repo).message.must_equal "message\n" }
@@ -354,6 +524,7 @@ describe Gitdocs::Repository do
354
524
 
355
525
  describe 'and this is nothing to push' do
356
526
  it { subject.must_equal :nothing }
527
+ it { subject ; commit_count(local_repo).must_equal 1 }
357
528
  end
358
529
 
359
530
  describe 'and there is a conflicted commit to push' do
@@ -505,20 +676,26 @@ describe Gitdocs::Repository do
505
676
 
506
677
  describe 'file does not include the revision' do
507
678
  let(:ref) { @commit0 }
508
- it { subject ; File.read(file_name).must_equal 'beef' }
679
+ it { subject ; local_file_content('directory', 'file2').must_equal 'beef' }
509
680
  end
510
681
 
511
682
  describe 'file does include the revision' do
512
683
  let(:ref) { @commit2 }
513
- it { subject ; File.read(file_name).must_equal "bar\n" }
684
+ it { subject ; local_file_content('directory', 'file2').must_equal "bar\n" }
514
685
  end
515
686
  end
516
687
 
517
688
  ##############################################################################
518
689
 
519
690
  private
520
-
521
691
  def create_local_repo_with_remote
692
+ FileUtils.rm_rf(local_repo_path)
693
+ repo = Rugged::Repository.clone_at(remote_repo.path, local_repo_path)
694
+ repo.config['user.email'] = 'afish@example.com'
695
+ repo.config['user.name'] = 'Art T. Fish'
696
+ end
697
+
698
+ def create_local_repo_with_remote_with_commit
522
699
  bare_commit(
523
700
  remote_repo,
524
701
  'file1', 'foobar',
@@ -531,13 +708,17 @@ describe Gitdocs::Repository do
531
708
  repo.config['user.name'] = 'Art T. Fish'
532
709
  end
533
710
 
711
+ def mkdir(*path)
712
+ FileUtils.mkdir_p(File.join(local_repo_path, *path))
713
+ end
714
+
534
715
  def write(filename, content)
535
- FileUtils.mkdir_p(File.join(local_repo_path, File.dirname(filename)))
716
+ mkdir(File.dirname(filename))
536
717
  File.write(File.join(local_repo_path, filename), content)
537
718
  end
538
719
 
539
720
  def write_and_commit(filename, content, commit_msg, author)
540
- FileUtils.mkdir_p(File.join(local_repo_path, File.dirname(filename)))
721
+ mkdir(File.dirname(filename))
541
722
  File.write(File.join(local_repo_path, filename), content)
542
723
  `cd #{local_repo_path} ; git add #{filename}; git commit -m '#{commit_msg}' --author='#{author}'`
543
724
  `cd #{local_repo_path} ; git rev-parse HEAD`.strip
@@ -565,21 +746,38 @@ describe Gitdocs::Repository do
565
746
  walker = Rugged::Walker.new(repo)
566
747
  walker.push(repo.head.target)
567
748
  walker.count
749
+ rescue Rugged::ReferenceError
750
+ # The repo does not have a head => no commits.
751
+ 0
568
752
  end
569
753
 
570
754
  def head_commit(repo)
571
755
  walker = Rugged::Walker.new(repo)
572
756
  walker.push(repo.head.target)
573
757
  walker.first
758
+ rescue Rugged::ReferenceError
759
+ # The repo does not have a head => no commits => no head commit.
760
+ nil
574
761
  end
575
762
 
576
763
  def head_tree_files(repo)
577
764
  head_commit(repo).tree.map { |x| x[:name] }
578
765
  end
579
766
 
580
- def local_repo_files
581
- Dir.chdir(local_repo_path) do
767
+ # NOTE: This method is ignoring hidden files.
768
+ def local_file_count
769
+ files = Dir.chdir(local_repo_path) do
582
770
  Dir.glob('*')
583
771
  end
772
+ files.count
773
+ end
774
+
775
+ def local_file_exist?(*path_elements)
776
+ File.exist?(File.join(local_repo_path, *path_elements))
777
+ end
778
+
779
+ def local_file_content(*path_elements)
780
+ local_file_exist?(*path_elements).must_equal true
781
+ File.read(File.join(local_repo_path, *path_elements))
584
782
  end
585
783
  end
data/test/runner_test.rb CHANGED
@@ -1,142 +1,114 @@
1
1
  require File.expand_path('../test_helper', __FILE__)
2
2
 
3
3
  describe 'gitdocs runner' do
4
- before { ENV['TEST'] = 'true' }
5
-
6
- describe 'syncing' do
7
- it 'should clone files' do
8
- with_clones(3) do |clone1, clone2, clone3|
9
- File.open(File.join(clone1, 'test'), 'w') { |f| f << 'testing' }
10
- sleep 3
11
- assert_equal 'testing', File.read(File.join(clone1, 'test'))
12
- assert_equal 'testing', File.read(File.join(clone2, 'test'))
13
- assert_equal 'testing', File.read(File.join(clone3, 'test'))
14
- end
15
- end
4
+ let(:runner) { Gitdocs::Runner.new(share)}
5
+
6
+ let(:share) { stub(polling_interval: 1, notification: true) }
7
+ let(:notifier) { stub }
8
+ let(:repository) { stub(root: 'root_path') }
9
+ before do
10
+ Gitdocs::Notifier.stubs(:new).with(true).returns(notifier)
11
+ Gitdocs::Repository.stubs(:new).with(share).returns(repository)
12
+ end
16
13
 
17
- it 'should resolve conflicts files' do
18
- with_clones(3) do |clone1, clone2, clone3|
19
- File.open(File.join(clone1, 'test.txt'), 'w') { |f| f << 'testing' }
20
- sleep 3
21
- File.open(File.join(clone1, 'test.txt'), 'w') { |f| f << "testing\n1" }
22
- File.open(File.join(clone2, 'test.txt'), 'w') { |f| f << "testing\n2" }
23
- sleep 3
24
- assert_includes 2..3, Dir[File.join(clone2, '*.txt')].to_a.size
25
- assert_includes 2..3, Dir[File.join(clone3, '*.txt')].to_a.size
26
- end
27
- end
14
+ describe '#root' do
15
+ subject { runner.root }
16
+ it { subject.must_equal 'root_path' }
28
17
  end
29
18
 
30
- describe 'public methods' do
31
- let(:runner) { Gitdocs::Runner.new(share)}
19
+ describe '#sync_changes' do
20
+ subject { runner.sync_changes }
32
21
 
33
- let(:share) { stub(polling_interval: 1, notification: true) }
34
- let(:notifier) { stub }
35
- let(:repository) { stub(root: 'root_path') }
36
- before do
37
- Gitdocs::Notifier.stubs(:new).with(true).returns(notifier)
38
- Gitdocs::Repository.stubs(:new).with(share).returns(repository)
39
- end
22
+ before { repository.expects(:pull).returns(pull_result) }
40
23
 
41
- describe '#root' do
42
- subject { runner.root }
43
- it { subject.must_equal 'root_path' }
24
+ describe 'when invalid' do
25
+ let(:pull_result) { nil }
26
+ it { subject.must_equal nil }
44
27
  end
45
28
 
46
- describe '#sync_changes' do
47
- subject { runner.sync_changes }
48
-
49
- before { repository.expects(:pull).returns(pull_result) }
50
-
51
- describe 'when invalid' do
52
- let(:pull_result) { nil }
53
- it { subject.must_equal nil }
54
- end
55
-
56
- describe 'when no remote present' do
57
- let(:pull_result) { :no_remote }
58
- it { subject.must_equal nil }
59
- end
29
+ describe 'when no remote present' do
30
+ let(:pull_result) { :no_remote }
31
+ it { subject.must_equal nil }
32
+ end
60
33
 
61
- describe 'when merge is conflicted' do
62
- let(:pull_result) { ['file'] }
63
- before do
64
- notifier.expects(:warn).with(
65
- 'There were some conflicts',
66
- "* file"
67
- )
68
- runner.expects(:push_changes)
69
- end
70
- it { subject.must_equal nil }
34
+ describe 'when merge is conflicted' do
35
+ let(:pull_result) { ['file'] }
36
+ before do
37
+ notifier.expects(:warn).with(
38
+ 'There were some conflicts',
39
+ "* file"
40
+ )
41
+ runner.expects(:push_changes)
71
42
  end
43
+ it { subject.must_equal nil }
44
+ end
72
45
 
73
- describe 'when merge is ok' do
74
- let(:pull_result) { :ok }
75
- before do
76
- runner.instance_variable_set(:@last_synced_revision, :oid)
77
- repository.stubs(:current_oid).returns(:next_oid)
78
- repository.stubs(:author_count).with(:oid).returns('Alice' => 1, 'Bob' => 2)
79
- notifier.expects(:info).with(
80
- 'Updated with 3 changes',
81
- "In 'root_path':\n* Alice (1 change)\n* Bob (2 changes)"
82
- )
83
- runner.expects(:push_changes)
84
- end
85
- it { subject.must_equal nil }
86
- it { subject ; runner.instance_variable_get(:@last_synced_revision).must_equal :next_oid }
46
+ describe 'when merge is ok' do
47
+ let(:pull_result) { :ok }
48
+ before do
49
+ runner.instance_variable_set(:@last_synced_revision, :oid)
50
+ repository.stubs(:current_oid).returns(:next_oid)
51
+ repository.stubs(:author_count).with(:oid).returns('Alice' => 1, 'Bob' => 2)
52
+ notifier.expects(:info).with(
53
+ 'Updated with 3 changes',
54
+ "In 'root_path':\n* Alice (1 change)\n* Bob (2 changes)"
55
+ )
56
+ runner.expects(:push_changes)
87
57
  end
58
+ it { subject.must_equal nil }
59
+ it { subject ; runner.instance_variable_get(:@last_synced_revision).must_equal :next_oid }
88
60
  end
61
+ end
89
62
 
90
- describe '#push_changes' do
91
- subject { runner.push_changes }
63
+ describe '#push_changes' do
64
+ subject { runner.push_changes }
92
65
 
93
- before { repository.expects(:push).returns(push_result) }
66
+ before { repository.expects(:push).returns(push_result) }
94
67
 
95
- describe 'when invalid' do
96
- let(:push_result) { nil }
97
- it { subject.must_equal nil }
98
- end
68
+ describe 'when invalid' do
69
+ let(:push_result) { nil }
70
+ it { subject.must_equal nil }
71
+ end
99
72
 
100
- describe 'when no remote present' do
101
- let(:push_result) { :no_remote }
102
- it { subject.must_equal nil }
103
- end
73
+ describe 'when no remote present' do
74
+ let(:push_result) { :no_remote }
75
+ it { subject.must_equal nil }
76
+ end
104
77
 
105
- describe 'when nothing happened' do
106
- let(:push_result) { :nothing }
107
- it { subject.must_equal nil }
108
- end
78
+ describe 'when nothing happened' do
79
+ let(:push_result) { :nothing }
80
+ it { subject.must_equal nil }
81
+ end
109
82
 
110
- describe 'when there is an error' do
111
- let(:push_result) { 'error' }
112
- before do
113
- notifier.expects(:error)
114
- .with('BAD Could not push changes in root_path', 'error')
115
- end
116
- it { subject.must_equal nil }
83
+ describe 'when there is an error' do
84
+ let(:push_result) { 'error' }
85
+ before do
86
+ notifier.expects(:error)
87
+ .with('BAD Could not push changes in root_path', 'error')
117
88
  end
89
+ it { subject.must_equal nil }
90
+ end
118
91
 
119
- describe 'when push is conflicted' do
120
- let(:push_result) { :conflict }
121
- before do
122
- notifier.expects(:warn)
123
- .with('There was a conflict in root_path, retrying', '')
124
- end
125
- it { subject.must_equal nil }
92
+ describe 'when push is conflicted' do
93
+ let(:push_result) { :conflict }
94
+ before do
95
+ notifier.expects(:warn)
96
+ .with('There was a conflict in root_path, retrying', '')
126
97
  end
98
+ it { subject.must_equal nil }
99
+ end
127
100
 
128
- describe 'when merge is ok' do
129
- let(:push_result) { :ok }
130
- before do
131
- runner.instance_variable_set(:@last_synced_revision, :oid)
132
- repository.stubs(:current_oid).returns(:next_oid)
133
- repository.stubs(:author_count).with(:oid).returns('Alice' => 1, 'Bob' => 2)
134
- notifier.expects(:info)
135
- .with('Pushed 3 changes', "'root_path' has been pushed")
136
- end
137
- it { subject.must_equal nil }
138
- it { subject ; runner.instance_variable_get(:@last_synced_revision).must_equal :next_oid }
101
+ describe 'when merge is ok' do
102
+ let(:push_result) { :ok }
103
+ before do
104
+ runner.instance_variable_set(:@last_synced_revision, :oid)
105
+ repository.stubs(:current_oid).returns(:next_oid)
106
+ repository.stubs(:author_count).with(:oid).returns('Alice' => 1, 'Bob' => 2)
107
+ notifier.expects(:info)
108
+ .with('Pushed 3 changes', "'root_path' has been pushed")
139
109
  end
110
+ it { subject.must_equal nil }
111
+ it { subject ; runner.instance_variable_get(:@last_synced_revision).must_equal :next_oid }
140
112
  end
141
113
  end
142
114
  end
data/test/test_helper.rb CHANGED
@@ -2,54 +2,4 @@ require 'rubygems'
2
2
  require 'minitest/autorun'
3
3
  $LOAD_PATH.unshift File.expand_path('../../lib')
4
4
  require 'gitdocs'
5
- require 'fakeweb'
6
5
  require 'mocha/setup'
7
-
8
- FakeWeb.allow_net_connect = false
9
-
10
- ## Kernel Extensions
11
- require 'stringio'
12
-
13
- class MiniTest::Spec
14
- def with_clones(count = 3)
15
- FileUtils.rm_rf('/tmp/gitdocs')
16
- master_path = '/tmp/gitdocs/master'
17
- FileUtils.mkdir_p('/tmp/gitdocs/master')
18
- ShellTools.capture { `git init /tmp/gitdocs/master --bare` }
19
- sub_paths = count.times.map do |c|
20
- ShellTools.capture { `cd /tmp/gitdocs && git clone file://#{master_path} #{c}` }
21
- ShellTools.capture { `cd /tmp/gitdocs/#{c} && git config --local user.email "afish@example.com" && git config --local user.name "Art T. Fish"` }
22
- conf_path = "/tmp/gitdocs/config/#{c}"
23
- FileUtils.mkdir_p(conf_path)
24
- ["/tmp/gitdocs/#{c}", conf_path]
25
- end
26
- pids = sub_paths.map do |(path, conf_path)|
27
- fork do
28
- unless ENV['DEBUG']
29
- STDOUT.reopen(File.open('/dev/null', 'w'))
30
- STDERR.reopen(File.open('/dev/null', 'w'))
31
- end
32
- begin
33
- puts 'RUNNING!'
34
- Gitdocs.start(config_path: conf_path) do |conf|
35
- conf.global.update_attributes(load_browser_on_startup: false, start_web_frontend: false)
36
- conf.add_path(path, polling_interval: 0.1, notification: false)
37
- end
38
- rescue
39
- puts 'RATHER BAD ~~~~~'
40
- puts $ERROR_INFO.message
41
- puts $ERROR_INFO.backtrace.join("\n ")
42
- end
43
- end
44
- end
45
-
46
- begin
47
- sleep 1
48
- yield sub_paths.map { |sp| sp.first }
49
- ensure
50
- pids.each { |pid| Process.kill('INT', pid) rescue nil }
51
- end
52
- ensure
53
- FileUtils.rm_rf('/tmp/gitdocs') unless ENV['DEBUG']
54
- end
55
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitdocs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0.pre3
4
+ version: 0.5.0.pre5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Hull
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-31 00:00:00.000000000 Z
12
+ date: 2014-05-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: joshbuddy-guard