algoliasearch-jekyll 0.9.1 → 1.0.0.beta.pre.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -4
  3. data/CONTRIBUTING.md +8 -1
  4. data/Gemfile +4 -5
  5. data/README.md +318 -11
  6. data/Rakefile +7 -12
  7. data/algoliasearch-jekyll.gemspec +66 -62
  8. data/gemfiles/jekyll_v2.gemfile +3 -3
  9. data/gemfiles/jekyll_v3.gemfile +4 -4
  10. data/gemfiles/jekyll_v3_1_3.gemfile +24 -0
  11. data/gemfiles/jekyll_v3_1_6.gemfile +24 -0
  12. data/lib/algoliasearch-jekyll.rb +1 -3
  13. data/lib/credential_checker.rb +2 -1
  14. data/lib/error_handler.rb +6 -0
  15. data/lib/push.rb +81 -19
  16. data/lib/record_extractor.rb +120 -140
  17. data/lib/utils.rb +13 -0
  18. data/lib/version.rb +1 -1
  19. data/scripts/release +13 -12
  20. data/scripts/test_v3 +1 -1
  21. data/scripts/watch +4 -0
  22. data/spec/error_handler_spec.rb +17 -0
  23. data/spec/fixtures/jekyll_version_2/404.html +8 -0
  24. data/spec/fixtures/jekyll_version_2/404.md +9 -0
  25. data/spec/fixtures/jekyll_version_2/_my-collection/collection-item.md +3 -0
  26. data/spec/fixtures/jekyll_version_2/_posts/2015-07-02-test-post.md +1 -1
  27. data/spec/fixtures/jekyll_version_2/about.md +3 -0
  28. data/spec/fixtures/jekyll_version_2/front_matter.md +15 -0
  29. data/spec/fixtures/jekyll_version_2/index.html +3 -1
  30. data/spec/fixtures/jekyll_version_2/only-divs.md +15 -0
  31. data/spec/fixtures/jekyll_version_2/only-paragraphs.md +15 -0
  32. data/spec/fixtures/jekyll_version_3/404.html +8 -0
  33. data/spec/fixtures/jekyll_version_3/404.md +9 -0
  34. data/spec/fixtures/jekyll_version_3/_config.yml +1 -1
  35. data/spec/fixtures/jekyll_version_3/_my-collection/collection-item.md +3 -0
  36. data/spec/fixtures/jekyll_version_3/_posts/2015-07-02-test-post.md +1 -1
  37. data/spec/fixtures/jekyll_version_3/about.md +3 -0
  38. data/spec/fixtures/jekyll_version_3/front_matter.md +15 -0
  39. data/spec/fixtures/jekyll_version_3/index.html +4 -1
  40. data/spec/fixtures/jekyll_version_3/only-divs.md +15 -0
  41. data/spec/fixtures/jekyll_version_3/only-paragraphs.md +15 -0
  42. data/spec/push_spec.rb +211 -8
  43. data/spec/record_extractor_spec.rb +296 -358
  44. data/spec/spec_helper.rb +32 -11
  45. data/txt/record_too_big +19 -0
  46. metadata +40 -51
  47. data/scripts/watch +0 -1
@@ -0,0 +1,13 @@
1
+ # Generic util helpers
2
+ class AlgoliaSearchUtils
3
+ # Check the current Jekyll version
4
+ def self.restrict_jekyll_version(more_than: nil, less_than: nil)
5
+ jekyll_version = Gem::Version.new(Jekyll::VERSION)
6
+ minimum_version = Gem::Version.new(more_than)
7
+ maximum_version = Gem::Version.new(less_than)
8
+
9
+ return false if !more_than.nil? && jekyll_version < minimum_version
10
+ return false if !less_than.nil? && jekyll_version > maximum_version
11
+ true
12
+ end
13
+ end
@@ -1,6 +1,6 @@
1
1
  # Expose gem version
2
2
  class AlgoliaSearchJekyllVersion
3
3
  def self.to_s
4
- '0.9.1'
4
+ '1.0.0.beta-1'
5
5
  end
