gitdocs 0.5.0 → 0.6.0

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.
Files changed (65) hide show
  1. checksums.yaml +6 -14
  2. data/.codeclimate.yml +26 -0
  3. data/.rubocop.yml +8 -2
  4. data/.travis.yml +8 -0
  5. data/CHANGELOG +13 -0
  6. data/Gemfile +1 -1
  7. data/README.md +7 -6
  8. data/Rakefile +31 -5
  9. data/bin/gitdocs +1 -0
  10. data/config.ru +6 -4
  11. data/gitdocs.gemspec +22 -19
  12. data/lib/gitdocs.rb +54 -16
  13. data/lib/gitdocs/browser_app.rb +34 -41
  14. data/lib/gitdocs/cli.rb +41 -32
  15. data/lib/gitdocs/configuration.rb +40 -101
  16. data/lib/gitdocs/git_notifier.rb +111 -0
  17. data/lib/gitdocs/initializer.rb +83 -0
  18. data/lib/gitdocs/manager.rb +90 -60
  19. data/lib/gitdocs/migration/004_add_index_for_path.rb +1 -1
  20. data/lib/gitdocs/notifier.rb +70 -104
  21. data/lib/gitdocs/rendering_helper.rb +3 -0
  22. data/lib/gitdocs/repository.rb +324 -307
  23. data/lib/gitdocs/repository/committer.rb +77 -0
  24. data/lib/gitdocs/repository/path.rb +157 -140
  25. data/lib/gitdocs/search.rb +40 -25
  26. data/lib/gitdocs/settings_app.rb +5 -3
  27. data/lib/gitdocs/share.rb +64 -0
  28. data/lib/gitdocs/synchronizer.rb +40 -0
  29. data/lib/gitdocs/version.rb +1 -1
  30. data/lib/gitdocs/views/_header.haml +2 -2
  31. data/lib/gitdocs/views/dir.haml +3 -3
  32. data/lib/gitdocs/views/edit.haml +1 -1
  33. data/lib/gitdocs/views/file.haml +1 -1
  34. data/lib/gitdocs/views/home.haml +3 -3
  35. data/lib/gitdocs/views/layout.haml +13 -13
  36. data/lib/gitdocs/views/revisions.haml +3 -3
  37. data/lib/gitdocs/views/search.haml +1 -1
  38. data/lib/gitdocs/views/settings.haml +6 -6
  39. data/test/integration/cli/full_sync_test.rb +83 -0
  40. data/test/integration/cli/share_management_test.rb +29 -0
  41. data/test/integration/cli/status_test.rb +14 -0
  42. data/test/integration/test_helper.rb +185 -151
  43. data/test/integration/{browse_test.rb → web/browse_test.rb} +11 -29
  44. data/test/integration/web/share_management_test.rb +46 -0
  45. data/test/support/git_factory.rb +276 -0
  46. data/test/unit/browser_app_test.rb +346 -0
  47. data/test/unit/configuration_test.rb +8 -70
  48. data/test/unit/git_notifier_test.rb +116 -0
  49. data/test/unit/gitdocs_test.rb +90 -0
  50. data/test/unit/manager_test.rb +36 -0
  51. data/test/unit/notifier_test.rb +60 -124
  52. data/test/unit/repository_committer_test.rb +111 -0
  53. data/test/unit/repository_path_test.rb +92 -76
  54. data/test/unit/repository_test.rb +243 -356
  55. data/test/unit/search_test.rb +15 -0
  56. data/test/unit/settings_app_test.rb +80 -0
  57. data/test/unit/share_test.rb +97 -0
  58. data/test/unit/test_helper.rb +17 -3
  59. metadata +114 -108
  60. data/lib/gitdocs/runner.rb +0 -108
  61. data/lib/gitdocs/server.rb +0 -62
  62. data/test/integration/full_sync_test.rb +0 -66
  63. data/test/integration/share_management_test.rb +0 -95
  64. data/test/integration/status_test.rb +0 -21
  65. data/test/unit/runner_test.rb +0 -122
@@ -2,56 +2,57 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'minitest/autorun'
5
- $LOAD_PATH.unshift File.expand_path('../../lib')
6
- require 'gitdocs'
7
5
  require 'aruba'
8
6
  require 'aruba/api'
9
7
  require 'timeout'
10
8
  require 'capybara'
11
9
  require 'capybara_minitest_spec'
10
+ require 'capybara/dsl'
12
11
  require 'capybara/poltergeist'
