Skip to content

CI/CD - Run Tests & Build Project #682

CI/CD - Run Tests & Build Project

CI/CD - Run Tests & Build Project #682

name: CI/CD - Run Tests & Build Project
on:
workflow_dispatch:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
schedule:
- cron: "0 0 * * *" # run daily at midnight (UTC)
jobs:
runtime-tests:
name: Runtime Tests (IL2CPP)
runs-on: ubuntu-latest
env:
RUNTIME_TEST_IMAGE: 'unityci/editor:ubuntu-6000.0.63f1-linux-il2cpp-3.2.2'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Git
run: git config --global --add safe.directory /github/workspace
- name: Free Disk space
uses: jlumbroso/free-disk-space@v1.2.0
with:
dotnet: false
- name: Remove assemblies incompatible with linux-il2cpp image
run: |
rm -rf Assets/Plugins/StreamChat/SampleProject
rm -rf Assets/Plugins/StreamChat/Samples
# The repo intentionally does not track Packages/manifest.json so the
# legacy Unity 2020/2021 build job can fall back to its image's default
# manifest. The IL2CPP runtime test job runs on Unity 6000.0 and must
# pin its own packages (notably com.unity.test-framework for NUnit).
- name: Install runtime-tests Packages/manifest.json
run: |
mkdir -p Packages
cp .github/workflows/manifests/runtime-tests.manifest.json Packages/manifest.json
rm -f Packages/packages-lock.json
- name: Prepare project for IL2CPP runtime tests
uses: game-ci/unity-builder@v4
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
with:
buildMethod: StreamChat.EditorTools.StreamEditorTools.PrepareStandaloneIL2CPPTests
customImage: ${{ env.RUNTIME_TEST_IMAGE }}
allowDirtyBuild: true
- name: Remove editor-only test assemblies before player build
run: |
rm -rf Assets/Plugins/StreamChat/EditorTools
rm -rf Assets/Plugins/StreamChat/Tests/StreamChat.Tests.asmdef
rm -rf Assets/Plugins/StreamChat/Tests/LowLevelClient
rm -rf Assets/Plugins/StreamChat/Tests/StatefulClient
rm -rf Assets/Plugins/StreamChat/Tests/StreamTestClients.cs
rm -rf Assets/Plugins/StreamChat/Tests/TestUtils.cs
rm -rf Assets/Plugins/StreamChat/Tests/ToolsTests.cs
rm -rf Assets/Plugins/StreamChat/Tests/UnityTestRunnerCallbacks.cs
rm -rf Assets/Plugins/StreamChat/Tests/UnityTestUtils.cs
- name: Debug - inspect NUnit and test framework state
run: |
echo "=== Runtime test asmdef ==="
cat Assets/Plugins/StreamChat/Tests/Runtime/StreamChat.Tests.Runtime.asmdef
echo ""
echo "=== Packages/manifest.json (test-framework entry) ==="
grep -i "test-framework" Packages/manifest.json || echo "NOT FOUND in manifest"
echo ""
echo "=== Packages/packages-lock.json (test-framework entry) ==="
grep -A5 "test-framework" Packages/packages-lock.json 2>/dev/null || echo "No packages-lock.json"
echo ""
echo "=== Find nunit.framework.dll anywhere in project ==="
find . -name "nunit.framework.dll" -type f 2>/dev/null || echo "NOT FOUND"
echo ""
echo "=== Find nunit.framework.dll in Unity install ==="
find /opt/unity -name "nunit.framework.dll" -type f 2>/dev/null || echo "NOT FOUND in /opt/unity"
echo ""
echo "=== Find nunit.framework.dll in package cache ==="
find Library/PackageCache -name "nunit.framework.dll" -type f 2>/dev/null || echo "NOT FOUND in PackageCache"
echo ""
echo "=== nunit.framework.dll.meta (if found) ==="
for f in $(find . Library/PackageCache /opt/unity -name "nunit.framework.dll.meta" -type f 2>/dev/null); do
echo "--- $f ---"
cat "$f"
done
echo ""
echo "=== ProjectSettings scripting defines ==="
grep -A2 "scriptingDefineSymbols" ProjectSettings/ProjectSettings.asset || echo "NOT FOUND"
echo ""
echo "=== Remaining test assembly files ==="
find Assets/Plugins/StreamChat/Tests -type f -name "*.cs" -o -name "*.asmdef" | sort
- name: Run runtime tests in IL2CPP player
uses: game-ci/unity-test-runner@v4
id: runtime_tests
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
testMode: playmode
customImage: ${{ env.RUNTIME_TEST_IMAGE }}
customParameters: -testPlatform StandaloneLinux64
allowDirtyBuild: true
timeout-minutes: 90
- name: Upload Runtime Test Results
uses: actions/upload-artifact@v4
if: always()
with:
name: Runtime_Test_Results_IL2CPP
path: artifacts
- name: Notify Slack if failed
uses: voxmedia/github-action-slack-notify-build@v1
if: always() && failure()
with:
channel_id: C07KW7ZCJ6T
color: danger
status: "RUNTIME TESTS FAILED (IL2CPP)"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_NOTIFICATIONS_BOT_TOKEN }}
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target_platform: [android, ios]
unity_version: [2020, 2021]
dotnet_version: [NET_4_x, STANDARD_2_x]
compiler: [mono, il2cpp]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Calculate Sequential Index
id: calculate-index
run: |
target_index=$([[ "${{ matrix.target_platform }}" == 'android' ]] && echo '0' || echo '1')
unity_index=$([[ "${{ matrix.unity_version }}" == '2020' ]] && echo '0' || echo '1')
dotnet_index=$([[ "${{ matrix.dotnet_version }}" == 'NET_4_x' ]] && echo '0' || echo '1')
compiler_index=$([[ "${{ matrix.compiler }}" == 'mono' ]] && echo '0' || echo '1')
index=$((target_index * 1 + unity_index * 2 + dotnet_index * 4 + compiler_index * 8))
echo "SEQUENTIAL_INDEX=$index" >> $GITHUB_ENV
- name: Print Sequential Index
run: |
echo "Sequential Index: $SEQUENTIAL_INDEX"
- name: Install Git
run: git config --global --add safe.directory /github/workspace
- name: Install dependencies (Linux)
if: runner.os == 'Linux'
run: sudo apt-get update
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew update
- name: Install dependencies (Linux)
if: runner.os == 'Linux'
run: sudo apt-get install -y libxtst6 libgtk-3-0
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install --cask adoptopenjdk
brew install gtk+3
- name: Determine Docker Image
id: dockerImageSelector
run: |
if [ "${{ matrix.unity_version }}" == '2020' ]; then
if [ "${{ matrix.target_platform }}" == 'android' ]; then
TAG='unityci/editor:ubuntu-2020.3.40f1-android-3.1.0'
elif [ "${{ matrix.target_platform }}" == 'ios' ]; then
TAG='unityci/editor:ubuntu-2020.3.40f1-ios-3.1.0'
else
echo "Unsupported platform"
exit 1
fi
elif [ "${{ matrix.unity_version }}" == '2021' ]; then
if [ "${{ matrix.target_platform }}" == 'android' ]; then
TAG='unityci/editor:ubuntu-2021.3.36f1-android-3.1.0'
elif [ "${{ matrix.target_platform }}" == 'ios' ]; then
TAG='unityci/editor:ubuntu-2021.3.36f1-ios-3.1.0'
else
echo "Unsupported platform"
exit 1
fi
else
echo "Unsupported Unity version"
exit 1
fi
echo "DOCKER_TAG=$TAG" >> $GITHUB_ENV
- name: Echo Docker Image
run: |
echo ${{ env.DOCKER_TAG }}
- name: Determine Build Name
run: |
RUNNER_ID="${{ matrix.unity_version }}_${{ matrix.target_platform }}_${{ matrix.compiler }}_${{ matrix.dotnet_version }}"
if [ "${{ matrix.target_platform }}" == "android" ]; then
BUILD_NAME="${RUNNER_ID}.apk"
elif [ "${{ matrix.target_platform }}" == "ios" ]; then
BUILD_NAME="${RUNNER_ID}.ipa"
else
echo "Unsupported platform"
exit 1
fi
echo "RUNNER_ID=$RUNNER_ID" >> $GITHUB_ENV
echo "BUILD_NAME=$BUILD_NAME" >> $GITHUB_ENV
- name: Enable Tests
uses: game-ci/unity-builder@v4
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
with:
buildMethod: StreamChat.EditorTools.StreamEditorTools.EnableStreamTestsEnabledCompilerFlag
customImage: ${{ env.DOCKER_TAG }}
- name: Run Tests (Attempt 1)
id: run_tests_1
uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
customParameters: -streamBase64TestDataSet "${{ secrets.STREAM_AUTH_TEST_DATA_BASE64 }}" -testDataSetIndex ${{ env.SEQUENTIAL_INDEX }}
customImage: ${{ env.DOCKER_TAG }}
timeout-minutes: 40
continue-on-error: true
- name: Run Tests (Attempt 2)
id: run_tests_2
if: steps.run_tests_1.outcome == 'failure'
uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
customParameters: -streamBase64TestDataSet "${{ secrets.STREAM_AUTH_TEST_DATA_BASE64 }}" -testDataSetIndex ${{ env.SEQUENTIAL_INDEX }}
customImage: ${{ env.DOCKER_TAG }}
timeout-minutes: 50
continue-on-error: true
- name: Run Tests (Attempt 3)
id: run_tests_3
if: steps.run_tests_2.outcome == 'failure'
uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
customParameters: -streamBase64TestDataSet "${{ secrets.STREAM_AUTH_TEST_DATA_BASE64 }}" -testDataSetIndex ${{ env.SEQUENTIAL_INDEX }}
customImage: ${{ env.DOCKER_TAG }}
timeout-minutes: 60
continue-on-error: true
- name: Run Tests (Attempt 4)
id: run_tests_4
if: steps.run_tests_3.outcome == 'failure'
uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
customParameters: -streamBase64TestDataSet "${{ secrets.STREAM_AUTH_TEST_DATA_BASE64 }}" -testDataSetIndex ${{ env.SEQUENTIAL_INDEX }}
customImage: ${{ env.DOCKER_TAG }}
timeout-minutes: 60
continue-on-error: true
- name: Run Tests (Attempt 5)
id: run_tests_5
if: steps.run_tests_4.outcome == 'failure'
uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
customParameters: -streamBase64TestDataSet "${{ secrets.STREAM_AUTH_TEST_DATA_BASE64 }}" -testDataSetIndex ${{ env.SEQUENTIAL_INDEX }}
customImage: ${{ env.DOCKER_TAG }}
timeout-minutes: 60
- name: Upload Test Results as Artifact
uses: actions/upload-artifact@v4
with:
name: Test_Results_${{ env.RUNNER_ID }}
path: artifacts
- name: Free Disk space
uses: jlumbroso/free-disk-space@v1.2.0
if: matrix.target_platform == 'android' || matrix.target_platform == 'ios'
with:
dotnet: false
- name: List changes
run: |
git diff
- name: Build Sample Project
uses: game-ci/unity-builder@v4
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
with:
buildMethod: StreamChat.EditorTools.StreamEditorTools.BuildSampleApp
customParameters: -streamBase64TestDataSet ${{ secrets.STREAM_AUTH_TEST_DATA_BASE64 }} -testDataSetIndex ${{ env.SEQUENTIAL_INDEX }} -apiCompatibility ${{ matrix.dotnet_version }} -scriptingBackend ${{ matrix.compiler }} -buildTargetPlatform ${{ matrix.target_platform }} -buildTargetPath $(pwd)/SampleAppBuild/${{ env.BUILD_NAME }}
customImage: ${{ env.DOCKER_TAG }}
allowDirtyBuild: true #Needed because the import process may update ProjectSettings
- name: Upload Build as Artifact
uses: actions/upload-artifact@v4
with:
name: Build_${{ env.BUILD_NAME }}
path: $(pwd)/SampleAppBuild/${{ env.BUILD_NAME }}
- name: Notify Slack if failed
uses: voxmedia/github-action-slack-notify-build@v1
if: always() && failure()
with:
channel_id: C07KW7ZCJ6T
color: danger
status: FAILED
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_NOTIFICATIONS_BOT_TOKEN }}