diff --git a/Tasks/UnityBuild/UnityBuildV3/CHANGELOG.md b/Tasks/UnityBuild/UnityBuildV3/CHANGELOG.md index 66ca826..7a317f3 100644 --- a/Tasks/UnityBuild/UnityBuildV3/CHANGELOG.md +++ b/Tasks/UnityBuild/UnityBuildV3/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.4.0] + +### Added + +- Project versioning configuration to modify a project's bundle version and/or build code and commit the change to the repository as well as create a tag + ## [3.3.0] ### Added @@ -112,4 +118,4 @@ Maintenance release ### Removed - Removed build output path output variable. The build output path can now be set by the user as part of the build task configuration, hence output variable is not needed anymore -- Removed build log output variable. Whether to create a build log or not and where can be specified as part of the additional arguments setting \ No newline at end of file +- Removed build log output variable. Whether to create a build log or not and where can be specified as part of the additional arguments setting diff --git a/Tasks/UnityBuild/UnityBuildV3/build-platform.ts b/Tasks/UnityBuild/UnityBuildV3/build-platform.ts new file mode 100644 index 0000000..5d7c73a --- /dev/null +++ b/Tasks/UnityBuild/UnityBuildV3/build-platform.ts @@ -0,0 +1,21 @@ +export enum BuildPlatform { + Standalone = "standalone", + Windows32 = "Win", + Windows64 = "Win64", + OSXUniversal = "OSXUniversal", + Linux = "Linux", + Linux64 = "Linux64", + LinuxUniversal = "LinuxUniversal", + IOS = "iOS", + Android = "Android", + Web = "Web", + WebStreamed = "WebStreamed", + WebGL = "WebGL", + XboxOne = "XboxOne", + PS4 = "PS4", + WindowsStoreApps = "WindowsStoreApps", + Switch = "Switch", + N3DS = "N3DS", + TVOS = "tvOS", + VisionOS = "visionos", +} diff --git a/Tasks/UnityBuild/UnityBuildV3/package-lock.json b/Tasks/UnityBuild/UnityBuildV3/package-lock.json index e44faa1..adc1a0d 100644 --- a/Tasks/UnityBuild/UnityBuildV3/package-lock.json +++ b/Tasks/UnityBuild/UnityBuildV3/package-lock.json @@ -1,19 +1,19 @@ { "name": "@dinomite-studios/unity-build-task", - "version": "3.2.3", + "version": "3.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@dinomite-studios/unity-build-task", - "version": "3.2.3", + "version": "3.4.0", "license": "MIT", "dependencies": { - "@dinomite-studios/unity-azure-pipelines-tasks-lib": "^1.0.11", + "@dinomite-studios/unity-azure-pipelines-tasks-lib": "^1.1.3", "@types/fs-extra": "^9.0.6", "@types/node": "^22.9.1", "@types/q": "^1.5.8", - "azure-pipelines-task-lib": "^4.17.3", + "azure-pipelines-task-lib": "^5.1.0", "fs-extra": "^8.1.0" }, "devDependencies": { @@ -21,15 +21,27 @@ } }, "node_modules/@dinomite-studios/unity-azure-pipelines-tasks-lib": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@dinomite-studios/unity-azure-pipelines-tasks-lib/-/unity-azure-pipelines-tasks-lib-1.0.11.tgz", - "integrity": "sha512-aK626w3jAbeg59Is9xjZs3/4a228w/C0xhY0KHEYSpHn224bdvM65KMb/ov4i5D7o6H57vY18KYI7FAk5pr/Zw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@dinomite-studios/unity-azure-pipelines-tasks-lib/-/unity-azure-pipelines-tasks-lib-1.1.3.tgz", + "integrity": "sha512-m8Yazek76eS22cSj/+XvrkcXNz7A+sr0eIHk7FJQEy75bReJ1fU7LQmtYbLnFukuE9/5l+ghXdP6CuNR+ExheA==", "dependencies": { - "azure-pipelines-task-lib": "^4.17.3", + "azure-pipelines-task-lib": "^5.1.0", "sanitize-filename": "^1.6.3", + "semver": "^7.7.1", "tail": "^2.2.6" } }, + "node_modules/@dinomite-studios/unity-azure-pipelines-tasks-lib/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@types/fs-extra": { "version": "9.0.13", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", @@ -71,9 +83,9 @@ } }, "node_modules/azure-pipelines-task-lib": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-4.17.3.tgz", - "integrity": "sha512-UxfH5pk3uOHTi9TtLtdDyugQVkFES5A836ZEePjcs3jYyxm3EJ6IlFYq6gbfd6mNBhrM9fxG2u/MFYIJ+Z0cxQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-5.1.0.tgz", + "integrity": "sha512-uoIIAlN9piFEB6XD26iZecYdND1rhr1r05UpyesXvRzFJiuVUCwJfyD2wdfLIlGuVT9MYBLQ+8Xiou6WSrEFwA==", "dependencies": { "adm-zip": "^0.5.10", "minimatch": "3.0.5", @@ -471,13 +483,21 @@ }, "dependencies": { "@dinomite-studios/unity-azure-pipelines-tasks-lib": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@dinomite-studios/unity-azure-pipelines-tasks-lib/-/unity-azure-pipelines-tasks-lib-1.0.11.tgz", - "integrity": "sha512-aK626w3jAbeg59Is9xjZs3/4a228w/C0xhY0KHEYSpHn224bdvM65KMb/ov4i5D7o6H57vY18KYI7FAk5pr/Zw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@dinomite-studios/unity-azure-pipelines-tasks-lib/-/unity-azure-pipelines-tasks-lib-1.1.3.tgz", + "integrity": "sha512-m8Yazek76eS22cSj/+XvrkcXNz7A+sr0eIHk7FJQEy75bReJ1fU7LQmtYbLnFukuE9/5l+ghXdP6CuNR+ExheA==", "requires": { - "azure-pipelines-task-lib": "^4.17.3", + "azure-pipelines-task-lib": "^5.1.0", "sanitize-filename": "^1.6.3", + "semver": "^7.7.1", "tail": "^2.2.6" + }, + "dependencies": { + "semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==" + } } }, "@types/fs-extra": { @@ -515,9 +535,9 @@ } }, "azure-pipelines-task-lib": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-4.17.3.tgz", - "integrity": "sha512-UxfH5pk3uOHTi9TtLtdDyugQVkFES5A836ZEePjcs3jYyxm3EJ6IlFYq6gbfd6mNBhrM9fxG2u/MFYIJ+Z0cxQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-5.1.0.tgz", + "integrity": "sha512-uoIIAlN9piFEB6XD26iZecYdND1rhr1r05UpyesXvRzFJiuVUCwJfyD2wdfLIlGuVT9MYBLQ+8Xiou6WSrEFwA==", "requires": { "adm-zip": "^0.5.10", "minimatch": "3.0.5", diff --git a/Tasks/UnityBuild/UnityBuildV3/package.json b/Tasks/UnityBuild/UnityBuildV3/package.json index e9732bc..44fcc46 100644 --- a/Tasks/UnityBuild/UnityBuildV3/package.json +++ b/Tasks/UnityBuild/UnityBuildV3/package.json @@ -1,6 +1,6 @@ { "name": "@dinomite-studios/unity-build-task", - "version": "3.3.0", + "version": "3.4.0", "description": "An Azure Pipelines task to build Unity projects.", "main": "unity-build.js", "scripts": { @@ -21,8 +21,8 @@ "@types/fs-extra": "^9.0.6", "@types/node": "^22.9.1", "@types/q": "^1.5.8", - "@dinomite-studios/unity-azure-pipelines-tasks-lib": "^1.0.11", - "azure-pipelines-task-lib": "^4.17.3", + "@dinomite-studios/unity-azure-pipelines-tasks-lib": "^1.1.3", + "azure-pipelines-task-lib": "^5.1.0", "fs-extra": "^8.1.0" }, "devDependencies": { diff --git a/Tasks/UnityBuild/UnityBuildV3/task.json b/Tasks/UnityBuild/UnityBuildV3/task.json index 0055cc8..35c5439 100644 --- a/Tasks/UnityBuild/UnityBuildV3/task.json +++ b/Tasks/UnityBuild/UnityBuildV3/task.json @@ -6,13 +6,11 @@ "helpMarkDown": "Use this task to build your Unity project and generate the target platform's output files. [More Information](https://unitydevops.com/docs/unity-build-task)", "category": "Azure Pipelines", "preview": false, - "visibility": [ - "Build" - ], + "visibility": ["Build"], "author": "Dinomite", "version": { "Major": 3, - "Minor": 3, + "Minor": 4, "Patch": 0 }, "releaseNotes": "[Full Changelog](https://github.com/Dinomite-Studios/unity-azure-pipelines-tasks/blob/master/Tasks/UnityBuild/UnityBuildV3/CHANGELOG.md)", @@ -24,6 +22,11 @@ "displayName": "General", "isExpanded": true }, + { + "name": "versioning", + "displayName": "Versioning", + "isExpanded": true + }, { "name": "build", "displayName": "Build", @@ -91,6 +94,118 @@ "required": false, "helpMarkDown": "(Optional) Enter the path to the Unity project within the repository. If no value is entered, the root of the repository will be used." }, + { + "name": "projectVersioningBundleVersionMode", + "type": "pickList", + "label": "Bundle versioning mode", + "defaultValue": "none", + "helpMarkDown": "Define if and how to modify the project's bundle version.", + "groupName": "versioning", + "options": { + "none": "None", + "increment": "Increment bundle version", + "set": "Set bundle version" + } + }, + { + "name": "projectVersioningBundleVersionMajor", + "type": "string", + "label": "Major (Increment by / Set to)", + "groupName": "versioning", + "helpMarkDown": "Either the new value for the bundle major version or the increment for the major version to apply.", + "visibleRule": "projectVersioningBundleVersionMode = increment || projectVersioningBundleVersionMode = set" + }, + { + "name": "projectVersioningBundleVersionMinor", + "type": "string", + "label": "Minor (Increment by / Set to)", + "groupName": "versioning", + "helpMarkDown": "Either the new value for the bundle minor version or the increment for the minor version to apply.", + "visibleRule": "projectVersioningBundleVersionMode = increment || projectVersioningBundleVersionMode = set" + }, + { + "name": "projectVersioningBundleVersionPatch", + "type": "string", + "label": "Patch (Increment by / Set to)", + "groupName": "versioning", + "helpMarkDown": "Either the new value for the bundle patch version or the increment for the patch version to apply.", + "visibleRule": "projectVersioningBundleVersionMode = increment || projectVersioningBundleVersionMode = set" + }, + { + "name": "projectVersioningBuildNumberMode", + "type": "pickList", + "label": "Build number mode", + "defaultValue": "none", + "helpMarkDown": "Define if and how to modify the project's build number.", + "groupName": "versioning", + "options": { + "none": "None", + "increment": "Increment build number", + "set": "Set build number" + } + }, + { + "name": "projectVersioningBuildNumber", + "type": "string", + "label": "Build number (Increment by / Set to)", + "groupName": "versioning", + "helpMarkDown": "Either the new value for the build number or the increment for the build number to apply.", + "visibleRule": "projectVersioningBuildNumberMode = increment || projectVersioningBuildNumberMode = set" + }, + { + "name": "projectVersioningCommitChanges", + "type": "boolean", + "label": "Commit changes to repository", + "defaultValue": true, + "groupName": "versioning", + "visibleRule": "projectVersioningBundleVersionMode != none || projectVersioningBuildNumberMode != none", + "helpMarkDown": "(Optional) Commit the updated bundle version / build number to the repository." + }, + { + "name": "projectVersioningCommitChangesUserName", + "type": "string", + "label": "git user name", + "groupName": "versioning", + "defaultValue": "Azure Pipelines", + "helpMarkDown": "The user name to use when commiting changes.", + "visibleRule": "projectVersioningCommitChanges = true" + }, + { + "name": "projectVersioningCommitChangesUserMail", + "type": "string", + "label": "git user mail", + "groupName": "versioning", + "defaultValue": "agent@dev.azure.com", + "helpMarkDown": "The user mail to use when commiting changes.", + "visibleRule": "projectVersioningCommitChanges = true" + }, + { + "name": "projectVersioningCommitChangesMessage", + "type": "string", + "label": "Commit message", + "groupName": "versioning", + "defaultValue": "Azure Pipelines Build - v{{bundleVersion}} ({{buildNumber}})", + "helpMarkDown": "The commit message. Valid placeholders are: {{bundleVersion}}, {{buildNumber}}", + "visibleRule": "projectVersioningCommitChanges = true" + }, + { + "name": "projectVersioningCreateTag", + "type": "boolean", + "label": "Create a git tag for the changes", + "defaultValue": true, + "groupName": "versioning", + "visibleRule": "projectVersioningCommitChanges = true", + "helpMarkDown": "(Optional) Creates a git tag for the changeset." + }, + { + "name": "projectVersioningCreateTagPattern", + "type": "string", + "label": "git tag pattern", + "groupName": "versioning", + "defaultValue": "v{{bundleVersion}}", + "helpMarkDown": "The pattern defines what the created git tag will look like. Valid placeholders are: {{bundleVersion}}, {{buildNumber}}", + "visibleRule": "projectVersioningCreateTag = true" + }, { "name": "buildFlow", "type": "radio", @@ -273,6 +388,18 @@ { "name": "editorLogFilePath", "description": "Specifies the location of the editor log file generated." + }, + { + "name": "bundleVersion", + "description": "The bundle version of the Unity project after the build." + }, + { + "name": "buildNumber", + "description": "The build number of the Unity project after the build." + }, + { + "name": "gitTag", + "description": "The git tag created for the changeset." } ], "execution": { @@ -291,6 +418,7 @@ "warningAlphaBetaVersion": "You are using a Unity Alpha/Beta version. It may not be supported by the extension!", "projectPathInfo": "Determining Unity editor version for project at", "successGetUnityEditorVersion": "Success, Unity editor version found", - "failGetUnityEditorVersion": "Fail, Unity editor version not found" + "failGetUnityEditorVersion": "\nERROR: Fail, Unity editor version not found", + "taskResultFailedVersioning": "\nERROR: Failed during the project versioning process with exit code:" } -} \ No newline at end of file +} diff --git a/Tasks/UnityBuild/UnityBuildV3/unity-build-project.ts b/Tasks/UnityBuild/UnityBuildV3/unity-build-project.ts new file mode 100644 index 0000000..86d9b42 --- /dev/null +++ b/Tasks/UnityBuild/UnityBuildV3/unity-build-project.ts @@ -0,0 +1,222 @@ +import { + UnityToolRunner, + UnityPathTools, + UnityVersionInfoResult, + Utilities, + UnityPackageManagerTools, + UnityVersionTools, +} from "@dinomite-studios/unity-azure-pipelines-tasks-lib"; +import fs = require("fs-extra"); +import tl = require("azure-pipelines-task-lib/task"); +import path = require("path"); +import { + outputFileNameInputVariableName, + unityProjectPathInputVariableName, + versionSelectionModeVariableName, + outputPathInputVariableName, + unityEditorsPathModeInputVariableName, + customUnityEditorsPathInputVariableName, + versionInputVariableName, + cleanBuildInputVariableName, + buildFlowInputVariableName, + buildTargetInputVariableName, + buildProfileInputVariableName, + additionalCmdArgsInputVariableName, + buildScriptTypeInputVariableName, + signAppBundleInputVariableName, + keystoreNameInputVariableName, + keystorePassInputVariableName, + keystoreAliasNameInputVariableName, + keystoreAliasPassInputVariableName, + buildAppBundleInputVariableName, + inlineBuildScriptInputVariableName, + scriptExecuteMethodInputVariableName, + editorLogFilePathOutputVariableName, +} from "./variables"; + +export class UnityBuildProject { + public static async run(): Promise { + // Setup and read inputs. + const outputFileName = + tl.getInput(outputFileNameInputVariableName) ?? "drop"; + const projectPath = + tl.getPathInput(unityProjectPathInputVariableName) ?? ""; + const versionSelectionMode = tl.getInput( + versionSelectionModeVariableName, + true + )!; + const outputPath = tl.getPathInput(outputPathInputVariableName) ?? ""; + const unityEditorsPath = UnityPathTools.getUnityEditorsPath( + tl.getInput(unityEditorsPathModeInputVariableName, true)!, + tl.getInput(customUnityEditorsPathInputVariableName) + ); + + let unityVersion: UnityVersionInfoResult; + if (versionSelectionMode === "specify") { + let customVersion = tl.getInput(versionInputVariableName, true)!; + unityVersion = { + info: { + isAlpha: false, + isBeta: false, + version: customVersion, + revision: undefined, + }, + error: undefined, + }; + } else { + unityVersion = getUnityEditorVersion(); + } + + const unityExecutablePath = UnityPathTools.getUnityExecutableFullPath( + unityEditorsPath, + unityVersion.info! + ); + const cleanBuild = tl.getVariable(cleanBuildInputVariableName); + + // Set output variable values. + const logFilesDirectory = path.join( + tl.getVariable("Agent.TempDirectory")!, + "Logs" + ); + const logFilePath = path.join( + logFilesDirectory, + `UnityBuildLog_${Utilities.getLogFileNameTimeStamp()}.log` + ); + tl.setVariable(editorLogFilePathOutputVariableName, logFilePath); + + // If clean was specified by the user, delete the existing output directory, if it exists + if (cleanBuild === "true") { + fs.removeSync(outputPath); + } + + // No matter if clean build or not, make sure the output diretory exists + tl.mkdirP(outputPath); + tl.checkPath(outputPath, "Build Output Directory"); + + // Execute Unity command line. + const buildFlow = tl.getInput(buildFlowInputVariableName) ?? "platform"; + const unityCmd = tl + .tool(unityExecutablePath) + .arg("-batchmode") + .arg(buildFlow === "platform" ? "-buildTarget" : "-activeBuildProfile") + .arg( + tl.getInput( + buildFlow === "platform" + ? buildTargetInputVariableName + : buildProfileInputVariableName, + true + )! + ) + .arg("-projectPath") + .arg(projectPath) + .arg("-logfile") + .arg(logFilePath); + + const additionalArgs = + tl.getInput(additionalCmdArgsInputVariableName) ?? ""; + if (additionalArgs !== "") { + unityCmd.line(additionalArgs); + } + + // Perform setup depending on build script type selected + const buildScriptType = + tl.getInput(buildScriptTypeInputVariableName) ?? "default"; + + if (buildScriptType === "default") { + // When using default build scripts we rely on a Utility package being installed to the project via the Unity Package Manager. + // By adding it to the manifest before opening the project, Unity will load the package before trying to build the project. + UnityPackageManagerTools.addPackageToProject( + projectPath, + "games.dinomite.azurepipelines", + "https://github.com/Dinomite-Studios/games.dinomite.azurepipelines.git#v1.0.14" + ); + unityCmd.arg("-executeMethod").arg("AzurePipelinesBuild.PerformBuild"); + unityCmd.arg("-outputFileName").arg(outputFileName); + unityCmd.arg("-outputPath").arg(outputPath); + + if (tl.getBoolInput(signAppBundleInputVariableName)) { + unityCmd + .arg("-keystoreName") + .arg(tl.getPathInput(keystoreNameInputVariableName) ?? ""); + unityCmd + .arg("-keystorePass") + .arg(tl.getInput(keystorePassInputVariableName) ?? ""); + unityCmd + .arg("-keystoreAliasName") + .arg(tl.getInput(keystoreAliasNameInputVariableName) ?? ""); + + // The alias password is optional and should only be passed, if not empty or undefined. + const keystoreAliasPass = + tl.getInput(keystoreAliasPassInputVariableName) ?? ""; + if (keystoreAliasPass) { + unityCmd.arg("-keystoreAliasPass").arg(keystoreAliasPass); + } + } + + if (tl.getBoolInput(buildAppBundleInputVariableName)) { + unityCmd.arg("-buildAppBundle"); + } + } else if (buildScriptType === "inline") { + // Create a C# script file in a Editor folder at the root Assets directory level. Then write + // the default or the user's script into it. Unity will then compile it on launch and make sure it's available. + const projectAssetsEditorFolderPath = path.join( + `${projectPath}`, + "Assets", + "Editor" + ); + tl.mkdirP(projectAssetsEditorFolderPath); + tl.cd(projectAssetsEditorFolderPath); + tl.writeFile( + "AzureDevOps.cs", + tl.getInput(inlineBuildScriptInputVariableName)! + ); + tl.cd(projectPath); + + // Tell Unity which method to execute for build. + unityCmd + .arg("-executeMethod") + .arg(tl.getInput(scriptExecuteMethodInputVariableName)!); + } else if (buildScriptType === "existing") { + // If the user already has an existing build script we only need the method to execute. + unityCmd + .arg("-executeMethod") + .arg(tl.getInput(scriptExecuteMethodInputVariableName)!) + .arg("-quit"); + } else { + throw `Unsupported build script type ${buildScriptType}`; + } + + const result = await UnityToolRunner.run(unityCmd, logFilePath); + return result; + } +} + +function getUnityEditorVersion(): UnityVersionInfoResult { + const projectPath = tl.getPathInput("unityProjectPath") ?? ""; + console.log(`${tl.loc("projectPathInfo")} ${projectPath}`); + + const unityVersion = + UnityVersionTools.determineProjectVersionFromFile(projectPath); + if (unityVersion.error) { + const error = `${tl.loc("failGetUnityEditorVersion")} | ${ + unityVersion.error + }`; + console.error(error); + throw new Error(error); + } + + const successGetVersionLog = `${tl.loc("successGetUnityEditorVersion")} ${ + unityVersion.info!.version + }${ + unityVersion.info!.revision + ? `, revision=${unityVersion.info!.revision}` + : "" + }, alpha=${unityVersion.info!.isAlpha}, beta=${unityVersion.info!.isBeta}`; + console.log(successGetVersionLog); + + if (unityVersion.info!.isAlpha || unityVersion.info!.isBeta) { + console.warn(tl.loc("warningAlphaBetaVersion")); + } + + return unityVersion; +} diff --git a/Tasks/UnityBuild/UnityBuildV3/unity-build.ts b/Tasks/UnityBuild/UnityBuildV3/unity-build.ts index 2f11511..e41514a 100644 --- a/Tasks/UnityBuild/UnityBuildV3/unity-build.ts +++ b/Tasks/UnityBuild/UnityBuildV3/unity-build.ts @@ -1,190 +1,58 @@ -import path = require('path'); -import tl = require('azure-pipelines-task-lib/task'); -import fs = require('fs-extra'); -import { - UnityToolRunner, - UnityPathTools, - UnityVersionInfoResult, - Utilities, - UnityVersionTools, - UnityPackageManagerTools -} from '@dinomite-studios/unity-azure-pipelines-tasks-lib'; - -// Input variables. -const outputFileNameInputVariableName = 'outputFileName'; -const buildTargetInputVariableName = 'buildTarget'; -const outputPathInputVariableName = 'outputPath'; -const unityProjectPathInputVariableName = 'unityProjectPath'; -const versionInputVariableName = 'version'; -const buildScriptTypeInputVariableName = 'buildScriptType'; -const unityEditorsPathModeInputVariableName = 'unityEditorsPathMode'; -const inlineBuildScriptInputVariableName = 'inlineBuildScript'; -const scriptExecuteMethodInputVariableName = 'scriptExecuteMethod'; -const additionalCmdArgsInputVariableName = 'additionalCmdArgs'; -const customUnityEditorsPathInputVariableName = 'customUnityEditorsPath'; -const cleanBuildInputVariableName = 'Build.Repository.Clean'; -const versionSelectionModeVariableName = 'versionSelectionMode'; -const signAppBundleInputVariableName = 'androidSignAppBundle'; -const keystoreNameInputVariableName = 'androidKeystoreName'; -const keystorePassInputVariableName = 'androidKeystorePass'; -const keystoreAliasNameInputVariableName = 'androidKeystoreAliasName'; -const keystoreAliasPassInputVariableName = 'androidKeystoreAliasPass'; -const buildAppBundleInputVariableName = 'androidBuildAppBundle'; -const buildFlowInputVariableName = 'buildFlow'; -const buildProfileInputVariableName = 'buildProfile'; - -// Output variables. -const editorLogFilePathOutputVariableName = 'editorLogFilePath'; +import path = require("path"); +import tl = require("azure-pipelines-task-lib/task"); +import { UnityVersioning } from "./unity-versioning"; +import { UnityBuildProject } from "./unity-build-project"; async function run() { - try { - // Configure localization. - tl.setResourcePath(path.join(__dirname, 'task.json')); - - // Setup and read inputs. - const outputFileName = tl.getInput(outputFileNameInputVariableName) ?? 'drop'; - const projectPath = tl.getPathInput(unityProjectPathInputVariableName) ?? ''; - const versionSelectionMode = tl.getInput(versionSelectionModeVariableName, true)! - const outputPath = tl.getPathInput(outputPathInputVariableName) ?? ''; - const unityEditorsPath = UnityPathTools.getUnityEditorsPath( - tl.getInput(unityEditorsPathModeInputVariableName, true)!, - tl.getInput(customUnityEditorsPathInputVariableName)); - - let unityVersion: UnityVersionInfoResult; - if (versionSelectionMode === 'specify') { - let customVersion = tl.getInput(versionInputVariableName, true)!; - unityVersion = { - info: { - isAlpha: false, - isBeta: false, - version: customVersion, - revision: undefined - }, - error: undefined - } - } else { - unityVersion = getUnityEditorVersion(); - } - - const unityExecutablePath = UnityPathTools.getUnityExecutableFullPath(unityEditorsPath, unityVersion.info!); - const cleanBuild = tl.getVariable(cleanBuildInputVariableName); - - // Set output variable values. - const logFilesDirectory = path.join(tl.getVariable('Agent.TempDirectory')!, 'Logs'); - const logFilePath = path.join(logFilesDirectory, `UnityBuildLog_${Utilities.getLogFileNameTimeStamp()}.log`); - tl.setVariable(editorLogFilePathOutputVariableName, logFilePath); - - // If clean was specified by the user, delete the existing output directory, if it exists - if (cleanBuild === 'true') { - fs.removeSync(outputPath); - } - - // No matter if clean build or not, make sure the output diretory exists - tl.mkdirP(outputPath); - tl.checkPath(outputPath, 'Build Output Directory'); - - // Execute Unity command line. - const buildFlow = tl.getInput(buildFlowInputVariableName) ?? 'platform'; - const unityCmd = tl.tool(unityExecutablePath) - .arg('-batchmode') - .arg(buildFlow === 'platform' ? '-buildTarget' : '-activeBuildProfile') - .arg(tl.getInput(buildFlow === 'platform' ? buildTargetInputVariableName : buildProfileInputVariableName, true)!) - .arg('-projectPath') - .arg(projectPath) - .arg('-logfile') - .arg(logFilePath); - - const additionalArgs = tl.getInput(additionalCmdArgsInputVariableName) ?? ''; - if (additionalArgs !== '') { - unityCmd.line(additionalArgs); - } - - // Perform setup depending on build script type selected - const buildScriptType = tl.getInput(buildScriptTypeInputVariableName) ?? 'default'; - - if (buildScriptType === 'default') { - // When using default build scripts we rely on a Utility package being installed to the project via the Unity Package Manager. - // By adding it to the manifest before opening the project, Unity will load the package before trying to build the project. - UnityPackageManagerTools.addPackageToProject(projectPath, 'games.dinomite.azurepipelines', 'https://github.com/Dinomite-Studios/games.dinomite.azurepipelines.git#v1.0.14'); - unityCmd.arg('-executeMethod').arg('AzurePipelinesBuild.PerformBuild'); - unityCmd.arg('-outputFileName').arg(outputFileName); - unityCmd.arg('-outputPath').arg(outputPath); - - if (tl.getBoolInput(signAppBundleInputVariableName)) { - unityCmd.arg('-keystoreName').arg(tl.getPathInput(keystoreNameInputVariableName) ?? ''); - unityCmd.arg('-keystorePass').arg(tl.getInput(keystorePassInputVariableName) ?? ''); - unityCmd.arg('-keystoreAliasName').arg(tl.getInput(keystoreAliasNameInputVariableName) ?? ''); - - // The alias password is optional and should only be passed, if not empty or undefined. - const keystoreAliasPass = tl.getInput(keystoreAliasPassInputVariableName) ?? ''; - if (keystoreAliasPass) { - unityCmd.arg('-keystoreAliasPass').arg(keystoreAliasPass); - } - } - - if (tl.getBoolInput(buildAppBundleInputVariableName)) { - unityCmd.arg('-buildAppBundle'); - } - } else if (buildScriptType === 'inline') { - // Create a C# script file in a Editor folder at the root Assets directory level. Then write - // the default or the user's script into it. Unity will then compile it on launch and make sure it's available. - const projectAssetsEditorFolderPath = path.join(`${projectPath}`, 'Assets', 'Editor'); - tl.mkdirP(projectAssetsEditorFolderPath); - tl.cd(projectAssetsEditorFolderPath); - tl.writeFile('AzureDevOps.cs', tl.getInput(inlineBuildScriptInputVariableName)!); - tl.cd(projectPath); - - // Tell Unity which method to execute for build. - unityCmd.arg('-executeMethod').arg(tl.getInput(scriptExecuteMethodInputVariableName)!); - } else if (buildScriptType === 'existing') { - // If the user already has an existing build script we only need the method to execute. - unityCmd.arg('-executeMethod').arg(tl.getInput(scriptExecuteMethodInputVariableName)!).arg('-quit'); - } else { - throw `Unsupported build script type ${buildScriptType}` - } - - const result = await UnityToolRunner.run(unityCmd, logFilePath); - - // Unity process has finished. Set task result. - if (result === 0) { - const buildSuccessLog = tl.loc('buildSuccess'); - console.log(buildSuccessLog); - tl.setResult(tl.TaskResult.Succeeded, buildSuccessLog); - } else { - const buildFailLog = `${tl.loc('buildFailed')} ${result}`; - console.log(buildFailLog); - tl.setResult(tl.TaskResult.Failed, buildFailLog); - } - } catch (e) { - if (e instanceof Error) { - console.error(e.message); - tl.setResult(tl.TaskResult.Failed, e.message); - } else { - console.error(e); - tl.setResult(tl.TaskResult.Failed, `${e}`); - } + try { + // Configure localization. + tl.setResourcePath(path.join(__dirname, "task.json")); + + const versioningPreBuildResult = UnityVersioning.runPreBuild(); + if (versioningPreBuildResult !== 0) { + const log = `${tl.loc( + "taskResultFailedVersioning" + )} ${versioningPreBuildResult}`; + console.error(log); + tl.setResult(tl.TaskResult.Failed, log); + return; } -} - -function getUnityEditorVersion(): UnityVersionInfoResult { - const projectPath = tl.getPathInput('unityProjectPath') ?? ''; - console.log(`${tl.loc('projectPathInfo')} ${projectPath}`); - const unityVersion = UnityVersionTools.determineProjectVersionFromFile(projectPath); - if (unityVersion.error) { - const error = `${tl.loc('failGetUnityEditorVersion')} | ${unityVersion.error}`; - console.error(error); - throw new Error(error); + const buildProjectResult = await UnityBuildProject.run(); + + // Only if the project was built successfully, run the post build + // steps of the versioning tool. + if (buildProjectResult === 0) { + const versioningPostBuildResult = UnityVersioning.runPostBuild(); + if (versioningPostBuildResult !== 0) { + const log = `${tl.loc( + "taskResultFailedVersioning" + )} ${versioningPostBuildResult}`; + console.error(log); + tl.setResult(tl.TaskResult.Failed, log); + return; + } } - const successGetVersionLog = `${tl.loc('successGetUnityEditorVersion')} ${unityVersion.info!.version}${unityVersion.info!.revision ? `, revision=${unityVersion.info!.revision}` : ''}, alpha=${unityVersion.info!.isAlpha}, beta=${unityVersion.info!.isBeta}`; - console.log(successGetVersionLog); - - if (unityVersion.info!.isAlpha || unityVersion.info!.isBeta) { - console.warn(tl.loc('warningAlphaBetaVersion')); + // Unity process has finished. Set task result. + if (buildProjectResult === 0) { + const buildSuccessLog = tl.loc("buildSuccess"); + console.log(buildSuccessLog); + tl.setResult(tl.TaskResult.Succeeded, buildSuccessLog); + } else { + const buildFailLog = `${tl.loc("buildFailed")} ${buildProjectResult}`; + console.log(buildFailLog); + tl.setResult(tl.TaskResult.Failed, buildFailLog); } - - return unityVersion; + } catch (e) { + if (e instanceof Error) { + console.error(e.message); + tl.setResult(tl.TaskResult.Failed, e.message); + } else { + console.error(e); + tl.setResult(tl.TaskResult.Failed, `${e}`); + } + } } -run(); \ No newline at end of file +run(); diff --git a/Tasks/UnityBuild/UnityBuildV3/unity-versioning.ts b/Tasks/UnityBuild/UnityBuildV3/unity-versioning.ts new file mode 100644 index 0000000..32b42e6 --- /dev/null +++ b/Tasks/UnityBuild/UnityBuildV3/unity-versioning.ts @@ -0,0 +1,380 @@ +import tl = require("azure-pipelines-task-lib/task"); +import { + buildNumberOutputVariableName, + buildTargetInputVariableName, + bundleVersionOutputVariableName, + gitTagOutputVariableName, + projectVersioningBuildNumberModeVariableName, + projectVersioningBuildNumberVariableName, + projectVersioningBundleVersionMajorVariableName, + projectVersioningBundleVersionMinorVariableName, + projectVersioningBundleVersionModeVariableName, + projectVersioningBundleVersionPatchVariableName, + projectVersioningCommitChangesMessageVariableName, + projectVersioningCommitChangesUserMailVariableName, + projectVersioningCommitChangesUserNameVariableName, + projectVersioningCommitChangesVariableName, + projectVersioningCreateTagPatternVariableName, + projectVersioningCreateTagVariableName, + unityProjectPathInputVariableName, +} from "./variables"; +import { + SemanticVersion, + UnityVersioningTools, +} from "@dinomite-studios/unity-azure-pipelines-tasks-lib"; +import { BuildPlatform } from "./build-platform"; +import path = require("path"); + +enum VersioningMode { + None = "none", + Increment = "increment", + Set = "set", +} + +export class UnityVersioning { + public static runPreBuild(): number { + const projectPath = + tl.getPathInput(unityProjectPathInputVariableName) ?? ""; + const buildPlatform = tl.getInput(buildTargetInputVariableName, true)!; + + const bundleVersionMode = tl.getInput( + projectVersioningBundleVersionModeVariableName, + true + )!; + + const buildNumberMode = tl.getInput( + projectVersioningBuildNumberModeVariableName, + true + )!; + + // Are we going to modify anything at all? + if ( + bundleVersionMode !== VersioningMode.None || + buildNumberMode !== VersioningMode.None + ) { + // ... if yes, then we must make sure the git checkout + // is in the right state to handle our changes. Azure Pipelines + // will be default do a shallow clone and leave us with an unattached + // HEAD state. So we must make sure to switch to the source branch before + // making any changes to the repository. + const sourceBranchName = tl.getVariable("Build.SourceBranchName")!; + tl.execSync("git", ["branch", "-f", sourceBranchName]); + tl.execSync("git", ["switch", sourceBranchName]); + } + + // Does the user want to modify the bundle version? + if (bundleVersionMode !== VersioningMode.None) { + let bundleVersion: SemanticVersion = { + major: 0, + minor: 0, + patch: 0, + }; + + // Read increments / values from the task inputs. + // The bundle version input is either an increment or a value to set. + bundleVersion.major = parseInt( + tl.getInput(projectVersioningBundleVersionMajorVariableName, true)!, + 10 + ); + bundleVersion.minor = parseInt( + tl.getInput(projectVersioningBundleVersionMinorVariableName, true)!, + 10 + ); + bundleVersion.patch = parseInt( + tl.getInput(projectVersioningBundleVersionPatchVariableName, true)!, + 10 + ); + + if ( + buildPlatform !== BuildPlatform.VisionOS && + buildPlatform !== BuildPlatform.TVOS + ) { + bundleVersion = UnityVersioningTools.updateBundleVersion( + projectPath, + bundleVersionMode === VersioningMode.Increment, + bundleVersion + ); + } else if (buildPlatform === BuildPlatform.VisionOS) { + bundleVersion = UnityVersioningTools.updateVisionOSBundleVersion( + projectPath, + bundleVersionMode === VersioningMode.Increment, + bundleVersion + ); + } else if (buildPlatform === BuildPlatform.TVOS) { + bundleVersion = UnityVersioningTools.updateTvOSBundleVersion( + projectPath, + bundleVersionMode === VersioningMode.Increment, + bundleVersion + ); + } else { + throw new Error(`Invalid build platform: ${buildPlatform}`); + } + } + + // Does the user want to modify the build number? + if (buildNumberMode !== VersioningMode.None) { + // The build number input is either an increment or a value to set. + const buildNumber = parseInt( + tl.getInput(projectVersioningBuildNumberVariableName, true)!, + 10 + ); + + if ( + buildPlatform !== BuildPlatform.VisionOS && + buildPlatform !== BuildPlatform.IOS && + buildPlatform !== BuildPlatform.TVOS && + buildPlatform !== BuildPlatform.Android + ) { + UnityVersioningTools.updateBuildNumber( + projectPath, + buildNumberMode === VersioningMode.Increment, + { + Standalone: buildNumber, + } + ).Standalone; + } else if (buildPlatform === BuildPlatform.Android) { + UnityVersioningTools.updateAndroidBundleVersionCode( + projectPath, + buildNumberMode === VersioningMode.Increment, + buildNumber + ); + } else if (buildPlatform === BuildPlatform.VisionOS) { + UnityVersioningTools.updateBuildNumber( + projectPath, + buildNumberMode === VersioningMode.Increment, + { + VisionOS: buildNumber, + } + ).VisionOS; + } else if (buildPlatform === BuildPlatform.IOS) { + UnityVersioningTools.updateBuildNumber( + projectPath, + buildNumberMode === VersioningMode.Increment, + { + iPhone: buildNumber, + } + ).iPhone; + } else if (buildPlatform === BuildPlatform.TVOS) { + UnityVersioningTools.updateBuildNumber( + projectPath, + buildNumberMode === VersioningMode.Increment, + { + tvOS: buildNumber, + } + ).tvOS; + } else { + throw new Error(`Invalid build platform: ${buildPlatform}`); + } + } + + return 0; + } + + public static runPostBuild(): number { + const projectPath = + tl.getPathInput(unityProjectPathInputVariableName) ?? ""; + const buildPlatform = tl.getInput(buildTargetInputVariableName, true)!; + + const bundleVersionMode = tl.getInput( + projectVersioningBundleVersionModeVariableName, + true + )!; + + const buildNumberMode = tl.getInput( + projectVersioningBuildNumberModeVariableName, + true + )!; + + // We did neither update the bundle version nor the build number in this run, + // so we can stop here and consider things a success. + if ( + bundleVersionMode === VersioningMode.None && + buildNumberMode === VersioningMode.None + ) { + return 0; + } + + let bundleVersion: SemanticVersion = { + major: 0, + minor: 0, + patch: 0, + }; + + // By passing 0 increment, we'll essentially just read the current version. + if ( + buildPlatform !== BuildPlatform.VisionOS && + buildPlatform !== BuildPlatform.TVOS + ) { + bundleVersion = UnityVersioningTools.updateBundleVersion( + projectPath, + true, + bundleVersion + ); + } else if (buildPlatform === BuildPlatform.VisionOS) { + bundleVersion = UnityVersioningTools.updateVisionOSBundleVersion( + projectPath, + true, + bundleVersion + ); + } else if (buildPlatform === BuildPlatform.TVOS) { + bundleVersion = UnityVersioningTools.updateTvOSBundleVersion( + projectPath, + true, + bundleVersion + ); + } else { + throw new Error(`Invalid build platform: ${buildPlatform}`); + } + + let buildCode: number = 0; + + // By passing 0 increment, we'll essentially just read the current build number. + if ( + buildPlatform !== BuildPlatform.VisionOS && + buildPlatform !== BuildPlatform.IOS && + buildPlatform !== BuildPlatform.TVOS && + buildPlatform !== BuildPlatform.Android + ) { + buildCode = UnityVersioningTools.updateBuildNumber(projectPath, true, { + Standalone: 0, + }).Standalone; + } else if (buildPlatform === BuildPlatform.Android) { + buildCode = UnityVersioningTools.updateAndroidBundleVersionCode( + projectPath, + true, + 0 + ); + } else if (buildPlatform === BuildPlatform.VisionOS) { + buildCode = UnityVersioningTools.updateBuildNumber(projectPath, true, { + VisionOS: 0, + }).VisionOS; + } else if (buildPlatform === BuildPlatform.IOS) { + buildCode = UnityVersioningTools.updateBuildNumber(projectPath, true, { + iPhone: 0, + }).iPhone; + } else if (buildPlatform === BuildPlatform.TVOS) { + buildCode = UnityVersioningTools.updateBuildNumber(projectPath, true, { + tvOS: 0, + }).tvOS; + } else { + throw new Error(`Invalid build platform: ${buildPlatform}`); + } + + const commitChanges = tl.getBoolInput( + projectVersioningCommitChangesVariableName, + true + )!; + + let gitTag: string | "" = ""; + + // Does the user want to commit changes to the repository? + if (commitChanges) { + const commitChangesUserName = tl.getInput( + projectVersioningCommitChangesUserNameVariableName, + true + )!; + const commitChangesUserMail = tl.getInput( + projectVersioningCommitChangesUserMailVariableName, + true + )!; + + const createTag = tl.getBoolInput( + projectVersioningCreateTagVariableName, + true + )!; + + let commitMessage = tl.getInput( + projectVersioningCommitChangesMessageVariableName + )!; + + commitMessage = this.replacePlaceholders( + commitMessage, + bundleVersion, + buildCode + ); + commitMessage = this.ensureSkipCIFlag(commitMessage); + + // Now we can commit the changes. + tl.execSync("git", ["config", "user.name", commitChangesUserName]); + tl.execSync("git", ["config", "user.email", commitChangesUserMail]); + tl.execSync("git", [ + "add", + path.join(projectPath, "ProjectSettings", "ProjectSettings.asset"), + ]); + tl.execSync("git", ["commit", `-m ${commitMessage}`]); + + // Since we pushed to the repository, does the user also want to create a tag? + if (createTag) { + const createTagPattern = tl.getInput( + projectVersioningCreateTagPatternVariableName, + true + )!; + + gitTag = this.replacePlaceholders( + createTagPattern, + bundleVersion, + buildCode + ); + + tl.execSync("git", ["tag", gitTag]); + } + + // Finally push the changeset and tag, if created. + const sourceBranchName = tl.getVariable("Build.SourceBranchName")!; + tl.execSync("git", ["push", "origin", sourceBranchName]); + if (createTag) { + tl.execSync("git", ["push", "origin", gitTag]); + } + } + + tl.setVariable( + bundleVersionOutputVariableName, + `${bundleVersion.major}.${bundleVersion.minor}.${bundleVersion.patch}`, + false, + true + ); + tl.setVariable( + buildNumberOutputVariableName, + buildCode.toString(), + false, + true + ); + tl.setVariable(gitTagOutputVariableName, gitTag, false, true); + + return 0; + } + + private static replacePlaceholders( + input: string, + bundleVersion: SemanticVersion, + buildCode: number + ): string { + return input + .replace( + /{{bundleVersion}}/g, + `${bundleVersion.major}.${bundleVersion.minor}.${bundleVersion.patch}` + ) + .replace(/{{buildNumber}}/g, buildCode.toString()); + } + + private static ensureSkipCIFlag(commitMessage: string): string { + const skipPatterns = [ + /\[skip ci\]/i, + /\[ci skip\]/i, + /skip-checks:\s*true/i, + /\[skip azurepipelines\]/i, + /\[azurepipelines skip\]/i, + /\[skip azpipelines\]/i, + /\[azpipelines skip\]/i, + /\[skip azp\]/i, + /\[azp skip\]/i, + /\*\*\*NO_CI\*\*\*/i, + ]; + + if (skipPatterns.some((pattern) => pattern.test(commitMessage))) { + return commitMessage; + } + + return `${commitMessage} [skip ci]`; + } +} diff --git a/Tasks/UnityBuild/UnityBuildV3/variables.ts b/Tasks/UnityBuild/UnityBuildV3/variables.ts new file mode 100644 index 0000000..6121b9e --- /dev/null +++ b/Tasks/UnityBuild/UnityBuildV3/variables.ts @@ -0,0 +1,52 @@ +// Input variables. +export const outputFileNameInputVariableName = "outputFileName"; +export const buildTargetInputVariableName = "buildTarget"; +export const outputPathInputVariableName = "outputPath"; +export const unityProjectPathInputVariableName = "unityProjectPath"; +export const versionInputVariableName = "version"; +export const buildScriptTypeInputVariableName = "buildScriptType"; +export const unityEditorsPathModeInputVariableName = "unityEditorsPathMode"; +export const inlineBuildScriptInputVariableName = "inlineBuildScript"; +export const scriptExecuteMethodInputVariableName = "scriptExecuteMethod"; +export const additionalCmdArgsInputVariableName = "additionalCmdArgs"; +export const customUnityEditorsPathInputVariableName = "customUnityEditorsPath"; +export const cleanBuildInputVariableName = "Build.Repository.Clean"; +export const versionSelectionModeVariableName = "versionSelectionMode"; +export const signAppBundleInputVariableName = "androidSignAppBundle"; +export const keystoreNameInputVariableName = "androidKeystoreName"; +export const keystorePassInputVariableName = "androidKeystorePass"; +export const keystoreAliasNameInputVariableName = "androidKeystoreAliasName"; +export const keystoreAliasPassInputVariableName = "androidKeystoreAliasPass"; +export const buildAppBundleInputVariableName = "androidBuildAppBundle"; +export const buildFlowInputVariableName = "buildFlow"; +export const buildProfileInputVariableName = "buildProfile"; +export const projectVersioningBundleVersionModeVariableName = + "projectVersioningBundleVersionMode"; +export const projectVersioningBundleVersionMajorVariableName = + "projectVersioningBundleVersionMajor"; +export const projectVersioningBundleVersionMinorVariableName = + "projectVersioningBundleVersionMinor"; +export const projectVersioningBundleVersionPatchVariableName = + "projectVersioningBundleVersionPatch"; +export const projectVersioningBuildNumberModeVariableName = + "projectVersioningBuildNumberMode"; +export const projectVersioningBuildNumberVariableName = + "projectVersioningBuildNumber"; +export const projectVersioningCommitChangesVariableName = + "projectVersioningCommitChanges"; +export const projectVersioningCommitChangesUserNameVariableName = + "projectVersioningCommitChangesUserName"; +export const projectVersioningCommitChangesUserMailVariableName = + "projectVersioningCommitChangesUserMail"; +export const projectVersioningCommitChangesMessageVariableName = + "projectVersioningCommitChangesMessage"; +export const projectVersioningCreateTagVariableName = + "projectVersioningCreateTag"; +export const projectVersioningCreateTagPatternVariableName = + "projectVersioningCreateTagPattern"; + +// Output variables. +export const editorLogFilePathOutputVariableName = "editorLogFilePath"; +export const bundleVersionOutputVariableName = "bundleVersion"; +export const buildNumberOutputVariableName = "buildNumber"; +export const gitTagOutputVariableName = "gitTag"; diff --git a/Tasks/UnitySetup/UnitySetupV2/variables.ts b/Tasks/UnitySetup/UnitySetupV2/variables.ts index 2ac3253..ccc63a7 100644 --- a/Tasks/UnitySetup/UnitySetupV2/variables.ts +++ b/Tasks/UnitySetup/UnitySetupV2/variables.ts @@ -1,6 +1,3 @@ -import tl = require('azure-pipelines-task-lib/task'); - -// Input variables export const versionSelectionModeVariableName = "versionSelectionMode"; export const versionInputVariableName = 'version'; export const revisionInputVariableName = 'revision';