Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
59 changes: 56 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ on:
- '!CHANGELOG.md'
# Manual escape hatch for the opt-in jobs. Maintainers (write access)
# can dispatch the workflow against any ref with `run_extended_tests=true`
# to run parity / compile-smoke / doc-tests on demand without tagging
# a release.
# to run parity / compile-smoke / package smokes / doc-tests on demand
# without tagging a release.
workflow_dispatch:
inputs:
run_extended_tests:
description: 'Run extended tests (parity, compile-smoke, doc-tests)'
description: 'Run extended tests (parity, compile-smoke, package smokes, doc-tests)'
type: boolean
default: false

Expand Down Expand Up @@ -943,6 +943,59 @@ jobs:
cd tests/release/packages/drizzle-mysql
PERRY_BIN="$GITHUB_WORKSPACE/target/release/perry" bash fixture.sh

# ---------------------------------------------------------------------------
# ink-link-smoke: runs the tier-3 release fixture
# `tests/release/packages/ink-link-smoke/` as the CI counterpart to #803.
#
# This is intentionally compile/link-only. #348 tracks broader Ink runtime
# and rendering compatibility; this job guards the package-graph +
# compilePackages linker contract that the fixture documents.
#
# Gated to tag pushes + opt-in (parity with drizzle-mysql-smoke /
# compile-smoke / doc-tests). The fixture installs Ink + React and builds a
# release Perry compiler, so PRs shouldn't pay it by default. Opt-in via the
# `run-extended-tests` label or workflow dispatch.
# ---------------------------------------------------------------------------
ink-link-smoke:
if: >-
github.event_name == 'push' ||
(github.event_name == 'workflow_dispatch' && inputs.run_extended_tests) ||
(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'run-extended-tests'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2
with:
shared-key: "${{ runner.os }}-perry"
save-if: ${{ github.ref == 'refs/heads/main' }}

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'

- name: Build perry compiler
run: cargo build --release -p perry-runtime -p perry-stdlib -p perry

- name: Run Ink link fixture
run: |
cd tests/release/packages/ink-link-smoke
PERRY_BIN="$GITHUB_WORKSPACE/target/release/perry" bash fixture.sh

- name: Upload Ink fixture logs
if: always()
uses: actions/upload-artifact@v7
with:
name: ink-link-smoke-logs
path: |
tests/release/packages/ink-link-smoke/install.log
tests/release/packages/ink-link-smoke/perry-compile.log
if-no-files-found: ignore

# ---------------------------------------------------------------------------
# Doc-example tests: compile + run every .ts under docs/examples/.
# UI examples launch with PERRY_UI_TEST_MODE=1 so they auto-exit after one
Expand Down
6 changes: 6 additions & 0 deletions tests/release/packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,9 @@ PERRY_TEST_SUMMARY_OUT=/tmp/x.json _harness.sh # emit JSON summary

The harness defines its own pass/fail/skip totals; downstream consumers
(release_sweep tier 3) only care about the JSON summary.

The `ink-link-smoke` fixture also has a named CI job in
`.github/workflows/test.yml`. It runs on release tags, on manual dispatch with
`run_extended_tests=true`, and on PRs with the `run-extended-tests` label. That
job intentionally stops at compile/link plus symbol inspection; end-to-end Ink
rendering remains tracked separately from the release fixture contract.
33 changes: 33 additions & 0 deletions tests/release/packages/ink-link-smoke/fixture.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
# compile/link and symbol inspection. Executing the binary currently reaches a
# broader React/Object runtime interop gap (`hasOwnProperty is not a function`),
# which is not the #678 contract.
# The locked yoga-layout package bootstraps its default export from a WASM helper.
# This fixture does not execute layout code, so we patch that default export to an
# inert object after npm install to keep the link-only guard focused on Ink's
# package graph and native symbol surface.

set -uo pipefail
cd "$(dirname "$0")"
Expand All @@ -14,6 +18,35 @@ cd "$(dirname "$0")"
NAME="ink-link-smoke"
fixture_setup "$NAME" || exit 1

node --input-type=commonjs <<'JS'
const fs = require('fs');

const patches = [
{
file: 'node_modules/yoga-layout/src/index.ts',
importBlock:
"// @ts-ignore untyped from Emscripten\nimport loadYoga from '../binaries/yoga-wasm-base64-esm.js';\nimport wrapAssembly from './wrapAssembly.ts';\n",
},
{
file: 'node_modules/yoga-layout/dist/src/index.js',
importBlock:
"// @ts-ignore untyped from Emscripten\nimport loadYoga from '../binaries/yoga-wasm-base64-esm.js';\nimport wrapAssembly from \"./wrapAssembly.js\";\n",
},
];

for (const patch of patches) {
let text = fs.readFileSync(patch.file, 'utf8');
if (text.includes(patch.importBlock)) {
text = text.replace(patch.importBlock, '');
}
text = text.replace('const Yoga = wrapAssembly(await loadYoga());', 'const Yoga = {};');
if (!text.includes('const Yoga = {};')) {
throw new Error(`failed to patch yoga-layout link stub in ${patch.file}`);
}
fs.writeFileSync(patch.file, text);
}
JS

echo " [perry compile/link] entry.tsx"
if ! "$PERRY_BIN" compile entry.tsx -o ./out > perry-compile.log 2>&1; then
echo "FAIL $NAME - perry compile/link errored"
Expand Down
77 changes: 75 additions & 2 deletions tests/release/packages/ink-link-smoke/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,87 @@
"react": "18.3.1"
},
"perry": {
"define": {
"process.env.DEV": "false",
"process.env.NODE_ENV": "production"
},
"experiments": {
"treeShake": true
},
"compilePackages": [
"@alcalzone/ansi-tokenize",
"ansi-escapes",
"ansi-regex",
"ansi-styles",
"auto-bind",
"chalk",
"cli-boxes",
"cli-cursor",
"cli-truncate",
"code-excerpt",
"convert-to-spaces",
"emoji-regex",
"environment",
"es-toolkit",
"escape-string-regexp",
"get-east-asian-width",
"indent-string",
"ink",
"is-fullwidth-code-point",
"is-in-ci",
"mimic-fn",
"onetime",
"patch-console",
"react",
"ink"
"react-reconciler",
"restore-cursor",
"scheduler",
"signal-exit",
"slice-ansi",
"stack-utils",
"strip-ansi",
"string-width",
"widest-line",
"wrap-ansi",
"yoga-layout"
],
"allow": {
"compilePackages": [
"@alcalzone/ansi-tokenize",
"ansi-escapes",
"ansi-regex",
"ansi-styles",
"auto-bind",
"chalk",
"cli-boxes",
"cli-cursor",
"cli-truncate",
"code-excerpt",
"convert-to-spaces",
"emoji-regex",
"environment",
"es-toolkit",
"escape-string-regexp",
"get-east-asian-width",
"indent-string",
"ink",
"is-fullwidth-code-point",
"is-in-ci",
"mimic-fn",
"onetime",
"patch-console",
"react",
"ink"
"react-reconciler",
"restore-cursor",
"scheduler",
"signal-exit",
"slice-ansi",
"stack-utils",
"strip-ansi",
"string-width",
"widest-line",
"wrap-ansi",
"yoga-layout"
]
}
}
Expand Down