CI Regression Testing a Shared Unity Library with Unity Cloud Build
Intended Audience: Advanced Unity Developers
Estimated Reading Time: 5 minutes
The Problem
A shared library that compiles locally but breaks in CI is worse than no shared library at all. You deploy with confidence, then discover the build server sees a different state than your dev machine.
My shared library, MetroplexWebUnityLib (MWUL), is referenced by multiple Unity projects as a local package. Changes to MWUL can silently break client projects. I needed a way to catch those breaks before they affected real projects.
The Thin Wrapper Project Strategy
To catch regressions, I created a thin wrapper project whose sole purpose is regression testing MWUL in CI. It contains:
- A reference to MWUL as a local package
- Minimal scene and configuration to trigger compilation
- Build configurations for each target platform (Windows, Android)
Every push to MWUL triggers a build of the thin wrapper in Unity Cloud Build. If the wrapper builds successfully on all platforms, MWUL is healthy. If it fails, I know before any real project is affected.
The Prebuild Script Problem
Unity Cloud Build has a complication: it clones only the repository being built. My wrapper project references MWUL via a relative file path:
{
"dependencies": {
"com.metroplexweb.unitylib": "file:../../MetroplexWebUnityLib"
}
}
That path does not exist on the build server. UCB only has the wrapper project.
The solution is a prebuild script that runs before Unity opens the project. It:
- Downloads MWUL from GitHub (authenticated via a personal access token)
- Extracts it into the
Packages/folder - Rewrites
manifest.jsonto point to the local copy
This script lives in the MWUL repository and gets copied to each client project that uses UCB.
The Failure That Revealed the Brittleness
After adding a new platform assemblies architecture to MWUL, all UCB builds failed with:
error CS0246: The type or namespace name 'IPlatform' could not be found
The error was confusing because:
- Local builds worked fine
- The assembly references were correct
- The GUIDs matched
- No conditional compilation was involved
The actual problem: the prebuild script had a hardcoded list of directories to copy:
for dir in Runtime Editor BuildTools; do
cp -r "$EXTRACTED_DIR/$dir"/* "$EXTRACT_PATH/$dir"
done
The new PlatformAssemblies folder was not in that list. The build server received MWUL without the folder containing IPlatform. Hence the compilation error.
The fix was trivial once identified:
for dir in Runtime Editor BuildTools PlatformAssemblies Plugins Prefabs Resources; do
cp -r "$EXTRACTED_DIR/$dir"/* "$EXTRACT_PATH/$dir"
done
But finding it required tracing through the entire build pipeline, understanding what UCB actually sees versus what exists locally, and recognizing that the error message was pointing at a symptom rather than a cause.
Lessons
Thin wrapper projects justify their existence in moments of crisis. The wrapper caught the prebuild script bug before it affected real projects. The cost of maintaining a minimal test project is low compared to the cost of discovering shared library problems during a real release cycle.
CI prebuild scripts need maintenance alongside the code they deploy. The script was written before the platform assemblies architecture existed. It worked for the old structure and silently failed for the new one. Any structural change to a shared library should prompt a review of deployment scripts.
The build server sees a different world than your dev machine. Local builds have access to your full directory structure. CI builds only have what you explicitly provide. When debugging CI failures, always ask: "What files does the build server actually have?"
Error messages point at symptoms, not causes. "Type not found" is technically accurate—the type genuinely wasn't found. But the reason wasn't a missing reference or compilation error. It was a missing folder in a shell script. Work backwards from the error to find the root cause.
Current State
The thin wrapper runs regression builds on every MWUL change. Build configurations exist for Windows and Android targets. When builds succeed across all platforms, the shared library is validated for deployment to real projects.
The prebuild script now copies all necessary directories, and I've documented the need to update it whenever MWUL's folder structure changes.