Live on Steam • BUAS Capstone Project

Katharsi - DevOps & Steam Integration

Managing build pipeline and Steam integration for a 15-person BUAS capstone team. Built automated Jenkins CI/CD, Steam deployment systems, and developer tools that enabled our team to successfully ship a commercial game demo and final release.

Project Overview

The Challenge

A 15-person capstone team (3 programmers, 6 artists, 5 designers, 1 producer) needed efficient collaboration on a year-long commercial game project. Manual builds, inconsistent testing, and complex Steam deployment were blocking progress and creating integration headaches.

My Solution

Built comprehensive DevOps infrastructure with automated Jenkins pipelines, daily testing suites, Steam deployment automation, and custom Discord integration. Managed both our team's pipeline and served as Jenkins administrator for the entire BUAS program.

15
Team Members
1
Year Development
3
Programmers Total
Daily
Automated Tests
2
Steam Releases

My Role & Responsibilities

🔧

Jenkins CI/CD Pipeline

Built automated Jenkins pipelines for daily testing and weekly deployment builds. Created custom Groovy libraries for Unreal Engine integration and Discord notifications.

🎮

Steam Integration & Management

Managed SteamWorks page, implemented Steam Input API, and built automated Steam deployment pipeline with branch management and SteamGuard authentication handling.

🧪

Automated Testing Framework

Implemented daily automated testing with Unreal's automation framework, custom test result parsing, and detailed Discord reporting for immediate team feedback.

👨‍💼

BUAS Jenkins Administration

Served as Jenkins administrator for the entire BUAS program, managing infrastructure for multiple teams and maintaining shared Jenkins libraries for Unreal projects.

📊

Custom Discord Integration

Created comprehensive Discord notification system with rich embed formatting, automated test reports, and Steam deployment status updates for seamless team communication.

⚙️

Multi-Platform Build System

Set up cross-platform builds with Perforce integration, automated Google Drive backup, and flexible deployment targeting for Steam, Itch.io, and internal testing.

Jenkins Pipeline Architecture

Two-pipeline approach: daily automated testing for continuous quality assurance and weekly deployment builds for release management.

Daily Testing Pipeline

Perforce Sync

Latest changelist from depot

Automated Testing

Run project automation tests

Discord Reporting

Rich embed test results

Daily Test Pipeline (DailyTest.txt)
// Custom Discord tools library for rich notifications
def JenkinsTools = library('DiscordTools@master').com.github.cynic1254

library identifier: 'JenkinsLib@master',
    retriever: modernSCM([
      $class: 'GitSCMSource',
      credentialsId: '',
      remote: 'redacted'
    ])

pipeline {
    agent {
        node {
            label "Win64"
            customWorkspace "C:\\Jenkins\\${env.JOB_NAME}"
        }
    }
    environment {
        // Redacted
    }

    stages {
        stage ("Init") {
            steps {
                script {
                    JenkinsTools.Library.Init(this)
                }
            }
        }

        stage ("P4 Setup") {
            steps {
                script {
                    def newestChangeList = p4v.initGetLatestCL(env.P4USER, env.P4HOST)
                    echo("NEWEST CHANGELIST: ${newestChangeList}")
                    p4v.init(env.P4USER, env.P4HOST, env.P4WORKSPACE, env.P4MAPPING, newestChangeList, !true)
                    echo("P4 synced to: ${env.P4_CHANGELIST}")
                }
            }
        }

        stage ("Testing") {
            steps {
                script {
                    // Run Unreal automation tests and parse results
                    def testResult = JenkinsTools.Unreal.RunAutomationCommand("RunTests Project")

                    // Send rich Discord embed with test results
                    JenkinsTools.DiscordMessage.FromTestResults(testResult).Send(env.DiscordWebhook)

                    // Generate JUnit XML for Jenkins integration
                    testResult.WriteXMLToFile("${env.WORKSPACE}/Logs/UnitTestsReport/Report.xml")

                    junit allowEmptyResults: true,
                          skipMarkingBuildUnstable: true,
                          testResults: 'Logs/UnitTestsReport/Report.xml'
                }
            }
        }
    }

    post {
        success {
            script {
                JenkinsTools.DiscordMessage.Succeeded().Send(env.DiscordWebhook)
            }
        }
        failure {
            script {
                JenkinsTools.DiscordMessage.Failed().Send(env.DiscordWebhook)
            }
        }
        cleanup {
            script {
                if(env.CLEANWORKSPACE.toBoolean()) {
                    cleanWs()
                }
            }
        }
    }
}

