algoliasearch-jekyll 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +4 -1
  5. data/README.md +8 -0
  6. data/Rakefile +2 -1
  7. data/VERSION +1 -1
  8. data/algoliasearch-jekyll.gemspec +129 -0
  9. data/lib/algoliasearch-jekyll.rb +13 -1
  10. data/lib/credential_checker.rb +74 -0
  11. data/lib/push.rb +52 -89
  12. data/lib/record_extractor.rb +1 -0
  13. data/scripts/check_flay +30 -0
  14. data/scripts/check_flog +31 -0
  15. data/scripts/git_hooks/pre-commit +2 -1
  16. data/scripts/git_hooks/pre-push +6 -1
  17. data/spec/credential_checker_spec.rb +116 -0
  18. data/spec/fixtures/_config.yml +9 -4
  19. data/spec/fixtures/_layouts/default.html +6 -0
  20. data/spec/fixtures/_posts/2015-07-03-test-post-again.md +7 -0
  21. data/spec/fixtures/_site/2015/07/02/test-post.html +26 -0
  22. data/spec/fixtures/_site/2015/07/03/test-post-again.html +3 -0
  23. data/spec/fixtures/_site/about.html +31 -0
  24. data/spec/fixtures/_site/assets/ring.png +0 -0
  25. data/spec/fixtures/_site/authors.html +1 -0
  26. data/spec/fixtures/_site/excluded.html +1 -0
  27. data/spec/fixtures/_site/hierarchy.html +31 -0
  28. data/spec/fixtures/_site/index.html +17 -0
  29. data/spec/fixtures/_site/my-collection/collection-item.html +2 -0
  30. data/spec/fixtures/_site/page2/index.html +40 -0
  31. data/spec/fixtures/_site/weight.html +15 -0
  32. data/spec/fixtures/index.html +13 -0
  33. data/spec/push_spec.rb +134 -113
  34. data/spec/record_extractor_spec.rb +10 -0
  35. data/spec/spec_helper.rb +21 -11
  36. data/spec/spec_helper_simplecov.rb +1 -1
  37. data/txt/api_key_missing +4 -0
  38. data/txt/application_id_missing +8 -0
  39. data/txt/index_name_missing +9 -0
  40. metadata +69 -5
  41. data/scripts/run_tests +0 -2
  42. data/scripts/update_gem +0 -10
data/spec/push_spec.rb CHANGED
@@ -10,26 +10,23 @@ describe(AlgoliaSearchJekyllPush) do
10
10
  let(:static_file) { site.file_by_name('ring.png') }
11
11
  let(:document_file) { site.file_by_name('collection-item.md') }
12
12
  let(:html_document_file) { site.file_by_name('collection-item.html') }
13
- let(:options) do
14
- {
15
- 'drafts' => true
16
- }
17
- end
18
- let(:config) do
19
- {
20
- 'source' => File.expand_path('./spec/fixtures'),
21
- 'markdown_ext' => 'md,mkd',
22
- 'algolia' => {
23
- 'application_id' => 'APPID',
24
- 'index_name' => 'INDEXNAME'
25
- }
26
- }
13
+ let(:pagination_page) { site.file_by_name('page2/index.html') }
14
+ let(:items) do
15
+ [{
16
+ name: 'foo',
17
+ url: '/foo'
18
+ }, {
19
+ name: 'bar',
20
+ url: '/bar'
21
+ }]
27
22
  end
28
23
 
29
24
  describe 'init_options' do
30
25
  it 'sets options and config' do
31
26
  # Given
32
27
  args = nil
28
+ options = { 'foo' => 'bar' }
29
+ config = { 'bar' => 'foo' }
33
30
 
34
31
  # When
35
32
  push.init_options(args, options, config)
@@ -38,24 +35,9 @@ describe(AlgoliaSearchJekyllPush) do
38
35
  expect(push.options).to include(options)
39
36
  expect(push.config).to include(config)
40
37
  end
41
-
42
- it 'sets indexname from the commandline' do
43
- # Given
44
- args = ['newindex']
45
-
46
- # When
47
- push.init_options(args, options, config)
48
-
49
- # Then
50
- expect(push.config['algolia']['index_name']).to eq 'newindex'
51
- end
52
38
  end
53
39
 
54
40
  describe 'indexable?' do
