pandorga 1.2.3 → 1.3.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
  SHA256:
3
- metadata.gz: 6564a5382e67a496ec1fb1a08c3bd76601f7fe3e49bfcd7c6950e96c7fec84be
4
- data.tar.gz: 3a57c483bbd9c36e1db0caa694e996ab6b6b9f72c9fb0db248b02bb419307888
3
+ metadata.gz: 19d2883dc4b29f8c6b614997004f69d32d2cacfa67ab83ef61544364a7d57cb3
4
+ data.tar.gz: 73f29c402a3259ec374c2d15746f7a6898d10f24258c11d626e5afe561d6a2e5
5
5
  SHA512:
6
- metadata.gz: 38e07ea84144b6fe8812369ee5f0282493ce98cea31454ed8a6a6f072c7275024189524e8e863a3be0307ce55f6dc7bac81d6198f5ae202704df67164d0423fb
7
- data.tar.gz: 36ce18aedcd108d7d247bd050badf62f64d83000b1d0c97dbc7325f7a03bdea8a7dc0ef15ca38fa595222c0e3efe9e4f5c8ba1668e5c831f6ce3558da793b176
6
+ metadata.gz: 692b1745fea99d185aaf2ed170a584fb83bf9c870eaa6e03b9567e9d9883930cc136b7e7821cb4746781d87c5131f688bc79f9b0d4cb8aa90208a4d47ef6462f
7
+ data.tar.gz: e9a2698daffc89e5ee9502a1450dce6e736aad68ca500ed1e37dffa4e5c34ed9709ed0f724888959bee6bd680085d56d7beb7c80504610f2a04683a21d6386a7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.3.0] — 2026-10-05
4
+
5
+ ### Fixed
6
+
7
+ - Object-store publish fails fast when `PANDORGA_SITE_ROOT` is unset and the
8
+ script runs from the pandorga gem (no more silent skip of `content/media`)
9
+ - `pandorga publish` exports `PANDORGA_SITE_ROOT` even when delegating to a
10
+ site-local `publish-content-to-r2.sh` wrapper
11
+
12
+ ## [1.2.4] — 2026-10-05
13
+
14
+ ### Fixed
15
+
16
+ - An omitted `pandorga.content.backend` keeps a configured `base_url` or legacy `content_api_base_url` as an object-store origin. `static` remains the default only when no public URL is set, and an explicit `backend: static` still wins.
17
+
3
18
  ## [1.2.3] — 2026-10-05
4
19
 
5
20
  ### Changed
@@ -22,9 +22,9 @@ module Pandorga
22
22
 
23
23
  source "https://rubygems.org"
24
24
 
25
- gem "pandorga", "~> 1.2"
25
+ gem "pandorga", "~> 1.3"
26
26
  # Local checkout: gem "pandorga", path: "../pandorga"
27
- # GitHub tag: gem "pandorga", github: "alexandrelheinen/pandorga", tag: "v1.2.3"
27
+ # GitHub tag: gem "pandorga", github: "alexandrelheinen/pandorga", tag: "v1.3.0"
28
28
  gem "csv"
29
29
  gem "base64"
30
30
  RUBY
@@ -12,8 +12,9 @@ module Pandorga
12
12
  root = Pathname.new(argv[0] || Dir.pwd).expand_path
13
13
  site_script = root.join("scripts", "content", "publish-content-to-r2.sh")
14
14
  if site_script.file? && site_script.expand_path != gem_publish_script
15
+ env = ENV.to_h.merge("PANDORGA_SITE_ROOT" => root.to_s)
15
16
  Dir.chdir(root) do
16
- exec("bash", site_script.to_s, *argv[1..])
17
+ exec(env, "bash", site_script.to_s, *argv[1..])
17
18
  end
18
19
  end
19
20
 
@@ -26,10 +26,11 @@ content:
26
26
  title: "`pandorga.content`"
27
27
  intro: |
28
28
  Legacy `content_api_base_url` still works as a fallback for `base_url`.
29
+ When `backend` is omitted, a non-empty `base_url` or `content_api_base_url` selects `object_store`. With no origin, the default is `static`. An explicit `backend: static` still serves JSON from `_site` and clears the public URL at build time.
29
30
  keys:
30
31
  backend:
31
32
  type: "`static` \\| `r2` \\| `object_store` \\| `s3`"
32
- notes: "`static` serves JSON from `_site`. The others use `base_url` as the public object-store origin"
33
+ notes: "`static` serves JSON from `_site`. The others use `base_url` as the public object-store origin. Omitted plus a public URL selects `object_store`"
33
34
  base_url:
34
35
  type: string
35
36
  notes: Public content origin when backend is not `static`
@@ -256,9 +256,14 @@ module PandorgaRegistry
256
256
 
257
257
  def content_backend(config)
258
258
  raw = config.dig("pandorga", "content", "backend").to_s.strip
259
- return "static" if raw.empty?
259
+ return raw unless raw.empty?
260
260
 