12
+ require 'find'
13
+ require 'gitdocs/version'
14
+ Dir.glob(File.expand_path('../../support/**/*.rb', __FILE__)).each do |filename|
15
+ require_relative filename
16
+ end
13
17
 
14
- Capybara.app_host = 'http://localhost:7777/'
15
- Capybara.default_driver = :poltergeist
16
- Capybara.run_server = false
17
- Capybara.default_wait_time = 20
18
+ Capybara.app_host = 'http://localhost:7777/'
19
+ Capybara.default_driver = :poltergeist
20
+ Capybara.run_server = false
21
+ Capybara.default_max_wait_time = ENV['TRAVIS'] ? 120 : 30
18
22
 
19
23
  Capybara.register_driver :poltergeist do |app|
20
- Capybara::Poltergeist::Driver.new(app, timeout: 20)
24
+ Capybara::Poltergeist::Driver.new(
25
+ app,
26
+ timeout: Capybara.default_max_wait_time,
27
+ # Disable catching javascript errors because of the possibility of errors
28
+ # from the Ace code.
29
+ js_errors: false
30
+ )
21
31
  end
22
32
 
23
- module MiniTest::Aruba
24
- class ArubaApiWrapper
25
- include Aruba::Api
26
- end
33
+ PID_FILE = File.expand_path('../../../tmp/gitdocs.pid', __FILE__)
27
34
 
28
- def aruba
29
- @aruba ||= ArubaApiWrapper.new
30
- end
31
-
32
- def run(*args)
33
- if args.length == 0
34
- super
35
- else
36
- aruba.run(*args)
35
+ module MiniTest
36
+ module Aruba
37
+ class ArubaApiWrapper
38
+ include ::Aruba::Api
37
39
  end
38
- end
39
40
 
40
- def method_missing(method, *args, &block)
41
- aruba.send(method, *args, &block)
42
- end
41
+ def aruba
42
+ @aruba ||= ArubaApiWrapper.new
43
+ end
43
44
 
44
- def before_setup
45
- super
46
- original = (ENV['PATH'] || '').split(File::PATH_SEPARATOR)
47
- set_env('PATH', ([File.expand_path('bin')] + original).join(File::PATH_SEPARATOR))
48
- FileUtils.rm_rf(current_dir)
49
- end
45
+ def run(*args)
46
+ if args.empty?
47
+ super
48
+ else
49
+ aruba.run(*args)
50
+ end
51
+ end
50
52
 
51
- def after_teardown
52
- super
53
- restore_env
54
- processes.clear
53
+ def method_missing(method, *args, &block)
54
+ aruba.send(method, *args, &block)
55
+ end
55
56
  end
56
57
  end
57
58
 
@@ -61,9 +62,30 @@ module Helper
61
62
  include Capybara::RSpecMatchers
62
63
 
63
64
  def before_setup
64
- super
65
+ clean_current_dir
66
+
67
+ # HACK: In order to ensure that rugged/libgit2 see the expected HOME
68
+ # directory we must set it before requiring rugged. This seems to occur
69
+ # because libgit2 reads HOME only one the initial load.
65
70
  set_env('HOME', abs_current_dir)
66
- ENV['TEST'] = nil
71
+ require 'rugged'
72
+
73
+ # Make sure that we are not accidentally overwriting an existing gitconfig.
74
+ if Rugged::Config.global['user.name'] || Rugged::Config.global['user.name']
75
+ puts <<-EOS.gsub(/^\s{8}/, '')
76
+ Unexpected git config:
77
+ user.name = #{Rugged::Config.global['user.name']}
78
+ user.email = #{Rugged::Config.global['user.email']}
79
+ Something went wrong when setting the HOME directory and the test
80
+ will not execute in isolation.'
81
+ EXITING
82
+ EOS
83
+ exit
84
+ end
85
+
86
+ GitFactory.working_directory = abs_current_dir
87
+ Rugged::Config.global['user.name'] = GitFactory.users[0][:name]
88
+ Rugged::Config.global['user.email'] = GitFactory.users[0][:email]
67
89
  end
68
90
 
69
91
  def teardown
@@ -72,33 +94,85 @@ module Helper
72
94
  end
73
95
 
74
96
  def after_teardown
75
- super
97
+ restore_env
98
+ processes.clear
76
99
 
77
100
  terminate_processes!
78
101
  prep_for_fs_check do