55
- before(:each) do
56
- push.init_options(nil, options, config)
57
- end
58
-
59
41
  it 'exclude StaticFiles' do
60
42
  expect(push.indexable?(static_file)).to eq false
61
43
  end
@@ -77,144 +59,183 @@ describe(AlgoliaSearchJekyllPush) do
77
59
  end
78
60
 
79
61
  it 'exclude file specified in config' do
80
- # Given
81
- config['algolia']['excluded_files'] = [
82
- 'excluded.html'
83
- ]
84
- push.init_options(nil, options, config)
85
-
86
- # Then
87
62
  expect(push.indexable?(excluded_page_file)).to eq false
88
63
  end
64
+
65
+ it 'does not index pagination pages' do
66
+ expect(push.indexable?(pagination_page)).to eq false
67
+ end
89
68
  end
90
69
 
91
- describe 'api_key' do
92
- it 'returns nil if no key found' do
70
+ describe 'excluded_files?' do
71
+ before(:each) do
72
+ push.init_options(nil, {}, site.config)
73
+ end
74
+
75
+ it 'should alway exclude pagination pages' do
76
+ expect(push.excluded_file?('page3/index.html')).to eq true
77
+ end
78
+
79
+ it 'should exclude user specified strings' do
80
+ expect(push.excluded_file?('excluded.html')).to eq true
81
+ end
82
+ end
83
+
84
+ describe 'configure_index' do
85
+ it 'sets some sane defaults' do
93
86
  # Given
94
- push.init_options(nil, options, config)
87
+ push.init_options(nil, {}, {})
88
+ index = double
89
+
90
+ # Then
91
+ expected = {
92
+ attributeForDistinct: 'title',
93
+ distinct: true,
94
+ customRanking: ['desc(posted_at)', 'desc(weight)']
95
+ }
96
+ expect(index).to receive(:set_settings).with(hash_including(expected))
95
97
 
96
98
  # When
97
- expect(push.api_key).to be_nil
99
+ push.configure_index(index)
98
100
  end
99
101
 
100
- it 'reads from ENV var if set' do
102
+ it 'allow user to override all settings' do
101
103
  # Given
102
- push.init_options(nil, options, config)
103
- stub_const('ENV', 'ALGOLIA_API_KEY' => 'APIKEY_FROM_ENV')
104
+ settings = {
105
+ distinct: false,
106
+ customSetting: 'foo',
107
+ customRanking: ['asc(foo)', 'desc(bar)']
108
+ }
109
+ config = {
110
+ 'algolia' => {
111
+ 'settings' => settings
112
+ }
113
+ }
114
+ push.init_options(nil, {}, config)
115
+ index = double
116
+
117
+ # Then
118
+ expect(index).to receive(:set_settings).with(hash_including(settings))
104
119
 
105
120
  # When
106
- actual = push.api_key
121
+ push.configure_index(index)
122
+ end
123
+ end
124
+
125
+ describe 'jekyll_new' do
126
+ it 'should return a patched version of site with a custom write' do
127
+ # Given
128
+ normal_site = Jekyll::Site.new(Jekyll.configuration)
129
+ normal_method = normal_site.method(:write).source_location
130
+
131
+ patched_site = get_site({}, mock_write_method: false, process: false)
132
+ patched_method = patched_site.method(:write).source_location
107
133
 
134
+ # When
108
135
  # Then
109
- expect(actual).to eq 'APIKEY_FROM_ENV'
136
+ expect(patched_method).not_to eq normal_method
110
137
  end
138
+ end
111
139
 
112
- it 'reads from _algolia_api_key in source if set' do
140
+ describe 'process' do
141
+ it 'should call the site write method' do
113
142
  # Given
114
- config['source'] = File.join(config['source'], 'api_key_dir')
115
- push.init_options(nil, options, config)
143
+ site = get_site({}, process: false)
116
144
 
117
145
  # When
118
- actual = push.api_key
146
+ site.process
119
147
 
120
148
  # Then
121
- expect(actual).to eq 'APIKEY_FROM_FILE'
149
+ expect(site).to have_received(:write)
122
150
  end
123
151
 
124
- it 'reads from ENV before from file' do
152
+ it 'should push items to Algolia' do
125
153
  # Given
