Building with CI/CD
[!SUMMARY] This page explains:
- What the GitLab pipeline builds and publishes for each branch
- How to publish a pre-release and a release
- Which CI/CD variables the pipeline needs
- How each platform job runs, and what its runner needs
Testing Builds, Pre-Releases and Releases
Which branch is pushed decides what the pipeline publishes:
| Push to | Channel | Seafile | Docker (server and docs) | Git |
|---|---|---|---|---|
| any other protected branch | testing | Testing/<branch>/<commit>/ |
— | — |
pre-release-vX-Y-Z |
pre-release | Pre-Release/X.Y.Z-pre.N/ |
:pre-release |
tag X.Y.Z-pre.N |
main |
release | Build Archive/X.Y.Z/ and Public/ |
:X.Y.Z, :latest, :stable |
tag X.Y.Z; main and the tag pushed to the public mirror |
X.Y.Z is the project version (Project Settings → Player → Version). N is GitLab's running
pipeline number for the project: unique and increasing, and the dot makes version sorting treat it
as a number (pre.10 after pre.9). Pushes to unprotected branches start no pipeline.
Build → Pipelines → Run pipeline on such a branch builds and checks everything, but publishes
nothing: the protected credentials do not reach it.
Every pipeline uploads into a folder of its own and only then points latest.json at it, once all
platforms are known to belong together; a release also has its packages copied into Public/ then,
next to Public/latest.json. See
Downloads are grouped per commit. How the
Docker tags reach the hosted servers is described in Server Images.
To publish a release
- Set the new version under Project Settings → Player → Version, e.g.
1.0.5. - Optionally, push to
pre-release-v1-0-5first. Every push there publishes the next pre-release (1.0.5-pre.N). - Merge into
main. The pipeline builds, publishes, tags1.0.5and updates the public mirror.
The first job (verify) refuses, before anything is built, to:
- release a version whose tag already exists (forgotten version bump),
- release a version that is not plain
X.Y.Z, - pre-release from
pre-release-vX-Y-Zwhen the project version is notX.Y.Z, - run a pre-release or release without its credentials.
The git tag is created last, after Seafile, Docker Hub and the docs were updated, so a tag always names something that was published. A failed release leaves no tag, and the next attempt can reuse the version.
CI/CD variables
Important
Required CI/CD variables (Settings → CI/CD → Variables, masked). Protected variables only reach
protected branches, so main and every pre-release-v* branch must be protected.
| Variable | What | Needed for |
|---|---|---|
SEAFILE_URL, SEAFILE_REPO_TOKEN |
Seafile library API token, read-write | all |
DOCKERHUB_USERNAME, DOCKERHUB_TOKEN |
Docker Hub personal access token, scope Read, Write, Delete | pre-release, release |
RELEASE_TOKEN |
project access token of this project, role Maintainer, scope write_repository; creates the tags |
pre-release, release |
MIRROR_TOKEN |
project access token of the public mirror, role Maintainer, scope write_repository; Git LFS must be enabled there |
release |
The Meta Quest job additionally needs the signing variables.
Platform Jobs
Each platform job runs the same BuildCommand as the Tools → Build menu (see
Building in the Editor), through a script in Tools/Build/ that can also be run
by hand.
Windows
CI_PROJECT_DIR=$(pwd) \
BUILD_TARGET=StandaloneWindows64 \
BUILD_NAME="Anywhere Academy" \
Tools/Build/build-windows.sh
This is the one job that does not run on a Linux runner. IL2CPP compiles the C++ it generates with MSVC, so a Windows IL2CPP player can only be produced on Windows, and GameCI publishes the windows-il2cpp variant exclusively as a Windows-based image — unityci/editor:windows-6000.3.8f1-windows-il2cpp-3.2.2. There is no Ubuntu equivalent; Linux can only cross-compile a Windows Mono player, which BuildCommand does not use.
The job therefore runs on a self-hosted docker-windows runner tagged windows-unity, under Git Bash, with MSVC, the Windows SDK, PowerShell 7 and the WiX Toolset mounted in from the runner host.
Meta Quest
CI_PROJECT_DIR=$(pwd) \
BUILD_TARGET=Android \
BUILD_NAME="Anywhere Academy" \
ANDROID_KEYSTORE_PATH=/secure/anywhere-academy.keystore \
ANDROID_KEYSTORE_PASS=... \
ANDROID_KEYALIAS_NAME=... \
ANDROID_KEYALIAS_PASS=... \
Tools/Build/build-quest.sh
The runner image needs xvfb, pwsh, and a Unity editor with the Android build support module including OpenJDK and the SDK/NDK — on GameCI, the android variant, e.g. unityci/editor:ubuntu-6000.3.8f1-android-3.
Linux Server
CI_PROJECT_DIR=$(pwd) \
BUILD_TARGET=StandaloneLinux64 \
BUILD_NAME="Anywhere Academy" \
Tools/Build/build-server.sh
The runner image needs xvfb, pwsh, tar, and a Unity editor with Linux build support — Mono2x needs no IL2CPP module, so the base editor image is enough.
Note this script writes to the fixed Build/Server, not Build/$BUILD_TARGET like the Windows and Quest scripts, so that a docker build -f Server-Dockerfile . can run in the same job with no copying.