bridgetown_directus 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 +4 -4
- data/.github/workflows/release-please.yml +1 -0
- data/.github/workflows/release.yml +3 -3
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +15 -0
- data/README.md +165 -74
- data/RELEASING.md +109 -0
- data/lib/bridgetown_directus/builder.rb +72 -9
- data/lib/bridgetown_directus/client.rb +3 -2
- data/lib/bridgetown_directus/configuration.rb +23 -1
- data/lib/bridgetown_directus/version.rb +1 -1
- data/lib/bridgetown_directus.rb +47 -8
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2212f8e06630de61f4abdc8f50fb65339d3928e9a39e6658fd16f5af37986fdd
|
|
4
|
+
data.tar.gz: 2e02c25a8dcf030d9497caab17a1970c1170151ef777c26538ef2d0f47fb06c2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8843466b19c819f8f8cbc3e36188524f4f46774f95ee79b9cd4b2042fd39a38a640accc54addae8666e0249384619ec23ea3c2379daf5d91c0085f3e8019009a
|
|
7
|
+
data.tar.gz: bc119472aa06bfebf3a09357f622224248f4405b5f5bb8d895c215e71b4ddff7d7be2064eac98940dc3c8ebf6857d617ec6529004b7f4cd5da8430930917c73c
|
|
@@ -3,11 +3,12 @@ name: Release
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
tags:
|
|
6
|
-
- "v*"
|
|
6
|
+
- "bridgetown_directus/v*"
|
|
7
7
|
workflow_dispatch:
|
|
8
8
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
|
+
id-token: write
|
|
11
12
|
|
|
12
13
|
jobs:
|
|
13
14
|
publish:
|
|
@@ -22,7 +23,6 @@ jobs:
|
|
|
22
23
|
run: bundle exec rake test
|
|
23
24
|
- name: Build gem
|
|
24
25
|
run: bundle exec rake build
|
|
26
|
+
- uses: rubygems/configure-rubygems-credentials@v1.0.0
|
|
25
27
|
- name: Push gem
|
|
26
|
-
env:
|
|
27
|
-
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
|
|
28
28
|
run: gem push pkg/*.gem
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.1](https://github.com/Munkun-Estudio/bridgetown_directus/compare/bridgetown_directus/v0.4.0...bridgetown_directus/v0.4.1) (2026-02-16)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* match release-please tag format in release workflow ([70bd081](https://github.com/Munkun-Estudio/bridgetown_directus/commit/70bd08125477acb33f10e06de5fd41ba889d472a))
|
|
14
|
+
|
|
15
|
+
## [0.4.0](https://github.com/Munkun-Estudio/bridgetown_directus/compare/bridgetown_directus/v0.3.0...bridgetown_directus/v0.4.0) (2026-02-16)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* add data collections, singleton support, flatten_m2m, and BridgetownDirectus.configure API ([31e99ac](https://github.com/Munkun-Estudio/bridgetown_directus/commit/31e99ac31463b944d20de1e81931219d2c0de59a))
|
|
21
|
+
* make SSL verify configurable via Configuration#ssl_verify ([6cb9033](https://github.com/Munkun-Estudio/bridgetown_directus/commit/6cb90331b0b2e99bd26ecde862c26d6969b0fbf6))
|
|
22
|
+
|
|
8
23
|
## [0.3.0](https://github.com/Munkun-Estudio/bridgetown_directus/compare/bridgetown_directus-v0.2.0...bridgetown_directus/v0.3.0) (2026-01-27)
|
|
9
24
|
|
|
10
25
|
|
data/README.md
CHANGED
|
@@ -2,132 +2,223 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/bridgetown_directus)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A [Bridgetown](https://www.bridgetownrb.com/) plugin that syncs content from [Directus](https://directus.io/) at build time. It fetches collections from the Directus API and either generates static Markdown files or injects data directly into `site.data`.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- **
|
|
13
|
-
-
|
|
9
|
+
- **Output collections** — fetch Directus items and generate Markdown files (posts, pages, custom types)
|
|
10
|
+
- **Data collections** — fetch Directus items and inject into `site.data` (no file generation)
|
|
11
|
+
- **Singletons** — single-object collections (e.g. site settings)
|
|
12
|
+
- **M2M junction flattening** — unwrap Directus many-to-many junction objects automatically
|
|
13
|
+
- **Flexible field mapping** with custom converters
|
|
14
|
+
- **Multilingual content** via Directus translations
|
|
15
|
+
- **Configurable SSL verification** for environments with strict OpenSSL
|
|
16
|
+
- **Graceful skip** — build succeeds even without Directus credentials configured
|
|
14
17
|
|
|
15
18
|
## Installation
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
### Recommended (Bridgetown Automation)
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
```bash
|
|
23
|
+
bin/bridgetown apply https://github.com/munkun-estudio/bridgetown_directus
|
|
24
|
+
```
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
### Manual
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
```ruby
|
|
29
|
+
bundle add "bridgetown_directus"
|
|
30
|
+
```
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
- All further customization is done in Ruby, not YAML
|
|
32
|
+
```bash
|
|
33
|
+
bundle install
|
|
34
|
+
```
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
## Configuration
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
### Basic Setup
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
```ruby
|
|
41
|
+
# config/initializers.rb
|
|
42
|
+
init :bridgetown_directus
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
BridgetownDirectus.configure do |directus|
|
|
45
|
+
directus.api_url = ENV["DIRECTUS_API_URL"]
|
|
46
|
+
directus.token = ENV["DIRECTUS_API_TOKEN"]
|
|
42
47
|
|
|
43
|
-
|
|
48
|
+
directus.register_collection(:posts) do |c|
|
|
49
|
+
c.endpoint = "blog_posts"
|
|
50
|
+
c.layout = "post"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The plugin reads `DIRECTUS_API_URL` and `DIRECTUS_API_TOKEN` from the environment by default. If neither is set, the build skips Directus sync gracefully.
|
|
56
|
+
|
|
57
|
+
### Data Collections
|
|
44
58
|
|
|
45
|
-
|
|
59
|
+
Data collections populate `site.data` without generating files. Useful for navigation, settings, or any shared data.
|
|
46
60
|
|
|
47
61
|
```ruby
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
62
|
+
directus.register_collection(:navigation) do |c|
|
|
63
|
+
c.endpoint = "navigation_items"
|
|
64
|
+
c.resource_type = :data
|
|
65
|
+
c.default_query = {
|
|
66
|
+
sort: "sort",
|
|
67
|
+
filter: { status: { _eq: "published" } }.to_json
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
```
|
|
52
71
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
Access in templates via `site.data.navigation`.
|
|
73
|
+
|
|
74
|
+
### Singletons
|
|
75
|
+
|
|
76
|
+
For collections that contain a single record (e.g. site settings):
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
directus.register_collection(:site_settings) do |c|
|
|
80
|
+
c.endpoint = "site_settings"
|
|
81
|
+
c.resource_type = :data
|
|
82
|
+
c.singleton = true
|
|
62
83
|
end
|
|
63
84
|
```
|
|
64
85
|
|
|
65
|
-
|
|
86
|
+
Returns a single hash instead of an array. Access via `site.data.site_settings`.
|
|
87
|
+
|
|
88
|
+
### Output Collections
|
|
66
89
|
|
|
67
|
-
|
|
68
|
-
You only need to declare fields with `c.field` if you want to:
|
|
90
|
+
Generate Markdown files for posts, pages, or custom collection types:
|
|
69
91
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
92
|
+
```ruby
|
|
93
|
+
directus.register_collection(:events) do |c|
|
|
94
|
+
c.endpoint = "events"
|
|
95
|
+
c.resource_type = :custom_collection
|
|
96
|
+
c.layout = "event"
|
|
97
|
+
c.default_query = {
|
|
98
|
+
filter: { status: { _eq: "published" } }.to_json
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
```
|
|
73
102
|
|
|
74
|
-
|
|
103
|
+
Generated files include `directus_generated: true` in front matter. Only these files are cleaned up on rebuild — user-authored files are never deleted.
|
|
75
104
|
|
|
76
|
-
###
|
|
105
|
+
### M2M Junction Flattening
|
|
77
106
|
|
|
78
|
-
|
|
79
|
-
- `DIRECTUS_API_TOKEN` (required unless you set `directus.token` in config)
|
|
80
|
-
- `DIRECTUS_TOKEN` (legacy fallback; supported for backward compatibility)
|
|
107
|
+
Directus returns many-to-many relationships wrapped in junction objects:
|
|
81
108
|
|
|
82
|
-
|
|
109
|
+
```json
|
|
110
|
+
[{ "raus_stats_id": { "id": 1, "value": "8+" } }]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Use `flatten_m2m` to unwrap them:
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
directus.register_collection(:pages) do |c|
|
|
117
|
+
c.endpoint = "pages"
|
|
118
|
+
c.resource_type = :data
|
|
119
|
+
c.default_query = {
|
|
120
|
+
fields: "id,title,sections.stats.raus_stats_id.*"
|
|
121
|
+
}
|
|
122
|
+
c.flatten_m2m "sections.stats", key: "raus_stats_id"
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
After flattening:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
[{ "id": 1, "value": "8+" }]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Field Mapping
|
|
133
|
+
|
|
134
|
+
All Directus fields are included in the output by default. Use `c.field` only when you need to rename or transform a value:
|
|
83
135
|
|
|
84
136
|
```ruby
|
|
85
137
|
c.field :slug, "slug" do |value|
|
|
86
|
-
value || "
|
|
138
|
+
value || "fallback-#{SecureRandom.hex(4)}"
|
|
87
139
|
end
|
|
88
140
|
```
|
|
89
141
|
|
|
90
142
|
### Translations
|
|
91
143
|
|
|
92
|
-
To enable translations for specific fields, add this inside your collection block:
|
|
93
|
-
|
|
94
144
|
```ruby
|
|
95
145
|
c.enable_translations([:title, :content])
|
|
96
146
|
```
|
|
97
147
|
|
|
98
|
-
|
|
99
|
-
|
|
148
|
+
### SSL Verification
|
|
149
|
+
|
|
150
|
+
If your local OpenSSL (3.6+) fails with CRL verification errors, you can disable SSL verification:
|
|
100
151
|
|
|
101
|
-
|
|
152
|
+
```ruby
|
|
153
|
+
directus.ssl_verify = false
|
|
154
|
+
```
|
|
102
155
|
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
|
|
156
|
+
This is a client-side issue with recent OpenSSL versions that enforce CRL checking but cannot auto-download CRLs during the TLS handshake. It typically only affects local development — CI/CD environments use standard OpenSSL builds without this issue.
|
|
157
|
+
|
|
158
|
+
Default: `true`.
|
|
106
159
|
|
|
107
160
|
### Debug Logging
|
|
108
161
|
|
|
109
|
-
|
|
162
|
+
```bash
|
|
163
|
+
BRIDGETOWN_DIRECTUS_LOG=1 bin/bt build
|
|
164
|
+
```
|
|
110
165
|
|
|
111
|
-
###
|
|
166
|
+
### Environment Variables
|
|
112
167
|
|
|
113
|
-
|
|
168
|
+
| Variable | Description |
|
|
169
|
+
| -------- | ----------- |
|
|
170
|
+
| `DIRECTUS_API_URL` | Directus instance URL |
|
|
171
|
+
| `DIRECTUS_API_TOKEN` | Static access token |
|
|
172
|
+
| `DIRECTUS_TOKEN` | Legacy fallback for token |
|
|
173
|
+
| `BRIDGETOWN_DIRECTUS_LOG` | Set to `1` for verbose logging |
|
|
114
174
|
|
|
115
|
-
|
|
116
|
-
- Custom layouts per collection
|
|
117
|
-
- Filtering, sorting, and pagination via `c.default_query` (**experimental**; not fully tested in production—see notes below)
|
|
118
|
-
- Selective field output
|
|
175
|
+
## Full Example
|
|
119
176
|
|
|
120
|
-
|
|
177
|
+
```ruby
|
|
178
|
+
# config/initializers.rb
|
|
179
|
+
init :bridgetown_directus
|
|
180
|
+
|
|
181
|
+
BridgetownDirectus.configure do |directus|
|
|
182
|
+
directus.api_url = ENV["DIRECTUS_API_URL"]
|
|
183
|
+
directus.token = ENV["DIRECTUS_API_TOKEN"]
|
|
184
|
+
directus.ssl_verify = false
|
|
185
|
+
|
|
186
|
+
# Data-only: populates site.data
|
|
187
|
+
directus.register_collection(:site_settings) do |c|
|
|
188
|
+
c.endpoint = "site_settings"
|
|
189
|
+
c.resource_type = :data
|
|
190
|
+
c.singleton = true
|
|
191
|
+
end
|
|
121
192
|
|
|
122
|
-
|
|
193
|
+
directus.register_collection(:navigation) do |c|
|
|
194
|
+
c.endpoint = "navigation_items"
|
|
195
|
+
c.resource_type = :data
|
|
196
|
+
c.default_query = { sort: "sort" }
|
|
197
|
+
end
|
|
123
198
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
199
|
+
# Output: generates Markdown files
|
|
200
|
+
directus.register_collection(:events) do |c|
|
|
201
|
+
c.endpoint = "events"
|
|
202
|
+
c.resource_type = :custom_collection
|
|
203
|
+
c.layout = "event"
|
|
204
|
+
c.default_query = {
|
|
205
|
+
filter: { status: { _eq: "published" } }.to_json
|
|
206
|
+
}
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
```
|
|
128
210
|
|
|
129
|
-
|
|
211
|
+
## Migrating from 0.2.x
|
|
130
212
|
|
|
131
|
-
|
|
213
|
+
- Configuration now uses `BridgetownDirectus.configure` block after `init :bridgetown_directus`
|
|
214
|
+
- New `resource_type: :data` for collections that inject into `site.data`
|
|
215
|
+
- New `singleton: true` for single-record collections
|
|
216
|
+
- New `flatten_m2m` for M2M junction unwrapping
|
|
217
|
+
- Build no longer fails when Directus credentials are missing — it skips gracefully
|
|
218
|
+
- SSL verification is configurable via `ssl_verify`
|
|
132
219
|
|
|
133
220
|
See [CHANGELOG.md](CHANGELOG.md) for upgrade notes and detailed changes.
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
See [LICENSE](LICENSE) for details.
|
data/RELEASING.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Releasing `bridgetown_directus`
|
|
2
|
+
|
|
3
|
+
This document explains the release workflow for this gem and how to recover if automation fails.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
There are three parts:
|
|
8
|
+
|
|
9
|
+
1. **release-please** creates a release PR and a `vX.Y.Z` tag.
|
|
10
|
+
2. **Release** workflow publishes the gem to RubyGems.
|
|
11
|
+
3. **CI** runs tests on PRs and pushes.
|
|
12
|
+
|
|
13
|
+
## Normal automated release flow (recommended)
|
|
14
|
+
|
|
15
|
+
1. **Make changes on a branch** and merge to `main` with a Conventional Commit title:
|
|
16
|
+
- `fix:` → patch (e.g., `0.3.1`)
|
|
17
|
+
- `feat:` → minor (e.g., `0.4.0`)
|
|
18
|
+
- `feat!:` or `BREAKING CHANGE:` → major (e.g., `1.0.0`)
|
|
19
|
+
2. `release-please` runs on push to `main` and **opens a release PR**.
|
|
20
|
+
3. Merge the release PR:
|
|
21
|
+
- `release-please` **creates a tag** `vX.Y.Z` and a GitHub Release.
|
|
22
|
+
4. The **Release workflow** runs on the tag and **publishes to RubyGems** via Trusted Publishing.
|
|
23
|
+
|
|
24
|
+
### Requirements for the automated flow
|
|
25
|
+
|
|
26
|
+
- A **PAT** stored as the repo secret `RELEASE_PLEASE_TOKEN` so the tag created by release-please triggers other workflows.
|
|
27
|
+
- RubyGems **Trusted Publisher** configured for this repo/workflow (see below).
|
|
28
|
+
|
|
29
|
+
## Workflows (GitHub Actions)
|
|
30
|
+
|
|
31
|
+
### CI
|
|
32
|
+
|
|
33
|
+
File: `.github/workflows/ci.yml`
|
|
34
|
+
Runs tests on PRs and pushes.
|
|
35
|
+
|
|
36
|
+
### Release Please
|
|
37
|
+
|
|
38
|
+
File: `.github/workflows/release-please.yml`
|
|
39
|
+
Creates release PRs and tags.
|
|
40
|
+
|
|
41
|
+
Important: it uses a PAT:
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Release
|
|
48
|
+
|
|
49
|
+
File: `.github/workflows/release.yml`
|
|
50
|
+
Runs tests and publishes using OIDC (Trusted Publishing).
|
|
51
|
+
|
|
52
|
+
## Secrets you need
|
|
53
|
+
|
|
54
|
+
1. **RELEASE_PLEASE_TOKEN** (GitHub PAT, classic token with `repo` scope)
|
|
55
|
+
- Used by release-please to create tags that trigger the Release workflow.
|
|
56
|
+
|
|
57
|
+
> NOTE: You no longer need `RUBYGEMS_API_KEY` once Trusted Publishing is configured.
|
|
58
|
+
|
|
59
|
+
## RubyGems Trusted Publishing setup
|
|
60
|
+
|
|
61
|
+
1. Go to RubyGems → your gem → **Trusted Publishers** → **Create**.
|
|
62
|
+
2. Fill in:
|
|
63
|
+
- Owner: `Munkun-Estudio`
|
|
64
|
+
- Repo: `bridgetown_directus`
|
|
65
|
+
- Workflow file: `release.yml`
|
|
66
|
+
- Environment: leave blank (unless you use one in GitHub)
|
|
67
|
+
3. Save.
|
|
68
|
+
|
|
69
|
+
After this, GitHub can publish without API keys or OTP.
|
|
70
|
+
|
|
71
|
+
## Local release (manual fallback)
|
|
72
|
+
|
|
73
|
+
Use this if the Release workflow fails or you need to publish immediately:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cd /Users/pablo/projects/bridgetown_directus
|
|
77
|
+
bundle install
|
|
78
|
+
bundle exec rake build
|
|
79
|
+
ls pkg
|
|
80
|
+
gem push pkg/bridgetown_directus-X.Y.Z.gem
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If RubyGems MFA is enabled, you will be prompted for an OTP.
|
|
84
|
+
|
|
85
|
+
## Troubleshooting
|
|
86
|
+
|
|
87
|
+
### Release PR merged but gem not published
|
|
88
|
+
|
|
89
|
+
Likely cause: tag created by `release-please` didn’t trigger the Release workflow.
|
|
90
|
+
Fix: ensure `RELEASE_PLEASE_TOKEN` is set and the workflow uses it.
|
|
91
|
+
|
|
92
|
+
### Release workflow failed with MFA/OTP
|
|
93
|
+
|
|
94
|
+
You are not using Trusted Publishing. Configure it as above, then re-run the Release workflow.
|
|
95
|
+
|
|
96
|
+
### Tag exists but no Release workflow run
|
|
97
|
+
|
|
98
|
+
1. Verify the tag is `vX.Y.Z`.
|
|
99
|
+
2. Go to **Actions → Release → Run workflow** (manual run).
|
|
100
|
+
3. If it still fails, check the workflow logs.
|
|
101
|
+
|
|
102
|
+
## Version file
|
|
103
|
+
|
|
104
|
+
`lib/bridgetown_directus/version.rb` is updated by release-please.
|
|
105
|
+
Do **not** bump it manually if you use release-please.
|
|
106
|
+
|
|
107
|
+
## Changelog
|
|
108
|
+
|
|
109
|
+
`CHANGELOG.md` is updated by release-please. Keep entries under `Unreleased` if editing manually.
|
|
@@ -9,17 +9,16 @@ module BridgetownDirectus
|
|
|
9
9
|
def build
|
|
10
10
|
config = site.config.bridgetown_directus
|
|
11
11
|
return if site.ssr?
|
|
12
|
+
return unless config&.api_url && config&.token
|
|
13
|
+
|
|
14
|
+
client = Client.new(api_url: config.api_url, token: config.token, ssl_verify: config.ssl_verify)
|
|
12
15
|
|
|
13
16
|
config.collections.each_value do |collection_config|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
client:
|
|
18
|
-
|
|
19
|
-
token: config.token
|
|
20
|
-
),
|
|
21
|
-
collection_config: collection_config
|
|
22
|
-
)
|
|
17
|
+
if collection_config.data?
|
|
18
|
+
process_data_collection(client: client, collection_config: collection_config)
|
|
19
|
+
elsif [:posts, :pages, :custom_collection].include?(collection_config.resource_type)
|
|
20
|
+
process_collection(client: client, collection_config: collection_config)
|
|
21
|
+
end
|
|
23
22
|
end
|
|
24
23
|
end
|
|
25
24
|
|
|
@@ -166,6 +165,34 @@ module BridgetownDirectus
|
|
|
166
165
|
deleted
|
|
167
166
|
end
|
|
168
167
|
|
|
168
|
+
# Fetch a data-only collection and inject into site.data (no file generation)
|
|
169
|
+
def process_data_collection(client:, collection_config:)
|
|
170
|
+
endpoint = collection_config.endpoint || collection_config.name.to_s
|
|
171
|
+
begin
|
|
172
|
+
response = client.fetch_collection(endpoint, collection_config.default_query)
|
|
173
|
+
rescue StandardError => e
|
|
174
|
+
warn "Error fetching data collection '#{endpoint}': #{e.message}"
|
|
175
|
+
return
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
process_data_collection_with_data(response, collection_config)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Process already-fetched data for a data collection (also used in tests)
|
|
182
|
+
def process_data_collection_with_data(response, collection_config)
|
|
183
|
+
data = sanitize_keys(response)
|
|
184
|
+
|
|
185
|
+
if collection_config.singleton
|
|
186
|
+
data = data.is_a?(Array) ? data.first : data
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Apply M2M flattening if configured
|
|
190
|
+
apply_m2m_flattenings!(data, collection_config)
|
|
191
|
+
|
|
192
|
+
site.data[collection_config.name.to_s] = data
|
|
193
|
+
log_directus("Loaded data collection: #{collection_label(collection_config)}#{collection_config.singleton ? ' (singleton)' : " (#{Array(data).size} items)"}")
|
|
194
|
+
end
|
|
195
|
+
|
|
169
196
|
def process_collection(client:, collection_config:)
|
|
170
197
|
endpoint = collection_config.endpoint || collection_config.name.to_s
|
|
171
198
|
begin
|
|
@@ -197,6 +224,42 @@ module BridgetownDirectus
|
|
|
197
224
|
log_directus("Updated #{collection_label(collection_config)}: wrote #{written}, skipped #{skipped}, deleted #{deleted}")
|
|
198
225
|
end
|
|
199
226
|
|
|
227
|
+
# Apply M2M junction flattening to fetched data.
|
|
228
|
+
# Walks the configured dot-paths and unwraps junction objects.
|
|
229
|
+
def apply_m2m_flattenings!(data, collection_config)
|
|
230
|
+
return if collection_config.m2m_flattenings.empty?
|
|
231
|
+
|
|
232
|
+
items = data.is_a?(Array) ? data : [data].compact
|
|
233
|
+
collection_config.m2m_flattenings.each do |flattening|
|
|
234
|
+
path_parts = flattening[:path].split(".")
|
|
235
|
+
junction_key = flattening[:key]
|
|
236
|
+
items.each { |item| flatten_at_path!(item, path_parts, junction_key) }
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Recursively walk a dot-path and flatten the M2M array at the leaf.
|
|
241
|
+
def flatten_at_path!(obj, path_parts, junction_key)
|
|
242
|
+
return unless obj.is_a?(Hash)
|
|
243
|
+
|
|
244
|
+
key = path_parts.first
|
|
245
|
+
remaining = path_parts[1..]
|
|
246
|
+
|
|
247
|
+
if remaining.empty?
|
|
248
|
+
# We're at the leaf — flatten the junction array
|
|
249
|
+
return unless obj[key].is_a?(Array)
|
|
250
|
+
|
|
251
|
+
obj[key] = obj[key].filter_map { |junction| junction[junction_key] if junction.is_a?(Hash) }
|
|
252
|
+
else
|
|
253
|
+
# Intermediate path — recurse into nested object(s)
|
|
254
|
+
target = obj[key]
|
|
255
|
+
if target.is_a?(Array)
|
|
256
|
+
target.each { |nested| flatten_at_path!(nested, remaining, junction_key) }
|
|
257
|
+
elsif target.is_a?(Hash)
|
|
258
|
+
flatten_at_path!(target, remaining, junction_key)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
200
263
|
def log_directus(message)
|
|
201
264
|
return unless directus_logging_enabled?
|
|
202
265
|
|
|
@@ -8,9 +8,10 @@ module BridgetownDirectus
|
|
|
8
8
|
class Client
|
|
9
9
|
attr_reader :api_url, :token
|
|
10
10
|
|
|
11
|
-
def initialize(api_url:, token:)
|
|
11
|
+
def initialize(api_url:, token:, ssl_verify: true)
|
|
12
12
|
@api_url = api_url
|
|
13
13
|
@token = token
|
|
14
|
+
@ssl_verify = ssl_verify
|
|
14
15
|
return unless @token.nil? || @api_url.nil?
|
|
15
16
|
|
|
16
17
|
raise StandardError, "Invalid Directus configuration: missing API token or URL"
|
|
@@ -45,7 +46,7 @@ module BridgetownDirectus
|
|
|
45
46
|
private
|
|
46
47
|
|
|
47
48
|
def connection
|
|
48
|
-
@connection ||= Faraday.new(url: @api_url) do |faraday|
|
|
49
|
+
@connection ||= Faraday.new(url: @api_url, ssl: { verify: @ssl_verify }) do |faraday|
|
|
49
50
|
faraday.headers["Authorization"] = "Bearer #{@token}"
|
|
50
51
|
faraday.headers["Content-Type"] = "application/json"
|
|
51
52
|
faraday.adapter Faraday.default_adapter
|
|
@@ -43,11 +43,33 @@ module BridgetownDirectus
|
|
|
43
43
|
@translations_enabled = false
|
|
44
44
|
@translatable_fields = []
|
|
45
45
|
@endpoint = nil
|
|
46
|
+
@singleton = false
|
|
47
|
+
@m2m_flattenings = []
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
# Set up accessors for collection configuration properties
|
|
49
51
|
attr_accessor :endpoint, :fields, :default_query, :resource_type, :layout,
|
|
50
|
-
:translations_enabled, :translatable_fields
|
|
52
|
+
:translations_enabled, :translatable_fields, :singleton
|
|
53
|
+
attr_reader :m2m_flattenings
|
|
54
|
+
|
|
55
|
+
# Register a many-to-many junction to flatten after fetching.
|
|
56
|
+
# Directus returns M2M data wrapped in junction objects like:
|
|
57
|
+
# [{"raus_stats_id": {"id": 1, "value": "8+"}}]
|
|
58
|
+
# This unwraps them to:
|
|
59
|
+
# [{"id": 1, "value": "8+"}]
|
|
60
|
+
#
|
|
61
|
+
# @param path [String] Dot-separated path to the M2M field (e.g. "sections.stats")
|
|
62
|
+
# @param key [String] The junction key containing the actual related item
|
|
63
|
+
# @return [void]
|
|
64
|
+
def flatten_m2m(path, key:)
|
|
65
|
+
@m2m_flattenings << { path: path, key: key }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Check if this collection is a data-only collection
|
|
69
|
+
# @return [Boolean]
|
|
70
|
+
def data?
|
|
71
|
+
@resource_type == :data
|
|
72
|
+
end
|
|
51
73
|
|
|
52
74
|
# Define a field mapping with optional converter
|
|
53
75
|
# @param bridgetown_field [Symbol] The field name in Bridgetown
|
data/lib/bridgetown_directus.rb
CHANGED
|
@@ -8,25 +8,53 @@ require_relative "bridgetown_directus/configuration"
|
|
|
8
8
|
require_relative "bridgetown_directus/builder"
|
|
9
9
|
|
|
10
10
|
module BridgetownDirectus
|
|
11
|
-
# Bridgetown initializer for the plugin
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
# Bridgetown initializer for the plugin.
|
|
12
|
+
#
|
|
13
|
+
# Usage in config/initializers.rb:
|
|
14
|
+
#
|
|
15
|
+
# init :bridgetown_directus do
|
|
16
|
+
# api_url ENV["DIRECTUS_API_URL"]
|
|
17
|
+
# token ENV["DIRECTUS_API_TOKEN"]
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# Then configure collections separately:
|
|
21
|
+
#
|
|
22
|
+
# BridgetownDirectus.configure do |directus|
|
|
23
|
+
# directus.register_collection(:posts) { |c| ... }
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
Bridgetown.initializer :bridgetown_directus do |config, **kwargs|
|
|
27
|
+
bd_config = Configuration.instance
|
|
15
28
|
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
# Apply keyword args from init block (e.g. api_url, token)
|
|
30
|
+
bd_config.api_url ||= kwargs[:api_url]&.to_s || ENV["DIRECTUS_API_URL"]
|
|
31
|
+
bd_config.token ||= kwargs[:token]&.to_s || ENV["DIRECTUS_API_TOKEN"] || ENV["DIRECTUS_TOKEN"]
|
|
32
|
+
|
|
33
|
+
# Store on the Bridgetown config so the Builder can access it
|
|
34
|
+
config.bridgetown_directus = bd_config
|
|
19
35
|
|
|
20
36
|
# Register the builder
|
|
21
37
|
config.builder BridgetownDirectus::Builder
|
|
22
38
|
end
|
|
23
39
|
|
|
40
|
+
# Global configuration singleton. Call BridgetownDirectus.configure to register collections.
|
|
24
41
|
class Configuration
|
|
25
|
-
attr_accessor :api_url, :token
|
|
42
|
+
attr_accessor :api_url, :token, :ssl_verify
|
|
26
43
|
attr_reader :collections
|
|
27
44
|
|
|
28
45
|
def initialize
|
|
29
46
|
@collections = {}
|
|
47
|
+
@ssl_verify = true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Returns the singleton Configuration instance
|
|
51
|
+
def self.instance
|
|
52
|
+
@instance ||= new
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Reset the singleton (useful in tests)
|
|
56
|
+
def self.reset!
|
|
57
|
+
@instance = nil
|
|
30
58
|
end
|
|
31
59
|
|
|
32
60
|
def register_collection(name, &block)
|
|
@@ -36,4 +64,15 @@ module BridgetownDirectus
|
|
|
36
64
|
collection
|
|
37
65
|
end
|
|
38
66
|
end
|
|
67
|
+
|
|
68
|
+
# Configure the plugin. Call this after `init :bridgetown_directus`.
|
|
69
|
+
#
|
|
70
|
+
# BridgetownDirectus.configure do |directus|
|
|
71
|
+
# directus.api_url = ENV["DIRECTUS_API_URL"]
|
|
72
|
+
# directus.register_collection(:posts) { |c| ... }
|
|
73
|
+
# end
|
|
74
|
+
#
|
|
75
|
+
def self.configure
|
|
76
|
+
yield Configuration.instance if block_given?
|
|
77
|
+
end
|
|
39
78
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bridgetown_directus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Munkun
|
|
@@ -171,6 +171,7 @@ files:
|
|
|
171
171
|
- Gemfile
|
|
172
172
|
- LICENSE.txt
|
|
173
173
|
- README.md
|
|
174
|
+
- RELEASING.md
|
|
174
175
|
- Rakefile
|
|
175
176
|
- bridgetown.automation.rb
|
|
176
177
|
- bridgetown_directus.gemspec
|
|
@@ -206,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
206
207
|
- !ruby/object:Gem::Version
|
|
207
208
|
version: '0'
|
|
208
209
|
requirements: []
|
|
209
|
-
rubygems_version: 3.
|
|
210
|
+
rubygems_version: 3.6.9
|
|
210
211
|
specification_version: 4
|
|
211
212
|
summary: Use Directus as headless CMS for Bridgetown
|
|
212
213
|
test_files: []
|