79
- next unless File.exist?('gitdocs.pid')
102
+ next unless File.exist?(PID_FILE)
103
+
104
+ pid = IO.read(PID_FILE).to_i
105
+ begin
106
+ Process.kill('KILL', pid)
107
+ rescue Errno::ESRCH # rubocop:disable Lint/HandleExceptions
108
+ # Nothing to do since the process is already gone.
109
+ end
80
110
 
81
- pid = IO.read('gitdocs.pid').to_i
82
- Process.kill('KILL', pid)
83
111
  begin
84
112
  Process.wait(pid)
85
113
  rescue SystemCallError # rubocop:disable Lint/HandleExceptions
86
114
  # This means that the process is already gone.
87
115
  # Nothing to do.
88
116
  end
117
+ FileUtils.rm_rf(PID_FILE)
118
+ end
119
+
120
+ return if passed?
121
+
122
+ # Report gitdocs execution details on failure
123
+ puts "\n\n----------------------------------"
124
+ puts "Aruba details for failure: #{name}"
125
+ puts failures.inspect.to_s
126
+
127
+ log_filename = File.join(abs_current_dir, '.gitdocs', 'log')
128
+ if File.exist?(log_filename)
129
+ puts '----------------------------------'
130
+ puts "Log file: #{log_filename}"
131
+ puts File.read(log_filename)
132
+ end
133
+
134
+ if Dir.exist?(abs_current_dir)
135
+ puts '----------------------------------'
136
+ puts 'Aruba current directory file list:'
137
+ Find.find(abs_current_dir) do |path|
138
+ Find.prune if path =~ %r{.git/?$}
139
+ puts " #{path}"
140
+ end
89
141
  end
142
+
143
+ puts "----------------------------------\n\n"
90
144
  end
91
145
 
92
- def start_daemon
93
- configuration = Gitdocs::Configuration.new
94
- configuration.shares.each do |share|
146
+ # @param [String] method pass to the CLI
147
+ # @param [String] arguments which will be passed to the CLI in addition
148
+ # @param [String] expected_output that the CLI should return
149
+ #
150
+ # @return [String] full text of the command being executed
151
+ def gitdocs_command(method, arguments, expected_output)
152
+ binary_path = File.expand_path('../../../bin/gitdocs', __FILE__)
153
+ full_command = "#{binary_path} #{method} #{arguments} --pid=#{PID_FILE}"
154
+
155
+ run(full_command, Capybara.default_max_wait_time)
156
+ assert_success(true)
157
+ assert_partial_output(expected_output, output_from(full_command))
158
+
159
+ full_command
160
+ end
161
+
162
+ # @return [void]
163
+ def gitdocs_start
164
+ # FIXME: Calling internal funcations directly because we cannot currently
165
+ # set polling or notification on the CLI. After that has been added this
166
+ # should be removed. [ASC 2015-10-26]
167
+ require 'gitdocs/initializer'
168
+ require 'gitdocs/share'
169
+ Gitdocs::Initializer.initialize_database
170
+ Gitdocs::Share.all.each do |share|
95
171
  share.update_attributes(polling_interval: 0.1, notification: false)
96
172
  end
97
173
 
98
- start_cmd = 'gitdocs start --debug --pid=gitdocs.pid --port 7777'
99
- run(start_cmd, 15)
100
- assert_success(true)
101
- assert_partial_output('Started gitdocs', output_from(start_cmd))
174
+ FileUtils.rm_rf(PID_FILE)
175
+ gitdocs_command('start', '--verbose --port=7777', 'Started gitdocs')
102
176
  end
103
177
 
104
178
  # @overload abs_current_dir
@@ -111,128 +185,88 @@ module Helper
111
185
  File.absolute_path(File.join(current_dir, relative_path))
112
186
  end
113
187
 
114
- # @return [String] the absolute path for the repository
115
- def git_init_local(path = 'local')
116
- abs_path = abs_current_dir(path)
117
- Rugged::Repository.init_at(abs_path)
118
- abs_path
188
+ # @param [String] path
189
+ #
190
+ # @return [#gitdocs_command]
191
+ def gitdocs_add(path)
192
+ GitFactory.init(path)
193
+ gitdocs_command('add', path, "Added path #{path} to doc list")
119
194
  end
120
195
 
