[6/50] A quick and dirty Python script to automate builds in Unreal
![[6/50] A quick and dirty Python script to automate builds in Unreal](/content/images/size/w960/2023/05/Untitled-1.jpeg)
Sometimes, a quick and a dirty solution is better than a well thought and a well designed one. Build scripts are perfect candidates for these types. While building games in Unreal Engine from within the editor is matter of a few clicks, it still requires human intervention and is therefore not suitable for automation use cases like Continuous Integration and Deployment.
We use Git with LFS for our version control needs. In the past, we used to periodically aggregate all the commits to the master and manually generate a clean build of the game. With time we wanted to move to a more frequent build cadence but did not want any single person to be responsible for the same which meant no editor.
After digging around the online forums and official Unreal documentation, we hacked together a Python script which we trigger via a scheduled task.
#!/usr/bin/env python
import click
import os
import pathlib
import subprocess
from loguru import logger
@click.group()
def main():
pass
@main.command()
@click.option("--mode", "-m", required=True, default='Development')
@click.option("--target", "-t", required=True, default='Win64')
@click.option("--dest", "-d", required=True)
@click.option("--uproject", "-u", required=True)
@click.option("--ue-batch-dir", "-b", required=True)
def build(mode, target, dest, uproject, ue_batch_dir):
start_cwd = os.getcwd()
uproject_path = pathlib.Path(uproject)
if not uproject_path.exists():
logger.error(f"uproject file not found at {uproject}")
return 1
dest_path = pathlib.Path(dest)
if not dest_path.exists():
logger.error(f"Destination directory not found at {dest_path}")
return 1
try:
uat_directory = pathlib.Path(ue_batch_dir)
run_uat_bin = uat_directory.joinpath("RunUAT.bat")
logger.info(f"Changed directory to: {os.getcwd()}")
cmd_ue5 = [
f'{run_uat_bin} BuildCookRun -project={uproject} -noP4 -platform={target} -clientconfig={mode} -cook -maps=AllMaps -compile -stage -pak -archive -archivedirectory={dest}'
]
logger.info(f"Executing: {' '.join(cmd_ue5)}")
subprocess.run(cmd_ue5, shell=True, check=True)
except Exception as exc:
logger.exception(exc)
return 1
finally:
logger.info(f"Changing directory back to: {start_cwd}")
os.chdir(start_cwd)
if __name__ == "__main__":
main()
As the folks in Skyrim would say,
It ain't much, but it's honest work.