August 2020. This is an article to accompany my video about setting up an Azure DevOps pipeline for a local build agent with Unity3D.
For those who want the files: https://gamefeelingsblog.blob.core.windows.net/supportfiles/helper-files-for-azure-devops-unity-build-2.zip
And here the links to a few other resources:
Why Azure DevOps
I did a video on a Jenkins setup this year. In that video I show how to setup a local build system for Unity3D with Jenkins.
Azure DevOps is a CI/CD tool. That means it facilitates continues integration and continues deployment. Why you want to use CI/CD is a story on its own and has to do with facilitating iterative development, see for instance this article from me about this subject.
Doing CI/CD was already kind-of a practice in game dev. It was often called a pipeline and revolved around getting newly build stuff integrated in the existing code base. So the current move of automating and streamlining more stuff into pipelines is only an evolution of this old practice. You only have to pay attention on what to automate and how stringent you are, but other that that it is a worthwhile exercise. See a good YouTube about this: https://www.youtube.com/watch?v=t9HRzE7_2Xc.
So why Azure DevOps? Well, I’m a Microsoft developer from when I grew up and have used their tools for over decades now. I do find that over time I like their approach to empowering the developer with good working tools, I tried a few other tools but always got back to them having the better maintained and better thought-out philosophy.
I tried Jenkins but found it to be outdated and non intuitive. So yeah, I do have a few (payed) Microsoft accounts already so for me Azure DevOps is the better choice.
Update: a major reason for me to use Azure DevOps is because it integrates different aspects of ‘good’ CI/CD practices a lot better. In Jenkins you need a lot of plugins to make stuff work, and ‘pipeline as code’ is not integrated as good as in Azure DevOps.
Helper files
If you follow the tutorial you see me using a batch file, a setup, and a specific pipeline.
You can download the content in a zip over here, or copy it from the source code paragraphs below.
(Replace the game name, organization name, and project name specific folders with your names. In all files. See the zip for the folder structure as I used them with these scripts for reference.)
The pipeline yaml file:
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- master
pool:
name: Default
demands:
Unity_2019.3.2f1
steps:
#cleanup for unity build
- task: DeleteFiles@1
inputs:
SourceFolder: '$(Build.ArtifactStagingDirectory)'
Contents: '**/*'
#get the previously secured library (if any) for performance reasons
- task: DeleteFiles@1
inputs:
SourceFolder: '$(Build.Repository.LocalPath)\Unity Source\Manage the Universe\Library'
Contents: '**/*'
- task: CmdLine@2
inputs:
script: 'if EXIST "$(Build.BinariesDirectory)\Library\" move "$(Build.BinariesDirectory)\Library" "$(Build.Repository.LocalPath)\Unity Source\Manage the Universe\Library"'
#unity PC build
- task: UnityBuildTask@3
inputs:
buildTarget: 'Win64'
unityProjectPath: 'Unity Source\Manage the Universe'
outputPath: '$(Build.BinariesDirectory)\Build'
outputFileName: 'ManageTheUniverse'
#create the installer
- task: BatchScript@1
inputs:
filename: 'Installer/createsetup.bat'
arguments: '"$(Build.BinariesDirectory)\Build\*" "$(Build.ArtifactStagingDirectory)\SetupCreation" "0.1.$(Build.BuildNumber)"'
workingFolder: '$(Build.Repository.LocalPath)\Installer'
#upload artifact
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)\SetupCreation'
ArtifactName: 'drop'
publishLocation: 'Container'
#secure the library for performance reasons
- task: DeleteFiles@1
inputs:
SourceFolder: '$(Build.BinariesDirectory)\Library'
Contents: '**/*'
- task: CmdLine@2
inputs:
script: 'move "$(Build.Repository.LocalPath)\Unity Source\Manage the Universe\Library" "$(Build.BinariesDirectory)\Library"'
The setup batch file:
set arg1=%~1
set arg2=%~2
set arg3=%~3
"Inno Setup 6\ISCC.exe" "/DBuildSource=%arg1%" "/DBuildTarget=%arg2%" "/DMyAppVersion=%arg3%" setup.iss
The Inno setup 6 file:
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "ManageTheUniverse"
#define MyAppPublisher "GameFeelings"
#define MyAppURL "https://gamefeelings.com/"
#define MyAppExeName "managetheuniverse.exe"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{A3C19EB9-57D2-4DCD-870D-9A8A0CCCBFB2}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DisableProgramGroupPage=yes
; Remove the following line to run in administrative install mode (install for all users.)
PrivilegesRequired=lowest
OutputDir={#BuildTarget}
OutputBaseFilename=SetupPc
Compression=lzma
SolidCompression=yes
WizardStyle=modern
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "{#BuildSource}"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Admin Access
You need to have a high access level in your Azure DevOps organizations to pull this off. So in an existing organization with a DevOps account already in use you probably need to work with the admins to get everything going.
However if you have your own (free) account you by default have the admin role.
Azure DevOps plan limitations
Depending on your DevOps account plan you have limitations to the amount of running agents. And you have limited build minutes a month.
If you are on a free version you probably are limited to 1 local build agent, and have 1800 free build minutes a month (and for more you pay).
Even with a local build agent a few things still count for build minutes like uploading your artifacts or coordinating stuff.
Next level
Update: In April 2021 I released a blog with an evolution of the pipeline featured in the video. Better yaml practices, different builds, although not accompanied by much explanation.
Update: As of June 2021 I am working on an improved tutorial that will show better CI/CD practices in general and how to release automatically to Steam.