diff --git a/.vscode/launch.json b/.vscode/launch.json index 9c7be0a5..ade9bd7b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,5 +1,12 @@ { "configurations": [ + { + "name": "PowerShell Launch Current File", + "type": "PowerShell", + "request": "launch", + "script": "${file}", + "cwd": "${cwd}" + }, { "type": "node", "request": "launch", diff --git a/action.yml b/action.yml index ef48e8c2..2ada25e6 100644 --- a/action.yml +++ b/action.yml @@ -106,6 +106,24 @@ inputs: default: '' description: 'User and optionally group (user or user:group or uid:gid) to give ownership of the resulting build artifacts' + dockerCpuLimit: + required: false + default: '' + description: 'Number of CPU cores to assign the docker container. Defaults to all available cores on all platforms.' + dockerMemoryLimit: + required: false + default: '' + description: + 'Amount of memory to assign the docker container. Defaults to 95% of total system memory rounded down to the + nearest megabyte on Linux and 80% on Windows. On unrecognized platforms, defaults to 75% of total system memory. + To manually specify a value, use the format , where unit is either m or g. ie: 512m = 512 megabytes' + dockerIsolationMode: + required: false + default: 'default' + description: + 'Isolation mode to use for the docker container. Can be one of process, hyperv, or default. Default will pick the + default mode as described by Microsoft where server versions use process and desktop versions use hyperv. Only + applicable on Windows' allowDirtyBuild: required: false default: '' diff --git a/dist/index.js b/dist/index.js index 9c38ab9a..b6f1c1bd 100644 Binary files a/dist/index.js and b/dist/index.js differ diff --git a/dist/index.js.map b/dist/index.js.map index ca610bdb..6379d2f2 100644 Binary files a/dist/index.js.map and b/dist/index.js.map differ diff --git a/dist/platforms/windows/build.ps1 b/dist/platforms/windows/build.ps1 index 50ae2795..bbae3d21 100644 --- a/dist/platforms/windows/build.ps1 +++ b/dist/platforms/windows/build.ps1 @@ -66,6 +66,26 @@ else Get-ChildItem -Path $Env:UNITY_PROJECT_PATH\Assets\Editor -Recurse } +if ( "$Env:BUILD_TARGET" -eq "Android" -and -not ([string]::IsNullOrEmpty("$Env:ANDROID_KEYSTORE_BASE64")) ) +{ + Write-Output "Creating Android keystore." + + # Write to consistent location as Windows Unity seems to have issues with pwd and can't find the keystore + $keystorePath = "C:/android.keystore" + [System.IO.File]::WriteAllBytes($keystorePath, [System.Convert]::FromBase64String($Env:ANDROID_KEYSTORE_BASE64)) + + # Ensure the project settings are pointed at the correct path + $unitySettingsPath = "$Env:UNITY_PROJECT_PATH\ProjectSettings\ProjectSettings.asset" + $fileContent = Get-Content -Path "$unitySettingsPath" + $fileContent = $fileContent -replace "AndroidKeystoreName:\s+.*", "AndroidKeystoreName: $keystorePath" + $fileContent | Set-Content -Path "$unitySettingsPath" + + Write-Output "Created Android keystore." +} +else { + Write-Output "Not creating Android keystore." +} + # # Pre-build debug information # @@ -112,48 +132,63 @@ Write-Output "" # If $Env:CUSTOM_PARAMETERS contains spaces and is passed directly on the command line to Unity, powershell will wrap it # in double quotes. To avoid this, parse $Env:CUSTOM_PARAMETERS into an array, while respecting any quotations within the string. $_, $customParametersArray = Invoke-Expression('Write-Output -- "" ' + $Env:CUSTOM_PARAMETERS) +$unityArgs = @( + "-quit", + "-batchmode", + "-nographics", + "-silent-crashes", + "-projectPath", $Env:UNITY_PROJECT_PATH, + "-executeMethod", $Env:BUILD_METHOD, + "-buildTarget", $Env:BUILD_TARGET, + "-customBuildTarget", $Env:BUILD_TARGET, + "-customBuildPath", $Env:CUSTOM_BUILD_PATH, + "-buildVersion", $Env:VERSION, + "-androidVersionCode", $Env:ANDROID_VERSION_CODE, + "-androidKeystorePass", $Env:ANDROID_KEYSTORE_PASS, + "-androidKeyaliasName", $Env:ANDROID_KEYALIAS_NAME, + "-androidKeyaliasPass", $Env:ANDROID_KEYALIAS_PASS, + "-androidTargetSdkVersion", $Env:ANDROID_TARGET_SDK_VERSION, + "-androidExportType", $Env:ANDROID_EXPORT_TYPE, + "-androidSymbolType", $Env:ANDROID_SYMBOL_TYPE, + "-logfile", "-" +) + $customParametersArray -& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -quit -batchmode -nographics ` - -projectPath $Env:UNITY_PROJECT_PATH ` - -executeMethod $Env:BUILD_METHOD ` - -buildTarget $Env:BUILD_TARGET ` - -customBuildTarget $Env:BUILD_TARGET ` - -customBuildPath $Env:CUSTOM_BUILD_PATH ` - -buildVersion $Env:VERSION ` - -androidVersionCode $Env:ANDROID_VERSION_CODE ` - -androidKeystoreName $Env:ANDROID_KEYSTORE_NAME ` - -androidKeystorePass $Env:ANDROID_KEYSTORE_PASS ` - -androidKeyaliasName $Env:ANDROID_KEYALIAS_NAME ` - -androidKeyaliasPass $Env:ANDROID_KEYALIAS_PASS ` - -androidTargetSdkVersion $Env:ANDROID_TARGET_SDK_VERSION ` - -androidExportType $Env:ANDROID_EXPORT_TYPE ` - -androidSymbolType $Env:ANDROID_SYMBOL_TYPE ` - $customParametersArray ` - -logfile | Out-Host +# Remove null items as that will fail the Start-Process call +$unityArgs = $unityArgs | Where-Object { $_ -ne $null } -# Catch exit code -$Env:BUILD_EXIT_CODE=$LastExitCode +$process = Start-Process -FilePath "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" ` + -ArgumentList $unityArgs ` + -PassThru ` + -NoNewWindow -# Display results -if ($Env:BUILD_EXIT_CODE -eq 0) -{ - Write-Output "Build Succeeded!" -} else -{ - Write-Output "$('Build failed, with exit code ')$($Env:BUILD_EXIT_CODE)$('"')" +while (!$process.HasExited) { + if ($process.HasExited) { + Get-Process + + Start-Sleep -Seconds 10 + + Get-Process + + # Display results + if ($process.ExitCode -eq 0) + { + Write-Output "Build Succeeded!!" + } else + { + Write-Output "$('Build failed, with exit code ')$($process.ExitCode)$('"')" + } + + Write-Output "" + Write-Output "###########################" + Write-Output "# Build output #" + Write-Output "###########################" + Write-Output "" + + Get-ChildItem $Env:BUILD_PATH_FULL + Write-Output "" + + exit $process.ExitCode + } + + Start-Sleep -Seconds 5 } - -# TODO: Determine if we need to set permissions on any files - -# -# Results -# - -Write-Output "" -Write-Output "###########################" -Write-Output "# Build output #" -Write-Output "###########################" -Write-Output "" - -Get-ChildItem $Env:BUILD_PATH_FULL -Write-Output "" diff --git a/dist/platforms/windows/entrypoint.ps1 b/dist/platforms/windows/entrypoint.ps1 index f0a6b555..fb3ccc10 100644 --- a/dist/platforms/windows/entrypoint.ps1 +++ b/dist/platforms/windows/entrypoint.ps1 @@ -1,10 +1,15 @@ +Get-Process + # Import any necessary registry keys, ie: location of windows 10 sdk # No guarantee that there will be any necessary registry keys, ie: tvOS -Get-ChildItem -Path c:\regkeys -File | Foreach {reg import $_.fullname} +Get-ChildItem -Path c:\regkeys -File | ForEach-Object {reg import $_.fullname} # Register the Visual Studio installation so Unity can find it regsvr32 C:\ProgramData\Microsoft\VisualStudio\Setup\x64\Microsoft.VisualStudio.Setup.Configuration.Native.dll +# Kill the regsvr process +Get-Process -Name regsvr32 | ForEach-Object { Stop-Process -Id $_.Id -Force } + # Setup Git Credentials & "c:\steps\set_gitcredential.ps1" @@ -16,3 +21,6 @@ regsvr32 C:\ProgramData\Microsoft\VisualStudio\Setup\x64\Microsoft.VisualStudio. # Free the seat for the activated license & "c:\steps\return_license.ps1" + +Start-Sleep 3 +Get-Process diff --git a/src/index.ts b/src/index.ts index 3f621d8e..2457eb1d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,7 +25,11 @@ async function runMain() { if (process.platform === 'darwin') { MacBuilder.run(actionFolder); } else { - await Docker.run(baseImage.toString(), { workspace, actionFolder, ...buildParameters }); + await Docker.run(baseImage.toString(), { + workspace, + actionFolder, + ...buildParameters, + }); } } else { await CloudRunner.run(buildParameters, baseImage.toString()); @@ -38,4 +42,5 @@ async function runMain() { core.setFailed((error as Error).message); } } + runMain(); diff --git a/src/model/build-parameters.ts b/src/model/build-parameters.ts index bd5f9103..8c322124 100644 --- a/src/model/build-parameters.ts +++ b/src/model/build-parameters.ts @@ -40,6 +40,9 @@ class BuildParameters { public androidSdkManagerParameters!: string; public androidExportType!: string; public androidSymbolType!: string; + public dockerCpuLimit!: string; + public dockerMemoryLimit!: string; + public dockerIsolationMode!: string; public customParameters!: string; public sshAgent!: string; @@ -116,10 +119,12 @@ class BuildParameters { if (!Input.unitySerial && GitHub.githubInputEnabled) { // No serial was present, so it is a personal license that we need to convert if (!Input.unityLicense) { - throw new Error(`Missing Unity License File and no Serial was found. If this + throw new Error( + `Missing Unity License File and no Serial was found. If this is a personal license, make sure to follow the activation steps and set the UNITY_LICENSE GitHub secret or enter a Unity - serial number inside the UNITY_SERIAL GitHub secret.`); + serial number inside the UNITY_SERIAL GitHub secret.`, + ); } unitySerial = this.getSerialFromLicenseFile(Input.unityLicense); } else { @@ -156,6 +161,9 @@ class BuildParameters { sshPublicKeysDirectoryPath: Input.sshPublicKeysDirectoryPath, gitPrivateToken: Input.gitPrivateToken || (await GithubCliReader.GetGitHubAuthToken()), chownFilesTo: Input.chownFilesTo, + dockerCpuLimit: Input.dockerCpuLimit, + dockerMemoryLimit: Input.dockerMemoryLimit, + dockerIsolationMode: Input.dockerIsolationMode, providerStrategy: CloudRunnerOptions.providerStrategy, buildPlatform: CloudRunnerOptions.buildPlatform, kubeConfig: CloudRunnerOptions.kubeConfig, diff --git a/src/model/docker.ts b/src/model/docker.ts index 24b93ab5..aec955bc 100644 --- a/src/model/docker.ts +++ b/src/model/docker.ts @@ -48,6 +48,8 @@ class Docker { sshPublicKeysDirectoryPath, gitPrivateToken, dockerWorkspacePath, + dockerCpuLimit, + dockerMemoryLimit, } = parameters; const githubHome = path.join(runnerTempPath, '_github_home'); @@ -72,6 +74,8 @@ class Docker { --volume "${actionFolder}/platforms/ubuntu/steps:/steps:z" \ --volume "${actionFolder}/platforms/ubuntu/entrypoint.sh:/entrypoint.sh:z" \ --volume "${actionFolder}/unity-config:/usr/share/unity3d/config/:z" \ + --cpus=${dockerCpuLimit} \ + --memory=${dockerMemoryLimit} \ ${sshAgent ? `--volume ${sshAgent}:/ssh-agent` : ''} \ ${ sshAgent && !sshPublicKeysDirectoryPath @@ -86,7 +90,16 @@ class Docker { } static getWindowsCommand(image: string, parameters: DockerParameters): string { - const { workspace, actionFolder, unitySerial, gitPrivateToken, dockerWorkspacePath } = parameters; + const { + workspace, + actionFolder, + unitySerial, + gitPrivateToken, + dockerWorkspacePath, + dockerCpuLimit, + dockerMemoryLimit, + dockerIsolationMode, + } = parameters; return `docker run \ --workdir c:${dockerWorkspacePath} \ @@ -97,12 +110,16 @@ class Docker { ${gitPrivateToken ? `--env GIT_PRIVATE_TOKEN="${gitPrivateToken}"` : ''} \ --volume "${workspace}":"c:${dockerWorkspacePath}" \ --volume "c:/regkeys":"c:/regkeys" \ + --volume "C:/Program Files/Microsoft Visual Studio":"C:/Program Files/Microsoft Visual Studio" \ --volume "C:/Program Files (x86)/Microsoft Visual Studio":"C:/Program Files (x86)/Microsoft Visual Studio" \ --volume "C:/Program Files (x86)/Windows Kits":"C:/Program Files (x86)/Windows Kits" \ --volume "C:/ProgramData/Microsoft/VisualStudio":"C:/ProgramData/Microsoft/VisualStudio" \ --volume "${actionFolder}/default-build-script":"c:/UnityBuilderAction" \ --volume "${actionFolder}/platforms/windows":"c:/steps" \ --volume "${actionFolder}/BlankProject":"c:/BlankProject" \ + --cpus=${dockerCpuLimit} \ + --memory=${dockerMemoryLimit} \ + --isolation=${dockerIsolationMode} \ ${image} \ powershell c:/steps/entrypoint.ps1`; } diff --git a/src/model/input.ts b/src/model/input.ts index f50b0633..94a0f2b4 100644 --- a/src/model/input.ts +++ b/src/model/input.ts @@ -4,6 +4,7 @@ import { Cli } from './cli/cli'; import CloudRunnerQueryOverride from './cloud-runner/options/cloud-runner-query-override'; import Platform from './platform'; import GitHub from './github'; +import os from 'node:os'; import * as core from '@actions/core'; @@ -226,6 +227,35 @@ class Input { return Input.getInput('dockerWorkspacePath') || '/github/workspace'; } + static get dockerCpuLimit(): string { + return Input.getInput('dockerCpuLimit') || os.cpus().length.toString(); + } + + static get dockerMemoryLimit(): string { + const bytesInMegabyte = 1024 * 1024; + + let memoryMultiplier; + switch (os.platform()) { + case 'linux': + memoryMultiplier = 0.95; + break; + case 'win32': + memoryMultiplier = 0.8; + break; + default: + memoryMultiplier = 0.75; + break; + } + + return ( + Input.getInput('dockerMemoryLimit') || `${Math.floor((os.totalmem() / bytesInMegabyte) * memoryMultiplier)}m` + ); + } + + static get dockerIsolationMode(): string { + return Input.getInput('dockerIsolationMode') || 'default'; + } + public static ToEnvVarFormat(input: string) { if (input.toUpperCase() === input) { return input;