261
- raw
261
+ # A public origin is the pre-registry signal that JSON lives on an object
262
+ # store. Static is the default only when no origin is configured; an
263
+ # explicit `backend: static` still wins and the build clears the URL.
264
+ return "object_store" unless content_base_url(config).empty?
265
+
266
+ "static"
262
267
  end
263
268
 
264
269
  def content_base_url(config)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pandorga
4
- VERSION = "1.2.3"
4
+ VERSION = "1.3.0"
5
5
  end
@@ -5,7 +5,19 @@
5
5
  set -euo pipefail
6
6
 
7
7
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
8
+
9
+ # When this script lives in an installed (or checked-out) gem, ROOT is the gem
10
+ # tree — not the consumer site. Media sync must use the site root; without it
11
+ # we used to skip content/media silently and leave Studio uploads on GitHub
12
+ # only. Require an explicit site root whenever ROOT looks like the gem.
13
+ if [ -z "${PANDORGA_SITE_ROOT:-}" ] && [ -f "$ROOT/pandorga.gemspec" ]; then
14
+ echo "error: PANDORGA_SITE_ROOT must be set when publish-content-to-object-store.sh runs from the pandorga gem." >&2
15
+ echo "hint: export PANDORGA_SITE_ROOT to the Jekyll site root before exec (site wrappers must set this)." >&2
16
+ exit 1
17
+ fi
18
+
8
19
  SITE_ROOT="${PANDORGA_SITE_ROOT:-$ROOT}"
20
+ SITE_ROOT="$(cd "$SITE_ROOT" && pwd)"
9
21
  EXPORT_ROOT="${1:-$SITE_ROOT/_content_json}"
10
22
 
11
23
  # Prefer S3_* names; fall back to R2_* for Cloudflare R2 callers.
