jekyll-algolia 1.0.1 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2de0f9bc4ac08d49c4f78093c469d778b1d69001
4
- data.tar.gz: dcce0aafc47b6661063e645f03bed64b3cc849d9
3
+ metadata.gz: 18ee9d2d725bb531703ddc05d9f31250959d81ff
4
+ data.tar.gz: 93115f75f4d41d301898b77809732453d5c195f2
5
5
  SHA512:
6
- metadata.gz: 8c898016647a648a10d3aeaa270aeca5257399a47a124e55902581ae935cedab196295204f6e4177d58b4a56b544fd54f9825b8dc7198995fa2dfa367de1c875
7
- data.tar.gz: 486d9709cd1de0ed485d921e2c22640776c36fc7d45edabceff1f45e9f50f65879b7e0971daa9d038ffbe5d8e5143bb256cd00429203f0590c17a243eba25bca
6
+ metadata.gz: fed961094843fdf503620f86fcb83313c96b68061ce0d170b1a66f018d60cf1edf0a68a9dd5df7f17dee5c2a6e6e4fa05e677ae5a743383c859c42f3443e6bba
7
+ data.tar.gz: d66ea9ca93b8cafc3749711f17d27f03753ddfc6f4de70d2cc94296e5209b9247f2e3bbbefbf924414e5fe3c380f13c13fac87f80b8eed9322ccb0338d2dad2b
data/CONTRIBUTING.md CHANGED
@@ -1,10 +1,9 @@
1
1
  Hi collaborator!
2
2
 