6
6
  end
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
- git checkout master || exit 1
4
- git pull || exit 1
5
- bundle install && appraisal install
6
-
7
- git rebase develop || exit 1
8
- bundle install && appraisal install
9
- rake release || exit 1
10
-
11
- git checkout develop || exit 1
12
- bundle install && appraisal install
13
- git rebase master || exit 1
14
- bundle install && appraisal install
3
+ # Stop if any command fails
4
+ set -e
5
+
6
+ git checkout master
7
+ git pull
8
+
9
+ git rebase develop
10
+ bundle install
11
+ appraisal install
12
+ rake release
13
+
14
+ git checkout develop
15
+ git rebase master
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  cd "$(dirname "$BASH_SOURCE")"/..
3
3
 
4
- echo "Testing under Jekyll 3.0"
4
+ echo "Testing under Jekyll 3"
5
5
  COVERAGE=1 appraisal jekyll-v3 bundle exec rspec
6
6
 
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bash
2
+ cd "$(dirname "$BASH_SOURCE")"/..
3
+
4
+ guard --guardfile ./Guardfile_jekyllv2
@@ -121,6 +121,23 @@ describe(AlgoliaSearchErrorHandler) do
121
121
  expect(actual).to eq('check_key_acl_to_tmp_index')
122
122
  end
123
123
 
124
+ it 'should warn about big records' do
125
+ # Given
126
+ parsed = {
127
+ 'http_error' => 400,
128
+ 'json' => {
129
+ 'message' => 'Record is too big size=220062 bytes'
130
+ }
131
+ }
132
+ allow(@error_handler).to receive(:parse_algolia_error).and_return(parsed)
133
+
134
+ # When
135
+ actual = @error_handler.readable_algolia_error('error')
136
+
137
+ # Then
138
+ expect(actual).to eq('record_too_big')
139
+ end
140
+
124
141
  it 'should return false if no nice message found' do
125
142
  # Given
