jekyll-algolia 1.0.1 → 1.1.0

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