Custom Discord Integration

Built a comprehensive Discord notification system with rich embeds for test results, build status, and Steam deployment updates.

Discord Message System (DiscordMessage.groovy)
static DiscordMessage FromTestResults(UnrealTestResult testResults) {
    def embed = new Embed()

    if (testResults.failed > 0) {
        embed.title = "Some tests failed!"
        embed.color = 16776960  // Yellow
        embed.description = "(${testResults.failed}/${testResults.failed + testResults.succeeded}) tests failed"
        embed.fields = ParseTestResultFields(testResults)
    } else {
        embed.title = "All tests succeeded!"
        embed.color = 65280     // Green
        embed.description = "Successfully ran all tests"
    }

    embed.footer = new Embed.Footer(
        text: "Ran ${testResults.succeeded + testResults.failed} tests in ${String.format("%.4f", testResults.totalDuration)} seconds. Full results: ${Library.steps.env.BUILD_URL}"
    )

    return new DiscordMessage(
        avatar_url: "https://preview.redd.it/is-it-normal-for-games-to-have-a-unreal-engine-logo-as-its-v0-ekvife6ql3xc1.jpeg",
        username: "Unreal Test Result",
        embeds: [embed]
    )
}

static DiscordMessage SteamPushStarted(String AuthorizerID) {
    return new DiscordMessage(
        embeds: [
            new Embed(
                title: "Started push to steam",
                color: 16777215, // White
                fields: [
                    new Embed.Field(
                        name: "Push to Steam has been initiated, SteamGuard Authorization might be required",
                        value: "${Library.steps.env.BUILD_URL}"
                    ),
                    new Embed.Field(
                        name: "Authorizer:",
                        value: "<@${AuthorizerID}>"
                    )
                ]
            )
        ],
        allowed_mentions: new Mentions(users: ["${AuthorizerID}"]),
        username: "Steam Auth",
        avatar_url: "https://e1.pngegg.com/pngimages/855/514/png-clipart-clay-os-6-a-macos-icon-steam-steam-logo-thumbnail.png"
    )
}

Discord Integration Features

  • Rich Embed Formatting: Color-coded messages with structured test results and build status
  • Automated Test Reporting: Daily test results with failure details and duration metrics
  • Steam Deployment Notifications: SteamGuard authorization requests with user mentions
  • Build Status Updates: Success/failure notifications with changelist information and build links
  • Custom Avatars & Usernames: Context-specific bot appearance for different message types

Development Timeline

Year-long capstone project from concept to commercial Steam release:

1
September 2023: Project Start
Initial Setup & Planning

Team formation, initial concept development, and Jenkins infrastructure setup. Established basic build pipeline and Steam development environment.

2
October-December 2023: Foundation
Core Pipeline Development

Built daily testing pipeline, implemented Discord integration, and established automated Perforce sync. Created custom Groovy libraries for team workflow.

3
January-March 2024: Production
Steam Integration & Advanced Features

Implemented Steam Input API, built deployment automation with SteamGuard handling, and refined testing framework based on development needs.

4
April 9, 2024: Demo Release
Successful Steam Demo Launch

Deployed playable Steam demo using automated pipeline. Zero critical deployment issues thanks to comprehensive testing and deployment automation.

5
June 12, 2024: Final Release
Commercial Game Release

Successfully launched complete game on Steam. Pipeline handled final release deployment smoothly, enabling team to focus on last-minute polish and marketing.

Steam Deployment Architecture

Automated Steam Pipeline with SteamGuard Integration

Built sophisticated Steam deployment with authentication handling and branch management:

