Skip to content

Latest commit

 

History

History
145 lines (103 loc) · 9.25 KB

File metadata and controls

145 lines (103 loc) · 9.25 KB

Contributing to Perry

Thanks for your interest in Perry. This document covers everything you need to land a PR — what to build, how to test, and what the review flow looks like.

For building and installing Perry as a user, see README.md. For runtime/compiler architecture, see CLAUDE.md. This file is about contributing, not using.

Ways to contribute

All of these are welcome and none are ranked:

  • Fix a bug. Check the issue tracker, especially good first issue and help wanted.
  • Close a TypeScript parity gap. The gap test suite tracks divergences from node --experimental-strip-types; CLAUDE.md's "TypeScript Parity Status" table is the current scoreboard.
  • Add a platform backend or widget. See the "To add a new widget" and "Native UI" sections in CLAUDE.md.
  • Improve docs or examples. Everything under docs/src/ and docs/examples/ is fair game.
  • Report an issue. File one even if you don't have a fix — reproducers are themselves a contribution.

Not sure where to start? Open a Discussion and describe what you'd like to work on; we'll help you scope it.

Building from source

Prerequisites match what CI installs — see .github/workflows/test.yml for the authoritative list. In short:

Component Version Needed for
Rust stable (≥ 1.94) Everything. The workspace pins no toolchain, so an older stable fails deep in the dependency graph with a sqlx@0.9.0 requires rustc 1.94.0 MSRV error rather than a clear message — rustup update stable fixes it.
Rust nightly + rust-src latest tvOS / watchOS cross-compile only (-Zbuild-std)
Node.js see .node-version Parity tests (run_parity_tests.sh). Use that exact version — an older Node makes the harness classify tests node_fail and silently DROP them from the gate instead of failing.
C linker any Linking compiled binaries (xcode-select --install / build-essential / MSVC)
libclang any bindgen, via the libsqlite3-sys build script. Without it the build dies with Unable to find libclang. Debian/Ubuntu: libclang-dev; Fedora: clang-devel; Arch: clang. If it lives somewhere non-standard, point at it with LIBCLANG_PATH=/path/to/dir (and, if bindgen then can't find stdarg.h, BINDGEN_EXTRA_CLANG_ARGS="-isystem /path/to/clang/<ver>/include").
clang ≥ 15 Perry's own LLVM codegen shells out to clang -c. Separate from the linker above — see the installation guide. perry doctor verifies it.

Platform-specific extras — only required if you're touching that backend:

  • macOS UI (perry-ui-macos): Xcode Command Line Tools
  • iOS / tvOS / watchOS: Xcode + matching SDKs; rustup target add aarch64-apple-ios-sim
  • Android (perry-ui-android): Android NDK ($ANDROID_NDK_HOME or $ANDROID_HOME/ndk/*); rustup target add aarch64-linux-android
  • Linux UI (perry-ui-gtk4): libgtk-4-dev libadwaita-1-dev libpulse-dev pkg-config (Xvfb for headless UI tests)
  • Windows UI (perry-ui-windows): MSVC (ilammy/msvc-dev-cmd or a vcvars64.bat session)

Build the default (platform-independent) workspace and run the affected crates' fast unit tests:

cargo build --release
./scripts/test_affected_crates.sh --base origin/main

The runner includes committed, staged, and unstaged paths relative to the base revision; stage new files before running it because untracked paths are ignored. Use --dry-run to inspect its per-crate Cargo commands, or set PERRY_TEST_BASE to change the default base. It mirrors CI's scripts/ci_test_scope.py selection and unit-target filtering, including the single-threaded perry-runtime run. It deliberately skips integration tests under crates/*/tests/; CI runs those through its scoped and nightly jobs. Never replace it with cargo test --workspace: Perry's per-crate feature sets must remain isolated.

For a faster inner loop, cargo check -p perry (correctness only) or cargo build --profile perry-dev -p perry (optimized local dev build). The .a static archives now come from dedicated wrapper crates — build them with cargo build --release -p perry-runtime-static -p perry-stdlib-static when you need libperry_{runtime,stdlib}.a. See docs/src/contributing/building.md for the full dev/release/dist taxonomy and the slim --features dev-cli CLI (#5422).

The full README Development section has more cargo run recipes (HIR dumps, per-crate rebuilds).

For fixture-only parity reruns, PERRY_SKIP_BUILD=1 ./run_parity_tests.sh reuses PERRY_BIN and the matching runtime/stdlib archives from PERRY_RUNTIME_DIR (or the binary's directory) with auto-optimization disabled. Rebuild instead whenever Rust or Cargo inputs, or compiler, runtime, stdlib, or required extension sources differ; reuse does not prove that prebuilt artifacts match the checkout.

Making changes

What goes in a PR

  • One logical change. Small PRs land faster. If you find yourself writing "also, I fixed …", split.
  • Tests. New behavior needs a test; a bug fix needs a regression test. For compiler changes, drop a .ts file under test-files/ exercising the path. For runtime/stdlib, #[test] in the relevant crate.
  • Docs where user-visible. New CLI flags, new perry.toml fields, new stdlib APIs → update docs/src/.

What does NOT go in a PR (maintainer handles these at merge)

  • Do not bump [workspace.package] version in Cargo.toml.
  • Do not edit **Current Version:** at the top of CLAUDE.md.
  • Do not add a "Recent Changes" entry to CLAUDE.md or CHANGELOG.md.

Perry releases frequently — often several patch versions between a PR being opened and merged. If contributors bump the version on their branch, those bumps conflict on merge day through no fault of the contributor. The maintainer folds version + changelog metadata in when landing your PR, so it always matches the actually-shipped release.

Commit messages

We loosely follow Conventional Commits — not enforced, but you'll see feat: / fix: / docs: / chore: / refactor: prefixes in the log. Match that style and your PR reads better in the changelog. A good commit message answers "why" more than "what"; the diff already shows what.

Claiming an issue

Comment on the issue saying you'd like to take it. We'll assign it to you. If you go quiet for a week or two, we may un-assign to let someone else pick it up — no hard feelings, just keeping the board moving.

Running CI's checks locally

Most red PRs come from gates that cargo build never looks at — a file that crossed the 2000-line cap, fmt drift, or an unbarriered GC store site. Run the fast, non-compiling subset with:

./scripts/pre-tag-check.sh --quick

That is every gate in the lint job that doesn't compile anything, so it costs seconds. Drop --quick to add the docs linter, cargo check, and Clippy; it also runs cargo deny when installed. The script prints every failure in one pass rather than one per push.

Behavioral changes (HIR, codegen, runtime) also need the conformance suite, which diffs compiled programs byte-for-byte against Node:

./scripts/run_gap_tests.sh                          # 401 tests; ~1h serially
./scripts/run_doc_tests.sh                          # Compile + run every docs/examples/*.ts

Use the Node version pinned in .node-version, not whatever you have. Node is the oracle the suite diffs against, so its version is a correctness input: on a Node too old for a test, node fails, the harness classifies the test node_fail, and it is dropped from the run instead of going red. CI sat on Node 22 while the suite grew Node 24/26 features and hid 14 tests that way.

Any PR touching crates/ also needs a changelog.d/<PR-number>-<slug>.md fragment; see changelog.d/README.md.

UI doc-tests launch real windows. On headless hosts, wrap in xvfb-run -a (Linux) or rely on PERRY_UI_TEST_MODE=1 which auto-exits after one frame.

Asking questions

  • Bug: open an issue — the template asks for Perry version, target, host OS, and a minimal repro.
  • Feature request: open an issue with the "feature request" template.
  • Open-ended question, design discussion, "is Perry right for my use case": start a Discussion.
  • Security issue: email ralph@skelpo.com directly; please don't file a public issue for anything exploitable.

Code of Conduct

Participation is governed by the Code of Conduct — tl;dr: be kind, assume good faith, disagree in the open on technical merits. Reports go to ralph@skelpo.com.

License

Perry is MIT-licensed. By contributing, you agree your contributions are licensed under the same terms. We do not require a CLA or DCO sign-off.