algoliasearch-jekyll 0.2.3 → 0.3.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 (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