jekyll-meilisearch 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ea5866f93ee6d60be594b225c5c161329787250f6ead78082f141cd723e1e27
4
- data.tar.gz: 9e3b6508edcbd98d94d302369246f4984463019e3bb21909e8263b185d3cd072
3
+ metadata.gz: 4ac85d23f98262c0435458e1e8dfb102fd8339055082e9148f3baccf94ff6323
4
+ data.tar.gz: 0fec3f6b8f11663d4fe3dc09245a4cfe364bba94f387c8aab0eabbb2af977f28
5
5
  SHA512:
6
- metadata.gz: 55858897684e4042eb808f737d892c902d2c0d9be925fb6421da478224f75a2ceae2af59a699a097c1d6fa9f9641e4ccbf29264b3a60bf86837f4fdc50aac04c
7
- data.tar.gz: 7b2ac53a64ef94ea33294c240560b6e1df667d4625e3416ce8221dd1efc43d8e78320caa4665d3fad22dbdad50d8d7d6c69a954c05394d347a352da69312cb1b
6
+ metadata.gz: e03b3235366de8406732eb8f4be82540b9b74594538b5bb12cdc0a100c0d90244387ba3fcf66a22f16e51c4114ffa72e5f1bc9e2be2ad8bfed16055a1083a7c1
7
+ data.tar.gz: 48acdf958bc540cafb1893fb47f98392348b6e2b38c0f8444a4fa3ddc4a5ed3a73746a871724b7439a929f501cecb312c681409ab3f1edbab3e60c37ec3265eb
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Jekyll Meilisearch Plugin
2
+
2
3
  A Jekyll plugin that indexes your site’s content into Meilisearch, a fast and lightweight search engine. This plugin supports incremental indexing, ensuring efficient updates by only syncing changes between your Jekyll site and Meilisearch.
3
4
 
