# 3. GameCI and GitHub Actions Part of [[Build Automation and CI]]. Previous: [[2. Command Line Builds and a Build Script]]. Next: [[4. Unity Build Automation]]. > [!note] Verification status > `game-ci/unity-builder@v4` and its `buildProfile` input (passed as Unity's `-activeBuildProfile`) come from GameCI's public Builder docs, fetched 2026-11-10. License/activation must follow [GameCI's current activation guide](https://game.ci/docs/github/activation) for your license type — **secret names and personal vs professional/educational flows can change; do not treat the env block below as a substitute for that page.** This workflow has **not** been run on GitHub. ## 3.1 What GameCI is [GameCI](https://game.ci/) is a set of GitHub Actions (and siblings for other CI systems) that download a Unity Editor, activate a license, run tests, and build players inside a runner. For a class or a small studio already on GitHub ([[Setting Up GitHub for Unity]]), it is the most common self-hosted-pipeline path. You still need a **valid Unity license** the runner is allowed to use. There is no workaround, and the license file or serial belongs in **GitHub encrypted secrets**, never in the repo, never in a screenshot in a lecture slide. ## 3.2 Activation (read the official page) Before a workflow will build, you activate Unity in CI. GameCI documents this separately because personal licenses, Professional/Enterprise serials, and floating licenses differ. Do this, in order: 1. Open https://game.ci/docs/github/activation and follow the flow for **the license you actually have**. 2. Store whatever that page tells you to store as GitHub Actions secrets (typically a license file body and/or a serial, plus account credentials when the page requires them). 3. Reference those secrets only as `${{ secrets.NAME }}` in the workflow `env:`. If activation fails, stop and fix activation. Do not paste a license into a log, a gist, or chat. ## 3.3 A starter workflow `.github/workflows/unity-ci.yml` — tests first, then a Windows player from a Build Profile. Adjust Unity version, runner, and paths. ```yaml name: Unity CI on: push: branches: [main] pull_request: jobs: test-editmode: name: Edit Mode tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: lfs: true - uses: actions/cache@v4 with: path: Library key: library-${{ runner.os }}-${{ hashFiles('Packages/packages-lock.json') }} restore-keys: library-${{ runner.os }}- - uses: game-ci/unity-test-runner@v4 env: UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} with: unityVersion: 6000.5.0f1 testMode: editmode checkName: Edit Mode tests - uses: actions/upload-artifact@v4 if: always() with: name: test-results path: artifacts build-windows: name: Windows player needs: test-editmode runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: lfs: true - uses: actions/cache@v4 with: path: Library key: library-${{ runner.os }}-${{ hashFiles('Packages/packages-lock.json') }} restore-keys: library-${{ runner.os }}- - uses: game-ci/unity-builder@v4 env: UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} with: unityVersion: 6000.5.0f1 targetPlatform: StandaloneWindows64 buildProfile: Assets/Settings/Build Profiles/WindowsDemo.asset - uses: actions/upload-artifact@v4 with: name: windows-player path: build ``` Read this as a **template**: - Pin `unityVersion` to the **exact** Editor the project was made with (`6000.5.0f1` here is a placeholder — use the version in your ProjectSettings, do not invent a patch). GameCI has to offer an image for that version; check their version list if a tag is missing. - `buildProfile` is relative to the project (and to `projectPath` if you set one). If you omit it, GameCI builds with `-buildTarget` only. - `targetPlatform` is still required by the action even when a profile is present (per the Builder docs' required field). Keep it consistent with the profile's platform. - A Linux runner can cross-compile many **Mono** standalone players; **IL2CPP** and platform SDKs (Android, iOS, Switch, …) need a runner with the right toolchain. Android / Quest IL2CPP often means a more specialized runner or Unity Build Automation (part 4). - `lfs: true` matters if you followed [[2. Git LFS]]. - Caching `Library` speeds CI and can also poison a run if a cache is stale in a nasty way. If a job acts possessed, rerun with a fresh cache key. The `UNITY_*` env names above are the ones GameCI's builder docs commonly show for a **license-file** flow. If you use a serial-based license, the activation page will tell you to pass a serial instead (and *not* to commit it). Prefer the official page over this paragraph. ## 3.4 Tests in CI `game-ci/unity-test-runner@v4` is the usual pair for [[Unity Test Framework]]. Start with **Edit Mode** on every PR. Add Play Mode when the fixture scene is stable. Quest Player tests probably stay manual or nightly; a hosted runner will not have a headset. Upload the XML / `artifacts` folder even on failure (`if: always()`). ## 3.5 Secrets hygiene for class - One GitHub organization, one set of secrets, limited access. - Students get fork PRs that **cannot** read the org's license secrets unless you design for that (GitHub's pull_request secrets rules). A common teaching setup is: CI runs on the class origin, not on every fork. - Rotate the password or serial if it ever appears in a log. ## Official docs - GameCI Builder: https://github.com/game-ci/documentation/blob/main/docs/03-github/04-builder.mdx - GameCI activation: https://game.ci/docs/github/activation - Unity command-line builds: https://docs.unity.com/en-us/engine/6000.5/manual/building-and-publishing/build-customize-build-pipeline/build-command-line