Skip to main content

How I Set Up GitHub Collaboration and CI/CD with GitHub Actions for our Unity Game Project

Transitioning to GitHub collaboration and CI/CD for "Masters of Mischief" was a game-changer. It all started with the frustration of the old-school ZIP file transfers among developers, waiting for one another to finish their tasks before diving in. That approach was inefficient, to say the least. So, we decided to bid farewell to that headache and revamp our workflow.

Sure thing! Got the new ZIP file from the developer with the latest updates.

I've set up a public GitHub repository because we need to use Github Actions for CI/CD and I didn't want to bother with free minute limits and what not, for now.

Branching Strategy:

Our first step was to set up a structured branching model. We divided our repository into three main branches:

Production Branch: This served as our final main branch. Any push to the production branch triggered a production build of the game using GitHub Actions.

Dev Branch: Acting as the base branch for ongoing development, the dev branch was where developers collaborated and merged their feature branches.

Feature Branches: Each new feature or bug fix got its own dedicated feature branch. This allowed for focused development and smoother code reviews.

Fig 1. Github repository

User Flow:

With our branching strategy in place, we streamlined our version control process:

Clone Repository: Developers cloned the remote repository to their local machines.

🟢 Clone remote repository 🟫 Terminal
mandeep@Masters-Of-Mischief %:
git clone https://github.com/koiralamandip/UnityMastersOfMischief.git

Switch to Dev Branch: They switched to the dev branch to start with and always ensured up-to-date dev branch before working on a new feature.

🟢 Switch to development base 🟫 Terminal
mandeep@Masters-Of-Mischief %:
git checkout dev
mandeep@Masters-Of-Mischief %:
git pull origin dev

Create Feature Branch: From the dev branch, developers created a new feature branch.

🟢 Create Feature Branch 🟫 Terminal
mandeep@Masters-Of-Mischief %:
git branch branch_auth
mandeep@Masters-Of-Mischief %:
git checkout branch_auth

Work on Feature: Developers implemented the desired feature or fix within their feature branch.

Push Changes: After completing their work, developers pushed their changes to the remote repository.

🟢 Push the changes 🟫 Terminal
mandeep@Masters-Of-Mischief %:
git add .
mandeep@Masters-Of-Mischief %:
git commit -m "Added authentication feature in Unity and created Scene"
mandeep@Masters-Of-Mischief %:
git push --set-upstream origin branch_auth

Pull Request: Upon pushing changes, developers created a pull request from their feature branch to the dev branch, initiating the code review process.

Merge and Sync: Once approved, the pull request was merged into the dev branch, keeping the codebase up-to-date. Developers regularly pulled from the dev branch to sync their local repositories.

Merge to Production: After thorough testing and ensuring stability, features were merged into the production branch, triggering a production build.

GitHub Actions Workflow:

To automate our CI/CD pipeline, we leveraged GitHub Actions. Our workflow was defined in a YAML file (main.yml) located within the .github/workflows directory at the root of our project.

Fig 2. Github Actions workflow

Managing a large Unity project comes with its challenges, especially when it comes to version control and managing what gets pushed to the remote repository. To address this, we incorporated a .gitignore file in the project root. This file specifies which files and folders should be ignored by Git, preventing them from being included in the staging area and ultimately in the remote repository.

If you're unfamiliar with .gitignore files or need a starting point, you can find templates tailored for various configurations, including Unity projects, on platforms like gitignore.io. Simply search for "Unity" and copy the content into a .gitignore file in your project directory.

Fig 3. Gitignore repository

With the .gitignore file in place, our repository was properly set up to exclude unnecessary files and folders. The next step was to integrate GitHub Actions into the main branch to automate the production build process upon every push.

To accomplish this, we created a directory structure at the root of the project as follows, and we had to create the exact path structure and naming for GitHub actions to work:

🟧 Directory structure
-
.github /
-
workflows /
*
main.yml

Inside the directory, I created a YML file named main.yml. This file defined our GitHub Actions workflow, specifically targeting the production branch for triggers.Here is the file.

🟢 main.yml file 🟨 YML 🟦 Github
name: Build Unity Project
'on':
  push:
    branches:
      - production
jobs:
  buildForAllSupportedPlatforms:
    name: 'Build for ${{ matrix.targetPlatform }}'
    if: github.ref == 'refs/heads/production'
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        targetPlatform:
          - StandaloneWindows64
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          lfs: true
      - uses: actions/cache@v3
        with:
          path: Library
          key: 'Library-${{ matrix.targetPlatform }}'
          restore-keys: Library-
      - if: matrix.targetPlatform == 'Android'
        uses: jlumbroso/free-disk-space@v1.3.1
      - uses: game-ci/unity-builder@v4
        env:
          UNITY_LICENSE: '${{ secrets.UNITY_LICENSE }}'
          UNITY_EMAIL: '${{ secrets.UNITY_EMAIL }}'
          UNITY_PASSWORD: '${{ secrets.UNITY_PASSWORD }}'
        with:
          targetPlatform: '${{ matrix.targetPlatform }}'
      - uses: actions/upload-artifact@v3
        with:
          name: 'Build-${{ matrix.targetPlatform }}'
          path: 'build/${{ matrix.targetPlatform }}'

The workflow, titled "Build Unity Project," was designed to execute a job named `buildForAllSupportedPlatforms` on every push to the main branch. However, given the platform preferences of our developers, we opted to focus the build process solely on `StandaloneWindows64`.

It's important to note that Unity requires verification of your license to build the project. For this reason, we set up secrets (UNITY_LICENSE, UNITY_EMAIL, UNITY_PASSWORD) in the GitHub repository, containing the necessary credentials. 

If you're using a Mac, you can find your Unity personal license at:

🟧 Directory structure
-
~/Library /
-
Application Support /
-
Unity /
*
Unity_lic.ulf

Simply copy the contents of this file into the UNITY_LICENSE secret. The UNITY_EMAIL and UNITY_PASSWORD secrets correspond to your Unity login credentials.

For a detailed guide on obtaining and adding Unity secrets, as well as configuring the workflow YAML file for Unity builds, refer to the resources linked below:

1. Get and add Unity secrets 

2. Workflow .yml for Unity build

Comments

Popular posts from this blog

Implement Authentication (in Unity) | Link and Unlink account using PlayerPrefs

In this blog post, we'll delve into the process of implementing authentication in Unity, along with user account linking and unlinking using PlayerPrefs. Let's break down each step, from setting up the UI canvas to managing player data effectively.

Creating and Hosting the Game Backend using Node.js in Render

This is the first development blog post in a series  for "Masters of Mischief".  This post specifically is about the development of a backend for our 3D multiplayer game.