Skip to content

Instantly share code, notes, and snippets.

@jerricko
Last active October 4, 2022 17:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jerricko/16c709e60cb99a468402bcae47c0a285 to your computer and use it in GitHub Desktop.
Save jerricko/16c709e60cb99a468402bcae47c0a285 to your computer and use it in GitHub Desktop.
GameCI Azure Pipeline
# IMPORTANT NOTES
# This workflow was ported over from the gitlab example: https://gitlab.com/game-ci/unity3d-gitlab-ci-example/
# There may be better ways to do this, but this is what I came up with in a short timespan
# Azure creates its own user to inject into docker containers which causes weird problems with containers that don't have
# sudo installed. As you'll see in the game-ci containers, we install sudo before our scripts because otherwise, they run
# into all kinds of permission errors. Related issue: https://github.com/microsoft/azure-pipelines-agent/issues/2043
# Unity License string needs to be stored as a base64 string in order to work.
# See https://game.ci/docs/troubleshooting/common-issues#the-digital-signature-is-invalid
trigger:
- develop
resources:
containers:
- container: ubuntu
image: ubuntu:latest
variables:
- group: "MyLibrary" # Storing unity.license, unity.username, unity.password in pipeline library
- name: tag
value: '$(Build.BuildId)'
# Unity-specific
# Azure variables automatically convert to all caps and "." to "_" for bash environment variables
- name: unity.build.name
value: 'MyGame'
- name: unity.activationFile
value: './unity3d.alf'
- name: unity.imageName
value: 'unityci/editor'
- name: imageVersion
value: '1.0.1'
- name: unity.dir
value: '$(Build.SourcesDirectory)' # If unity is the top level project, otherwise drill down folders
pool:
vmImage: ubuntu-latest
stages:
- stage: Prepare
displayName: Prepare
variables:
git.depth: ${{ 1 }}
jobs:
- job: GetUnityVersion
displayName: Get Unity Version
container: ubuntu
steps:
- script: |
UNITY_VERSION=$(cat $(unity.dir)/ProjectSettings/ProjectVersion.txt | grep "m_EditorVersion:.*" | awk '{ print $2}')
echo $UNITY_VERSION
echo "##vso[task.setvariable variable=unityVersion;isoutput=true]$UNITY_VERSION"
name: SetUnityVersion
- job: GetActivationFile
displayName: Get Activation File
condition: eq(variables['unity.license'], '')
container:
image: $(unity.imageName):2021.3.4f1-base-$(imageVersion) # Using workaround from https://gitlab.com/game-ci/unity3d-gitlab-ci-example/-/issues/171#note_974622879
steps:
- task: Bash@3
inputs:
targetType: inline
script: |
chmod +x ./ci/before_script.sh && ./ci/before_script.sh
chmod +x ./ci/get_activation_file.sh && ./ci/get_activation_file.sh
env:
UNITY_PASSWORD: $(unity.password)
- publish: $(unity.activationFile)
artifact: UnityLicense
- stage: Build
displayName: Build and push stage
dependsOn: Prepare
variables:
unity.version: $[stageDependencies.Prepare.GetUnityVersion.outputs['SetUnityVersion.unityVersion']]
condition: and(ne(variables['unity.license'], ''), ne(dependencies.Prepare.outputs['GetUnityVersion.SetUnityVersion.unityVersion'], ''))
jobs:
- job: BuildStandaloneLinux64
displayName: Build Standalone Linux 64
container:
image: $(unity.imageName):$(unity.version)-linux-il2cpp-$(imageVersion)
options: "--name ci-container -v /usr/bin/docker:/tmp/docker:ro" # Needed so we can install sudo on image
variables:
unity.build.target: 'StandaloneLinux64'
scripting.backend: 'IL2CPP'
unity.build.options: 'Development'
steps:
- task: Cache@2
inputs:
key: '"unity-packages" | "$(Agent.OS)" | $(unity.build.target) | $(unity.dir)/Packages/packages-lock.json'
restoreKeys: |
unity-packages | "$(Agent.OS)" | $(unity.build.target)
unity-packages | "$(Agent.OS)"
unity-packages
path: $(unity.dir)/Library/
displayName: Cache Unity Library
- script: |
/tmp/docker exec -t -u 0 ci-container \
sh -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" -y install sudo"
displayName: 'Install Sudo in container (thanks Microsoft!)'
- script: |
chmod +x ./ci/before_script.sh && ./ci/before_script.sh
chmod +x ./ci/build.sh && ./ci/build.sh
cp $(Build.SourcesDirectory)/ci/dockerfiles/$(unity.build.target) $(unity.dir)/Builds/$(unity.build.target)/Dockerfile
cat $(unity.dir)/Builds/$(unity.build.target)/Dockerfile
cp $(Build.SourcesDirectory)/ci/devSettings.json $(unity.dir)/Builds/$(unity.build.target)/$(unity.build.name)_Data/StreamingAssets/ServerSettings.json
- publish: $(unity.dir)/Builds/$(unity.build.target)
artifact: Server
- job: BuildWebGL
displayName: Build WebGL
dependsOn: BuildStandaloneLinux64 # Remove to run parallel with linux build
container:
image: $(unity.imageName):$(unity.version)-webgl-$(imageVersion)
options: "--name ci-container -v /usr/bin/docker:/tmp/docker:ro"
variables:
unity.build.target: 'WebGL'
unity.build.options: 'Development'
steps:
- task: Cache@2
inputs:
key: '"unity-packages" | "$(Agent.OS)" | $(unity.build.target) | $(unity.dir)/Packages/packages-lock.json'
restoreKeys: |
unity-packages | "$(Agent.OS)" | $(unity.build.target)
unity-packages | "$(Agent.OS)"
unity-packages
path: $(unity.dir)/Library/
displayName: Cache Unity Library
- script: |
/tmp/docker exec -t -u 0 ci-container \
sh -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" -y install sudo"
displayName: 'Install Sudo in container (thanks Microsoft!)'
- script: |
sudo apt-get update && sudo apt-get install ffmpeg apache2-utils -y
chmod +x ./ci/before_script.sh && ./ci/before_script.sh
chmod +x ./ci/build.sh && ./ci/build.sh
- publish: $(unity.dir)/Builds/$(unity.build.target)
artifact: WebGL
#!/bin/bash
set -e
set -x
# Main difference between the gitlab version is that we write to the user's folder instead of /root because of permission
# problems. Even though the editor is run with sudo, it doesn't see the license in /root for some reason, but it is able
# to see it in the user folder.
mkdir -p ~/.cache/unity3d
mkdir -p ~/.local/share/unity3d/Unity/
set +x
unity_license_destination=~/.local/share/unity3d/Unity/Unity_lic.ulf
if [ -n "$UNITY_LICENSE" ]
then
echo "Writing '\$UNITY_LICENSE' to license file $unity_license_destination"
echo "${UNITY_LICENSE}" | base64 -d > $unity_license_destination
else
echo "'\$UNITY_LICENSE' env var not found"
fi
#!/bin/bash
set -e
set -x
echo "Building for $UNITY_BUILD_TARGET"
export BUILD_PATH=$UNITY_DIR/Builds/$UNITY_BUILD_TARGET/
# Have to run sudo here otherwise it runs into write permission in /opt/unity/Editor.
sudo xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' /opt/unity/Editor/Unity \
-projectPath $UNITY_DIR \
-quit \
-batchmode \
-nographics \
-buildTarget $UNITY_BUILD_TARGET \
-customBuildTarget $UNITY_BUILD_TARGET \
-BUILD_SUBTARGET $UNITY_BUILD_SUBTARGET \
-customBuildName $UNITY_BUILD_NAME \
-customBuildPath $BUILD_PATH \
-executeMethod BuildCommand.PerformBuild \
-logFile /dev/stdout | tee ./unity-output.log
UNITY_EXIT_CODE=$?
if [ $UNITY_EXIT_CODE -eq 0 ]; then
echo "Run succeeded, no failures occurred";
elif [ $UNITY_EXIT_CODE -eq 2 ]; then
echo "Run succeeded, some tests failed";
elif [ $UNITY_EXIT_CODE -eq 3 ]; then
echo "Run failure (other failure)";
else
echo "Unexpected exit code $UNITY_EXIT_CODE";
fi
ls -la $BUILD_PATH
[ -n "$(ls -A $BUILD_PATH)" ] # fail job if build folder is empty
# Reset owner back to container because all new built files will be owned by root
CONTAINER_USER=$(whoami)
sudo chown -R $CONTAINER_USER:$CONTAINER_USER $UNITY_DIR
#!/bin/bash
activation_file=${UNITY_ACTIVATIONFILE:-./unity3d.alf}
if [[ -z "${UNITY_USERNAME}" ]] || [[ -z "${UNITY_PASSWORD}" ]]; then
echo "UNITY_USERNAME or UNITY_PASSWORD environment variables are not set, please refer to instructions in the readme and add these to your secret environment variables."
exit 1
fi
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
unity-editor \
-logFile /dev/stdout \
-batchmode \
-nographics \
-username "$UNITY_USERNAME" -password "$UNITY_PASSWORD" |
tee ./unity-output.log
cat ./unity-output.log |
grep 'LICENSE SYSTEM .* Posting *' |
sed 's/.*Posting *//' > "${activation_file}"
# Fail job if unity.alf is empty
ls "${UNITY_ACTIVATIONFILE:-./unity3d.alf}"
exit_code=$?
echo "$(cat ${activation_file})"
if [[ ${exit_code} -eq 0 ]]; then
echo ""
echo ""
echo "### Congratulations! ###"
echo "${activation_file} was generated successfully!"
echo ""
echo "### Next steps ###"
echo ""
echo "Complete the activation process manually"
echo ""
echo " 1. Download the artifact which should contain ${activation_file}"
echo " 2. Visit https://license.unity3d.com/manual"
echo " 3. Upload ${activation_file} in the form"
echo " 4. Answer questions (unity pro vs personal edition, both will work, just pick the one you use)"
echo " 5. Download 'Unity_v2019.x.ulf' file (year should match your unity version here, 'Unity_v2018.x.ulf' for 2018, etc.)"
echo " 6. Copy the content of 'Unity_v2019.x.ulf' license file to your CI's environment variable 'UNITY_LICENSE'. (Open your project's parameters > CI/CD > Variables and add 'UNITY_LICENSE' as the key and paste the content of the license file into the value)"
echo ""
echo "Once you're done, hit retry on the pipeline where other jobs failed, or just push another commit. Things should be green"
echo ""
echo "(optional) For more details on why this is not fully automated, visit https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/73"
else
echo "License file could not be found at ${UNITY_ACTIVATIONFILE:-./unity3d.alf}"
fi
exit $exit_code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment