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,81 +2,19 @@
2
2
 
3
3
  require File.expand_path('../test_helper', __FILE__)
4
4
 
5
- describe 'gitdocs configuration' do
5
+ describe Gitdocs::Configuration do
6
6
  before do
7
- ENV['TEST'] = 'true'
8
- ShellTools.capture { @config = Gitdocs::Configuration.new('/tmp/gitdocs') }
7
+ ShellTools.capture { Gitdocs::Initializer.initialize_database }
9
8
  end
10
9
 
11
- it 'has sensible default config root' do
12
- assert_equal '/tmp/gitdocs', @config.config_root
13
- end
14
-
15
- it 'can retrieve empty shares' do
16
- assert_equal [], @config.shares
17
- end
18
-
19
- it 'can have a path added' do
20
- @config.add_path('/my/../my/path') # normalized test
21
- assert_equal '/my/path', @config.shares.first.path
22
- assert_equal 15.0, @config.shares.first.polling_interval
23
- end
24
-
25
- it 'can have a path removed' do
26
- @config.add_path('/my/path')
27
- @config.add_path('/my/path/2')
28
- @config.remove_path('/my/../my/path/2') # normalized test
29
- assert_equal ['/my/path'], @config.shares.map(&:path)
30
- end
31
-
32
- it 'can have a share removed by id' do
33
- @config.add_path('/my/path')
34
- @config.add_path('/my/path/2')
35
-
36
- # Delete an index which exists
37
- @config.remove_by_id(2).must_equal(true) # normalized test
38
- assert_equal ['/my/path'], @config.shares.map(&:path)
39
-
40
- # Try to delete an index which does not exist
41
- @config.remove_by_id(5).must_equal(false) # normalized test
42
- assert_equal ['/my/path'], @config.shares.map(&:path)
43
- end
44
-
45
- it 'can clear paths' do
46
- @config.add_path('/my/path')
47
- @config.add_path('/my/path/2')
48
- @config.clear
49
- assert_equal [], @config.shares.map(&:path)
50
- end
51
-
52
- describe '#update_all' do
10
+ describe 'Config.update' do
53
11
  before do