126
- config['source'] = File.join(config['source'], 'api_key_dir')
127
- stub_const('ENV', 'ALGOLIA_API_KEY' => 'APIKEY_FROM_ENV')
128
- push.init_options(nil, options, config)
154
+ site = get_site({}, mock_write_method: false, process: false)
155
+ # Keep only page_file
156
+ allow(AlgoliaSearchJekyllPush).to receive(:indexable?) do |file|
157
+ file.path == page_file.path
158
+ end
159
+ allow(AlgoliaSearchJekyllPush).to receive(:push)
129
160
 
130
161
  # When
131
- actual = push.api_key
162
+ site.process
132
163
 
133
164
  # Then
134
- expect(actual).to eq 'APIKEY_FROM_ENV'
165
+ expect(AlgoliaSearchJekyllPush).to have_received(:push) do |arg|
166
+ expect(arg.size).to eq 6
167
+ end
135
168
  end
136
169
  end
137
170
 
138
- describe 'check_credentials' do
139
- it 'should display error if no api key' do
140
- # Given
141
- config['algolia'] = {
142
- 'application_id' => 'APP_ID',
143
- 'index_name' => 'INDEX_NAME'
171
+ describe 'push' do
172
+ let(:index_double) { double('Algolia Index').as_null_object }
173
+ let(:config) do
174
+ {
175
+ 'algolia' => {
176
+ 'index_name' => 'INDEXNAME'
177
+ }
144
178
  }
145
- push.init_options(nil, options, config)
179
+ end
146
180
 
147
- # Then
148
- expect(Jekyll.logger).to receive(:error).with(/api key/i)
149
- expect(Jekyll.logger).to receive(:warn).at_least(:once)
150
- expect(-> { push.check_credentials }).to raise_error SystemExit
181
+ before(:each) do
182
+ push.init_options(nil, {}, config)
183
+ # Mock all calls to not send anything
184
+ allow_any_instance_of(AlgoliaSearchCredentialChecker)
185
+ .to receive(:assert_valid)
186
+ allow(Algolia).to receive(:init)
187
+ allow(Algolia).to receive(:move_index)
188
+ allow(Algolia::Index).to receive(:new).and_return(index_double)
189
+ allow(Jekyll.logger).to receive(:info)
151
190
  end
152
191
 
153
- it 'should display error if no application id' do
192
+ it 'should create a temporary index' do
154
193
  # Given
155
- config['algolia'] = {
156
- 'application_id' => nil,
157
- 'index_name' => 'INDEX_NAME'
158
- }
159
- stub_const('ENV', 'ALGOLIA_API_KEY' => 'APIKEY_FROM_ENV')
160
- push.init_options(nil, options, config)
194
+
195
+ # When
196
+ push.push(items)
161
197
 
162
198
  # Then
163
- expect(Jekyll.logger).to receive(:error).with(/application id/i)
164
- expect(Jekyll.logger).to receive(:warn).at_least(:once)
165
- expect(-> { push.check_credentials }).to raise_error SystemExit
199
+ expect(Algolia::Index).to have_received(:new).with('INDEXNAME_tmp')
166
200
  end
167
201
 
168
- it 'should display error if no index name' do
202
+ it 'should add elements to the temporary index' do
169
203
  # Given
170
- config['algolia'] = {
171
- 'application_id' => 'APPLICATION_ID',
172
- 'index_name' => nil
173
- }
174
- stub_const('ENV', 'ALGOLIA_API_KEY' => 'APIKEY_FROM_ENV')
175
- push.init_options(nil, options, config)
204
+
205
+ # When
206
+ push.push(items)
176
207
 
177
208
  # Then
178
- expect(Jekyll.logger).to receive(:error).with(/index name/i)
179
- expect(Jekyll.logger).to receive(:warn).at_least(:once)
180
- expect(-> { push.check_credentials }).to raise_error SystemExit
209
+ expect(index_double).to have_received(:add_objects!)
181
210
  end
182
- end
183
211
 
184
- describe 'configure_index' do
185
- it 'sets some sane defaults' do
212
+ it 'should move the temporary index as the main one' do
186
213
  # Given
187
- push.init_options(nil, options, config)
188
- index = double
189
-
190
- # Then
191
- expected = {
192
- attributeForDistinct: 'title',
193
- distinct: true,
194
- customRanking: ['desc(posted_at)', 'desc(weight)']
195
- }
196
- expect(index).to receive(:set_settings).with(hash_including(expected))
197
214
 
198
215
  # When
199
- push.configure_index(index)
216
+ push.push(items)
217
+
218
+ # Then
219
+ expect(Algolia).to have_received(:move_index)
220
+ .with('INDEXNAME_tmp', 'INDEXNAME')
200
221
  end
201
222
 
202
- it 'allow user to override all settings' do
223
+ it 'should display the number of elements indexed' do
203
224
  # Given
204
- settings = {
205
- distinct: false,
206
- customSetting: 'foo',
207
- customRanking: ['asc(foo)', 'desc(bar)']
208
- }
209
- config['algolia']['settings'] = settings
210
- push.init_options(nil, options, config)
211
- index = double
225
+
226
+ # When
227
+ push.push(items)
212
228
 
213
229
  # Then
214
- expect(index).to receive(:set_settings).with(hash_including(settings))
230
+ expect(Jekyll.logger).to have_received(:info).with(/of 2 items/i)
231
+ end
215
232
 
216
- # When
217
- push.configure_index(index)
233
+ it 'should display an error if `add_objects!` failed' do
234
+ # Given
235
+ allow(index_double).to receive(:add_objects!).and_raise
236
+
237
+ expect(Jekyll.logger).to receive(:error)
238
+ expect(-> { push.push(items) }).to raise_error SystemExit
218
239
  end
219
240
  end
220
241
  end
@@ -36,6 +36,16 @@ describe(AlgoliaSearchRecordExtractor) do
36
36
  expect(actual[:custom]).to eq 'Foo'
37
37
  end
38
38
 
39
+ it 'gets posted_at timestamp based on the configured timezone' do
40
+ # Given
41
+ site = get_site(timezone: 'America/New_York')
42
+ post_file = extractor.new(site.file_by_name('test-post.md'))
43
+ actual = post_file.metadata
44
+
45
+ # Then
46
+ expect(actual[:posted_at]).to eq 1_435_809_600
47
+ end
48
+
39
49
  it 'gets metadata from document' do
40
50
  # Given
41
51
  actual = document_file.metadata
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,8 @@
1
+ if ENV['TRAVIS']
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+ end
5
+
1
6
  require 'awesome_print'
2
7
  require_relative './spec_helper_jekyll.rb'
3
8
  require_relative './spec_helper_simplecov.rb'
@@ -7,27 +12,32 @@ RSpec.configure do |config|
7
12
  config.filter_run(focus: true)
8
13
  config.run_all_when_everything_filtered = true
9
14
 
10
- # Build a jekyll site, creating access to @__files used internally
11
- def get_site(config = {})
15
+ # Create a Jekyll::Site instance, patched with a `file_by_name` method
16
+ def get_site(config = {}, options = {})
17
+ default_options = {
18
+ mock_write_method: true,
19
+ process: true
20
+ }
21
+ options = default_options.merge(options)
22
+
12
23
  config = config.merge(
13
24
  source: File.expand_path('./spec/fixtures')
14
25
  )
15
26
  config = Jekyll.configuration(config)
16
- site = Jekyll::Site.new(config)
17
27
 
18
- # Keep a list of all files
19
- def site.write
20
- @__files = {}
28
+ site = AlgoliaSearchJekyllPush.init_options({}, options, config)
29
+ .jekyll_new(config)
30
+
31
+ def site.file_by_name(file_name)
21
32
  each_site_file do |file|
22
- @__files[file.path] = file
33
+ return file if file.path =~ /#{file_name}$/
23
34
  end
35
+ nil
24
36
  end
25
37
 
26
- def site.file_by_name(file_name)
27
- @__files.find { |path, _| path =~ /#{file_name}$/ }[1]
28
- end
38
+ allow(site).to receive(:write) if options[:mock_write_method]
29
39
 
30
- site.process
40
+ site.process if options[:process]
31
41
  site
32
42
  end
33
43
  end
@@ -1,7 +1,7 @@
1
1
  require 'simplecov'
2
2
 
3
3
  SimpleCov.configure do
4
- load_adapter 'test_frameworks'
4
+ load_profile 'test_frameworks'
5
5
  end
6
6
 
7
7
  ENV['COVERAGE'] && SimpleCov.start do
@@ -0,0 +1,4 @@
1
+ Algolia Error: No API key defined
2
+ You have two ways to configure your API key:
3
+ - The ALGOLIA_API_KEY environment variable
4
+ - A file named _algolia_api_key in your source folder
@@ -0,0 +1,8 @@
1
+ Algolia Error: No application ID defined
2
+ Please set your application id in the _config.yml file, like so:
3
+
4
+ algolia:
5
+ application_id: {your_application_id}
6
+
7
+ Your application ID can be found in your algolia dashboard:
8
+ https://www.algolia.com/licensing
@@ -0,0 +1,9 @@
1
+ Algolia Error: No index name defined
2
+ Please set your index name in the _config.yml file, like so:
3
+
4
+ algolia:
5
+ index_name: {your_index_name}
6
+
7
+ You can edit your indices in your dashboard:
8
+ https://www.algolia.com/explorer
9
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algoliasearch-jekyll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Carry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-16 00:00:00.000000000 Z
11
+ date: 2015-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: algoliasearch
@@ -66,6 +66,48 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: coveralls
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: flay
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.6'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: flog
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '4.3'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '4.3'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: guard-rspec
71
113
  requirement: !ruby/object:Gem::Requirement
@@ -159,37 +201,59 @@ extra_rdoc_files:
159
201
  - LICENSE.txt
160
202
  - README.md
161
203
  files:
204
+ - ".coveralls.yml"
162
205
  - ".rspec"
163
206
  - ".rubocop.yml"
207
+ - ".travis.yml"
164
208
  - Gemfile
165
209
  - Guardfile
166
210
  - LICENSE.txt
167
211
  - README.md
168
212
  - Rakefile
169
213
  - VERSION
214
+ - algoliasearch-jekyll.gemspec
170
215
  - lib/algoliasearch-jekyll.rb
216
+ - lib/credential_checker.rb
171
217
  - lib/push.rb
172
218
  - lib/record_extractor.rb
219
+ - scripts/check_flay
220
+ - scripts/check_flog
173
221
  - scripts/git_hooks/pre-commit
174
222
  - scripts/git_hooks/pre-push
175
- - scripts/run_tests
176
- - scripts/update_gem
223
+ - spec/credential_checker_spec.rb
177
224
  - spec/fixtures/_config.yml
225
+ - spec/fixtures/_layouts/default.html
178
226
  - spec/fixtures/_my-collection/collection-item.html
179
227
  - spec/fixtures/_my-collection/collection-item.md
180
228
  - spec/fixtures/_posts/2015-07-02-test-post.md
229
+ - spec/fixtures/_posts/2015-07-03-test-post-again.md
230
+ - spec/fixtures/_site/2015/07/02/test-post.html
231
+ - spec/fixtures/_site/2015/07/03/test-post-again.html
232
+ - spec/fixtures/_site/about.html
233
+ - spec/fixtures/_site/assets/ring.png
234
+ - spec/fixtures/_site/authors.html
235
+ - spec/fixtures/_site/excluded.html
236
+ - spec/fixtures/_site/hierarchy.html
237
+ - spec/fixtures/_site/index.html
238
+ - spec/fixtures/_site/my-collection/collection-item.html
239
+ - spec/fixtures/_site/page2/index.html
240
+ - spec/fixtures/_site/weight.html
181
241
  - spec/fixtures/about.md
182
242
  - spec/fixtures/api_key_dir/_algolia_api_key
183
243
  - spec/fixtures/assets/ring.png
184
244
  - spec/fixtures/authors.html
185
245
  - spec/fixtures/excluded.html
186
246
  - spec/fixtures/hierarchy.md
247
+ - spec/fixtures/index.html
187
248
  - spec/fixtures/weight.md
188
249
  - spec/push_spec.rb
189
250
  - spec/record_extractor_spec.rb
190
251
  - spec/spec_helper.rb
191
252
  - spec/spec_helper_jekyll.rb
192
253
  - spec/spec_helper_simplecov.rb
254
+ - txt/api_key_missing
255
+ - txt/application_id_missing
256
+ - txt/index_name_missing
193
257
  homepage: https://github.com/algolia/algoliasearch-jekyll
194
258
  licenses:
195
259
  - MIT
@@ -210,7 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
274
  version: '0'
211
275
  requirements: []
212
276
  rubyforge_project:
213
- rubygems_version: 2.4.6
277
+ rubygems_version: 2.4.8
214
278
  signing_key:
215
279
  specification_version: 4
216
280
  summary: AlgoliaSearch for Jekyll