@@ -55,6 +67,7 @@ sync_json_prefix() {
55
67
 
56
68
  echo "==> Publishing content JSON to bucket: ${S3_BUCKET}"
57
69
  echo "==> Endpoint: ${S3_ENDPOINT}"
70
+ echo "==> Site root: ${SITE_ROOT}"
58
71
  sync_json_prefix collections
59
72
  sync_json_prefix data
60
73
  sync_json_prefix pages
@@ -67,12 +80,14 @@ aws s3 cp "$EXPORT_ROOT/manifest.json" "s3://${S3_BUCKET}/manifest.json" \
67
80
 
68
81
  MEDIA_ROOT="$SITE_ROOT/content/media"
69
82
  if [ -d "$MEDIA_ROOT" ]; then
70
- echo "==> Sync media/"
83
+ echo "==> Sync media/ from ${MEDIA_ROOT}"
71
84
  aws s3 sync "$MEDIA_ROOT" "s3://${S3_BUCKET}/media" \
72
85
  --endpoint-url "$S3_ENDPOINT" \
73
86
  --delete \
74
87
  --size-only \
75
88
  --cache-control "public,max-age=31536000,immutable"
89
+ else
90
+ echo "==> No content/media at ${MEDIA_ROOT} (skipping media sync)"
76
91
  fi
77
92
 
78
93
  echo "==> Object-store publish complete"
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # An omitted backend must not discard a configured public origin.
4
+ # Explicit static still serves JSON from _site.
5
+ require "pathname"
6
+
7
+ ROOT = Pathname.new(__dir__).join("../..").expand_path
8
+ $LOAD_PATH.unshift(ROOT.join("lib").to_s)
9
+ require "pandorga/registry"
10
+
11
+ def check!(condition, message)
12
+ return if condition
13
+
14
+ warn "FAIL test-content-backend: #{message}"
15
+ exit 1
16
+ end
17
+
18
+ url = "https://pub-example.r2.dev"
19
+
20
+ check!(PandorgaRegistry.content_backend({}) == "static",
21
+ "no origin must stay static")
22
+ check!(PandorgaRegistry.static_backend?({}),
23
+ "static_backend? must be true when no origin is set")
24
+
25
+ legacy = { "content_api_base_url" => url }
26
+ check!(PandorgaRegistry.content_backend(legacy) == "object_store",
27
+ "legacy content_api_base_url must select object_store, got #{PandorgaRegistry.content_backend(legacy).inspect}")
28
+ check!(PandorgaRegistry.object_store_backend?(legacy),
29
+ "object_store_backend? must be true for a legacy URL")
30
+ check!(PandorgaRegistry.content_base_url(legacy) == url,
31
+ "legacy URL must remain the public origin")
32
+
33
+ base_only = { "pandorga" => { "content" => { "base_url" => "#{url}/" } } }
34
+ check!(PandorgaRegistry.content_backend(base_only) == "object_store",
35
+ "base_url without backend must select object_store")
36
+ check!(PandorgaRegistry.content_base_url(base_only) == url,
37
+ "base_url must be stripped of a trailing slash")
38
+
39
+ explicit_static = {
40
+ "content_api_base_url" => url,
41
+ "pandorga" => { "content" => { "backend" => "static" } }
42
+ }
43
+ check!(PandorgaRegistry.content_backend(explicit_static) == "static",
44
+ "explicit static must win over a leftover URL")
45
+
46
+ explicit_r2 = { "pandorga" => { "content" => { "backend" => "r2", "base_url" => url } } }
47
+ check!(PandorgaRegistry.content_backend(explicit_r2) == "r2",
48
+ "explicit r2 must be preserved")
49
+
50
+ puts "PASS test-content-backend"
@@ -57,8 +57,8 @@ end
57
57
  end
58
58
 
59
59
  gemfile = DEST.join("Gemfile").read
60
- unless gemfile.include?('gem "pandorga", "~> 1.2"')
61
- warn "FAIL test-new: Gemfile must pin pandorga ~> 1.2\n#{gemfile}"
60
+ unless gemfile.include?('gem "pandorga", "~> 1.3"')
61
+ warn "FAIL test-new: Gemfile must pin pandorga ~> 1.3\n#{gemfile}"
62
62
  exit 1
63
63
  end
64
64
  unless gemfile.include?("path:") && gemfile.include?("github:")
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Refs: media sync must not silently use the gem tree as SITE_ROOT.
5
+ require "open3"
6
+ require "pathname"
7
+
8
+ ROOT = Pathname.new(__dir__).join("../..").expand_path
9
+ SCRIPT = ROOT.join("scripts/content/publish-content-to-object-store.sh")
10
+
11
+ def fail!(message)
12
+ warn "FAIL test-publish-site-root: #{message}"
13
+ exit 1
14
+ end
15
+
16
+ fail!("missing #{SCRIPT}") unless SCRIPT.file?
17
+
18
+ env = ENV.to_h
19
+ env.delete("PANDORGA_SITE_ROOT")
20
+ # Avoid falling through to real credentials if a developer has them set.
21
+ %w[
22
+ S3_ENDPOINT S3_BUCKET S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY
23
+ R2_ENDPOINT R2_BUCKET R2_ACCESS_KEY_ID R2_SECRET_ACCESS_KEY
24
+ ].each { |key| env.delete(key) }
25
+
26
+ out, status = Open3.capture2e(env, "bash", SCRIPT.to_s)
27
+ fail!("expected exit 1 without PANDORGA_SITE_ROOT, got #{status.exitstatus}") unless status.exitstatus == 1
28
+ fail!("expected PANDORGA_SITE_ROOT error, got:\n#{out}") unless out.include?("PANDORGA_SITE_ROOT must be set")
29
+
30
+ ok_env = env.merge(
31
+ "PANDORGA_SITE_ROOT" => ROOT.join("examples/minimal").to_s,
32
+ "S3_ENDPOINT" => "https://example.invalid",
33
+ "S3_BUCKET" => "test-bucket",
34
+ "S3_ACCESS_KEY_ID" => "test",
35
+ "S3_SECRET_ACCESS_KEY" => "test"
36
+ )
37
+ out2, status2 = Open3.capture2e(ok_env, "bash", SCRIPT.to_s, ROOT.join("examples/minimal/_content_json").to_s)
38
+ fail!("with PANDORGA_SITE_ROOT set, must not fail the site-root guard; got #{status2.exitstatus}:\n#{out2}") if out2.include?("PANDORGA_SITE_ROOT must be set")
39
+
40
+ puts "PASS test-publish-site-root"
data/scripts/validate.sh CHANGED
@@ -34,6 +34,7 @@ TESTS=(
34
34
  scripts/test/test-dual-template-instances.rb
35
35
  scripts/test/test-dual-template-runtime.rb
36
36
  scripts/test/test-install-functions.rb
37
+ scripts/test/test-publish-site-root.rb
37
38
  scripts/test/test-no-personal-data.rb
38
39
  scripts/test/test-configuration-doc.rb
39
40
  scripts/test/test-cv-export-contract.rb
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pandorga
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Pandorga contributors
@@ -365,6 +365,7 @@ files:
365
365
  - scripts/test/test-cdn-pins.rb
366
366
  - scripts/test/test-cloudflare-watch-paths-doc.rb
367
367
  - scripts/test/test-configuration-doc.rb
368
+ - scripts/test/test-content-backend.rb
368
369
  - scripts/test/test-content-detail-urls.rb
369
370
  - scripts/test/test-content-keys.rb
370
371
  - scripts/test/test-content-license.rb
@@ -394,6 +395,7 @@ files:
394
395
  - scripts/test/test-new.rb
395
396
  - scripts/test/test-no-personal-data.rb
396
397
  - scripts/test/test-public-cv-export.rb
398
+ - scripts/test/test-publish-site-root.rb
397
399
  - scripts/test/test-r2-config-consistency.rb
398
400
  - scripts/test/test-r2-json-sync.rb
399
401
  - scripts/test/test-registry-home.rb