Files
nyaterm/docs-site/i18n/en/docusaurus-plugin-content-docs/current/development/setup.md
T
Kang 505e54b806 feat(ci): implement selective job execution for Rust workflows
- Introduced an `orchestrate` job to determine which CI jobs to run based on changed paths in pull requests.
- Updated Rust workflow to conditionally execute jobs like linting, testing, and plugin SDK based on the selection logic.
- Added a new script `select_rust_jobs.py` to handle job selection logic without requiring a Rust installation.
- Enhanced documentation to explain the new CI execution model and its implications for contributors.
2026-11-02 13:03:16 +08:00

245 lines
14 KiB
Markdown

# Development Setup
The NyaTerm application is a Cargo workspace. Node.js and pnpm are only required for the Docusaurus documentation site in this repository.
## Application prerequisites
### Rust and Git
Install the latest stable Rust toolchain:
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Windows users can install from [rustup.rs](https://rustup.rs/). Every platform also needs Git and its native compiler toolchain.
### Platform dependencies
#### Windows
Install [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) with the **Desktop development with C++** workload.
#### macOS
Install Xcode and its command-line tools:
```bash
xcode-select --install
```
GPUI uses Metal on macOS, so a working macOS SDK is required.
#### Linux (Ubuntu / Debian)
Install Rust crate build tools, font/window-system development libraries, and the Vulkan loader:
```bash
sudo apt update
sudo apt install build-essential clang pkg-config cmake \
libfontconfig1-dev libfreetype6-dev libssl-dev libudev-dev \
libwayland-dev libx11-dev libx11-xcb-dev \
libxcb-cursor-dev libxcb-icccm4-dev libxcb-image0-dev \
libxcb-keysyms1-dev libxcb-randr0-dev libxcb-render0-dev \
libxcb-shape0-dev libxcb-xfixes0-dev libxcb-xinerama0-dev \
libxkbcommon-dev libxkbcommon-x11-dev libzstd-dev \
libvulkan1 mesa-vulkan-drivers
```
Running the desktop application also requires a working Vulkan driver and an X11 or Wayland session.
## Clone the repository
```bash
git clone https://github.com/nyakang/nyaterm.git
cd nyaterm
```
Cargo manages all application dependencies. The Node.js dependencies in this repository belong to `docs-site` only.
## Run the application
```bash
cargo run -p nyaterm-app --bin nyaterm
```
The first build compiles GPUI and every dependency, so it takes noticeably longer than subsequent incremental builds.
### RDP / VNC need their helpers built first
RDP and VNC each run in a separate helper process that the application resolves beside its own executable. The command above **only builds the application**, so both protocols fail with `HelperMissing`. Build the helpers first:
```bash
cargo build -p nyaterm-rdp-helper -p nyaterm-vnc-helper
```
A bare `cargo build` builds the application and both helpers because they are the workspace `default-members`. `cargo check` checks all three too, but does not produce helper executables that the application can launch. If you use a custom `CARGO_TARGET_DIR`, `--target`, or profile, keep the helpers in the same directory as the application.
`NYATERM_RDP_HELPER` and `NYATERM_VNC_HELPER` override the lookup with an explicit path, which is handy for pointing at binaries in another target directory.
## Common checks
Prefer locked checks scoped to the affected crate while iterating:
```bash
cargo check -p <crate-name> --locked
cargo test -p <crate-name> --locked
```
Rust CI runs fmt and clippy on Linux, then runs workspace tests independently on Linux x64, macOS arm64, and Windows x64. The exact commands are:
```bash
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --locked
cargo test --workspace --locked --no-fail-fast
```
The separate Linux Python packaging-test job runs:
```bash
python -m unittest scripts.tests.test_check_release_assets scripts.tests.test_package_native scripts.tests.test_verify_native_package scripts.tests.test_generate_release_metadata
```
The non-ignored RDP/VNC helper lifecycle integration tests are covered automatically by workspace tests, including handshake, normal exit, and crash/hang reaping. They can also be run directly:
```bash
cargo test -p nyaterm-rdp-helper --test lifecycle --locked
cargo test -p nyaterm-vnc-helper --test lifecycle --locked
```
These lifecycle tests launch real helper executables but do not connect to real RDP/VNC servers, so they do not replace manual protocol interoperability, framebuffer, clipboard, or input-path acceptance. `cargo fmt --all` writes formatting changes; use it only when you intend to apply them.
## Release-profile build
```bash
cargo build -p nyaterm-app --bin nyaterm --release --locked
```
The native binary is written to `target/release/nyaterm`, or `target/release/nyaterm.exe` on Windows. This command builds only the application binary — neither the helpers nor any installer.
Release packages come from `scripts/release/package_native.py`. It builds the application and both helpers with locked dependencies, puts the helpers next to the application, and produces native installers and portable packages. When you add a helper, its `HELPER_BINS` list must be updated too.
### Six release targets
| Platform | Rust target | Artifacts |
| --- | --- | --- |
| macOS arm64 | `aarch64-apple-darwin` | `.dmg`, `.app.tar.gz` |
| macOS x64 | `x86_64-apple-darwin` | `.dmg`, `.app.tar.gz` |
| Linux x64 | `x86_64-unknown-linux-gnu` | `.AppImage`, `.deb`, `.rpm` |
| Linux arm64 | `aarch64-unknown-linux-gnu` | `.AppImage`, `.deb`, `.rpm` |
| Windows x64 | `x86_64-pc-windows-msvc` | `_portable.zip`, `-setup.exe` |
| Windows arm64 | `aarch64-pc-windows-msvc` | `_portable.zip`, `-setup.exe` |
Every release CI matrix leg runs:
```bash
python scripts/release/package_native.py "${TARGET}"
python scripts/release/verify_native_package.py --target "${TARGET}" --version "${VERSION}" --dist dist
```
Before publication, `scripts/ci/check_release_assets.py` also rejects missing or extra artifacts in the combined six-target asset set.
`NYATERM_ARTIFACT_VERSION` changes only the version segment in artifact names;
package metadata still uses the workspace SemVer. This interface is reserved
for manual snapshot builds, and packaging and verification must receive the
same value:
```bash
NYATERM_ARTIFACT_VERSION=main-snapshot \
python scripts/release/package_native.py "${TARGET}"
python scripts/release/verify_native_package.py \
--target "${TARGET}" --version "${VERSION}" \
--artifact-version main-snapshot --dist dist
```
### External package manager builds
Packagers that build from source (nixpkgs and similar) can declare that they own
the update channel by setting `NYATERM_PACKAGE_MANAGER` at build time:
```bash
NYATERM_PACKAGE_MANAGER=nix cargo build -p nyaterm-app --release --locked
```
The value is baked into the binary at compile time: the application skips the
startup silent update check, hides the in-app update entries in the title bar and
tray, and reports the package manager name in the About dialog's support
information. Leaving it unset keeps the ordinary build behaviour; development
builds should not set it. Cargo rebuilds the affected crates when the variable
changes, so no build script is required.
The variable only applies to packages built from source. AUR and the Homebrew
cask repack the published `.deb` / `.dmg` artifacts, so the application still
owns their updates and they must not set it.
After validation, a version tag publishes GitHub Release and versioned R2 assets, then triggers Gitee, AUR, and Homebrew. The website reads `downloads.json`; signed `latest.json` exists only to migrate installed Tauri releases to GPUI. Only stable releases replace the root R2 manifests, while prereleases retain versioned manifests. A manual `Main Snapshot` run overwrites the `main-snapshot` prerelease without publishing to downstream channels.
The Release workflow requires `NYATERM_GITHUB_GIST_CLIENT_ID`, the Gitee/R2 repository variables, and the updater, R2, Gitee, AUR, and Homebrew secrets named in the workflows. Missing configuration fails the relevant release step instead of producing an incomplete official release.
### Native tools and the manual-acceptance boundary
Native packaging depends on target-platform tools: Windows uses NSIS and package verification also needs 7-Zip; macOS uses `codesign` and `hdiutil`; Linux uses tools such as `appimagetool`, `dpkg-shlibdeps`, `dpkg-deb`, `rpmbuild`, and `rpm`/`rpm2cpio`. Running only the Python packaging unit tests on a machine without those tools is therefore not a native package build.
Automated verification checks the artifact set, archive paths, application and helper presence, binary architecture, version, and package metadata. It does not prove that the GUI launches, and does not cover real install/upgrade/uninstall flows, shortcuts or `nyaterm:` URL-handler invocation, signing/notarization and Gatekeeper/SmartScreen trust, real RDP/VNC sessions, or GPU, IME, PTY, clipboard, and window lifecycle behavior. Release candidates must be accepted manually on the corresponding target OS, with the actual platform and results recorded truthfully.
## Selective CI jobs
The Rust workflow starts with a lightweight `orchestrate` job that tests the selection rules and compares the PR event's base SHA with the merge commit being tested. It selects the union of jobs required by all changed paths and explains its choices in the Actions Job Summary. Ordinary Rust changes still run the existing lint and Linux, macOS, and Windows workspace tests; application translation JSON keeps those checks too.
The four tmux compatibility jobs run when transport, terminal, core, the plugin API, the MCP protocol, or shared build/CI configuration changes. The Plugin SDK job follows plugin examples, scripts, and related crates; Python and workflow checks have their own path rules. Documentation-site or root Markdown changes skip heavy Rust jobs, while the `Docs` workflow continues to build every locale.
Add the `run-tmux` label to a PR to force the full tmux matrix; later commits continue to run it while the label remains. Label events also rerun the other checks selected for that PR's paths, rather than reporting only tmux results. Pushes to `main` or `migration/gpui`, Merge Queue events, and manual runs of the `Rust` workflow execute the full job set.
Unclassified paths, new crates, Cargo manifests/lockfiles, and shared build configuration enable all jobs. Missing comparison revisions or a failed Git diff also fall back to the full suite. A selection-script exception or failing regression test fails `Rust gate`. When adding a workspace crate or changing a related crate's dependencies, update the registration and dependency sets in `scripts/ci/select_rust_jobs.py`; manifest checks guard against missing coverage.
`Rust gate` and `Docs gate` remain the unified Required Checks and support Merge Queue. Gates always aggregate dependency results: success and conditional skips pass, while failure or cancellation fails.
## Documentation development
When editing `docs-site`, also install Node.js 22.13+ and [pnpm](https://pnpm.io/). Docusaurus itself only needs Node 18+, but the pnpm version this repository pins imports `node:sqlite` and crashes outright on anything older. The `packageManager` field in `docs-site/package.json` pins that pnpm version, and corepack picks it up automatically.
```bash
pnpm --dir docs-site install --frozen-lockfile
pnpm --dir docs-site start:zh
```
Start the English documentation server with:
```bash
pnpm --dir docs-site start:en
```
The exact documentation CI commands are:
```bash
python3 scripts/ci/check_docs_translations.py
pnpm --dir docs-site install --frozen-lockfile
pnpm --dir docs-site build
```
The build checks pages and sidebars for every locale and reports Markdown-link problems according to the site configuration. The translation script verifies that every page exists in both locales, that both copies have the same heading count (which catches a whole section going untranslated), that every page is referenced from `sidebars.ts`, and that no authoring notes were left in the published text. The `Documentation site` CI job runs the script before installing locked dependencies and building every locale.
Note that the script compares heading counts, not translated wording.
## Changing third-party dependencies
The third-party dependencies NyaTerm patches are **not vendored into this repository**. Each is a patch series on a fork under [github.com/nyakang](https://github.com/nyakang) on branch `nyaterm`, consumed from a revision pinned in the root `Cargo.toml`: `alacritty`, `gpui-kit`, `IronRDP`, `russh`, `russh-sftp`, `sspi-rs`, `vnc-rs`, `zed` (`gpui`), and `zmodem2`.
The workflow is: commit to the fork branch, push, then bump the pinned revision in the root `Cargo.toml`. Keep the patch series split by concern rather than squashed, and record the reason and the validation performed on the patch commit and in that branch's `NYATERM.md`. Prefer rebasing an existing series onto a newer upstream revision over accumulating snapshots.
`temp/vendor/` holds read-only local copies of those sources, kept only so they can be read locally. **Nothing there is compiled — editing it has no effect on the build and produces no error.**
## Development conventions
- Read the root `AGENTS.md` and `CONTRIBUTING.md` first.
- UI state and views live in `nyaterm-desktop`; shared controls live in `nyaterm-ui`.
- Transport, terminal, and core crates stay independent of GPUI.
- New UI text updates both locale files under `crates/nyaterm-desktop/src/i18n/locales/`.
- Never use real credentials in tests, logs, or diagnostic data.
## GPUI main-branch cutover
The GPUI cutover candidate is submitted from `cutover/gpui` to `main`. Keep `migration/gpui` during the transition and archive the former Tauri main branch at `archive/tauri-v1`. Subsequent development and stable publishing move to `main` only after the cutover PR merges.
The candidate version `2.0.0` does not mean it has been published. Maintainers run Release with `verify_release=true`, `upload_release=false`, and a fixed `source_ref` for a signed rehearsal. See `scripts/release/GPUI_CUTOVER.md` in the repository for gates, evidence, and recovery steps, and the [migration guide](../getting-started/migration-v2) for user upgrades.