126
143
  parsed = false
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: 404 Not Found
3
+ ---
4
+
5
+ This is a 404.html error page. [GitHub pages](https://help.github.com/articles/creating-a-custom-404-page-for-your-github-pages-site/)
6
+ suggested that it should be a `.md` file, but the Hyde theme uses a `.html`, so we handle it as well.
7
+
8
+ It should not be indexed.
@@ -0,0 +1,9 @@
1
+ ---
2
+ title: 404 Not Found
3
+ ---
4
+
5
+ This is a classical error page, as suggested by
6
+ [GitHub pages](https://help.github.com/articles/creating-a-custom-404-page-for-your-github-pages-site/).
7
+
8
+ It should not be indexed.
9
+
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  title: Collection Item
3
3
  custom: Foo
4
+ tags:
5
+ - tag
6
+ - another tag
4
7
  ---
5
8
 
6
9
  The grandest of omelettes. Those that feast on dragon eggs often find that there
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "Test post"
3
- tags:
3
+ tags:
4
4
  - tag
5
5
  - another tag
6
6
  custom: Foo
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  title: About page
3
3
  custom: Foo
4
+ tags:
5
+ - tag
6
+ - another tag
4
7
  ---
5
8
 
6
9
  # Heading 1
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: Front-matter test
3
+ author: John Doe
4
+ custom: foo
5
+ slug: front_matter_test
6
+ date: foo
7
+ tags: foo
8
+ url: http://www.foo.com/
9
+ type: foo
10
+ ---
11
+
12
+ # Title
13
+
14
+ Paragraph content
15
+
@@ -3,7 +3,9 @@ layout: default
3
3
  title: Home
4
4
  ---
5
5
 
6
- This default index page is used to display the paginated posts
6
+ This default index page is usually used to display the list of posts, or briefly explain the product.
7
+
8
+ I feel that it should not be indexed.
7
9
 
8
10
  {% for post in paginator.posts %}
9
11
  <a href="{{ site.baseurl }}{{ post.url }}">
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: Only divs
3
+ ---
4
+
5
+ <div>This is the first paragraph</div>
6
+
7
+ <div>This is the second paragraph</div>
8
+
9
+ <div>This is the third paragraph</div>
10
+
11
+ <div>This is the fourth paragraph</div>
12
+
13
+ <div>This is the fifth paragraph</div>
14
+
15
+ <div>This is the last paragraph</div>
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: Only paragraphs
3
+ ---
4
+
5
+ This is the first paragraph
6
+
7
+ This is the second paragraph
8
+
9
+ This is the third paragraph
10
+
11
+ This is the fourth paragraph
12
+
13
+ This is the fifth paragraph
14
+
15
+ This is the last paragraph
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: 404 Not Found
3
+ ---
4
+
5
+ This is a 404.html error page. [GitHub pages](https://help.github.com/articles/creating-a-custom-404-page-for-your-github-pages-site/)
6
+ suggested that it should be a `.md` file, but the Hyde theme uses a `.html`, so we handle it as well.
7
+
8
+ It should not be indexed.
@@ -0,0 +1,9 @@
1
+ ---
2
+ title: 404 Not Found
3
+ ---
4
+
5
+ This is a classical error page, as suggested by
6
+ [GitHub pages](https://help.github.com/articles/creating-a-custom-404-page-for-your-github-pages-site/).
7
+
8
+ It should not be indexed.
9
+
@@ -12,6 +12,6 @@ algolia:
12
12
  - excluded.html
13
13
 
14
14
  # Jekyll 3.0 extracted the secondary features into their own plugins
15
- plugins:
15
+ gems:
16
16
  - jekyll-paginate
17
17
 
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  title: Collection Item
3
3
  custom: Foo
4
+ tags:
5
+ - tag
6
+ - another tag
4
7
  ---
5
8
 
6
9
  The grandest of omelettes. Those that feast on dragon eggs often find that there
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "Test post"
3
- tags:
3
+ tags:
4
4
  - tag
5
5
  - another tag
6
6
  custom: Foo
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  title: About page
3
3
  custom: Foo
4
+ tags:
5
+ - tag
6
+ - another tag
4
7
  ---
5
8
 
6
9
  # Heading 1
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: Front-matter test
3
+ author: John Doe
4
+ custom: foo
5
+ slug: front_matter_test
6
+ date: foo
7
+ tags: foo
8
+ url: http://www.foo.com/
9
+ type: foo
10
+ ---
11
+
12
+ # Title
13
+
14
+ Paragraph content
15
+
@@ -3,7 +3,9 @@ layout: default
3
3
  title: Home
4
4
  ---
5
5
 
6
- This default index page is used to display the paginated posts
6
+ This default index page is usually used to display the list of posts, or briefly explain the product.
7
+
8
+ I feel that it should not be indexed.
7
9
 
8
10
  {% for post in paginator.posts %}
9
11
  <a href="{{ site.baseurl }}{{ post.url }}">
@@ -11,3 +13,4 @@ This default index page is used to display the paginated posts
11
13
  </a>
12
14
  {{ post.content }}
13
15
  {% endfor %}
16
+
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: Only divs
3
+ ---
4
+
5
+ <div>This is the first paragraph</div>
6
+
7
+ <div>This is the second paragraph</div>
8
+
9
+ <div>This is the third paragraph</div>
10
+
11
+ <div>This is the fourth paragraph</div>
12
+
13
+ <div>This is the fifth paragraph</div>
14
+
15
+ <div>This is the last paragraph</div>
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: Only paragraphs
3
+ ---
4
+
5
+ This is the first paragraph
6
+
7
+ This is the second paragraph
8
+
9
+ This is the third paragraph
10
+
11
+ This is the fourth paragraph
12
+
13
+ This is the fifth paragraph
14
+
15
+ This is the last paragraph
@@ -11,6 +11,9 @@ describe(AlgoliaSearchJekyllPush) do
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
13
  let(:pagination_page) { site.file_by_name('page2/index.html') }
14
+ let(:err_404) { site.file_by_name('404.md') }
15
+ let(:err_404_html) { site.file_by_name('404.html') }
16
+ let(:homepage) { site.file_by_name('index.html') }
14
17
  let(:items) do
15
18
  [{
16
19
  name: 'foo',
@@ -21,6 +24,12 @@ describe(AlgoliaSearchJekyllPush) do
21
24
  }]
22
25
  end
23
26
 
27
+ before(:each) do
28
+ allow(Jekyll.logger).to receive(:info)
29
+ allow(Jekyll.logger).to receive(:warn)
30
+ allow(Jekyll.logger).to receive(:error)
31
+ end
32
+
24
33
  describe 'init_options' do
25
34
  it 'sets options and config' do
26
35
  # Given
@@ -37,6 +46,35 @@ describe(AlgoliaSearchJekyllPush) do
37
46
  end
38
47
  end
39
48
 
49
+ describe 'lazy_update?' do
50
+ it 'should return false by default' do
51
+ # Given
52
+ push.init_options(nil, {}, {})
53
+
54
+ # When
55
+ actual = push.lazy_update?
56
+
57
+ # Then
58
+ expect(actual).to eq false
59
+ end
60
+
61
+ it 'should return true if such an option is set in the config' do
62
+ # Given
63
+ config = {
64
+ 'algolia' => {
65
+ 'lazy_update' => true
66
+ }
67
+ }
68
+ push.init_options(nil, {}, config)
69
+
70
+ # When
71
+ actual = push.lazy_update?
72
+
73
+ # Then
74
+ expect(actual).to eq true
75
+ end
76
+ end
77
+
40
78
  describe 'indexable?' do
41
79
  it 'exclude StaticFiles' do
42
80
  expect(push.indexable?(static_file)).to eq false
@@ -65,6 +103,18 @@ describe(AlgoliaSearchJekyllPush) do
65
103
  it 'does not index pagination pages' do
66
104
  expect(push.indexable?(pagination_page)).to eq false
67
105
  end
106
+
107
+ it 'does not index 404 pages (in markdown)' do
108
+ expect(push.indexable?(err_404)).to eq false
109
+ end
110
+
111
+ it 'does not index 404 pages (in html)' do
112
+ expect(push.indexable?(err_404_html)).to eq false
113
+ end
114
+
115
+ it 'does not index homepage' do
116
+ expect(push.indexable?(homepage)).to eq false
117
+ end
68
118
  end
69
119
 
70
120
  describe 'excluded_files?' do
@@ -147,7 +197,6 @@ describe(AlgoliaSearchJekyllPush) do
147
197
  @error_handler_double = double('Error Handler double').as_null_object
148
198
  push.init_options(nil, {}, {})
149
199
  allow(@index_double).to receive(:set_settings).and_raise
150
- allow(Jekyll.logger).to receive(:error)
151
200
  end
152
201
 
153
202
  it 'stops if API throw an error' do
@@ -269,6 +318,53 @@ describe(AlgoliaSearchJekyllPush) do
269
318
  end
270
319
 
271
320
  describe 'push' do
321
+ before(:each) do
322
+ allow_any_instance_of(AlgoliaSearchCredentialChecker)
323
+ .to receive(:assert_valid)
324
+ end
325
+
326
+ it 'should do a lazy update if such is configured' do
327
+ # Given
328
+ allow(push).to receive(:lazy_update?).and_return(true)
329
+ allow(push).to receive(:lazy_update)
330
+ push.init_options(nil, {}, {})
331
+ items = ['foo']
332
+
333
+ # When
334
+ push.push(items)
335
+
336
+ # Then
337
+ expect(push).to have_received(:lazy_update).with(items)
338
+ end
339
+
340
+ it 'should do a greedy update if such is configured' do
341
+ # Given
342
+ allow(push).to receive(:greedy_update?).and_return(true)
343
+ allow(push).to receive(:greedy_update)
344
+ push.init_options(nil, {}, {})
345
+ items = ['foo']
346
+
347
+ # When
348
+ push.push(items)
349
+
350
+ # Then
351
+ expect(push).to have_received(:greedy_update).with(items)
352
+ end
353
+ end
354
+
355
+ describe 'batch_add_items' do
356
+ it 'should display an error if `add_objects!` failed' do
357
+ # Given
358
+ index = double('Algolia Index').as_null_object
359
+ allow(index).to receive(:add_objects!).and_raise
360
+
361
+ # When / Then
362
+ expect(-> { push.batch_add_items(items, index) })
363
+ .to raise_error SystemExit
364
+ end
365
+ end
366
+
367
+ describe 'greedy_update' do
272
368
  let(:index_double) { double('Algolia Index').as_null_object }
273
369
  let(:config) do
274
370
  {
@@ -280,21 +376,19 @@ describe(AlgoliaSearchJekyllPush) do
280
376
 
281
377
  before(:each) do
282
378
  push.init_options(nil, {}, config)
283
- # Mock all calls to not send anything
284
379
  allow_any_instance_of(AlgoliaSearchCredentialChecker)
285
380
  .to receive(:assert_valid)
286
381
  allow(Algolia).to receive(:set_extra_header)
287
382
  allow(Algolia).to receive(:init)
288
383
  allow(Algolia).to receive(:move_index)
289
384
  allow(Algolia::Index).to receive(:new).and_return(index_double)
290
- allow(Jekyll.logger).to receive(:info)
291
385
  end
292
386
 
293
387
  it 'should create a temporary index' do
294
388
  # Given
295
389
 
296
390
  # When
297
- push.push(items)
391
+ push.greedy_update(items)
298
392
 
299
393
  # Then
300
394
  expect(Algolia::Index).to have_received(:new).with('INDEXNAME_tmp')
@@ -330,12 +424,121 @@ describe(AlgoliaSearchJekyllPush) do
330
424
  # Then
331
425
  expect(Jekyll.logger).to have_received(:info).with(/of 2 items/i)
332
426
  end
427
+ end
428
+
429
+ describe 'lazy_update' do
430
+ let(:items) do
431
+ [
432
+ { objectID: 'foo' },
433
+ { objectID: 'baz' }
434
+ ]
435
+ end
436
+ let(:remote) { %w(foo bar) }
437
+ let(:local) { %w(foo baz) }
438
+ let(:index) { double.as_null_object }
333
439
 
334
- it 'should display an error if `add_objects!` failed' do
335
- allow(index_double).to receive(:add_objects!).and_raise
440
+ describe 'remote_ids' do
441
+ it 'should call browse on the index with the attributesToRetrieve ' do
442
+ # Given
443
+ index = double.as_null_object
444
+
445
+ # Then
446
+ push.remote_ids(index)
447
+
448
+ # Then
449
+ expect(index).to have_received(:browse)
450
+ end
451
+
452
+ it 'should return an array of all objectID returned by browse' do
453
+ # Given
454
+ index = double.as_null_object
455
+ hit1 = { 'objectID' => 'foo' }
456
+ hit2 = { 'objectID' => 'bar' }
457
+ allow(index).to receive(:browse).and_yield(hit1).and_yield(hit2)
458
+
459
+ # Then
460
+ actual = push.remote_ids(index)
461
+
462
+ # Then
463
+ expect(actual).to eq %w(foo bar)
464
+ end
465
+ end
466
+
467
+ describe 'delete_remote_not_in_local' do
468
+ it 'calls delete_objects! with the array of items to delete' do
469
+ # Given
470
+
471
+ # When
472
+ push.delete_remote_not_in_local(index, local, remote)
473
+
474
+ # Then
475
+ expect(index).to have_received(:delete_objects!).with(['bar'])
476
+ end
477
+
478
+ it 'displays the number of items deleted' do
479
+ # Given
480
+
481
+ # When
482
+ push.delete_remote_not_in_local(index, local, remote)
483
+
484
+ # Then
485
+ expect(Jekyll.logger).to have_received(:info).with('Deleting 1 items')
486
+ end
336
487
 
337
- expect(Jekyll.logger).to receive(:error)
338
- expect(-> { push.push(items) }).to raise_error SystemExit
488
+ it 'should do not do an API call if there is nothing to delete' do
489
+ # Given
490
+ input = %w(foo bar)
491
+
492
+ # When
493
+ push.delete_remote_not_in_local(index, input, input)
494
+
495
+ # Then
496
+ expect(index).not_to have_received(:delete_objects!)
497
+ end
498
+ end
499
+
500
+ describe 'add_local_not_in_remote' do
501
+ it 'should push all local items not yet in remote' do
502
+ # Given
503
+ allow(push).to receive(:batch_add_items)
504
+
505
+ # When
506
+ push.add_local_not_in_remote(index, items, local, remote)
507
+
508
+ # Then
509
+ expected = [{ objectID: 'baz' }]
510
+ expect(push).to have_received(:batch_add_items).with(expected, index)
511
+ end
512
+
513
+ it 'should warn about pushing 0 records' do
514
+ # Given
515
+ input = %w(foo bar)
516
+
517
+ # When
518
+ push.add_local_not_in_remote(index, items, input, input)
519
+
520
+ # Then
521
+ expect(Jekyll.logger)
522
+ .to have_received(:info).with('Adding 0 items')
523
+ end
524
+ end
525
+
526
+ it 'should delete items from remote and push new ones' do
527
+ # Given
528
+ allow(push).to receive(:create_index).and_return(index)
529
+ allow(push).to receive(:remote_ids).and_return(remote)
530
+ allow(push).to receive(:delete_remote_not_in_local)
531
+ allow(push).to receive(:add_local_not_in_remote)
532
+ push.init_options(nil, {}, {})
533
+
534
+ # When
535
+ push.lazy_update(items)
536
+
537
+ # Then
538
+ expect(push).to have_received(:delete_remote_not_in_local)
539
+ .with(index, local, remote)
540
+ expect(push).to have_received(:add_local_not_in_remote)
541
+ .with(index, items, local, remote)
339
542
  end
340
543
  end
341
544
  end