gitdocs 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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