gitdocs 0.5.0.pre3 → 0.5.0.pre5

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