4 releases

0.5.1 Nov 9, 2025
0.5.0 Nov 9, 2025
0.4.2 Nov 9, 2025
0.3.0 Nov 9, 2025
0.1.8 Nov 6, 2025

#774 in Command line utilities

21 downloads per month

Apache-2.0

85KB
2K SLoC

unity-ci

unity-ci is a Rust CLI that automates the repeatable pieces of building a Unity project in continuous integration. It detects which Unity editor version a project requires, makes sure the matching Unity Hub and editor binaries are available, optionally activates a license, and finally shells out to the Unity editor with the arguments you specify.

The tool is intentionally chatty. Every major operation is wrapped in structured logging so CI logs show exactly which checks passed, which resources were downloaded, and how Unity was eventually invoked.

✨ Features

🧭 Setup & Detection

  • Detects the required Unity editor version from the project metadata.
  • Installs or locates Unity Hub and the matching editor with cache overrides.

🔐 Licensing & Credentials

  • Supports optional license activation/return when Unity credentials are set.

🚀 Execution & Reporting

  • Normalises paths and prints a full command preview with optional prompts.
  • Scans the Unity log and fails fast when errors are detected.

📦 Installation

🦀 From crates.io (preferred)

Install the latest release directly from the public cargo registry:

cargo install unity-ci

🏗️ From this repository

When working from a specific revision of this repository, build with the stable Rust toolchain (1.75 or newer is recommended):

cargo install --path .

You can also install straight from git without cloning first:

cargo install --git https://github.com/sator-imaging/unity-ci

🚀 Usage

The CLI currently exposes a single subcommand, build:

unity-ci build [OPTIONS] --execute <UNITY_METHOD> <PROJECT_PATH>

Options:
    -f, --force                    Skip the confirmation prompt
    -t, --target <UNITY_TARGET>    Unity build target passed to -buildTarget
    -l, --log <LOG_PATH>           Destination for Unity's log file (defaults to ./build.log)
    -m, --module <MODULES>         Comma-separated Unity modules to install alongside the editor
    -e, --execute <UNITY_METHOD>   Fully-qualified static method invoked via -executeMethod (required)
        --no-graphics              Include -nographics when invoking Unity

Example:

unity-ci build \
  --execute Company.Product.Build.Perform \
  --target Win64 \
  --module android,android-sdk-ndk-tools \
  --log out/unity-build.log \
  /path/to/MyUnityProject

What happens when you run the command:

  1. Resolve the project path to an absolute location and parse ProjectVersion.txt for the editor version and changeset (m_EditorVersion and m_EditorVersionWithRevision). Missing revision metadata now causes the command to fail early so Unity Hub always receives a --changeset value.
  2. Collect Unity licensing environment variables and detect the current platform/architecture.
  3. Ensure Unity Hub exists (checking overrides, well-known locations, a writable cache, and finally downloading & installing if required).
  4. Ensure the matching Unity editor is installed via Unity Hub with the same series of checks and fallbacks, installing any extra modules supplied to --module and automatically passing the correct --architecture flag (x86_64 or arm64).
  5. Optionally activate a Unity license when all three required environment variables are non-empty.
  6. Print a colourised summary of the resolved paths, target, log file, and upcoming Unity command line. If --force is not supplied, prompt for confirmation.
  7. Execute Unity with -batchmode, -quit, the project path, optional build target, requested log file, and the -executeMethod payload. Supply --no-graphics to append Unity's -nographics switch.
  8. After Unity exits, scan the generated log. Messages containing "Build failed" or "Error" cause the CLI to exit with a failure status.
  9. If activation occurred, return the license using Unity's CLI switches, respecting the --no-graphics choice, even when the Unity command is cancelled after activation.

The default log location is ./build.log relative to the current working directory. Supplying --log replaces this path and accepts relative or absolute values.

🌐 Environment Variables

  • UNITY_SERIAL, UNITY_USERNAME, UNITY_PASSWORD: When all three are present and non-empty, the CLI will activate a seat before running the build and return it afterwards. If any are missing the licensing phase is skipped and a warning is emitted.
  • UNITY_HUB_PATH: Absolute path to an existing Unity Hub binary.
  • UNITY_EDITOR_INSTALL_ROOT: Directory containing Hub-managed installations; the tool will append the required version & standard subdirectories.
  • UNITY_CI_CACHE_DIR: Overrides the cache directory used for downloads.
  • Cache downloads underneath UNITY_CI_CACHE_DIR when set; otherwise the path falls back to Rust’s std::env::temp_dir().

🖥️ Platform Notes

  • Windows: Unity Hub commands run through PowerShell using the & call operator so quoted paths with spaces are forwarded reliably.
  • macOS: Unity Hub commands run through the current shell (falling back to /bin/zsh) to match how Hub is typically launched interactively.

🛡️ Sandbox Notes (Linux)

Unity Hub's AppImage bundles a Chromium runtime that expects a working user namespace sandbox. Please note that this tool always appends --no-sandbox flag when launching Unity Hub on Linux to keep CI runs working out of the box.

Running without the sandbox weakens isolation, so on self-managed runners you should still prefer running Unity as an unprivileged user. If you require the sandbox, fork or wrap the CLI so you can remove the flag and ensure your environment provides working user namespaces before running Unity Hub.

📝 Logging

Every significant step prints a [unity-ci] prefixed message. Helper functions produce explicit [SUCCESS] and [FAILURE] markers, making it easy to scan CI logs. Sensitive values such as licensing credentials are never echoed; the tool only reports whether a given variable was found.

🛠️ Development

This repository uses the standard Rust tooling workflow:

cargo fmt
cargo clippy --all-targets
cargo test

Network access is required when Unity Hub or editor installers need to be downloaded. Tests currently depend on the surrounding Unity project fixture under test-unity-project/.

🤝 Contribution

Contributions are welcome! Please open an issue or pull request describing the change you have in mind. The codebase avoids caching derived string versions of paths—prefer using the shared sanitising trait in src/path_ext.rs when adding new filesystem interactions.

Dependencies

~7–25MB
~333K SLoC