54
- @config.add_path('/my/path')
55
- @config.add_path('/my/path/2')
56
- @config.add_path('/my/path/3')
57
- @config.add_path('/my/path/4')
58
- @config.add_path('/my/path/5')
59
- @config.update_all(
60
- 'config' => { 'start_web_frontend' => false, 'web_frontend_port' => 9999 },
61
- 'share' => {
62
- '0' => { 'path' => '/my/path', 'polling_interval' => 42 },
63
- '1' => { 'path' => '/my/path/2', 'polling_interval' => 66 },
64
- '2' => { 'path' => '/my/path/3a', 'polling_interval' => 77 },
65
- '3' => { 'path' => '', 'polling_interval' => 88 },
66
- '4' => { 'polling_interval' => 99 }
67
- }
12
+ Gitdocs::Configuration.update(
13
+ 'start_web_frontend' => false, 'web_frontend_port' => 9999
68
14
  )
69
15
  end
70
- it { @config.shares.size.must_equal(5) }
71
- it { @config.shares[0].path.must_equal('/my/path') }
72
- it { @config.shares[0].polling_interval.must_equal(42) }
73
- it { @config.shares[1].path.must_equal('/my/path/2') }
74
- it { @config.shares[1].polling_interval.must_equal(66) }
75
- it { @config.shares[2].path.must_equal('/my/path/3a') }
76
- it { @config.shares[2].polling_interval.must_equal(77) }
77
- it { @config.shares[3].path.must_equal('/my/path/4') }
78
- it { @config.shares[3].polling_interval.must_equal(15) }
79
- it { @config.shares[4].path.must_equal('/my/path/5') }
80
- it { @config.shares[4].polling_interval.must_equal(15) }
16
+
17
+ it { Gitdocs::Configuration.start_web_frontend.must_equal(false) }
18
+ it { Gitdocs::Configuration.web_frontend_port.must_equal(9999) }
81
19
  end
82
20
  end
@@ -0,0 +1,116 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require File.expand_path('../test_helper', __FILE__)
3
+
4
+ describe Gitdocs::GitNotifier do
5
+ let(:git_notifier) { Gitdocs::GitNotifier.new(:root, :show_notifications) }
6
+
7
+ describe '.for_merge' do
8
+ subject { git_notifier.for_merge(result) }
9
+
10
+ describe 'with no changes' do
11
+ before do
12
+ # Ensure that the notification methods are not called.
13
+ Gitdocs::Notifier.stubs(:warn).raises
14
+ Gitdocs::Notifier.stubs(:info).raises
15
+ Gitdocs::Notifier.stubs(:error).raises
16
+ end
17
+ describe('with nil') { let(:result) { nil } ; it { subject } }
18
+ describe('with no_remote') { let(:result) { :no_remote } ; it { subject } }
19
+ describe('with no changes') { let(:result) { {} } ; it { subject } }
20
+ end
21
+
22
+ describe 'with changes' do
23
+ let(:result) { { 'Alice' => 1, 'Bob' => 3 } }
24
+ before do
25
+ Gitdocs::Notifier.expects(:info).with(
26
+ 'Updated with 4 changes',
27
+ "In root:\n* Alice (1 change)\n* Bob (3 changes)",
28
+ :show_notifications
29
+ )
30
+ end
31
+ it { subject }
32
+ end
33
+
34
+ describe 'with conflicts' do
35
+ let(:result) { ['file'] }
36
+ before do
37
+ Gitdocs::Notifier.expects(:warn).with(
38
+ 'There were some conflicts',
39
+ '* file',
40
+ :show_notifications
41
+ )
42
+ end
43
+ it { subject }
44
+ end
45
+
46
+ describe 'with anything else' do
47
+ let(:result) { 'error' }
48
+ before do
49
+ Gitdocs::Notifier.expects(:error).with(
50
+ 'There was a problem synchronizing this gitdoc',
51
+ "A problem occurred in root:\nerror",
52
+ :show_notifications
53
+ )
54
+ end
55
+ it { subject }
56
+ end
57
+ end
58
+
59
+ describe '.for_push' do
60
+ subject { git_notifier.for_push(result) }
61
+
62
+ describe 'with no changes' do
63
+ before do
64
+ # Ensure that the notification methods are not called.
65
+ Gitdocs::Notifier.stubs(:warn).raises
66
+ Gitdocs::Notifier.stubs(:info).raises
67
+ Gitdocs::Notifier.stubs(:error).raises
68
+ end
69
+ describe('with nil') { let(:result) { nil } ; it { subject } }
70
+ describe('with no_remote') { let(:result) { :no_remote } ; it { subject } }
71
+ describe('with nothing') { let(:result) { :nothing } ; it { subject } }
72
+ end
73
+
74
+ describe 'with changes' do
75
+ let(:result) { { 'Alice' => 1, 'Bob' => 3 } }
76
+ before do
77
+ Gitdocs::Notifier.expects(:info).with(
78
+ 'Pushed 4 changes', 'root has been pushed', :show_notifications
79
+ )
80
+ end
81
+ it { subject }
82
+ end
83
+
84
+ describe 'with conflict' do
85
+ let(:result) { :conflict }
86
+ before do
87
+ Gitdocs::Notifier.expects(:warn).with(
88
+ 'There was a conflict in root, retrying', '', :show_notifications
89
+ )
90
+ end
91
+ it { subject }
92
+ end
93
+
94
+ describe 'with anything else' do
95
+ let(:result) { 'error' }
96
+ before do
97
+ Gitdocs::Notifier.expects(:error).with(
98
+ 'BAD Could not push changes in root', 'error', :show_notifications
99
+ )
100
+ end
101
+ it { subject }
102
+ end
103
+ end
104
+
105
+ describe '.on_error' do
106
+ subject { git_notifier.on_error(:exception) }
107
+ before do
108
+ Gitdocs::Notifier.expects(:error).with(
109
+ 'Unexpected error when fetching/pushing in root',
110
+ 'exception',
111
+ :show_notifications
112
+ )
113
+ end
114
+ it { subject }
115
+ end
116
+ end
@@ -0,0 +1,90 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require File.expand_path('../test_helper', __FILE__)
4
+
5
+ describe 'Gitdocs' do
6
+ describe '.log_path' do
7
+ subject { Gitdocs.log_path }
8
+ before do
9
+ Gitdocs::Initializer.stubs(:root_dirname).returns(:root_dirname)
10
+ File.stubs(:expand_path).with('log', :root_dirname).returns(:result)
11
+ end
12
+ it { subject.must_equal(:result) }
13
+ end
14
+
15
+ describe 'log wrappers' do
16
+ let(:logger) { stubs('Logger') }
17
+
18
+ before do
19
+ Gitdocs::Initializer.stubs(:foreground).returns(foreground)
20
+ Gitdocs::Initializer.stubs(:verbose).returns(verbose)
21
+ Gitdocs.stubs(:log_path).returns(:log_path)
22
+
23
+ Gitdocs.instance_variable_set(:@initialized, nil)
24
+ Logger.stubs(:new).with(expected_path).returns(logger)
25
+ logger.expects(:level=).with(expected_level)
26
+ end
27
+
28
+ describe 'background and non-verbose' do
29
+ let(:foreground) { false }
30
+ let(:verbose) { false }
31
+ let(:expected_path) { :log_path }
32
+ let(:expected_level) { Logger::INFO }
33
+
34
+ describe '.log_debug' do
35
+ subject { Gitdocs.log_debug(:message) }
36
+ before { logger.expects(:debug).with(:message) }
37
+ it { subject }
38
+ end
39
+
40
+ describe '.log_info' do
41
+ subject { Gitdocs.log_info(:message) }
42
+ before { logger.expects(:info).with(:message) }
43
+ it { subject }
44
+ end
45
+
46
+ describe '.log_warn' do
47
+ subject { Gitdocs.log_warn(:message) }
48
+ before { logger.expects(:warn).with(:message) }
49
+ it { subject }
50
+ end
51
+
52
+ describe '.log_error' do
53
+ subject { Gitdocs.log_error(:message) }
54
+ before { logger.expects(:error).with(:message) }
55
+ it { subject }
56
+ end
57
+ end
58
+
59
+ describe 'foreground and verborse' do
60
+ let(:foreground) { true }
61
+ let(:verbose) { true }
62
+ let(:expected_path) { STDOUT }
63
+ let(:expected_level) { Logger::DEBUG }
64
+
65
+ describe '.log_debug' do
66
+ subject { Gitdocs.log_debug(:message) }
67
+ before { logger.expects(:debug).with(:message) }
68
+ it { subject }
69
+ end
70
+
71
+ describe '.log_info' do
72
+ subject { Gitdocs.log_info(:message) }
73
+ before { logger.expects(:info).with(:message) }
74
+ it { subject }
75
+ end
76
+
77
+ describe '.log_warn' do
78
+ subject { Gitdocs.log_warn(:message) }
79
+ before { logger.expects(:warn).with(:message) }
80
+ it { subject }
81
+ end
82
+
83
+ describe '.log_error' do
84
+ subject { Gitdocs.log_error(:message) }
85
+ before { logger.expects(:error).with(:message) }
86
+ it { subject }
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require File.expand_path('../test_helper', __FILE__)
4
+
5
+ describe 'Gitdocs::Manager' do
6
+ describe '.start' do
7
+ subject { Gitdocs::Manager.start(:web_port) }
8
+
9
+ before do
10
+ Gitdocs::Manager.stubs(:new).returns(manager = stub)
11
+ manager.expects(:start).with(:web_port)
12
+ end
13
+
14
+ it { subject }
15
+ end
16
+
17
+ # TODO: describe '.restart_synchronization' do
18
+
19
+ describe '.listen_method' do
20
+ subject { Gitdocs::Manager.listen_method }
21
+
22
+ before { Listen::Adapter.stubs(:select).returns(listen_adapter) }
23
+
24
+ describe 'polling' do
25
+ let(:listen_adapter) { Listen::Adapter::Polling }
26
+ it { subject.must_equal :polling }
27
+ end
28
+
29
+ describe 'notification' do
30
+ let(:listen_adapter) { :not_polling }
31
+ it { subject.must_equal :notification }
32
+ end
33
+ end
34
+
35
+ # TODO: describe '.start'
36
+ end
@@ -2,164 +2,100 @@
2
2
  require File.expand_path('../test_helper', __FILE__)
3
3
 
4
4
  describe Gitdocs::Notifier do
5
- let(:notifier) { Gitdocs::Notifier.new(show_notifications) }
5
+ describe 'public methods' do
6
+ let(:notifier) { mock }
7
+ before { Gitdocs::Notifier.stubs(:instance).returns(notifier) }
6
8
 
7
- describe '#error' do
8
- subject { Gitdocs::Notifier.error(:title, :message) }
9
- before do
10
- Gitdocs::Notifier.expects(:new).with(true).returns(notifier = mock)
11
- notifier.expects(:error).with(:title, :message)
12
- end
13
- it { subject }
14
- end
9
+ describe '.info' do
10
+ subject { Gitdocs::Notifier.info('title', 'message', show_notification) }
15
11
 
16
- describe '#info' do
17
- subject { notifier.info('title', 'message') }
12
+ before { Gitdocs.expects(:log_info).with('title: message') }
18
13
 
19
- describe 'without notifications' do
20
- let(:show_notifications) { false }
21
- before { notifier.expects(:puts).with('title: message') }
22
- it { subject }
23
- end
14
+ describe 'without notifications' do
15
+ let(:show_notification) { false }
16
+ before { Gitdocs::Notifier.expects(:puts).with('title: message') }
17
+ it { subject }
18
+ end
24
19
 
25
- describe 'with notifications' do
26
- let(:show_notifications) { true }
27
- before do
28
- Guard::Notifier.expects(:turn_on)
29
- Guard::Notifier.expects(:notify)
30
- .with(
31
- 'message',
32
- title: 'title',
33
- image: File.expand_path('../../../lib/img/icon.png', __FILE__)
34
- )
20
+ describe 'with notifications' do
21
+ let(:show_notification) { true }
22
+ before { notifier.expects(:notify).with('title', 'message', :success) }
23
+ it { subject }
35
24
  end
36
- it { subject }
37
25
  end
38
- end
39
26
 
40
- describe '#warn' do
41
- subject { notifier.warn('title', 'message') }
27
+ describe '.warn' do
28
+ subject { Gitdocs::Notifier.warn('title', 'message', show_notification) }
42
29
 
43
- describe 'without notifications' do
44
- let(:show_notifications) { false }
45
- before { Kernel.expects(:warn).with('title: message') }
46
- it { subject }
47
- end
30
+ before { Gitdocs.expects(:log_warn).with('title: message') }
48
31
 
49
- describe 'with notifications' do
50
- let(:show_notifications) { true }
51
- before do
52
- Guard::Notifier.expects(:turn_on)
53
- Guard::Notifier.expects(:notify).with('message', title: 'title')
32
+ describe 'without notifications' do
33
+ let(:show_notification) { false }
34
+ before { Kernel.expects(:warn).with('title: message') }
35
+ it { subject }
54
36
  end
55
- it { subject }
56
- end
57
- end
58
-
59
- describe '#error' do
60
- subject { notifier.error('title', 'message') }
61
37
 
62
- describe 'without notifications' do
63
- let(:show_notifications) { false }
64
- before { Kernel.expects(:warn).with('title: message') }
65
- it { subject }
66
- end
67
-
68
- describe 'with notifications' do
69
- let(:show_notifications) { true }
70
- before do
71
- Guard::Notifier.expects(:turn_on)
72
- Guard::Notifier.expects(:notify).with('message', title: 'title', image: :failure)
38
+ describe 'with notifications' do
39
+ let(:show_notification) { true }
40
+ before { notifier.expects(:notify).with('title', 'message', :pending) }
41
+ it { subject }
73
42
  end
74
- it { subject }
75
43
  end
76
- end
77
-
78
- describe '#merge_notification' do
79
- subject { notifier.merge_notification(result, 'root_path') }
80
44
 
81
- let(:show_notifications) { false }
45
+ describe '.error' do
46
+ subject { Gitdocs::Notifier.error('title', 'message', show_notification) }
82
47
 
83
- describe 'with no changes' do
84
- before do
85
- # Ensure that the notification methods are not called.
86
- notifier.stubs(:warn).raises
87
- notifier.stubs(:info).raises
88
- notifier.stubs(:error).raises
89
- end
90
- describe('with nil') { let(:result) { nil } ; it { subject } }
91
- describe('with no_remote') { let(:result) { :no_remote } ; it { subject } }
92
- describe('with no changes') { let(:result) { {} } ; it { subject } }
93
- end
48
+ before { Gitdocs.expects(:log_error).with('title: message') }
94
49
 
95
- describe 'with changes' do
96
- let(:result) { { 'Alice' => 1, 'Bob' => 3 } }
97
- before do
98
- notifier.expects(:info).with(
99
- 'Updated with 4 changes',
100
- "In root_path:\n* Alice (1 change)\n* Bob (3 changes)"
101
- )
50
+ describe 'without notifications' do
51
+ let(:show_notification) { false }
52
+ before { Kernel.expects(:warn).with('title: message') }
53
+ it { subject }
102
54
  end
103
- it { subject }
104
- end
105
55
 
106
- describe 'with conflicts' do
107
- let(:result) { ['file'] }
108
- before do
109
- notifier.expects(:warn).with(
110
- 'There were some conflicts',
111
- '* file'
112
- )
56
+ describe 'with notifications' do
57
+ let(:show_notification) { true }
58
+ before { notifier.expects(:notify).with('title', 'message', :failed) }
59
+ it { subject }
113
60
  end
114
- it { subject }
115
61
  end
116
62
 
117
- describe 'with anything else' do
118
- let(:result) { 'error' }
119
- before do
120
- notifier.expects(:error).with(
121
- 'There was a problem synchronizing this gitdoc',
122
- "A problem occurred in root_path:\nerror"
123
- )
124
- end
63
+ describe '.disconnect' do
64
+ subject { Gitdocs::Notifier.disconnect }
65
+ before { notifier.expects(:disconnect) }
125
66
  it { subject }
126
67
  end
127
68
  end
128
69
 
129
- describe '#push_notification' do
130
- subject { notifier.push_notification(result, 'root_path') }
131
-
132
- let(:show_notifications) { false }
70
+ describe 'private-ish instance methods' do
71
+ let(:notifier) { Gitdocs::Notifier.send(:new) }
72
+ let(:notiffany) { mock }
133
73
 
134
- describe('with nil') { let(:result) { nil } ; it { subject } }
135
- describe('with no_remote') { let(:result) { :no_remote } ; it { subject } }
136
- describe('with nothing') { let(:result) { :nothing } ; it { subject } }
137
-
138
- describe 'with changes' do
139
- let(:result) { { 'Alice' => 1, 'Bob' => 3 } }
74
+ describe '#notify' do
75
+ subject { notifier.notify(:title, :message, :type) }
140
76
  before do
141
- notifier.expects(:info)
142
- .with('Pushed 4 changes', 'root_path has been pushed')
77
+ Notiffany.expects(:connect).returns(notiffany)
78
+ notiffany.expects(:notify).with(:message, title: :title, image: :type)
143
79
  end
144
80
  it { subject }
145
81
  end
146
82
 
147
- describe 'with conflict' do
148
- let(:result) { :conflict }
149
- before do
150
- notifier.expects(:warn)
151
- .with('There was a conflict in root_path, retrying', '')
83
+ describe '#disconnect' do
84
+ subject { notifier.disconnect }
85
+
86
+ describe 'not connected' do
87
+ before { subject }
88
+ it { notifier.instance_variable_get(:@notifier).must_equal(nil) }
152
89
  end
153
- it { subject }
154
- end
155
90
 
156
- describe 'with anything else' do
157
- let(:result) { 'error' }
158
- before do
159
- notifier.expects(:error)
160
- .with('BAD Could not push changes in root_path', 'error')
91
+ describe 'connect' do
92
+ before do
93
+ notifier.instance_variable_set(:@notifier, notiffany)
94
+ notiffany.expects(:disconnect)
95
+ subject
96
+ end
97
+ it { notifier.instance_variable_get(:@notifier).must_equal(nil) }
161
98
  end
162
- it { subject }
163
99
  end
164
100
  end
165
101
  end