Skip to content

Build

Build #195

Workflow file for this run

name: Build
# specify which events will trigger the workflow
on:
# run workflow on push events on the development branch
# one can tell Actions to not run the pipeline
# by including [ci skip] or [no ci] in the commit message
push:
branches:
- 'develop'
# run workflow when a review for a PR is requested
pull_request:
types: [review_requested]
# allow to run the workflow manually
workflow_dispatch:
# run daily at 6am UTC
# idea: quickly spot issues with workflow/runner
# scheduled runs do not trigger deployment to steam
schedule:
- cron: 0 6 * * *
jobs:
# pulls source code
# tries to restore the cached library folder
# fetches user id of user running the workflow (needed later on)
setup:
name: Setup
runs-on: self-hosted
# very rarely, the cache download might get stuck
# if the download is not complete after 5 minutes, abort this step
env:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 5 # default = 10m
outputs:
# tells us if we got a cache hit or a cache miss
hit: ${{ steps.restore-cache.outputs.cache-hit }}
# the key of the cache
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
# the uid of the runner
uid: ${{ steps.get_uid.outputs.uid }}
steps:
# retrieve uid of runner (needed later on)
- name: Get Actions user id
id: get_uid
run: |
actions_user_id=`id -u $USER`
echo $actions_user_id
echo "uid=$actions_user_id" >> $GITHUB_OUTPUT
# check out repo
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
# try to restore Library folder from cache
# by hashing all files in Assets/ Packages/ and ProjectSettins/
# we can determine if there has been a change to the project
# if the files are unchanged: restore cache
# if there has been a change: skip this step and save the cache later on
- name: Restore Cache
id: restore-cache
uses: actions/cache/restore@v3
with:
path: unity/Library
key: Library-${{ hashFiles('unity/Assets/**', 'unity/Packages/**', 'unity/ProjectSettings/**') }}
# build project for PC, VR and WebGL
build:
name: Build for ${{ matrix.maroonBuildTarget }}
runs-on: self-hosted
# before this job can run, the setup must be complete
needs: setup
# create job matrix
# runs job once for each build target
strategy:
# if fail-fast is set to true, the job will abort if one of the builds fail
fail-fast: false
matrix:
include:
- targetPlatform: StandaloneWindows64
maroonBuildTarget: PC
- targetPlatform: StandaloneWindows64
maroonBuildTarget: VR
- targetPlatform: WebGL
maroonBuildTarget: WebGL
steps:
- name: Build
uses: game-ci/unity-builder@v2
# environment vars needed by unity-builder to activate the unity license
# defined in the Actions Secrets in the repo settings
env:
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
# run the custom build script
buildMethod: Maroon.Build.BuildPlayer.ActionsBuild
# with these params:
customParameters: -maroonBuildPath ../build -maroonBuildTarget ${{ matrix.maroonBuildTarget }}
# we must specify a target platform, build path, build name and project path for unity-builder
targetPlatform: ${{ matrix.targetPlatform }}
projectPath: unity
buildName: ${{ matrix.maroonBuildTarget }}
buildsPath: build
# if this is set to false, the job will fail if any file has changed since checkout
# since it is set to true, it will only raise a warning
allowDirtyBuild: true
# we want the repo to be in its original state before each build
- name: Restore Build Environment
shell: bash
run: |
git reset --hard
# store the library folder in the cache
# if the library folder has been retrieved from the cache during setup, this job is skipped
# as it has not changed
save-cache:
name: Save cache
runs-on: self-hosted
needs: [setup, build]
# only save the cache if we had a cache miss during setup
if: needs.setup.outputs.hit != 'true'
steps:
- name: Save Cache
uses: actions/cache/save@v3
with:
path: unity/Library
key: ${{ needs.setup.outputs.key }}
# execute playmode and editmode tests
test:
name: Run tests
runs-on: self-hosted
needs: [setup, build]
strategy:
# if fail-fast is set to true, the job will abort if one of the tests fail
fail-fast: false
matrix:
projectPath:
- unity
testMode:
- playmode
- editmode
steps:
- name: Test
uses: game-ci/unity-test-runner@v2
id: tests
env:
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
projectPath: ${{ matrix.projectPath }}
testMode: ${{ matrix.testMode }}
# save test results to ./test-results/
artifactsPath: ./test-results/${{ matrix.testMode }}-results
# upload build output and test results to github
# also fixes file permissions
upload-artifacts:
name: Upload artifacts
runs-on: self-hosted
# we want to upload artifacts even if the tests fail
# if both build and test fail, we don't want to upload
needs: [setup, build, test]
if: ${{ success() || (needs.build.result == 'success' || needs.test.result == 'success') }}
steps:
# chown files to the user that was identified during setup
# this is necessary because actions executed through docker have root:root permissions
- name: Restore file ownership
uses: peter-murray/reset-workspace-ownership-action@v1
with:
user_id: ${{ needs.setup.outputs.uid }}
# get rid of empty StandaloneWindows64 folder created by the build action
# compress build folder for faster up- and download
- name: Compress build folder
run: |
rmdir build/StandaloneWindows64
zip -r build.zip build
# upload build.zip and the test results
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: MaroonArtifacts
path: |
build.zip
test-results
# if no files match the supplied path, fail job with error
if-no-files-found: error
# deploy VR and PC version to steam
# requires build, test and upload-artifact jobs to pass
# do not deploy during scheduled runs
deploy:
name: Deploy to Steam
runs-on: self-hosted
needs: [setup, build, test, upload-artifacts]
# we do not want to deploy if we are doing a scheduled run
# make sure that we are on the develop branch
if: |
github.ref_name == 'develop' &&
github.event_name != 'schedule' &&
needs.build.result == 'success' &&
needs.test.result == 'success' &&
needs.upload-artifacts.result == 'success'
steps:
# remove the WebGL directory so we do not accidentally publish it to steam
- name: Prepare deployment
run: rm -rf build/WebGL
# run steam-deploy
# requires steam account that has permissions to upload builds
# for the specified appId
- name: Deploy
uses: game-ci/steam-deploy@v3
with:
# username of the steam account used to upload
username: ${{ secrets.STEAM_USERNAME }}
# needed so we do not have to complete 2FA every time we deploy
# if the login fails, even though username and password have not changed
# it may be necessary to regenerate the config.vdf,
# base64 encode it and update the STEAM_CONFIG_VDF github secret
# https://game.ci/docs/github/deployment/steam#3-add-github-secrets
configVdf: ${{ secrets.STEAM_CONFIG_VDF}}
# appId of the application we are uploading to build for
appId: ${{ secrets.STEAM_APP_ID }}
# set build description to commit hash
buildDescription: CI/CD build ${{ github.sha }}
# path where steampipe looks for the build
rootPath: build
# path for depot1, relative form rootPath
# we only have 1 depot, so . is sufficient
depot1Path: .
# deploy to the development branch of the app
releaseBranch: development
# this job is needed because in some instances, there might be some leftover files
# in the working directory, that have funky (=root:root) permissions
# this is not a problem on ephemeral runners, but on self-hosted ones it is
# thus, we ensure that the working dir is clean before our next pipeline run
# this job must **ALWAYS** run
cleanup:
name: Cleanup
runs-on: self-hosted
needs: [test, build, upload-artifacts, save-cache, deploy]
if: ${{ always() }}
steps:
- name: Cleanup
uses: AutoModality/action-clean@v1