Started work on packaging script, still WIP

This commit is contained in:
Steve Streeting 2020-10-02 18:27:56 +01:00
parent f0bbab4c79
commit 8d78f7b225
5 changed files with 454 additions and 4 deletions

View File

@ -2,8 +2,15 @@
## Summary
These scripts are to help me set up Git / Subversion repositories for UE4 without
having to remember everything.
These scripts are to help me with various repetetive or easy-to-forget tasks
related to [Unreal Engine 4](https://www.unrealengine.com).
* [Setting up a project for Git / Git-LFS](#git-setup)
* [Packaging Builds](#packaging-builds)
* [Releasing builds to Itch, Steam](#releasing-builds)
## Git Setup
Initially we'd decided to go back to Subversion because of the importance of
good locking workflow for uasset/umap files in UE4, to prevent binary merge errors.
@ -26,7 +33,7 @@ We use a particular content workflow:
Together the scripts below configure everything so I don't have to remember.
## Steps to set up Git + LFS for a UE4 project
### Steps to set up Git + LFS for a UE4 project
1. The script works for projects with no git repo yet, or those with an existing git repo
1. For existing repos, ideally you will not have committed any large files to Git yet
@ -39,7 +46,16 @@ Together the scripts below configure everything so I don't have to remember.
1. Push ALL BRANCHES of this new repo to the host of your choice
# Subversion Information (ignore below if using Git)
## Packaging builds
.. TODO
## Releasing Builds
.. TODO
# LEGACY: Subversion Information (ignore below if using Git)
## Steps to create a new SVN repo for a UE4 project

117
inc/packageconfig.ps1 Normal file
View File

@ -0,0 +1,117 @@
class PackageVariant {
# Name of the variant (can be anything)
[string]$Name
# Platform name (must be one supported by Unreal e.g. Win64)
[string]$Platform
# Configuration name i.e. Development, Shipping
[string]$Configuration
# Additional arguments to send to the build command line
[string]$ExtraBuildArguments
# Whether to create a zip of this package (default false)
[bool]$Zip
# The Steam application ID, if you intend to send this variant to Steam
[string]$SteamAppId
# The Steam depot ID, if you intend to send this variant to Steam
[string]$SteamDepotId
# Steam login to use to deploy to Steam (if you haven't cached your credential already you'll get a login prompt)
[string]$SteamLogin
# Itch application identifier e.g. your-account/game-name, if you intend to send this variant to Itch
[string]$ItchAppId
# Itch channel, if you intend to send this variant to Itch (usually a platform)
[string]$ItchChannel
PackageVariant() {
$this.Configuration = "Development"
$this.Zip = $false
}
PackageVariant([PSCustomObject]$obj) {
$this.Configuration = "Development"
$this.Zip = $false
# Override just properties that are set
$obj.PSObject.Properties | ForEach-Object {
try {
$this.$($_.Name) = $_.Value
} catch {
Write-Host "Invalid property for package variant: $($_.Name) = $($_.Value)"
}
}
}
}
# Our config for both building and releasing
# Note that environment variables also have an effect:
# - UE4INSTALL: a specific UE install to use (default blank, find a version in UE4ROOT)
# - UE4ROOT: Parent folder of all binary UE4 installs (default C:\Program Files\Epic Games)
class PackageConfig {
# The root of the folder structure which will contain packaged output
# Will be structured $OutputDir/$version/$variant
# If relative, will be considered relative to source folder
[string]$OutputDir
# Folder to place zipped releases (named $target_$platform_$variant_$version.zip)
# If relative, will be considered relative to source folder
[string]$ZipDir
# Target name: this will usually be the name of your game
[string]$Target
# Whether to cook all maps (default true)
[bool]$CookAllMaps
# If CookAllMaps=false, list the map names you want to cook
[array]$MapsIncluded
# If CookAllMaps=true, list the map names you want to exclude from cooking
[array]$MapsExcluded
# Whether to combine assets into a pak file (default true)
[bool]$UsePak
# Whether to compress the pak file (default false since deployments often compress & can detect diffs better)
[bool]$CompressPak
# List of PackageVariant entries
[array]$Variants
# Names of the default variant(s) to package / release if unspecified
[array]$DefaultVariants
PackageConfig([PSCustomObject]$obj) {
# Construct from JSON object
$this.CookAllMaps = $true
$this.UsePak = $true
$this.CompressPak = $false
$this.Variants = @()
# Override just properties that are set
$obj.PSObject.Properties | ForEach-Object {
if ($_.Name -ne "Variants") {
try {
# Nested array dealt with below
$this.$($_.Name) = $_.Value
} catch {
Write-Host "Invalid property in root package config: $($_.Name) = $($_.Value)"
}
}
}
$this.Variants = $obj.Variants | ForEach-Object {
[PackageVariant]::New($_)
}
}
}
# Read packageconfig.json file from a source location and return PackageConfig instance
function Read-Package-Config {
param (
[string]$srcfolder
)
Write-Host "Hello!!!"
$configfile = Resolve-Path "$srcfolder\packageconfig.json"
if (-not (Test-Path $configfile -PathType Leaf)) {
throw "$srcfolder\packageconfig.json does not exist!"
}
$obj = (Get-Content $configfile) | ConvertFrom-Json
return [PackageConfig]::New($obj)
}

96
inc/projectversion.ps1 Normal file
View File

@ -0,0 +1,96 @@
Import-Module PsIni
function Get-Project-Version-Ini-Filename {
return Join-Path $srcfolder "Config/DefaultGame.ini" -Resolve
}
function Get-Project-Version {
param (
[string]$srcfolder
)
$file = Get-Project-Version-Ini-Filename
$gameIni = Get-IniContent $file
return $gameIni["/Script/EngineSettings.GeneralProjectSettings"].ProjectVersion
}
function Increment-Project-Version {
param (
[string]$srcfolder,
[bool]$major,
[bool]$minor,
[bool]$patch,
[bool]$hotfix,
[bool]$dryrun = $false
)
if (($major + $minor + $patch + $hotfix) -gt 1) {
throw "Can't set more than one of major/minor/patch/hotfix at the same time!"
}
$gameIniFile = Get-Project-Version-Ini-Filename
$gameIni = Get-IniContent $gameIniFile
Write-Verbose "[version++] M:$major m:$minor p:$patch h:$hotfix"
# We have to use Write-Verbose now that we're using the return value, Write-Output
# appends to the return value. Write-Verbose works but doesn't appear by default
# Unless user sets $VerbosePreference="Continue"
# Bump the version number of the build
Write-Verbose "[inc_version] Updating $gameIniFile"
$versionString = $gameIni["/Script/EngineSettings.GeneralProjectSettings"].ProjectVersion
Write-Verbose "[version++] Current version is $versionString"
# Regex features:
# - Can read 2-4 version components but will pad with 0s up to 4 when writing
# - captures pre- and post-fix text and retains
$regex = "([^\d]*)(\d+)\.(\d+)(?:\.(\d+))?(?:\.(\d+))?(.*)"
$matches = $versionString | Select-String -Pattern $regex
# 1 = prefix
# 2-5 = version number components
# 6 = postfix
if (($matches.Matches.Count -gt 0) -and ($matches.Matches[0].Groups.Count -eq 7)) {
$prefix = $matches.Matches[0].Groups[1].Value
$postfix = $matches.Matches[0].Groups[6].Value
$intversions = $matches.Matches[0].Groups[2..5] | ForEach-Object {
if ($_.Value -ne "") {
[int]$_.Value
} else {
# We fill in the version numbers to 4 digits always
0
}
}
if ($major) {
$intversions[0]++
} elseif ($minor) {
$intversions[1]++
} elseif ($patch) {
$intversions[2]++
} else {
$intversions[3]++
}
$newver = "$prefix$($intversions[0]).$($intversions[1]).$($intversions[2]).$($intversions[3])$postfix"
Write-Verbose "[version++] Bumping version to $newver"
if ($dryrun) {
Write-Verbose "[version++] dryrun: not changing $gameIniFile"
} else {
$gameIni["/Script/EngineSettings.GeneralProjectSettings"].ProjectVersion = $newver
Out-IniFile -Force -InputObject $gameIni -FilePath $gameIniFile
Write-Verbose "[version++] Success! Version is now $newver"
}
return "$newver"
} else {
throw "[version++] Error: unable to read current version"
}
}

View File

@ -0,0 +1,51 @@
{
"OutputDir": "/Path/To/Output/Parent/Dir",
"ZipDir": "/Path/To/Zipped/Releases/Folder",
"Target": "GameName",
"CookAllMaps": true,
"MapsIncluded": [
],
"MapsExcluded": [
],
"UsePak": true,
"CompressPak": false,
"Variants": [
{
"Name": "PublicWin64SteamBuild",
"Platform": "Win64",
"Configuration": "Shipping",
"SteamAppId": "YourSteamAppId",
"SteamDepotId": "YourWindowsDepotId",
"Zip": false,
"ExtraBuildArguments": "-EnableSteamworks"
},
{
"Name": "PublicWin64Build",
"Platform": "Win64",
"Configuration": "Shipping",
"ItchAppId": "itch-user/app-name",
"ItchChannel": "win64",
"Zip": false
},
{
"Name": "PrivateWin64Build",
"Platform": "Win64",
"Configuration": "Development",
"ItchAppId": "itch-user/private-app-name",
"ItchChannel": "win64-dev",
"Zip": true,
"ExtraBuildArguments": "-Foo=Bar -Something"
}
],
"DefaultVariants": [
"PrivateWin64Build"
],
"SteamLogin": "YourSteamReleaseUser"
}

170
ue4-package.ps1 Normal file
View File

@ -0,0 +1,170 @@
[CmdletBinding()] # Fail on unknown args
param (
[string]$src,
[switch]$major = $false,
[switch]$minor = $false,
[switch]$patch = $false,
[switch]$hotfix = $false,
# Don't incrememnt version
[switch]$noversionbump = $false,
# Force move tag
[switch]$forcetag = $false,
# Name of variant to build (optional, uses DefaultVariants from packageconfig.json if unspecified)
[array]$variant,
# Testing mode; skips clean checks, tags
[switch]$test = $false,
# Dry-run; does nothing but report what *would* have happened
[switch]$dryrun = $false,
[switch]$help = $false
)
. $PSScriptRoot\inc\packageconfig.ps1
. $PSScriptRoot\inc\projectversion.ps1
function Write-Usage {
Write-Output "Steve's UE4 packaging tool"
Write-Output "Usage:"
Write-Output " ue4-package.ps1 [-src:sourcefolder] [-major|-minor|-patch|-hotfix] [-keepversion] [-force] [-variant=VariantName] [-test] [-dryrun]"
Write-Output " "
Write-Output " -src : Source folder (current folder if omitted), must contain buildconfig.json"
Write-Output " -major : Increment major version i.e. [x++].0.0.0"
Write-Output " -minor : Increment minor version i.e. x.[x++].0.0"
Write-Output " -patch : Increment patch version i.e. x.x.[x++].0 (default)"
Write-Output " -hotfix : Increment hotfix version i.e. x.x.x.[x++]"
Write-Output " -keepversion : Keep current version number, doesn't tag unless -forcetag"
Write-Output " -forcetag : Move any existing version tag"
Write-Output " -variant=Name : Build only a named variant instead of DefaultVariants from packageconfig.json"
Write-Output " -test : Testing mode, separate builds, allow dirty working copy"
Write-Output " -dryrun : Don't perform any actual actions, just report on what you would do"
Write-Output " -help : Print this help"
}
if ($src.Length -eq 0) {
$src = "."
Write-Verbose "-src not specified, assuming current directory"
}
# Import config
$config = Read-Package-Config -srcfolder:$src
$ErrorActionPreference = "Stop"
Write-Output "~-~-~ UE4 Packaging Helper Start ~-~-~"
if ($help) {
Write-Usage
Exit 0
}
if ($test) {
Write-Output "TEST MODE: No tagging, version bumping"
}
if (([bool]$major + [bool]$minor + [bool]$patch + [bool]$hotfix) -gt 1) {
Write-Output "ERROR: Can't set more than one of major/minor/patch/hotfix at the same time!"
Print-Usage
Exit 5
}
if (($major -or $minor -or $patch -or $hotfix) -and $keepversion) {
Write-Output "ERROR: Can't set keepversion at the same time as major/minor/patch/hotfix!"
Print-Usage
Exit 5
}
# Detect Git
if ($src -ne ".") { Push-Location $src }
$isGit = Test-Path ".git"
if ($src -ne ".") { Pop-Location }
# Check working copy is clean (Git only)
if (-not $test -and $isGit) {
if ($src -ne ".") { Push-Location $src }
if (Test-Path ".git") {
git diff --no-patch --exit-code
if ($LASTEXITCODE -ne 0) {
Write-Output "Working copy is not clean (unstaged changes)"
if ($dryrun) {
Write-Output "dryrun: Continuing but this will fail without -dryrun"
} else {
Exit $LASTEXITCODE
}
}
git diff --no-patch --cached --exit-code
if ($LASTEXITCODE -ne 0) {
Write-Output "Working copy is not clean (staged changes)"
if ($dryrun) {
Write-Output "dryrun: Continuing but this will fail without -dryrun"
} else {
Exit $LASTEXITCODE
}
}
}
if ($src -ne ".") { Pop-Location }
}
Write-Output ""
Write-Output "Package configuration:"
Write-Output $config
try {
if (([bool]$major + [bool]$minor + [bool]$patch + [bool]$hotfix) -eq 0) {
$patch = $true
}
$mainver = $null
if ($keepversion) {
$mainver = Get-Project-Version $src
} else {
# Bump up version, passthrough options
try {
$mainver = Increment-Project-Version -srcfolder:$src -major:$major -minor:$minor -patch:$patch -hotfix:$hotfix -dryrun:$dryrun
if (-not $dryrun -and $isGit) {
if ($src -ne ".") { Push-Location $src }
$verIniFile = Get-Project-Version-Ini-Filename
git add "$($verIniFile)"
if ($LASTEXITCODE -ne 0) { Exit $LASTEXITCODE }
git commit -m "Version bump to $mainver"
if ($LASTEXITCODE -ne 0) { Exit $LASTEXITCODE }
if ($src -ne ".") { Pop-Location }
}
}
catch {
Write-Output $_.Exception.Message
Exit 6
}
}
# Keep test builds separate
if ($test) {
$mainver = "$mainver-test"
}
Write-Output "Next version will be: $mainver"
# For tagging release
# We only need to grab the main version once
$forcearg = ""
if ($forcetag) {
$forcearg = "-f"
}
if (-not $test -and -not $dryrun) {
if ($src -ne ".") { Push-Location $src }
git tag $forcearg -a $mainver -m "Automated release tag"
if ($LASTEXITCODE -ne 0) { Exit $LASTEXITCODE }
if ($src -ne ".") { Pop-Location }
}
# TODO: actually package something!
}
catch {
Write-Output $_.Exception.Message
Exit 9
}
Write-Output "~-~-~ UE4 Packaging Helper Completed OK ~-~-~"