Azure DevOps Unity3D pipeline

August 2020. This is an article to accompany my video about setting up an Azure DevOps pipeline for a local build agent with Unity3D.

If you want to spend less time building and fixing bugs you want to setup a build/test pipeline for your Unity3D projects.

Azure DevOps is a CI/CD tool. That means it facilitates continues integration and continues deployment. This helps to get faster feedback on your development quality and progress, both for the developer as well as for the business. On top of that, you can use CI/CD to facilitate iterative product development with a lower time-to-market. In general, it helps to get results faster because you can trust the development cycle rather than planning for everything in advance.

See this article from me about this subject on how I think it can facilitate iterative development.

Video tutorial

Additional resources

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. However, I moved on from there and ended up with Azure DevOps CI/CD.

I switched because 1) I have an Azure DevOps account that comes with my VS license, and 2) I use Azure DevOps CI/CD on a daily base and are more experienced with this tool and 3) I have had much more professional guidance from other engineers on good tool chains in Azure DevOps CI/CD.

Update 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 March 2024: And I am still on Azure DevOps CI/CD. And still have this local build agent setup. I did upgrade my CI/CD practices to use yaml templates, tuned the Unity3D build scripts even more, and have fully automatic Steam deployment. All build on the core that you see here.

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.


Comments

Leave a Reply

Discover more from GameFeelings

Subscribe now to keep reading and get access to the full archive.

Continue reading