Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
69841bf
feat(ui): prototype automatic Shadow DOM style isolation (#347)
cameronapak Aug 19, 2026
a794931
Merge branch 'main' into journey-to-the-shadow-dom
aharms24 Aug 24, 2026
3c25b80
feat(ui): prototype shadow-local top-layer popovers (#357)
abharms Aug 25, 2026
e8bad1b
feat(ui): validate shadow DOM dialog top layer (#362)
abharms Aug 27, 2026
a161758
Merge branch 'main' into journey-to-the-shadow-dom
aharms24 Aug 28, 2026
bc7fc0e
Merge branch 'journey-to-the-shadow-dom' of https://github.com/youver…
aharms24 Aug 28, 2026
8b04908
fix(ui): harden Shadow DOM CSS isolation (YPE-5352) (#367)
abharms Aug 31, 2026
c764982
fix(ui): route verse actions through shadow portals (#369)
abharms Sep 1, 2026
19c8a0b
Merge branch 'main' into journey-to-the-shadow-dom
aharms24 Sep 2, 2026
3dec29a
Merge remote-tracking branch 'origin/journey-to-the-shadow-dom' into …
aharms24 Sep 2, 2026
7504630
test(ui): validate Shadow DOM consumer compatibility (YPE-5436) (#380)
abharms Sep 9, 2026
0222ae9
test(ui): prove nested overlays through the production shadow seam (#…
cameronapak Sep 9, 2026
dae9a49
fix(ui): address shadow DOM review regressions (YPE-5713) (#388)
abharms Sep 10, 2026
0e595c3
Merge branch 'main' into journey-to-the-shadow-dom
aharms24 Sep 10, 2026
2daf44d
fix(ui): enforce Shadow DOM custom property contract (YPE-5400) (#394)
abharms Sep 14, 2026
e91afcc
test(ui): prove Shadow DOM SSR hydration contract (#399)
abharms Sep 14, 2026
8c240ed
test(ui): validate realistic Shadow DOM usage (YPE-5437) (#408)
abharms Sep 16, 2026
358839f
Merge branch 'main' into journey-to-the-shadow-dom
ampagent Sep 17, 2026
1344034
fix(ci): unblock journey pull requests (#418)
abharms Sep 21, 2026
4b05279
fix(ui): restore shadow dialog focus after rapid reopen (YPE-5889) (#…
abharms Sep 21, 2026
b9c21f3
test(ui): consolidate Storybook DOM waits (#415)
abharms Sep 21, 2026
baa9b30
test(ui): add cross-browser Shadow DOM coverage (#420)
abharms Sep 24, 2026
7068c41
docs(ui): define Shadow DOM rollout policy (#423)
abharms Sep 25, 2026
1201b45
feat(ui): harden Shadow DOM rollout foundation (YPE-5947) (#424)
abharms Sep 26, 2026
7b3dbe2
Merge remote-tracking branch 'origin/main' into journey-to-the-shadow…
abharms Sep 26, 2026
4fbd7db
test(ui): keep auth shadow query type-safe
abharms Sep 26, 2026
a75cf71
feat(ui): isolate Bible pickers in Shadow DOM (#426)
abharms Sep 28, 2026
311649c
feat(ui): isolate leaf components (YPE-5948) (#427)
abharms Sep 29, 2026
33d8227
test(ui): catch shadow stylesheet cache poisoning (#429)
abharms Sep 30, 2026
44ee7e5
feat(ui): preserve standalone theme settings layout (YPE-5994) (#428)
abharms Oct 1, 2026
8e53dd9
Merge branch 'main' into journey-to-the-shadow-dom
abharms Oct 1, 2026
542e17f
feat(ui): isolate scripture presentation components (YPE-5950) (#431)
abharms Oct 5, 2026
c037af9
feat(ui): isolate Bible reader (YPE-5951) (#433)
abharms Oct 7, 2026
61fb7f5
Merge branch 'main' into journey-to-the-shadow-dom
abharms Oct 8, 2026
caaf04f
fix(ui): deduplicate shadow ancestor events (#439)
abharms Oct 8, 2026
a5aff31
Merge remote-tracking branch 'origin/main' into journey-to-the-shadow…
abharms Oct 13, 2026
80634f5
fix(ui): deduplicate shadow blur events (YPE-6135) (#444)
abharms Oct 14, 2026
eafffa7
feat(ui): complete coordinated Shadow DOM rollout (#442)
abharms Oct 15, 2026
9efbcca
Merge branch 'main' into journey-to-the-shadow-dom
abharms Oct 15, 2026
f8e3b9a
fix(ui): deduplicate shadow styles (#448)
abharms Oct 16, 2026
054a530
fix(ui): preserve shadow host layout after suspense (#449)
abharms Oct 16, 2026
e26eb9c
docs(ui): reconcile shadow dom release contract (#450)
abharms Oct 20, 2026
d495aab
fix(ui): deduplicate remaining composed events (#452)
abharms Oct 21, 2026
5bb6220
fix(ui): preserve Firefox version picker tab order (#456)
abharms Oct 23, 2026
00e83ad
docs(ui): record final Safari release validation (#455)
abharms Oct 23, 2026
6c3fcf9
fix(ui): preserve chapter picker tab order (#458)
abharms Oct 30, 2026
7ad1e78
test(ui): cover Firefox chapter picker book focus (#465)
abharms Nov 2, 2026
87fc2f9
fix(ui): make pending highlight pointer detection iframe-safe (#466)
abharms Nov 2, 2026
43423f7
fix(ui): keep inline shadow hosts phrasing-safe (#468)
abharms Nov 3, 2026
ffa6552
Merge branch 'main' into codex/journey-main-sync
abharms Nov 3, 2026
4d557b8
fix(ui): preserve picker v2 shadow focus (#472)
abharms Nov 4, 2026
a50f432
fix(ui): address shadow rollout review feedback
abharms Nov 4, 2026
0e51549
Merge remote-tracking branch 'origin/main' into codex/journey-main-sync
abharms Nov 4, 2026
1c2d5ac
test(ui): query publisher story in shadow overlay
abharms Nov 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/all-humans-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/bitter-pigs-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/bright-shadows-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
5 changes: 5 additions & 0 deletions .changeset/calm-browsers-test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Preserve SDK spacing in Safari inside Shadow DOM and document roots by scoping the host CSS reset and inlining the fixed Tailwind spacing scale.
5 changes: 5 additions & 0 deletions .changeset/calm-firefox-focus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Skip the Bible version picker's version list scroll area in keyboard Tab order, keep focus on the outside target when dismissing from a language screen, and focus the dialog consistently when opening or rapidly reopening the picker.
5 changes: 5 additions & 0 deletions .changeset/calm-tabs-loop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Preserve the Bible chapter picker's natural keyboard order and keep its scrolling book list out of Firefox's sequential focus order.
4 changes: 4 additions & 0 deletions .changeset/clean-shadows-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
---

Reconcile Shadow DOM release metadata and consumer documentation without adding another package release.
8 changes: 8 additions & 0 deletions .changeset/clear-packages-align.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@youversion/platform-core': major
'@youversion/platform-react-hooks': major
---

Align Core and React Hooks with the UI package at version 3.0.0 as part of the
fixed package release. This version alignment does not add breaking API changes
to either package.
4 changes: 4 additions & 0 deletions .changeset/clever-wolves-fall.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
---

Record YPE-6214 final Safari release-candidate validation without publishing a package release.
2 changes: 2 additions & 0 deletions .changeset/cool-settings-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
53 changes: 53 additions & 0 deletions .changeset/coordinated-shadow-dom-rollout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
'@youversion/platform-react-ui': major
---

Ship the coordinated Shadow DOM rollout as a breaking rendered-DOM change. The
compatible public UI boundary now mounts in client-created open shadow roots:
`YouVersionAuthButton`, the chapter and version picker roots,
`BibleReader.Root`, and standalone theme settings, scripture, card, avatar,
footnote, and separator surfaces. SDK-owned compound members and composed
children reuse their owning boundary.

Server output for these components is a childless light-DOM host whose inline
`display` declares the boundary's intended layout until the passive-effect client
mount. Automatic shadow hosts therefore require strict CSP applications to allow
or hash style attributes as described in the
[UI Content Security Policy guidance](https://github.com/youversion/platform-sdk-react/blob/main/packages/ui/README.md#content-security-policy).
Document queries and global CSS no longer reach component internals,
forwarded element refs become available after that mount, and native events
observed outside a root are retargeted to its host. Keep form
ownership, native labels, and ARIA ID references within one tree; use public
props, callbacks, refs, and role-based automation instead of depending on
internal markup. Fonts remain document-owned, `rem` sizing follows the document
root, `direction` remains inherited, and ancestor layout can still constrain the
host. Shadow-local overlays use the native top layer, and opening a peer popover
dismisses the current peer. The native Popover API is required for isolated
floating content; there is no inline fallback, and an unhandled open error can
unmount the affected consumer React root. Popover content also respects Radix's
available collision height. Validated bubbling `click`, `keydown`, `keyup`,
`pointerdown`, `pointerup`, `mousedown`, `mouseup`, `dblclick`, `contextmenu`,
focus, blur, and native `input` paths reach light-DOM ancestor React handlers
once. The host corrects duplicate React `onInput` delivery; React `onChange` was
already delivered once because the outer event is retargeted to the non-form
host. Capture handlers and unlisted composed bubbling families can still receive
duplicate delivery. YPE-6210 covers `onClickCapture`; focused Chromium probes
observed duplicate move, wheel, keypress, drag-start, and copy delivery. This
list is representative, not exhaustive.

`Textarea`, standalone `VerseActionPopover`, `YouVersionProvider`, and
`BaseYouVersionProvider` remain outside the automatic boundary for their
document-level form, anchor, context, style, or font contracts. The release does
not add runtime rollout controls or phased-release infrastructure.

See the
[release-candidate evidence](https://github.com/youversion/platform-sdk-react/blob/main/docs/shadow-dom-isolation-plan.md#ype-5952-release-candidate-validation)
for the automated browser matrix, assistive-technology environments and
per-journey results, and remaining validation gaps. The
[final actual-Safari gate decision](https://github.com/youversion/platform-sdk-react/blob/main/docs/shadow-dom-isolation-plan.md#ype-6214-final-release-candidate-safari-validation)
records the accepted standalone-picker limitations and future rerun requirement.

Shared popover dialogs now derive an accessible name from their visible heading
unless the consumer provides an explicit label. The reader sign-in and sign-out
menu has an explicit accessible name, and the version picker places initial
focus on its language selector.
2 changes: 2 additions & 0 deletions .changeset/flat-shadows-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
5 changes: 5 additions & 0 deletions .changeset/focused-versions-tab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Keep Firefox keyboard focus on Bible version options when tabbing forward through the version picker.
5 changes: 5 additions & 0 deletions .changeset/friendly-verses-scroll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Keep verse actions open when touch selection moves to another verse, restore focus for initially anchored or conditionally mounted verse actions, and keep reader settings scrollable in constrained popovers. Clarify the automatic Shadow DOM boundary's document-owned font and root-sizing dependencies without expanding its rollout scope.
2 changes: 2 additions & 0 deletions .changeset/full-flies-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/fuzzy-books-focus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
5 changes: 5 additions & 0 deletions .changeset/iframe-highlight-pointer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Classify pending-highlight pointer targets with the reader document's element realm.
2 changes: 2 additions & 0 deletions .changeset/leaf-shadows-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/little-fans-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
4 changes: 4 additions & 0 deletions .changeset/prove-production-shadow-overlays.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
---

Prove nested and concurrent overlays through the production ShadowRootHost seam (YPE-5355).
2 changes: 2 additions & 0 deletions .changeset/quiet-events-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/reader-shadows-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
5 changes: 5 additions & 0 deletions .changeset/safe-phrasing-hosts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Keep auth-button and Bible-picker Shadow DOM hosts valid in server-rendered phrasing content.
5 changes: 5 additions & 0 deletions .changeset/safe-shadows-fallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Keep isolated UI content rendered with local styles when constructable stylesheet setup fails.
2 changes: 2 additions & 0 deletions .changeset/salty-lizards-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/scripture-shadows-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
5 changes: 5 additions & 0 deletions .changeset/shadow-aware-verse-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@youversion/platform-react-ui': patch
---

Keep verse action popovers in their component's shadow-local portal and restore focus after dismissal.
2 changes: 2 additions & 0 deletions .changeset/six-shrimps-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/tall-banks-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/tidy-shadow-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
8 changes: 8 additions & 0 deletions .changeset/tidy-shadows-reset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@youversion/platform-react-ui': patch
---

Keep text direction as the only intentionally inherited CSS property across an
automatic Shadow DOM boundary. Ambient host custom properties cannot alter SDK
spacing or radius values, while document-root font sizing still affects rem-based
dimensions.
8 changes: 8 additions & 0 deletions .changeset/validate-shadow-dialog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@youversion/platform-react-ui': patch
---

Keep shadow-local top-layer dialogs focus-contained and their background inert
while mounted. Restore focus to the original opener after dismissal, including
close/reopen during exit, while ignoring disconnected targets and targets moved
outside their captured root.
151 changes: 150 additions & 1 deletion .github/scripts/major-release-signoff.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,58 @@ extract_step() {
}

extract_step "Resolve PR context" > "$TMP/context.sh"
extract_step "Restore release tooling from the base branch" > "$TMP/restore-tooling.sh"
extract_step "Compute release preview" > "$TMP/preview.sh"
extract_step "Decide whether a signoff is required" > "$TMP/decision.sh"
extract_step "Regenerate and verify release contents" > "$TMP/verify.sh"
extract_step "Post an unresolved status" > "$TMP/unresolved.sh"

TOOLING_SOURCE="$TMP/tooling-source"
TOOLING_WORK="$TMP/tooling-work"
git init --quiet "$TOOLING_SOURCE"
git -C "$TOOLING_SOURCE" config commit.gpgsign false
git -C "$TOOLING_SOURCE" config user.name test
git -C "$TOOLING_SOURCE" config user.email test@example.com
mkdir -p "$TOOLING_SOURCE/scripts" "$TOOLING_SOURCE/.changeset" \
"$TOOLING_SOURCE/packages/ui" "$TOOLING_SOURCE/examples/demo" "$TOOLING_SOURCE/tools/config"
for file in scripts/preview-release.mjs package.json pnpm-lock.yaml \
pnpm-workspace.yaml .changeset/config.json .npmrc packages/ui/package.json \
examples/demo/package.json tools/config/package.json; do
printf 'main %s\n' "$file" > "$TOOLING_SOURCE/$file"
done
git -C "$TOOLING_SOURCE" add -A
git -C "$TOOLING_SOURCE" commit --quiet -m main
git -C "$TOOLING_SOURCE" branch -M main
git -C "$TOOLING_SOURCE" switch --quiet -c journey
mkdir -p "$TOOLING_SOURCE/packages/pr-only"
printf 'journey-only importer\n' > "$TOOLING_SOURCE/packages/pr-only/package.json"
for file in scripts/preview-release.mjs package.json pnpm-lock.yaml \
pnpm-workspace.yaml .changeset/config.json packages/ui/package.json; do
printf 'journey %s\n' "$file" > "$TOOLING_SOURCE/$file"
done
rm "$TOOLING_SOURCE/.npmrc"
printf 'journey pnpm hook\n' > "$TOOLING_SOURCE/.pnpmfile.cjs"
git -C "$TOOLING_SOURCE" add -A
git -C "$TOOLING_SOURCE" commit --quiet -m journey
TOOLING_HEAD=$(git -C "$TOOLING_SOURCE" rev-parse HEAD)
git -C "$TOOLING_SOURCE" switch --quiet main
git clone --quiet "$TOOLING_SOURCE" "$TOOLING_WORK"
git -C "$TOOLING_WORK" checkout --quiet "$TOOLING_HEAD"

if (cd "$TOOLING_WORK" && bash "$TMP/restore-tooling.sh") >/dev/null 2>&1 &&
[ "$(git -C "$TOOLING_WORK" rev-parse HEAD)" = "$TOOLING_HEAD" ] &&
[ "$(cat "$TOOLING_WORK/package.json")" = 'main package.json' ] &&
[ "$(cat "$TOOLING_WORK/pnpm-lock.yaml")" = 'main pnpm-lock.yaml' ] &&
[ "$(cat "$TOOLING_WORK/packages/ui/package.json")" = 'main packages/ui/package.json' ] &&
[ "$(cat "$TOOLING_WORK/.npmrc")" = 'main .npmrc' ] &&
[ ! -e "$TOOLING_WORK/packages/pr-only/package.json" ] &&
[ ! -e "$TOOLING_WORK/.pnpmfile.cjs" ]; then
pass "restores the complete release dependency graph from trusted main"
else
fail "restores the complete release dependency graph from trusted main" \
"expected main-owned workspace manifests and install inputs with PR-only importers removed"
fi

mkdir "$TMP/bin"
# The context step backs off between retries; real delays would add ~9s per error case.
cat > "$TMP/bin/sleep" <<'EOF'
Expand Down Expand Up @@ -376,7 +424,7 @@ run_decision_case "failed ordinary previews remain blocked, not major" \
'blocked=release preview did not succeed (failure)' false false skipped '' failure ''

extract_step "Restore release tooling from the base branch" > "$TMP/restore.sh"
PREVIEW_REPO="$TMP/preview-repo"
PREVIEW_REPO="$TMP/restore-preview-repo"
git init --quiet --initial-branch=main "$PREVIEW_REPO"
git -C "$PREVIEW_REPO" config commit.gpgsign false
git -C "$PREVIEW_REPO" config user.name test
Expand Down Expand Up @@ -440,6 +488,107 @@ else
fail "generated release identity always stays out of the ordinary preview" "preview does not use generated release identity"
fi

PREVIEW_REMOTE="$TMP/preview-remote.git"
PREVIEW_REPO="$TMP/preview-repo"
git init --quiet --bare "$PREVIEW_REMOTE"
git init --quiet "$PREVIEW_REPO"
git -C "$PREVIEW_REPO" config commit.gpgsign false
git -C "$PREVIEW_REPO" config user.name test
git -C "$PREVIEW_REPO" config user.email test@example.com
git -C "$PREVIEW_REPO" remote add origin "$PREVIEW_REMOTE"
mkdir -p "$PREVIEW_REPO/scripts" "$PREVIEW_REPO/.changeset" \
"$PREVIEW_REPO/packages/core" "$PREVIEW_REPO/packages/hooks" "$PREVIEW_REPO/packages/ui"
cp "$ROOT/scripts/preview-release.mjs" "$PREVIEW_REPO/scripts/preview-release.mjs"
cp "$ROOT/scripts/signoff-token.mjs" "$PREVIEW_REPO/scripts/signoff-token.mjs"
cp "$ROOT/.changeset/config.json" "$PREVIEW_REPO/.changeset/config.json"
cat > "$PREVIEW_REPO/package.json" <<'EOF'
{"name":"preview-fixture","private":true,"packageManager":"pnpm@11.10.0"}
EOF
cat > "$PREVIEW_REPO/pnpm-workspace.yaml" <<'EOF'
packages:
- "packages/*"
EOF
for package in core hooks ui; do
case "$package" in
core) name='@youversion/platform-core' ;;
hooks) name='@youversion/platform-react-hooks' ;;
ui) name='@youversion/platform-react-ui' ;;
esac
printf '{"name":"%s","version":"1.0.0"}\n' "$name" > "$PREVIEW_REPO/packages/$package/package.json"
done
git -C "$PREVIEW_REPO" add -A
git -C "$PREVIEW_REPO" commit --quiet -m main
git -C "$PREVIEW_REPO" branch -M main
git -C "$PREVIEW_REPO" push --quiet origin main

git -C "$PREVIEW_REPO" switch --quiet -c target
cat > "$PREVIEW_REPO/.changeset/target-major.md" <<'EOF'
---
"@youversion/platform-core": major
---

Major change inherited from the target branch.
EOF
git -C "$PREVIEW_REPO" add -A
git -C "$PREVIEW_REPO" commit --quiet -m 'target major'
git -C "$PREVIEW_REPO" push --quiet origin target
PREVIEW_BASE_SHA=$(git -C "$PREVIEW_REPO" rev-parse HEAD)

git -C "$PREVIEW_REPO" switch --quiet -c pr
printf 'non-major PR change\n' > "$PREVIEW_REPO/README.md"
git -C "$PREVIEW_REPO" add README.md
git -C "$PREVIEW_REPO" commit --quiet -m 'non-major PR change'
git -C "$PREVIEW_REPO" push --quiet origin pr
ln -s "$ROOT/node_modules" "$PREVIEW_REPO/node_modules"
PREVIEW_BIN="$TMP/preview-bin"
mkdir "$PREVIEW_BIN"
cat > "$PREVIEW_BIN/pnpm" <<EOF
#!/usr/bin/env bash
set -euo pipefail
[ "\$1" = exec ] && [ "\$2" = changeset ] && [ "\$3" = status ]
output=\${4#--output=}
printf '%s\n' \
'{"releases":[{"name":"@youversion/platform-core","type":"major","oldVersion":"1.0.0","newVersion":"2.0.0"}]}' \
> "\$output"
EOF
chmod +x "$PREVIEW_BIN/pnpm"

run_preview_case() {
local name="$1" expected_introduced="$2" expected_output="$3"
local output="$TMP/preview-output"
local error="$TMP/preview-error"
local preview="$PREVIEW_REPO/preview.json"
local head_sha
head_sha=$(git -C "$PREVIEW_REPO" rev-parse HEAD)
: > "$output"
rm -f "$preview"
if (cd "$PREVIEW_REPO" && \
PATH="$PREVIEW_BIN:$PATH" BASE_SHA="$PREVIEW_BASE_SHA" HEAD_SHA="$head_sha" \
GITHUB_OUTPUT="$output" \
bash "$TMP/preview.sh") >/dev/null 2> "$error" &&
jq -e ".introduced_major == $expected_introduced" "$preview" >/dev/null &&
grep -Fxq "is_major=$expected_output" "$output"; then
pass "$name"
else
fail "$name" \
"expected introduced_major=$expected_introduced and is_major=$expected_output; preview: $(cat "$preview" 2>/dev/null || true); output: $(tr '\n' ' ' < "$output"); error: $(tr '\n' ' ' < "$error")"
fi
}

run_preview_case "stacked PRs ignore a major inherited from their target branch" false 0

cat > "$PREVIEW_REPO/.changeset/pr-major.md" <<'EOF'
---
"@youversion/platform-react-ui": major
---

Major change introduced by the pull request.
EOF
git -C "$PREVIEW_REPO" add .changeset/pr-major.md
git -C "$PREVIEW_REPO" commit --quiet -m 'PR major'
git -C "$PREVIEW_REPO" push --quiet origin pr
run_preview_case "stacked PRs require signoff for a newly introduced major" true 1

if grep -Fq 'Generated release PR; major signoff is enforced on source PRs.' "$WORKFLOW"; then
pass "generated releases publish an explicit lifecycle-aware success"
else
Expand Down
Loading
Loading