Steam Deployment Logic (BuildAndDeploy.txt)
stage("Primary-DDS-Deployment") {
    when {
        expression { env.DEPLOYTODDS.toBoolean() }
    }
    steps {
        script {
            if(env.DDS == "Steam") {
                if(currentBuild.result == "UNSTABLE") {
                    log.warning("====!!==== UNSTABLE BUILD - PUSH TO STEAM ABORTED ====!!====")
                } else if(env.PLATFORM == "PS5") {
                    log.warning("====!!==== PS5 BUILD - NOT ALLOWED TO UPLOAD TO STEAM ====!!====")
                } else {
                    // Notify team of Steam deployment start
                    discord.sendMessage(discord.createMessage(
                        "Started push to steam",
                        "white",
                        [[name:"Push to Steam has been initiated, SteamGuard Authorization might be required",
                          value:"${env.BUILD_URL}"],
                         [name:"Authorizer:",
                          value:"<@354316115704545281>"]],
                        [text:"${env.JOB_BASE_NAME}"])
                        , env.WebHook_BUILD)

                    steam.init(env.STEAMUSR, env.STEAMCMD)

                    // Create appropriate depot manifest based on platform
                    def appManifest
                    if (env.PLATFORM == "Linux"){
                        appManifest = steam.createAppManifest("3365850", "3365852", "",
                                     "${env.JOB_BASE_NAME}", false, "", "${env.STEAMBRANCH}", env.OUTPUTDIR)
                        steam.createDepotManifest("3365852", "${env.OUTPUTDIR}\\${platformDir}")
                    } else {
                        appManifest = steam.createAppManifest("3365850", "3365851", "",
                                     "${env.JOB_BASE_NAME}", false, "", "${env.STEAMBRANCH}", env.OUTPUTDIR)
                        steam.createDepotManifest("3365851", "${env.OUTPUTDIR}\\${platformDir}")
                    }

                    try {
                        steam.tryDeploy("${env.WORKSPACE}\\${appManifest}")
                    } catch (Exception e) {
                        dds_auth_timeout = true

                        // Handle SteamGuard timeout gracefully
                        discord.sendMessage(discord.createMessage(
                            "Steam Authorization Timed Out",
                            "white",
                            [[name:"Steam Authorization was not provided in time, Build has not been uploaded to steam, will be uploaded to GDrive instead",
                              value:"${env.BUILD_URL}"]],
                            [text:"${env.JOB_BASE_NAME}"])
                            , env.WebHook_BUILD)

                        catchError(stageResult: 'UNSTABLE', buildResult: currentBuild.result) {
                            error("Mark Stage as Skipped")
                        }
                    }
                }
            }
        }
    }
}

Key Infrastructure Features

  • Multi-Platform Support: Automated builds for Windows and Linux with platform-specific Steam depot handling
  • Branch Management: Flexible Steam branch targeting for development, testing, and production releases
  • SteamGuard Integration: Automated handling of Steam two-factor authentication with Discord notifications
  • Graceful Fallback: Automatic Google Drive backup if Steam deployment fails or times out
  • Build Quality Gates: Prevents unstable builds from reaching Steam while maintaining development velocity
  • Comprehensive Logging: Detailed build logs and Discord notifications for full deployment transparency

Impact & Results

2
Successful Steam Releases
365+
Days of Automated Testing
0
Critical Deployment Issues
7+
BUAS Teams Supported
100%
Automated Build Process

Measurable Team Benefits

  • Successful Commercial Release: Delivered both Steam demo (April 2024) and final game (June 2024) with zero critical deployment issues
  • Daily Quality Assurance: 365+ days of automated testing caught regressions before they impacted development
  • Team Productivity: Eliminated manual build and deployment overhead, allowing artists and designers to focus on creative work
  • Institutional Impact: Jenkins libraries and practices adopted by multiple BUAS teams for their capstone projects
  • Steam Integration Excellence: Seamless Steam Input API implementation and automated depot management
  • Professional Development Process: Established industry-standard DevOps practices in academic environment

Technologies & Tools Used

  • CI/CD: Jenkins with custom Groovy libraries, Windows build agents, and Unreal Engine integration
  • Version Control: Perforce with automated workspace management and changelist synchronization
  • Steam Integration: SteamWorks SDK, Steam Input API, SteamCMD for automated depot deployment
  • Testing: Unreal Engine Automation Framework with custom result parsing and XML generation
  • Communication: Discord webhooks with rich embed formatting and automated notifications
  • Build Tools: Unreal Automation Tool (UAT), cross-platform packaging, and asset validation
  • Backup Systems: Google Drive integration for build artifacts and emergency deployment fallback

Experience the Result

All this infrastructure work enabled our team to successfully ship a commercial game. The DevOps foundation allowed creators to focus on crafting an engaging puzzle experience.