-
Notifications
You must be signed in to change notification settings - Fork 2
Unity Pipeline
timrademaker edited this page Dec 15, 2020
·
15 revisions
A pipeline for unity that runs the project's tests, builds the project, deploys the build to Steam and notifies your team of the pipeline's result through a Discord webhook.
Run the pipeline once after creating it to set up the parameters.
library(identifier: 'JenkinsPipelineUtilities@master', retriever: modernSCM([$class: 'GitSCMSource', credentialsId: '', remote: 'https://github.com/timrademaker/JenkinsPipelineUtilities.git']))
pipeline {
parameters {
// Project
string(defaultValue: params.BUILD_METHOD ? params.BUILD_METHOD : '', description: 'The method to execute in order to build the project.', name: 'BUILD_METHOD', trim: true)
string(defaultValue: params.TEST_FILTERS ? params.TEST_FILTERS : '', description: 'The test filters to use when running tests. Separate different filters with a \';\', or leave empty to not run any tests.', name: 'TEST_FILTERS', trim: true)
// Discord
credentials(credentialType: 'org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl', defaultValue: params.DISCORD_WEBHOOK ? params.DISCORD_WEBHOOK : '', description: 'The webhook to use to notify the team of build results.', name: 'DISCORD_WEBHOOK', required: false)
// Shipping
booleanParam(defaultValue: params.SHOULD_DEPLOY ? params.SHOULD_DEPLOY : false, description: 'True if the build should be deployed.', name: 'SHOULD_DEPLOY')
booleanParam(defaultValue: params.DEPLOY_UNSTABLE_BUILD ? params.DEPLOY_UNSTABLE_BUILD : false, description: 'True if the build should be deployed even if it is marked as unstable.', name: 'DEPLOY_UNSTABLE_BUILD')
credentials(credentialType: 'com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl', defaultValue: params.STEAM_CREDS ? "${params.STEAM_CREDS}" : '', description: 'Login credentials for Steam.', name: 'STEAM_CREDS', required: true)
string(defaultValue: params.STEAM_DEPLOYMENTBRANCH ? params.STEAM_DEPLOYMENTBRANCH : '', description: 'The branch to which this game should automatically be deployed. Can\'t be \'default\'.', name: 'STEAM_DEPLOYMENTBRANCH', trim: true)
booleanParam(defaultValue: params.IS_PREVIEW ? params.IS_PREVIEW : false, description: 'True if this build is a preview (i.e. should not actually be deployed).', name: 'IS_PREVIEW')
}
agent {
node {
label ""
}
}
options {
timeout(time: 45, unit: 'MINUTES')
}
environment {
// Perforce
P4_CREDENTIALS = 'Tim180112_P4' // The ID of the Perforce credentials to use
P4_WORKSPACE_FORMAT = 'Tim180112-Jenkins-${JOB_BASE_NAME}'
P4_WORKSPACE_TEMPLATE = 'Tim180112-Jenkins' // The Perforce workspace to use as template
// Project settings
PROJECT_DIRECTORY = 'ExampleProject' // Project directory, relative to the workspace root
// Steam
STEAM_APPID = '1000' // The app ID of the game to ship to Steam.
STEAM_DEPOTID = '1001' // The depot ID of the games's depot.
// Unity base directory
UNITY_DIRECTORY = 'C:/Program Files/Unity/Hub/Editor/2019.2.16f1';
}
stages {
stage('Setup') {
steps {
script {
p4.init(env.P4_CREDENTIALS, env.P4_WORKSPACE_FORMAT, env.P4_WORKSPACE_TEMPLATE)
p4.pull();
unity.init(env.UNITY_DIRECTORY);
if(params.SHOULD_DEPLOY) {
steam.setup();
}
}
}
}
stage('Run Tests') {
when {
expression {
params.TEST_FILTERS.size() > 0;
}
}
steps {
script {
unity.runTests("${env.WORKSPACE}/${env.PROJECT_DIRECTORY}", 'PlayMode', params.TEST_FILTERS.split(';') as List<String>);
}
}
}
stage('Build') {
steps {
script {
unity.execute("${env.WORKSPACE}/${env.PROJECT_DIRECTORY}", params.BUILD_METHOD);
}
}
}
stage('Deploy') {
when {
expression {
params.SHOULD_DEPLOY &&
(currentBuild.result != 'UNSTABLE' || params.DEPLOY_UNSTABLE_BUILD)
}
}
steps {
script {
contentRoot = "${env.WORKSPACE}/out/build";
steam.createDepotManifest(env.STEAM_DEPOTID, contentRoot);
appManifest = steam.createAppManifest(env.STEAM_APPID, env.STEAM_DEPOTID, contentRoot, "${env.JOB_BASE_NAME}-${env.BUILD_NUMBER}", params.STEAM_DEPLOYMENTBRANCH, "${env.WORKSPACE}/SteamBuild", params.IS_PREVIEW);
steam.tryDeploy(params.STEAM_CREDS, appManifest);
}
}
}
}
post {
success {
script {
if(params.DISCORD_WEBHOOK) {
withCredentials([string(credentialsId: params.DISCORD_WEBHOOK, variable: 'WEBHOOK_URL')]) {
discord.sendEmbed(env.WEBHOOK_URL, "Ran Jenkins Pipeline for ${env.JOB_BASE_NAME}", "[Build #${env.BUILD_NUMBER}](${env.BUILD_URL})", '3066993', [['**Build Result**', ':white_check_mark: Build succeeded!']]);
}
}
}
}
unsuccessful {
script {
if(params.DISCORD_WEBHOOK) {
withCredentials([string(credentialsId: params.DISCORD_WEBHOOK, variable: 'WEBHOOK_URL')]) {
discord.sendEmbed(env.WEBHOOK_URL, "Ran Jenkins Pipeline for ${env.JOB_BASE_NAME}", "[Build #${env.BUILD_NUMBER}](${env.BUILD_URL})", '15158332', [['**Build Result**', ':x: Build failed!']]);
}
}
}
}
unstable {
script {
if(params.DISCORD_WEBHOOK) {
withCredentials([string(credentialsId: params.DISCORD_WEBHOOK, variable: 'WEBHOOK_URL')]) {
discord.sendEmbed(env.WEBHOOK_URL, "Ran Jenkins Pipeline for ${env.JOB_BASE_NAME}", "[Build #${env.BUILD_NUMBER}](${env.BUILD_URL})", '16776960', [['**Build Result**', ':warning: Build unstable!']]);
}
}
}
}
always {
script {
log.parse();
}
}
cleanup {
script {
file.delete("${env.WORKSPACE}/out");
file.delete("${env.WORKSPACE}/temp");
}
}
}
}
The build method used by the pipeline (BUILD_METHOD
parameter) could look something like this:
using UnityEditor;
public class ScriptBatch
{
public static void BuildGame()
{
string path = "../out/build";
string[] levels = new string[] { "Assets/Resources/TestMap.unity" };
BuildPlayerOptions options = new BuildPlayerOptions();
options.locationPathName = path + "/Game.exe";
options.scenes = levels;
options.target = BuildTarget.StandaloneWindows64;
BuildPipeline.BuildPlayer(options);
}
}
Using this would be done by setting BUILD_METHOD
to "ScriptBatch.BuildGame".
- Source Control
- Building and Testing
- Messaging
- Shipping
- Miscellaneous
- Example Pipelines