5
+ [![Continuous Integration](https://github.com/unicolored/jekyll-meilisearch/actions/workflows/ruby.yml/badge.svg)](https://github.com/unicolored/jekyll-meilisearch/actions/workflows/ruby.yml) [![Gem Version](https://badge.fury.io/rb/jekyll-meilisearch.svg)](https://badge.fury.io/rb/jekyll-meilisearch)
6
+
4
7
  ## Features
5
8
  - Indexes Jekyll collections (e.g., posts, pages) into Meilisearch.
6
9
  - Incremental updates: adds new documents, deletes obsolete ones, and skips unchanged content.
@@ -9,22 +12,18 @@ A Jekyll plugin that indexes your site’s content into Meilisearch, a fast and
9
12
  - Pagination support for large sites.
10
13
 
11
14
  ## Installation
12
- Add the gem to your Jekyll site’s Gemfile:
13
-
14
- ```shell
15
- gem "jekyll-meilisearch", "~> 0.2.0"
16
- ```
17
15
 
18
- Then run:
16
+ Add the gem to your Jekyll site’s Gemfile:
19
17
 
20
- ```shell
21
- bundle install
18
+ ```ruby
19
+ gem "jekyll-meilisearch"
22
20
  ```
23
21
 
24
- Alternatively, install it directly:
22
+ And then add this line to your site's `_config.yml`:
25
23
 
26
- ```shell
27
- gem install jekyll-meilisearch
24
+ ```yml
25
+ plugins:
26
+ - jekyll-meilisearch
28
27
  ```
29
28
 
30
29
  ## Configuration
@@ -44,15 +43,15 @@ meilisearch:
44
43
  ```
45
44
 
46
45
  ## Configuration Options
47
- - url: The Meilisearch server URL (required).
48
- - api_key: The Meilisearch API key (required). Recommended: use a dedicated api key for your index, not the admin one.
49
- - index_name: The name of the Meilisearch index (optional, defaults to jekyll_documents).
50
- - collections: A hash of Jekyll collections to index.
51
- - fields: Array of fields to extract from each document (e.g., title, content, url, date).
52
- - id_format: How to generate document IDs:
53
- - "default" | "id": Uses collection-name-number if a number field exists, otherwise sanitizes the document ID.
54
- - "url": Uses the document’s URL, sanitized.
55
- - fallback: if "number" exists, uses "collection_name" + "number"
46
+ * `url`: The Meilisearch server URL (required).
47
+ * `api_key`: The Meilisearch API key (required). Recommended: use a dedicated api key for your index, not the admin one.
48
+ * `index_name`: The name of the Meilisearch index (optional, defaults to jekyll_documents).
49
+ * `collections`: A hash of Jekyll collections to index.
50
+ * `fields`: Array of fields to extract from each document (e.g., title, content, url, date).
51
+ * `id_format`: How to generate document IDs:
52
+ * "default" | "id": Uses collection-name-number if a number field exists, otherwise sanitizes the document ID.
53
+ * "url": Uses the document’s URL, sanitized.
54
+ * fallback: if "number" exists, uses "collection_name" + "number"
56
55
 
57
56
  Run your Jekyll build:
58
57
 
@@ -115,39 +114,20 @@ Include the following for adding search to your front :
115
114
 
116
115
  ```
117
116
 
118
- ## Requirements
119
- - Ruby >= 2.7
120
- - Jekyll >= 3.0, < 5.0
121
- - Meilisearch server (local or hosted)
122
-
123
- ## Dependencies:
124
- - httparty (for HTTP requests)
125
-
126
- These are automatically installed when you add the gem to your Gemfile.
127
-
128
- ## Development
129
- To contribute or modify the plugin:
117
+ ## Skip development
130
118
 
131
- - Clone the repository: git clone https://github.com/unicolored/jekyll-meilisearch.git cd jekyll-meilisearch
132
- - Install dependencies: bundle install
133
- - Make changes and test locally: gem build jekyll-meilisearch.gemspec gem install ./jekyll-meilisearch-0.1.0.gem
119
+ Use `disable_in_development: true` if you want to turn off meilisearch indexation when `jekyll.environment == "development"`,
120
+ but don't want to remove the plugin (so you don't accidentally commit the removal). Default value is `false`.
134
121
 
135
- ## Releasing a New Version
136
- - Update the version in jekyll-meilisearch.gemspec.
137
- - Build the gem: gem build jekyll-meilisearch.gemspec
138
- - Push to RubyGems: gem push jekyll-meilisearch-x.x.x.gem
139
-
140
- ## License
141
- This project is licensed under the MIT License.
122
+ ```yml
123
+ meilisearch:
124
+ disable_in_development: true
125
+ ```
142
126
 
143
127
  ## Contributing
144
- Feel free to open issues or submit pull requests on GitHub.
145
128
 
146
- ```shell
147
- bundle install
148
- # Update version in ./jekyll-meilisearch.gemspec
149
- # Build the gem
150
- gem build jekyll-meilisearch.gemspec
151
- # Push the gem
152
- gem push jekyll-meilisearch-${version}.gem
153
- ```
129
+ 1. Fork it (https://github.com/unicolored/jekyll-meilisearch/fork)
130
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
131
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
132
+ 4. Push to the branch (`git push origin my-new-feature`)
133
+ 5. Create a new Pull Request
@@ -12,7 +12,7 @@ module JekyllMeilisearch
12
12
  Jekyll.logger.info "Jekyll Meilisearch:", "Skipping meilisearch indexation in development"
13
13
  return
14
14
  end
15
- Jekyll.logger.info 'Starting Meilisearch incremental indexing...'
15
+ Jekyll.logger.info "Starting Meilisearch incremental indexing..."
16
16
  return unless validate_config
17
17
 
18
18
  @documents = build_documents
@@ -27,12 +27,12 @@ module JekyllMeilisearch
27
27
  end
28
28
 
29
29
  def validate_config
30
- unless config['url']
31
- Jekyll.logger.info 'Error: Meilisearch URL not set in config. Skipping indexing.'
30
+ unless config["url"]
31
+ Jekyll.logger.info "Error: Meilisearch URL not set in config. Skipping indexing."
32
32
  return false
33
33
  end
34
- unless config['api_key']
35
- Jekyll.logger.info 'Error: Meilisearch API key not set in config. Skipping indexing.'
34
+ unless config["api_key"]
35
+ Jekyll.logger.info "Error: Meilisearch API key not set in config. Skipping indexing."
36
36
  return false
37
37
  end
38
38
  true
@@ -40,34 +40,34 @@ module JekyllMeilisearch
40
40
 
41
41
  def build_headers(api_key)
42
42
  {
43
- 'Content-Type' => 'application/json',
44
- 'Authorization' => "Bearer #{api_key}"
43
+ "Content-Type" => "application/json",
44
+ "Authorization" => "Bearer #{api_key}",
45
45
  }
46
46
  end
47
47
 
48
48
  def build_documents
49
49
  documents = []
50
- collections_config = config['collections'] || { 'posts' => { 'fields' => %w[title content url date] } }
50
+ collections_config = config["collections"] || { "posts" => { "fields" => %w(title content url date) } }
51
51
 
52
52
  collections_config.each do |collection_name, collection_settings|
53
53
  collection = @site.collections[collection_name]
54
54
  if collection
55
55
  Jekyll.logger.info "Processing collection: '#{collection_name}'..."
56
- fields_to_index = collection_settings['fields'] || %w[title content url date]
57
- id_format = collection_settings['id_format'] || :default
56
+ fields_to_index = collection_settings["fields"] || %w(title content url date)
57
+ id_format = collection_settings["id_format"] || :default
58
58
 
59
59
  collection_docs = collection.docs.map do |doc|
60
60
  sanitized_id = generate_id(doc, collection_name, id_format)
61
61
  doc_data = {
62
- 'id' => sanitized_id,
63
- 'content' => doc.content.strip,
64
- 'url' => doc.url
62
+ "id" => sanitized_id,
63
+ "content" => doc.content.strip,
64
+ "url" => doc.url,
65
65
  }
66
66
  fields_to_index.each do |field|
67
- next if %w[id content url].include?(field)
67
+ next if %w(id content url).include?(field)
68
68
 
69
69
  value = doc.data[field]
70
- doc_data[field] = field == 'date' && value ? value.strftime('%Y-%m-%d') : value
70
+ doc_data[field] = field == "date" && value ? value.strftime("%Y-%m-%d") : value
71
71
  end
72
72
  doc_data
73
73
  end
@@ -78,7 +78,7 @@ module JekyllMeilisearch
78
78
  end
79
79
 
80
80
  if documents.empty?
81
- Jekyll.logger.info "No documents found across configured collections: #{collections_config.keys.join(', ')}. Cleaning up index..."
81
+ Jekyll.logger.info "No documents found across configured collections: #{collections_config.keys.join(", ")}. Cleaning up index..."
82
82
  end
83
83
  documents
84
84
  end
@@ -86,11 +86,10 @@ module JekyllMeilisearch
86
86
  def generate_id(doc, collection_name, id_format)
87
87
  # Helper method to normalize strings
88
88
  normalize = lambda do |str|
89
- str.gsub('/', '-')
90
- .gsub(/[^a-zA-Z0-9_-]/, '-')
91
- .gsub(/-+/, '-')
92
- .downcase
93
- .slice(0, 100)
89
+ str.tr("/", "-")
90
+ .gsub(%r![^a-zA-Z0-9_-]!, "-").squeeze("-")
91
+ .downcase
92
+ .slice(0, 100)
94
93
  end
95
94
 
96
95
  case id_format
@@ -99,26 +98,26 @@ module JekyllMeilisearch
99
98
  when :url
100
99
  normalize.call(doc.url)
101
100
  else
102
- doc.data['number'] ? "#{collection_name}-#{doc.data['number']}" : normalize.call(doc.id)
101
+ doc.data["number"] ? "#{collection_name}-#{doc.data["number"]}" : normalize.call(doc.id)
103
102
  end
104
103
  end
105
104
 
106
105
  def sync_with_meilisearch
107
- headers = build_headers(config['api_key'])
108
- index_name = config['index_name'] || 'jekyll_documents'
109
- create_index_if_missing(config['url'], index_name, headers)
106
+ headers = build_headers(config["api_key"])
107
+ index_name = config["index_name"] || "jekyll_documents"
108
+ create_index_if_missing(config["url"], index_name, headers)
110
109
 
111
- meili_docs = fetch_all_documents(config['url'], index_name, headers)
110
+ meili_docs = fetch_all_documents(config["url"], index_name, headers)
112
111
  if meili_docs.nil?
113
- Jekyll.logger.info 'Failed to fetch existing documents. Falling back to full indexing.'
114
- return full_index(config['url'], index_name, @documents, headers)
112
+ Jekyll.logger.info "Failed to fetch existing documents. Falling back to full indexing."
113
+ return full_index(config["url"], index_name, @documents, headers)
115
114
  end
116
115
 
117
- meili_ids = meili_docs.map { |doc| doc['id'] }
118
- jekyll_ids = @documents.map { |doc| doc['id'] }
116
+ meili_ids = meili_docs.map { |doc| doc["id"] }
117
+ jekyll_ids = @documents.map { |doc| doc["id"] }
119
118
 
120
- delete_obsolete_documents(config['url'], index_name, meili_ids - jekyll_ids, headers)
121
- index_new_documents(config['url'], index_name, @documents, headers) if @documents.any?
119
+ delete_obsolete_documents(config["url"], index_name, meili_ids - jekyll_ids, headers)
120
+ index_new_documents(config["url"], index_name, @documents, headers) if @documents.any?
122
121
  end
123
122
 
124
123
  def fetch_all_documents(url, index_name, headers)
@@ -127,15 +126,15 @@ module JekyllMeilisearch
127
126
  limit = 1000
128
127
  loop do
129
128
  response = attempt_request(
130
- -> {
131
- HTTParty.get("#{url}/indexes/#{index_name}/documents?limit=#{limit}&offset=#{offset}", headers: headers,
132
- timeout: 30)
129
+ lambda {
130
+ HTTParty.get("#{url}/indexes/#{index_name}/documents?limit=#{limit}&offset=#{offset}", :headers => headers,
131
+ :timeout => 30)
133
132
  },
134
- 'fetching documents'
133
+ "fetching documents"
135
134
  )
136
135
  return nil unless response&.success?
137
136
 
138
- results = JSON.parse(response.body)['results']
137
+ results = JSON.parse(response.body)["results"]
139
138
  documents.concat(results)
140
139
  break if results.size < limit
141
140
 
@@ -145,18 +144,18 @@ module JekyllMeilisearch
145
144
  end
146
145
 
147
146
  def delete_obsolete_documents(url, index_name, ids_to_delete, headers)
148
- return Jekyll.logger.info 'No documents to delete from Meilisearch.' if ids_to_delete.empty?
147
+ return Jekyll.logger.info "No documents to delete from Meilisearch." if ids_to_delete.empty?
149
148
 
150
149
  Jekyll.logger.info "Deleting #{ids_to_delete.size} obsolete documents from Meilisearch..."
151
150
  response = attempt_request(
152
- -> {
153
- HTTParty.post("#{url}/indexes/#{index_name}/documents/delete-batch", body: ids_to_delete.to_json, headers: headers,
154
- timeout: 30)
151
+ lambda {
152
+ HTTParty.post("#{url}/indexes/#{index_name}/documents/delete-batch", :body => ids_to_delete.to_json, :headers => headers,
153
+ :timeout => 30)
155
154
  },
156
- 'deleting documents'
155
+ "deleting documents"
157
156
  )
158
157
  if response&.success?
159
- Jekyll.logger.info 'Delete task queued successfully.'
158
+ Jekyll.logger.info "Delete task queued successfully."
160
159
  elsif response
161
160
  Jekyll.logger.info "Failed to delete obsolete documents: #{response.code} - #{response.body}"
162
161
  end
@@ -167,20 +166,20 @@ module JekyllMeilisearch
167
166
  batch_size = 1000
168
167
  documents.each_slice(batch_size) do |batch|
169
168
  response = attempt_request(
170
- -> {
171
- HTTParty.post("#{url}/indexes/#{index_name}/documents", body: batch.to_json, headers: headers, timeout: 30)
169
+ lambda {
170
+ HTTParty.post("#{url}/indexes/#{index_name}/documents", :body => batch.to_json, :headers => headers, :timeout => 30)
172
171
  },
173
- 'indexing documents'
172
+ "indexing documents"
174
173
  )
175
174
  if response&.code == 202
176
175
  if response.body
177
176
  task = JSON.parse(response.body)
178
- Jekyll.logger.info "Task queued: UID #{task['taskUid']}. Check status at #{url}/tasks/#{task['taskUid']}"
177
+ Jekyll.logger.info "Task queued: UID #{task["taskUid"]}. Check status at #{url}/tasks/#{task["taskUid"]}"
179
178
  else
180
- Jekyll.logger.info 'Task queued (202), but no response body received.'
179
+ Jekyll.logger.info "Task queued (202), but no response body received."
181
180
  end
182
181
  elsif response.nil?
183
- Jekyll.logger.info 'Failed to queue indexing task: No response received from Meilisearch.'
182
+ Jekyll.logger.info "Failed to queue indexing task: No response received from Meilisearch."
184
183
  else
185
184
  Jekyll.logger.info "Failed to queue indexing task: #{response.code} - #{response.body}"
186
185
  end
@@ -189,14 +188,14 @@ module JekyllMeilisearch
189
188
 
190
189
  def create_index_if_missing(url, index_name, headers)
191
190
  Jekyll.logger.info "Checking if index '#{index_name}' exists..."
192
- response = HTTParty.get("#{url}/indexes/#{index_name}", headers: headers, timeout: 30)
191
+ response = HTTParty.get("#{url}/indexes/#{index_name}", :headers => headers, :timeout => 30)
193
192
  return if response.success?
194
193
 
195
194
  if response.code == 404
196
195
  Jekyll.logger.info "Index '#{index_name}' not found. Creating it..."
197
196
  response = attempt_request(
198
- -> { HTTParty.post("#{url}/indexes", body: { 'uid' => index_name }.to_json, headers: headers, timeout: 30) },
199
- 'creating index'
197
+ -> { HTTParty.post("#{url}/indexes", :body => { "uid" => index_name }.to_json, :headers => headers, :timeout => 30) },
198
+ "creating index"
200
199
  )
201
200
  if response&.success? || response&.code == 202
202
201
  Jekyll.logger.info "Index '#{index_name}' created successfully."
@@ -209,14 +208,14 @@ module JekyllMeilisearch
209
208
  end
210
209
 
211
210
  def full_index(url, index_name, documents, headers)
212
- Jekyll.logger.info 'Performing full index reset as fallback...'
211
+ Jekyll.logger.info "Performing full index reset as fallback..."
213
212
  response = attempt_request(
214
- -> { HTTParty.delete("#{url}/indexes/#{index_name}/documents", headers: headers, timeout: 30) },
215
- 'resetting index'
213
+ -> { HTTParty.delete("#{url}/indexes/#{index_name}/documents", :headers => headers, :timeout => 30) },
214
+ "resetting index"
216
215
  )
217
216
  unless response&.success? || response&.code == 404
218
217
  if response.nil?
219
- Jekyll.logger.info 'Failed to reset index: No response received from Meilisearch.'
218
+ Jekyll.logger.info "Failed to reset index: No response received from Meilisearch."
220
219
  else
221
220
  Jekyll.logger.info "Failed to reset index: #{response.code} - #{response.body}"
222
221
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Meilisearch
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.1"
6
6
  end
7
7
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "jekyll"
4
- require 'httparty'
5
- require 'json'
6
- require 'logger'
4
+ require "httparty"
5
+ require "json"
6
+ require "logger"
7
7
  require "jekyll-meilisearch/generator"
8
8
 
9
9
  module JekyllMeilisearch
10
- end
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-meilisearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - unicolored
@@ -86,18 +86,32 @@ dependencies:
86
86
  version: 1.6.6
87
87
  - !ruby/object:Gem::Dependency
88
88
  name: bundler
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ type: :development
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ - !ruby/object:Gem::Dependency
102
+ name: nokogiri
89
103
  requirement: !ruby/object:Gem::Requirement
90
104
  requirements:
91
105
  - - "~>"
92
106
  - !ruby/object:Gem::Version
93
- version: '2.0'
107
+ version: '1.6'
94
108
  type: :development
95
109
  prerelease: false
96
110
  version_requirements: !ruby/object:Gem::Requirement
97
111
  requirements:
98
112
  - - "~>"
99
113
  - !ruby/object:Gem::Version
100
- version: '2.0'
114
+ version: '1.6'
101
115
  - !ruby/object:Gem::Dependency
102
116
  name: rake
103
117
  requirement: !ruby/object:Gem::Requirement
@@ -112,6 +126,54 @@ dependencies:
112
126
  - - "~>"
113
127
  - !ruby/object:Gem::Version
114
128
  version: '13.0'
129
+ - !ruby/object:Gem::Dependency
130
+ name: rspec
131
+ requirement: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '3.0'
136
+ type: :development
137
+ prerelease: false
138
+ version_requirements: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
142
+ version: '3.0'
143
+ - !ruby/object:Gem::Dependency
144
+ name: rubocop-jekyll
145
+ requirement: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: 0.14.0
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: 0.14.0
157
+ - !ruby/object:Gem::Dependency
158
+ name: typhoeus
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0.7'
164
+ - - "<"
165
+ - !ruby/object:Gem::Version
166
+ version: '2.0'
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0.7'
174
+ - - "<"
175
+ - !ruby/object:Gem::Version
176
+ version: '2.0'
115
177
  description: This plugin incrementally indexes Jekyll collections into Meilisearch
116
178
  for fast search capabilities.
117
179
  email: hello@gilles.dev