121
- # @return [String] the absolute path for the repository
122
- def git_init_remote(path = 'remote')
123
- abs_path = abs_current_dir(path)
124
- Rugged::Repository.init_at(abs_path, :bare)
125
- abs_path
126
- end
127
-
128
- def wait_for_clean_workdir(path)
129
- dirty = true
130
- Timeout.timeout(20) do
131
- while dirty
132
- begin
133
- sleep(0.1)
134
- rugged = Rugged::Repository.new(abs_current_dir(path))
135
- dirty = !rugged.diff_workdir(rugged.head.target, include_untracked: true).deltas.empty?
136
- rescue Rugged::ReferenceError
137
- nil
138
- rescue Rugged::InvalidError
139
- nil
140
- rescue Rugged::RepositoryError
141
- nil
142
- end
143
- end
196
+ # @param [Array<String>] destination_paths
197
+ #
198
+ # @return [void]
199
+ def gitdocs_create_from_remote(*destination_paths)
200
+ full_destination_paths = destination_paths.map { |x| GitFactory.expand_path(x) }
201
+ remote_repository_path = GitFactory.init_bare(:remote)
202
+
203
+ full_destination_paths.each do |destination_path|
204
+ gitdocs_command(
205
+ 'create',
206
+ "#{destination_path} #{remote_repository_path}",
207
+ "Added path #{destination_path} to doc list"
208
+ )
144
209
  end
145
- rescue Timeout::Error
146
- assert(false, "#{path} workdir is still dirty")
147
210
  end
148
211
 
149
- def wait_for_exact_file_content(file, exact_content)
150
- in_current_dir do
151
- begin
152
- Timeout.timeout(20) do
153
- sleep(0.1) until File.exist?(file) && IO.read(file) == exact_content
154
- end
155
- rescue Timeout::Error
156
- nil
157
- end
158
-
159
- assert(File.exist?(file), "Missing #{file}")
160
- actual_content = IO.read(file)
161
- assert(
162
- actual_content == exact_content,
163
- "Expected #{file} content: #{exact_content}\nActual content #{actual_content}"
164
- )
212
+ # @param [Array<String>] expected_outputs
213
+ #
214
+ # @return [void]
215
+ def gitdocs_assert_status_contains(*expected_outputs)
216
+ command = gitdocs_command('status', '', Gitdocs::VERSION)
217
+ expected_outputs.each do |expected_output|
218
+ assert_partial_output(expected_output, output_from(command))
165
219
  end
166
220
  end
167
221
 
168
- def wait_for_directory(path)
169
- in_current_dir do
170
- begin
171
- Timeout.timeout(20) { sleep(0.1) until Dir.exist?(path) }
172
- rescue Timeout::Error
173
- nil
174
- end
175
-
176
- assert(Dir.exist?(path), "Missing #{path}")
222
+ # @param [Array<String>] not_expected_outputs
223
+ #
224
+ # @return [void]
225
+ def gitdocs_assert_status_not_contain(*not_expected_outputs)
226
+ command = gitdocs_command('status', '', Gitdocs::VERSION)
227
+ not_expected_outputs.each do |not_expected_output|
228
+ assert_no_partial_output(not_expected_output, output_from(command))
177
229
  end
178
230
  end
179
231
 
180
- def wait_for_conflict_markers(path)
181
- in_current_dir do
232
+ # @overload wait_for_assert
233
+ # @yield to a block which executes Minitest assertion
234
+ #
235
+ # @overload wait_for_assert(interval)
236
+ # @param [Float] interval
237
+ # @yield to a block which executes Minitest assertion
238
+ #
239
+ # @raise [Minitest::Assertion]
240
+ #
241
+ # @return [void]
242
+ def wait_for_assert(interval = 0.1)
243
+ Timeout.timeout(Capybara.default_max_wait_time) do
182
244
  begin
183
- Timeout.timeout(20) { sleep(0.1) if File.exist?(path) }
184
- rescue Timeout::Error
185
- nil
186
- ensure
187
- assert(!File.exist?(path), "#{path} should have been removed")
188
- end
189
-
190
- begin
191
- Timeout.timeout(20) { sleep(0.1) if Dir.glob("#{path} (*)").empty? }
192
- rescue Timeout::Error
193
- nil
194
- ensure
195
- assert(!Dir.glob("#{path} (*)").empty?, "#{path} conflict marks should have been created")
245
+ yield
246
+ rescue Minitest::Assertion, Capybara::Poltergeist::Error
247
+ sleep(interval)
248
+ retry
196
249
  end
197
250
  end
251
+ rescue Timeout::Error
252
+ yield
198
253
  end
199
254
 
