I recently began doing some work on a personal project in Unity Engine. As with any of my projects, the first thing I set up is a working CI pipeline for it. I find doing this early reinforces best practices. I liked the option of using GitHub Actions, since it is a relatively small project. Here's how I did it!
Getting Started
First, familiarize yourself with the community offerings for GitHub Actions - game-ci/unity-actions. There's a good overview here in the readme of the supported actions.
The other thing to check would be the official game-ci getting starting docs.
Setting up License
The instructions in the official docs aren't the most verbose, but it's actually quite simple.
I'll just go into a little more detail here to try to make things super clear.
Step 1 - Request Activation File on GitHub
This is an action that is intended to be a one-time use. Its purpose is to create a "license request file" that will be needed for the next step. This is what will allow unity to run builds on the GitHub Actions servers.
The file should end up looking something like this:
.github/workflows/activation.yml:
name: Acquire activation file
on:
workflow_dispatch: {}
jobs:
activation:
name: Request manual activation file 🔑
runs-on: ubuntu-latest
steps:
# Request manual activation file
- name: Request manual activation file
id: getManualLicenseFile
uses: game-ci/unity-request-activation-file@v2
# Upload artifact (Unity_v20XX.X.XXXX.alf)
- name: Expose as artifact
uses: actions/upload-artifact@v2
with:
name: ${{ steps.getManualLicenseFile.outputs.filePath }}
path: ${{ steps.getManualLicenseFile.outputs.filePath }}
After you push it up, you can manually run the worfklow to generate your license.
To find this file, go to GitHub
> Your Repository
> Actions
. Click on the commit that last ran. You should find a file named something like Unity_v2019.3.14f1.alf
. (The exact name depends on the version string that you put in unityVersion
above.)
You'll need to save this file locally for use in the next step.
Step 2 - Request License from Unity
Head over to the Unity Manual Activation link.
Here you simply upload your .alf
file from the previous step. Fill out the form with your license details.
On the last step you should be able to download a file that ends in .ulf
.
This is your license you will put in GitHub secrets for use in your build actions.
Step 3 - Save License in GitHub Secrets
Open GitHub
> Your Repository
> Settings
> Secrets
.
Create a secret called UNITY_LICENSE
and add the contents of the obtained license file (.ulf
). Yes, add the entire XML contents to the GitHub secret.
Now that this step is done, you can delete the .github/workflows/activation.yml
file.
Set up workflow
Now's the fun stuff! Now that you have your license ready to go, you can start setting up actions.
A couple of best practice recommendations:
- Cache your
Library
folder. This is where all your cached packages and large files end up during builds.- Note caches created on branches are scoped to that branch, regardless of key matches. Same goes for tags.
- Use GitHub Releases to store your file, not actions artifacts. You will quickly run into free limits using artifacts
- Due to the size and time of full builds, I like to generate target builds only on tags.
Here's an example of a couple of workflow files.
Test - Runs on every commit
.github/workflows/test.yml:
name: Test
on:
pull_request: {}
push: { branches: [master] }
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
jobs:
build:
name: Test project
runs-on: ubuntu-latest
steps:
# Checkout
- name: Checkout repository
uses: actions/checkout@v2
with:
lfs: true
# Cache
- uses: actions/cache@v2
with:
path: Library
key: Library
# Test
- name: Run tests
uses: game-ci/unity-test-runner@v2
with:
unityVersion: 2020.3.15f2
Build - Runs on tagged commits
This file uses this on.push.tags
trigger to only run when tags are pushed.
It then uploads artifacts, zips up the binaries, creates a GitHub release for the tag, and uploads the release assets to it.
Depending on your usage, you might not want to upload the artifacts. You'll quickly run into limits if you use it too much.
.github/workflows/main.yml:
name: Build
on:
push:
tags:
- '*'
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
jobs:
build:
name: Build my project
runs-on: ubuntu-latest
steps:
# Checkout
- name: Checkout repository
uses: actions/checkout@v2
with:
lfs: true
# Cache
- uses: actions/cache@v2
with:
path: Library
key: Library
# Test
- name: Run tests
uses: game-ci/unity-test-runner@v2
with:
unityVersion: 2020.3.15f2
# Build
- name: Build project
uses: game-ci/unity-builder@v2
with:
unityVersion: 2020.3.15f2
targetPlatform: StandaloneWindows64
# Output
- uses: actions/upload-artifact@v2
with:
name: Build
path: build
- name: Zip build
run: |
pushd build/StandaloneWindows64
zip -r ../../StandaloneWindows64.zip .
popd
- name: Release
uses: softprops/action-gh-release@v1
with:
files: StandaloneWindows64.zip
name: Release ${{ github.ref }}
Note: If you're using the above workflow, and experience an error on the build step like this:
Warning: Changes were made to the following files and folders:
Warning: ?? artifacts/
Error: Branch is dirty. Refusing to base semantic version on uncommitted changes
You will need to add the artifacts folder to your .gitignore
file, as referenced in this GitHub issue.
Another option would be using the allowDirtyBuild flag if you are still running into dirty branch issues.
Feel free to customize for your use case, as this workflow only outputs windows binaries. However, as mentioned in game-ci/unity-actions, there's a ton more supported actions/options.
Conclusion
Setting up a CI flow early tends to keep me honest in following best practices. I like to do it even for my hobby projects.
A good side effect, is if I have to let projects idle for a while, I can always come back and expect my builds to work.
Related Links
- Unity Plus - Unity Pro
- Github - Unity Actions - Unity Actions for GitHub
Note: This post includes affiliate links; I may receive compensation if you purchase products or services from the different links provided in this article.
Top comments (3)
Have been following your blog post. Very well explained in detail. Unfortunately test and build could not be executed. The error message was " Error: The process '/usr/bin/docker' failed with exit code 1".
After a short research, I believe that the error is with Github's Linux Runner. Do you perhaps have a suggested solution?
Sorry for the late reply, I must have missed the notification for this.
Anyways, if you are still having this issue, or for anyone else who sees this post. I've updated the content here, as well as on my website with updates for newer syntax.
Thanks a lot for updating. After a few problems, I finally got it running without problems (The Test Stage still gives me problems but isn't that neccessary).
I recommend updating the Unity Version to 2020 or higher ;)