diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 811193037..6ee68a7f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 @@ -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 diff --git a/tests/release/packages/README.md b/tests/release/packages/README.md index 0e26162d2..2b5d83632 100644 --- a/tests/release/packages/README.md +++ b/tests/release/packages/README.md @@ -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. diff --git a/tests/release/packages/ink-link-smoke/fixture.sh b/tests/release/packages/ink-link-smoke/fixture.sh index ae9d1080c..5791a548d 100755 --- a/tests/release/packages/ink-link-smoke/fixture.sh +++ b/tests/release/packages/ink-link-smoke/fixture.sh @@ -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")" @@ -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" diff --git a/tests/release/packages/ink-link-smoke/package.json b/tests/release/packages/ink-link-smoke/package.json index 1d6d0f15d..a96a43f8d 100644 --- a/tests/release/packages/ink-link-smoke/package.json +++ b/tests/release/packages/ink-link-smoke/package.json @@ -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" ] } }