200
- def gitdocs_add(path = 'local')
201
- add_cmd = "gitdocs add #{path} --pid=gitdocs.pid"
202
- run_simple(add_cmd, true, 15)
203
- assert_success(true)
204
- assert_partial_output("Added path #{path} to doc list", output_from(add_cmd))
205
- end
206
-
207
- def git_clone_and_gitdocs_add(remote_path, *clone_paths)
208
- clone_paths.each do |clone_path|
209
- abs_clone_path = abs_current_dir(clone_path)
210
- FileUtils.rm_rf(abs_clone_path)
211
- repo = Rugged::Repository.clone_at(
212
- "file://#{remote_path}",
213
- abs_clone_path
214
- )
215
- repo.config['user.email'] = 'afish@example.com'
216
- repo.config['user.name'] = 'Art T. Fish'
217
- gitdocs_add(clone_path)
255
+ # @param [String] locator
256
+ #
257
+ # @raise [Minitest::Assertion]
258
+ #
259
+ # @return [void]
260
+ def visit_and_click_link(locator)
261
+ wait_for_assert(1) do
262
+ visit('http://localhost:7777/')
263
+ click_link(locator)
218
264
  end
219
265
  end
220
-
221
- def gitdocs_status
222
- @status_cmd = 'gitdocs status --pid=gitdocs.pid'
223
- run(@status_cmd, 15)
224
- assert_success(true)
225
- end
226
-
227
- def assert_gitdocs_status_contains(expected)
228
- assert_partial_output(expected, output_from(@status_cmd))
229
- end
230
-
231
- def assert_gitdocs_status_not_contain(expected)
232
- assert_no_partial_output(expected, output_from(@status_cmd))
233
- end
234
266
  end
235
267
 
236
- class MiniTest::Spec
237
- include Helper
268
+ module MiniTest
269
+ class Spec
270
+ include Helper
271
+ end
238
272
  end
@@ -1,32 +1,22 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
- require File.expand_path('../test_helper', __FILE__)
3
+ require File.expand_path('../../test_helper', __FILE__)
4
4
 
5
5
  describe 'browse and edit repository file through the UI' do
6
6
  before do
7
- git_init_local('repo1')
8
7
  gitdocs_add('repo1')
9
-
10
- git_init_local
11
- gitdocs_add
8
+ gitdocs_add('local')
12
9
 
13
10
  # Create the various commits, to be able to see revisions.
14
- repository = Gitdocs::Repository.new(abs_current_dir('local'))
15
- write_file('local/file1', 'fbadbeef')
16
- repository.commit
17
- write_file('local/file1', 'foobar')
18
- repository.commit
19
- write_file('local/file1', 'deadbeef')
20
- repository.commit
21
- write_file('local/file2', 'A5A5A5A5')
22
- repository.commit
23
- write_file('local/README.md', 'hello i am a README')
24
- repository.commit
25
-
26
- start_daemon
27
-
28
- visit 'http://localhost:7777/'
29
- click_link('Home')
11
+ GitFactory.commit(:local, 'file1', 'fbadbeef')
12
+ GitFactory.commit(:local, 'file1', 'foobar')
13
+ GitFactory.commit(:local, 'file1', 'deadbeef')
14
+ GitFactory.commit(:local, 'file2', 'A5A5A5A5')
15
+ GitFactory.commit(:local, 'README.md', 'hello i am a README')
16
+
17
+ gitdocs_start
18
+ visit_and_click_link('Home')
19
+
30
20
  within('table#shares') do
31
21
  within('tbody') do
32
22
  click_link(abs_current_dir('local'))
@@ -59,10 +49,6 @@ describe 'browse and edit repository file through the UI' do
59
49
  end
60
50
 
61
51
  it 'should be able to browser a file revision' do
62
- # FIXME: This test is failing on TravisCI, but succeeding locally so skip
63
- # it for now and revisit in the future.
64
- next if ENV['TRAVIS']
65
-
66
52
  within('table#revisions') do
67
53
  within('tbody') do
68
54
  page.must_have_css('tr', count: 2)
@@ -77,10 +63,6 @@ describe 'browse and edit repository file through the UI' do
77
63
  end
78
64
 
79
65
  it 'should allow file revert' do
80
- # FIXME: This test is failing on TravisCI, but succeeding locally so skip
81
- # it for now and revisit in the future.
82
- next if ENV['TRAVIS']
83
-
84
66
  within('table#revisions') do
85
67
  within('tbody') do
86
68
  page.must_have_css('tr', count: 2)