3
- If you have a fix or a new feature, please start by checking in the
4
- [issues](https://github.com/algolia/jekyll-algolia/issues) if it is
5
- already referenced. If not, feel free to open one.
3
+ If you have a fix or a new feature, please start by checking in the [issues][1]
4
+ if it is already referenced. If not, feel free to open one.
6
5
 
7
- We use [pull requests](https://github.com/algolia/jekyll-algolia/pulls)
6
+ We use [pull requests][2]
8
7
  for collaboration. The workflow is as follow:
9
8
 
10
9
  - Create a local branch, starting from `develop`
@@ -20,23 +19,18 @@ Start by running `bundle install` to get all the dependencies up to date.
20
19
 
21
20
  ## Testing
22
21
 
23
- Run `rake test` to launch all tests. You can run `rake test_details` to get an
24
- output with more details about the tests.
22
+ Run `rake test` to launch the test suite. Run `./scripts/test_all_ruby_versions`
23
+ to run the test on all the supported ruby versions (requires `rvm`).
25
24
 
26
25
  ## TDD
27
26
 
28
- // TODO
29
-
30
- ## Testing different ruby versions
31
-
32
- You can test the gem across all the supported Ruby versions by running
33
- `./scripts/test_all_ruby_versions`. Note that you will need to have RVM
34
- installed for this to work.
27
+ Run `rake watch` to start a watcher on the code and test files. Whenever you
28
+ update the code, the relevant tests will be run. Incredibly useful for TDD.
35
29
 
36
30
  ## Testing local changes on an existing Jekyll website
37
31
 
38
32
  If you want to test the plugin on an existing Jekyll website while developping,
39
- I suggest updating the website `Gemfile` to point to the correct local directory
33
+ we suggest updating the website `Gemfile` to point to the correct local directory
40
34
 
41
35
  ```ruby
42
36
  group :jekyll_plugins do
@@ -44,10 +38,19 @@ group :jekyll_plugins do
44
38
  end
45
39
  ```
46
40
 
41
+ ## Linting
42
+
43
+ Run `rake lint` to check the style of all ruby files. Run `rake
44
+ lint:auto_correct` to try to automatically correct the potential violations.
45
+ It's always a good practice to double check the modification after an
46
+ auto-correct.
47
+
47
48
  # Git Hooks
48
49
 
49
- If you plan on submitting a PR, I suggest you install the git hooks located in
50
- `./scripts/git_hook`.
50
+ If you plan on submitting a PR, we suggest you install the git hooks located in
51
+ `./scripts/git_hook`. Those hooks will run the linter on each commit, and the
52
+ tests before each push. This greatly help reduce the chances of breaking the
53
+ build on Travis.
51
54
 
52
55
  The easiest way is to create a symlink from your `.git/hooks` folder:
53
56
 
@@ -67,28 +70,36 @@ the git tags, create the gem and push it to Rubygems.
67
70
 
68
71
  ## Requirements
69
72
 
70
- To run this project, you will need:
73
+ The documentation website uses Metalsmith (and not Jekyll), so you'll need:
71
74
 
72
- - Node.js >= v9.2.0, use nvm - [install instructions](https://github.com/creationix/nvm#install-script)
73
- - Yarn >= v1.3.2 - [install instructions](https://yarnpkg.com/en/docs/install#alternatives-tab)
75
+ - Node.js >= v9.2.0, use nvm - [install instructions][3]
76
+ - Yarn >= v1.3.2 - [install instructions][4]
74
77
 
75
78
  ## Development
76
79
 
77
- ```sh
78
- yarn
79
- yarn start
80
- ```
80
+ All the documentation source files live in the `./docs-src` folder.
81
81
 
82
- Go to <http://localhost:3000>.
82
+ To serve a local version of the documentation (including livereload), run `rake
83
+ docs:serve`. The documentation will be available on
84
+ [localhost:3000](http://localhost:3000/).
83
85
 
84
- ## Update docs
86
+ This will create a `./docs-dev` folder and serve files from there. This folder
87
+ is ignored by git.
85
88
 
86
- ```sh
87
- yarn docs:update
88
- git push
89
- ```
89
+ ## Deploying docs
90
90
 
91
+ To update the documentation website, you should run `rake docs:deploy` from the
92
+ `develop` branch. This will merge `develop` into master, build the documentation
93
+ into `docs` and push it. The content of the `./docs` folder will then be server
94
+ by GitHub pages.
91
95
 
92
96
  # Project owner
93
97
 
94
- [@pixelastic](https://github.com/pixelastic)
98
+ [@pixelastic][5]
99
+
100
+
101
+ [1]: https://github.com/algolia/jekyll-algolia/issues
102
+ [2]: https://github.com/algolia/jekyll-algolia/pulls
103
+ [3]: https://github.com/creationix/nvm#install-script
104
+ [4]: https://yarnpkg.com/en/docs/install#alternatives-tab
105
+ [5]: https://github.com/pixelastic
data/README.md CHANGED
@@ -6,7 +6,7 @@ Status][3]](https://coveralls.io/github/algolia/jekyll-algolia?branch=master)
6
6
  [![Code Climate][4]](https://codeclimate.com/github/algolia/jekyll-algolia)
7
7
  ![Jekyll >= 3.6.0][5] ![Ruby >= 2.3.0][6]
8
8
 
9
- Jekyll plugin to automatically index your content on Algolia.
9
+ Add fast and relevant search to your Jekyll site.
10
10
 
11
11
  ## Usage
12
12
 
@@ -33,6 +33,8 @@ module Jekyll
33
33
 
34
34
  exit 1 unless Configurator.assert_valid_credentials
35
35
 
36
+ Configurator.warn_of_deprecated_options
37
+
36
38
  if Configurator.dry_run?
37
39
  Logger.log('W:==== THIS IS A DRY RUN ====')
38
40
  Logger.log('W: - No records will be pushed to your index')
@@ -72,9 +74,10 @@ module Jekyll
72
74
 
73
75
  # Public: Get access to the time at which the command was run
74
76
  #
75
- # Jekyll will override some date with the current time, and we'll need to
76
- # keep them as nil, so we have to compare to this date to assume it has been
77
- # overwritten
77
+ # Jekyll will always set the updated time of pages to the time of the build
78
+ # run. The plugin needs those values to stay at nil if they did not change,
79
+ # so we'll keep track of the time at build time and revert any page build at
80
+ # that time to nil.
78
81
  def self.start_time
79
82
  @start_time
80
83
  end
@@ -12,7 +12,6 @@ module Jekyll
12
12
  'files_to_exclude' => nil,
13
13
  'nodes_to_index' => 'p',
14
14
  'indexing_batch_size' => 1000,
15
- 'indexing_mode' => 'diff',
16
15
  'settings' => {
17
16
  'distinct' => true,
18
17
  'attributeForDistinct' => 'url',
@@ -129,18 +128,6 @@ module Jekyll
129
128
  ALGOLIA_DEFAULTS['settings'].merge(user_settings)
130
129
  end
131
130
 
132
- # Public: Return the current indexing mode
133
- #
134
- # Default mode is `diff`, but users can configure their own by updating
135
- # the `indexing_mode` config in _config.yml. The only other authorized
136
- # value is `atomic`. If an unrecognized mode is defined, it defaults to
137
- # `diff`.
138
- def self.indexing_mode
139
- mode = algolia('indexing_mode') || ALGOLIA_DEFAULTS['indexing_mode']
140
- return 'diff' unless %w[diff atomic].include?(mode)
141
- mode
142
- end
143
-
144
131
  # Public: Check that all credentials are set
145
132
  #
146
133
  # Returns true if everything is ok, false otherwise. Will display helpful
@@ -197,6 +184,20 @@ module Jekyll
197
184
  return true if value == true
198
185
  false
199
186
  end
187
+
188
+ # Public: Check for any deprecated config option and warn the user
189
+ def self.warn_of_deprecated_options
190
+ # indexing_mode is no longer used
191
+ return if algolia('indexing_mode').nil?
192
+
193
+ # rubocop:disable Metrics/LineLength
194
+ Logger.log('I:')
195
+ Logger.log('W:[jekyll-algolia] You are using the algolia.indexing_mode option which has been deprecated in v1.1')
196
+ Logger.log('I: Indexing is now always using an atomic diff algorithm.')
197
+ Logger.log('I: This option is no longer necessary, you can remove it from your _config.yml')
198
+ Logger.log('I:')
199
+ # rubocop:enable Metrics/LineLength
200
+ end
200
201
  end
201
202
  end
202
203
  end
@@ -47,7 +47,6 @@ module Jekyll
47
47
  def self.identify(error, context = {})
48
48
  known_errors = %w[
49
49
  unknown_application_id
50
- invalid_credentials_for_tmp_index
51
50
  invalid_credentials
52
51
  record_too_big
53
52
  unknown_settings
@@ -156,29 +155,6 @@ module Jekyll
156
155
  { 'application_id' => app_id }
157
156
  end
158
157
 
159
- # Public: Check if credentials specifically can't access the _tmp index
160
- #
161
- # _context - Not used
162
- #
163
- # If the error happens on a _tmp folder, it might mean that the key does
164
- # not have access to the _tmp indices and the error message will reflect
165
- # that.
166
- def self.invalid_credentials_for_tmp_index?(error, _context = {})
167
- details = error_hash(error.message)
168
-
169
- index_name_tmp = details['index_name']
170
- if details['message'] != 'Index not allowed with this API key' ||
171
- index_name_tmp !~ /_tmp$/
172
- return false
173
- end
174
-
175
- {
176
- 'application_id' => Configurator.application_id,
177
- 'index_name' => Configurator.index_name,
178
- 'index_name_tmp' => index_name_tmp
179
- }
180
- end
181
-
182
158
  # Public: Check if the credentials are working
183
159
  #
184
160
  # _context - Not used
@@ -45,45 +45,17 @@ module Jekyll
45
45
  ::Algolia::Index.new(index_name)
46
46
  end
47
47
 
48
- # Public: Update records of the specified index
48
+ # Public: Check if an index exists
49
49
  #
50
- # index - Algolia Index to update
51
- # records - Array of records to update
50
+ # index_name - Name of the index
52
51
  #
53
- # New records will be automatically added. Technically existing records
54
- # should be updated but this case should never happen as changing a record
55
- # content will change its objectID as well.
56
- #
57
- # Does nothing in dry run mode
58
- def self.update_records(index, records)
59
- batch_size = Configurator.algolia('indexing_batch_size')
60
- records.each_slice(batch_size) do |batch|
61
- Logger.log("I:Pushing #{batch.size} records")
62
- next if Configurator.dry_run?
63
- begin
64
- index.add_objects!(batch)
65
- rescue StandardError => error
66
- ErrorHandler.stop(error, records: records)
67
- end
68
- end
69
- end
70
-
71
- # Public: Delete records whose objectIDs are passed
72
- #
73
- # index - Algolia Index to target
74
- # ids - Array of objectIDs to delete
75
- #
76
- # Does nothing in dry run mode
77
- def self.delete_records_by_id(index, ids)
78
- return if ids.empty?
79
- Logger.log("I:Deleting #{ids.length} records")
80
- return if Configurator.dry_run?
81
-
82
- begin
83
- index.delete_objects!(ids)
84
- rescue StandardError => error
85
- ErrorHandler.stop(error)
86
- end
52
+ # Note: there is no API endpoint to do that, so we try to get the settings
53
+ # instead, which will fail if the index does not exist
54
+ def self.index?(index_name)
55
+ index(index_name).get_settings
56
+ return true
57
+ rescue StandardError
58
+ return false
87
59
  end
88
60
 
89
61
  # Public: Returns an array of all the objectIDs in the index
@@ -119,113 +91,69 @@ module Jekyll
119
91
  # Public: Update settings of the index
120
92
  #
121
93
  # index - The Algolia Index
122
- # settings - The hash of settings to pass to the index
123
94
  #
124
95
  # Does nothing in dry run mode
125
- def self.update_settings(index, settings)
96
+ # Settings will only be updated in the first push, and if custom settings
97
+ # are defined in _config.yml. Otherwise, they are left untouched, allowing
98
+ # users to configure them through their dashboard.
99
+ def self.update_settings(index)
100
+ has_custom_settings = !Configurator.algolia('settings').nil?
101
+ index_exists = index?(index.name)
102
+
103
+ # No need to update the settings if the index is already configured and
104
+ # the user did not specify custom settings
105
+ return if index_exists && !has_custom_settings
106
+
126
107
  Logger.verbose('I:Updating settings')
127
108
  return if Configurator.dry_run?
109
+ settings = Configurator.settings
128
110
  begin
129
- index.set_settings(settings)
111
+ index.set_settings!(settings)
130
112
  rescue StandardError => error
131
113
  ErrorHandler.stop(error, settings: settings)
132
114
  end
133
115
  end
134
116
 
135
- # Public: Index content following the `diff` indexing mode
117
+ # Public: Update records of the index
136
118
  #
137
- # records - Array of local records
119
+ # index_name - The Algolia index
120
+ # old_records_ids - Ids of records to delete from the index
121
+ # new_records - Records to add to the index
138
122
  #
139
- # The `diff` indexing mode will only push new content to the index and
140
- # remove old content from it. It won't touch records that haven't been
141
- # updated. It will be a bit slower as it will first need to get the list
142
- # of all records in the index, but it will consume less operations.
143
- def self.run_diff_mode(records)
144
- index = index(Configurator.index_name)
145
-
146
- # Update settings
147
- update_settings(index, Configurator.settings)
148
-
149
- # Getting list of objectID in remote and locally
150
- remote_ids = remote_object_ids(index)
151
- local_ids = local_object_ids(records)
152
-
153
- old_records_ids = remote_ids - local_ids
154
- new_records_ids = local_ids - remote_ids
155
- if old_records_ids.empty? && new_records_ids.empty?
123
+ # Note: All operations will be done in one batch, assuring an atomic
124
+ # update
125
+ # Does nothing in dry run mode
126
+ def self.update_records(index_name, old_records_ids, new_records)
127
+ # Stop if nothing to change
128
+ if old_records_ids.empty? && new_records.empty?
156
129
  Logger.log('I:Nothing to index. Your content is already up to date.')
157
130
  return
158
131
  end
159
132
 
160
- Logger.log("I:Updating records in index #{index.name}...")
161
-
162
- # Delete remote records that are no longer available locally
163
- delete_records_by_id(index, old_records_ids)
133
+ Logger.log("I:Updating records in index #{index_name}...")
134
+ Logger.log("I:Records to delete: #{old_records_ids.length}")
135
+ Logger.log("I:Records to add: #{new_records.length}")
136
+ return if Configurator.dry_run?
164
137
 
165
- # Add only records that are not yet already in the remote
166
- new_records = records.select do |record|
167
- new_records_ids.include?(record[:objectID])
138
+ operations = new_records.map do |new_record|
139
+ { action: 'addObject', indexName: index_name, body: new_record }
168
140
  end
169
- update_records(index, new_records)
170
-
171
- Logger.log('I:✔ Indexing complete')
172
- end
173
-
174
- # Public: Get the settings of the remote index
175
- #
176
- # index - The Algolia Index
177
- def self.remote_settings(index)
178
- index.get_settings
179
- rescue StandardError => error
180
- ErrorHandler.stop(error)
181
- end
182
-
183
- # Public: Rename an index
184
- #
185
- # old_name - Current name of the index
186
- # new_name - New name of the index
187
- #
188
- # Does nothing in dry run mode
189
- def self.rename_index(old_name, new_name)
190
- Logger.verbose("I:Renaming `#{old_name}` to `#{new_name}`")
191
- return if Configurator.dry_run?
192
- begin
193
- ::Algolia.move_index(old_name, new_name)
194
- rescue StandardError => error
195
- ErrorHandler.stop(error, new_name: new_name)
141
+ old_records_ids.each do |object_id|
142
+ operations << {
143
+ action: 'deleteObject', indexName: index_name,
144
+ body: { objectID: object_id }
145
+ }
196
146
  end
197
- end
198
-
199
- # Public: Index content following the `atomic` indexing mode
200
- #
201
- # records - Array of records to push
202
- #
203
- # The `atomic` indexing mode will push all records to a brand new index,
204
- # configure it, and then overwrite the previous index with this new one.
205
- # For the end-user, it will make all the changes in one go, making sure
206
- # people are always searching into a fully configured index. It will
207
- # consume more operations, but will never leave the index in a transient
208
- # state.
209
- def self.run_atomic_mode(records)
210
- index_name = Configurator.index_name
211
- index = index(index_name)
212
- index_tmp_name = "#{Configurator.index_name}_tmp"
213
- index_tmp = index(index_tmp_name)
214
-
215
- Logger.verbose("I:Using `#{index_tmp_name}` as temporary index")
216
147
 
217
- # Copying original settings to the new index
218
- remote_settings = remote_settings(index)
219
- new_settings = remote_settings.merge(Configurator.settings)
220
- update_settings(index_tmp, new_settings)
221
-
222
- # Pushing everthing to a brand new index
223
- update_records(index_tmp, records)
224
-
225
- # Renaming the new index in place of the old
226
- rename_index(index_tmp_name, index_name)
227
-
228
- Logger.log('I:✔ Indexing complete')
148
+ # Run the batches in slices if they are too large
149
+ batch_size = Configurator.algolia('indexing_batch_size')
150
+ operations.each_slice(batch_size) do |slice|
151
+ begin
152
+ ::Algolia.batch!(slice)
153
+ rescue StandardError => error
154
+ ErrorHandler.stop(error)
155
+ end
156
+ end
229
157
  end
230
158
 
231
159
  # Public: Push all records to Algolia and configure the index
@@ -234,10 +162,8 @@ module Jekyll
234
162
  def self.run(records)
235
163
  init
236
164
 
237
- record_count = records.length
238
-
239
165
  # Indexing zero record is surely a misconfiguration
240
- if record_count.zero?
166
+ if records.length.zero?
241
167
  files_to_exclude = Configurator.algolia('files_to_exclude').join(', ')
242
168
  Logger.known_message(
243
169
  'no_records_found',
@@ -247,14 +173,25 @@ module Jekyll
247
173
  exit 1
248
174
  end
249
175
 
250
- indexing_mode = Configurator.indexing_mode
251
- Logger.verbose("I:Indexing mode: #{indexing_mode}")
252
- case indexing_mode
253
- when 'diff'
254
- run_diff_mode(records)
255
- when 'atomic'
256
- run_atomic_mode(records)
176
+ index_name = Configurator.index_name
177
+ index = index(index_name)
178
+
179
+ # Update settings
180
+ update_settings(index)
181
+
182
+ # Getting list of objectID in remote and locally
183
+ remote_ids = remote_object_ids(index)
184
+ local_ids = local_object_ids(records)
185
+
186
+ # Getting list of what to add and what to delete
187
+ old_records_ids = remote_ids - local_ids
188
+ new_records_ids = local_ids - remote_ids
189
+ new_records = records.select do |record|
190
+ new_records_ids.include?(record[:objectID])
257
191
  end
192
+ update_records(index_name, old_records_ids, new_records)
193
+
194
+ Logger.log('I:✔ Indexing complete')
258
195
  end
259
196
  end
260
197
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Algolia
5
- VERSION = '1.0.1'
5
+ VERSION = '1.1.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-algolia
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.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: 2017-12-22 00:00:00.000000000 Z
11
+ date: 2018-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: algolia_html_extractor
@@ -257,7 +257,6 @@ files:
257
257
  - CONTRIBUTING.md
258
258
  - README.md
259
259
  - lib/errors/invalid_credentials.txt
260
- - lib/errors/invalid_credentials_for_tmp_index.txt
261
260
  - lib/errors/invalid_index_name.txt
262
261
  - lib/errors/missing_api_key.txt
263
262
  - lib/errors/missing_application_id.txt
@@ -1,17 +0,0 @@
1
- E: [✗ Error] Invalid credentials for temporary index
2
- E:
3
- E: The jekyll-algolia plugin could not access your index with the API key you
4
- E: provided.
5
- W:
6
- W: When using the `atomic` indexing mode, we will push all your content to a
7
- W: temporary index, then overwrite the actual index with it. The API key you
8
- W: defined should have access rights on both.
9
- I:
10
- I: Make sure your API key has access:
11
- I: - {index_name}
12
- I: - {index_name_tmp}
13
- I:
14
- I: You can configure API keys from your dashboard:
15
- I: https://www.algolia.com/apps/{application_id}/api-keys/restricted
16
- I:
17
- I: