feat: distribute becwright on npm/pnpm (no Python required)#16
Conversation
…ardcode python3 Generated rules and exported BECs now use 'becwright run <check>' instead of 'python3 -m becwright.checks.<check>'. The same command works whether becwright is installed via pip, pipx or a standalone binary, which is the prerequisite for distributing it on npm to users without Python. - New 'becwright run <check> [args]' subcommand dispatching to built-in checks. - materialize() and init's starter rules emit the new form. - classify_check() still recognizes the legacy 'python3 -m ...' form on import. - Migrate dogfood .bec/rules.yaml, READMEs and documentation; add back-compat note. - Tests for the run subcommand and legacy-form back-compat.
Adds the tooling to ship becwright as a self-contained binary so users without Python can install it (the npm packaging in the next phase consumes these artifacts). - packaging/becwright.spec: one-file PyInstaller build. Uses collect_submodules on becwright.checks because checks are imported dynamically by 'becwright run' and would otherwise be missed by static analysis. - packaging/becwright_entry.py: absolute-import entry point for the freezer. - src/becwright/__main__.py: enables 'python -m becwright'. - pyproject: 'build' extra pinning pyinstaller. - .github/workflows/build-binaries.yml: builds and smoke-tests the binary on linux x64/arm64, macOS x64/arm64 and Windows x64, uploading one artifact each.
Lets JS/web/backend developers install becwright without Python, using the esbuild/ruff model: a thin launcher package plus os/cpu-gated optional dependencies that each carry one prebuilt binary. - npm/becwright: launcher package. bin/becwright.js resolves the platform binary via require.resolve and execs it. It prepends the binary's own directory to PATH so the engine's 'becwright run <check>' subprocess resolves even on a local-only (devDependency) install, where node_modules/.bin is not on PATH. - npm/platforms/*: five per-platform packages (linux x64/arm64, darwin x64/arm64, win32 x64) with os/cpu fields; the binary is staged in by CI. - npm/stage.mjs: copies a built binary into its platform package. - git hook now prefers ./node_modules/.bin/becwright before a global becwright, so local installs work inside git hooks. Verified locally end to end: with no Python and no global becwright, a devDependency install runs init/check and a real 'git commit' is blocked.
A published release (tag vX.Y.Z) now builds the platform binaries, publishes the npm packages and publishes to PyPI, all from one workflow. - release.yml: on release, calls the build matrix (now a reusable workflow), stages each binary into its platform package, derives every npm version from the tag, publishes the platform packages then the launcher, and publishes to PyPI via Trusted Publishing. - build-binaries.yml: switched to workflow_call (+ workflow_dispatch) so the release reuses it instead of double-building on the tag; publish.yml removed (folded into release.yml). - npm/set-version.mjs: syncs the version across launcher + platform packages and the launcher's optionalDependencies. Platform package.json normalized to its canonical (stable) form. - Document the release process and required NPM_TOKEN/scope setup; document npm/pnpm install in both READMEs.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (34)
📝 WalkthroughWalkthroughAdds a Changesbecwright run subcommand, bundle migration, hook update, and docs
npm binary distribution and CI release pipeline
Sequence DiagramsequenceDiagram
participant Release as GitHub Release (published)
participant BuildBinaries as build-binaries.yml
participant NpmJob as release / npm job
participant PyPIJob as release / pypi job
participant NpmRegistry as npm registry
participant PyPI as PyPI
Release->>BuildBinaries: workflow_call (matrix: 5 platforms)
BuildBinaries-->>NpmJob: upload dist/becwright[.exe] artifacts
NpmJob->>NpmJob: stage.mjs → copy binary to npm/platforms/<target>/
NpmJob->>NpmJob: set-version.mjs → patch package.json versions from release tag
NpmJob->>NpmRegistry: npm publish `@becwright/`<platform> (×5)
NpmJob->>NpmRegistry: npm publish becwright launcher
Release->>PyPIJob: parallel trigger
PyPIJob->>PyPI: pypa/gh-action-pypi-publish (OIDC)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Lets JS/web/backend developers — anyone without Python — install becwright via npm/pnpm, while keeping pip/pipx working. Distribution uses the esbuild/ruff model: a thin launcher package plus
os/cpu-gated optional packages that each carry a self-contained binary (no Python at runtime).Delivered in four atomic phases:
Phase 0 — Decouple checks from
python3(59d3323)The blocker: generated
.bec/rules.yamlhardcodedpython3 -m becwright.checks.X, so a binary alone wouldn't help. Now a newbecwright run <check> [args]subcommand dispatches to built-in checks, andinit/materializeemitbecwright run …. The same command works whether becwright comes from pip, pipx or a binary. Legacypython3 -m …is still recognized on import (back-compat).Phase 1 — Standalone binary (
8faf322)PyInstaller one-file spec (uses
collect_submodulesbecause checks load dynamically), abuildextra,python -m becwrightentry point, and a CI matrix building + smoke-testing the binary on linux x64/arm64, darwin x64/arm64, win32 x64.Phase 2 — npm packaging + local hook (
98099a8)Launcher
becwright+ five@becwright/<target>packages. The launcher prepends the binary's dir toPATHso the engine'sbecwright runsubprocess resolves even on a local devDependency install (wherenode_modules/.binisn't on the hook's PATH). The git hook now prefers./node_modules/.bin/becwrightbefore a global one.Phase 3 — Automated release (
c1ea31d)One published GitHub release → builds binaries, stages them, derives every npm version from the tag, publishes the 5 platform packages then the launcher, and publishes to PyPI (Trusted Publishing).
build-binaries.ymlbecame a reusable workflow;publish.ymlfolded intorelease.yml.Test plan
pytest— 110 passing throughout (107 + 3 new forrun; back-compat tests added)becwright check --allpasses with the newbecwright runformversion/list/run forbid/run debug_remnantswork; fullinit → checkblocks adebugger;with only the binary on PATH (no Python)--versionvia launcher;init+check+ a realgit commitblocked with no Python and no global becwright (local devDependency only)node --check;set-version.mjsdeterministicnpm publish— only run in CI on releaseBefore the first real release (maintainer)
Documented in
documentation/releasing.md:NPM_TOKENrepo secret.@becwrightnpm scope and own the unscopedbecwrightname.Summary by CodeRabbit
New Features
becwright runcommand for running built-in checks directly.Bug Fixes
becwright run ...form and the legacy command style for compatibility.Documentation