Skip to content

feat: wire UnityRetryService into the local provider's build retry (opt-in) #22

feat: wire UnityRetryService into the local provider's build retry (opt-in)

feat: wire UnityRetryService into the local provider's build retry (opt-in) #22

name: Orchestrator Engine Smoke Tests
# Port of plugins/orchestrator/.github/workflows/engine-smoke-test.yml,
# inert as a nested workflow. Distinct from root's own "Engine Smoke
# Tests" (engine-smoke-test.yml) - that one validates the CLI's built-in
# unity/godot/unreal plugins directly; this one validates the same
# engines dispatched THROUGH the orchestrator provider system. No secrets
# required - Docker-in-Docker against public third-party images only.
on:
push:
branches: [main, 'release/**', 'feat/**']
paths:
- 'plugins/orchestrator/**'
- '.github/workflows/orchestrator-engine-smoke-test.yml'
pull_request:
branches: [main, 'release/**']
paths:
- 'plugins/orchestrator/**'
- '.github/workflows/orchestrator-engine-smoke-test.yml'
workflow_dispatch:
inputs:
godot-version:
description: 'Godot version tag for barichello/godot-ci image'
required: false
default: '4.3'
unreal-image:
description: 'Real UE Docker image for full build test (leave empty to use CI stub)'
required: false
default: ''
defaults:
run:
working-directory: plugins/orchestrator
jobs:
# ─── Godot — actual project export using third-party image ─────
godot-build:
name: Godot build (barichello/godot-ci)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Export Godot project
run: |
GODOT_VERSION="${{ github.event.inputs.godot-version || '4.3' }}"
echo "Building with barichello/godot-ci:${GODOT_VERSION}"
mkdir -p test-projects/godot-minimal/build
docker run --rm \
-v "${{ github.workspace }}/plugins/orchestrator/test-projects/godot-minimal:/project" \
-w /project \
"barichello/godot-ci:${GODOT_VERSION}" \
bash -c '
echo "=== Godot $(godot --headless --version) ==="
mkdir -p build
# Try export first, fall back to import validation
godot --headless --verbose --export-release "Linux/X11" build/game.x86_64 2>&1 || \
godot --headless --verbose --export-release "Linux" build/game.x86_64 2>&1 || {
echo "Export preset not matched — validating project import instead"
godot --headless --import 2>&1
}
echo "=== Build artifacts ==="
ls -la build/ 2>/dev/null || echo "(import-only mode)"
echo "=== DONE ==="
'
- name: Verify build output
run: |
if [ -f test-projects/godot-minimal/build/game.x86_64 ]; then
echo "Godot export produced binary — full build success"
ls -la test-projects/godot-minimal/build/
else
echo "Godot import validation passed (no export binary in minimal project)"
fi
# ─── Godot — orchestrator integration ──────────────────────────
godot-orchestrator:
name: Godot orchestrator integration
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install package manager (from package.json)
run: |
corepack enable
corepack install
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Resolve yarn cache folder
id: yarn-config
run: echo "cacheFolder=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
- name: Restore yarn install cache (node_modules + cacheFolder + install-state)
uses: actions/cache@v4
with:
path: |
plugins/orchestrator/node_modules
${{ steps.yarn-config.outputs.cacheFolder }}
plugins/orchestrator/.yarn/install-state.gz
key: yarn-${{ runner.os }}-node-'20'-${{ hashFiles('plugins/orchestrator/yarn.lock') }}
restore-keys: |
yarn-${{ runner.os }}-node-'20'-
- run: yarn install --immutable
- run: yarn build
- name: Verify built-in Godot engine plugin
run: |
node -e "
const { initEngine, getEngine } = require('./dist/model/engine');
initEngine('godot');
const e = getEngine();
if (e.name !== 'godot') throw new Error('wrong engine');
if (!e.cacheFolders.includes('.godot/imported')) throw new Error('missing cache');
console.log('Godot plugin:', e.name, 'cache:', e.cacheFolders);
"
- name: Dispatch Godot version check via orchestrator
run: |
GODOT_VERSION="${{ github.event.inputs.godot-version || '4.3' }}"
RESPONSE=$(echo '{"command":"run-task","params":{"buildGuid":"godot-smoke","image":"barichello/godot-ci:'"${GODOT_VERSION}"'","commands":"godot --headless --version","mountdir":"/build","workingdir":"/build","environment":[],"secrets":[]}}' | \
node dist/cli.js serve \
--provider-strategy local-docker \
--engine godot \
--project-path test-projects/godot-minimal \
2>godot-stderr.log | tail -1) || true
echo "Response: ${RESPONSE}"
cat godot-stderr.log 2>/dev/null || true
# ─── UE — build with CI stub (validates full pipeline) ─────────
unreal-stub-build:
name: UE build (CI stub)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build UE CI stub image
run: |
docker build \
-t game-ci/ue-stub:latest \
-f test-projects/unreal-minimal/Dockerfile.ci-stub \
test-projects/unreal-minimal/
- name: Build Unreal project with stub
run: |
docker run --rm \
-v "${{ github.workspace }}/plugins/orchestrator/test-projects/unreal-minimal:/build" \
-w /build \
game-ci/ue-stub:latest \
/home/ue4/UnrealEngine/Engine/Build/BatchFiles/RunUAT.sh \
BuildCookRun \
-project=/build/MinimalTest.uproject \
-targetplatform=Linux \
-clientconfig=Shipping \
-build -cook -stage -pak -archive \
-archivedirectory=/build/output \
-noP4 -unattended
- name: Verify UE build artifacts
run: |
echo "=== Build output ==="
cat test-projects/unreal-minimal/output/build-manifest.json
node -e "
const m = require('./test-projects/unreal-minimal/output/build-manifest.json');
if (m.engine !== 'unreal') throw new Error('wrong engine');
if (m.engineVersion !== '5.4') throw new Error('wrong version');
console.log('UE stub build verified:', JSON.stringify(m));
"
# ─── UE — orchestrator integration ─────────────────────────────
unreal-orchestrator:
name: UE orchestrator integration
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install package manager (from package.json)
run: |
corepack enable
corepack install
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Resolve yarn cache folder
id: yarn-config
run: echo "cacheFolder=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
- name: Restore yarn install cache (node_modules + cacheFolder + install-state)
uses: actions/cache@v4
with:
path: |
plugins/orchestrator/node_modules
${{ steps.yarn-config.outputs.cacheFolder }}
plugins/orchestrator/.yarn/install-state.gz
key: yarn-${{ runner.os }}-node-'20'-${{ hashFiles('plugins/orchestrator/yarn.lock') }}
restore-keys: |
yarn-${{ runner.os }}-node-'20'-
- run: yarn install --immutable
- run: yarn build
- name: Verify built-in Unreal engine plugin
run: |
node -e "
const { initEngine, getEngine } = require('./dist/model/engine');
initEngine('unreal');
const e = getEngine();
if (e.name !== 'unreal') throw new Error('wrong engine');
console.log('UE plugin:', e.name, 'cache:', e.cacheFolders);
"
- name: Test serve protocol with Unreal engine
run: |
RESPONSE=$(echo '{"command":"list-resources","params":{}}' | \
node dist/cli.js serve \
--provider-strategy test \
--engine unreal \
--project-path test-projects/unreal-minimal \
2>/dev/null | tail -1) || true
echo "Response: ${RESPONSE}"
echo "${RESPONSE}" | node -e "
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8'));
if (!('success' in d)) throw new Error('bad protocol response');
"
# ─── UE — real image build (manual trigger) ────────────────────
unreal-real-build:
name: UE build (real image)
runs-on: ubuntu-latest
if: github.event.inputs.unreal-image != ''
steps:
- uses: actions/checkout@v4
- name: Pull and build with real UE image
run: |
UE_IMAGE="${{ github.event.inputs.unreal-image }}"
echo "Pulling: ${UE_IMAGE}"
docker pull "${UE_IMAGE}"
docker run --rm \
-v "${{ github.workspace }}/plugins/orchestrator/test-projects/unreal-minimal:/build" \
-w /build \
"${UE_IMAGE}" \
bash -c "echo 'UE container running' && ls / && echo 'SUCCESS'"
# ─── Protocol Integration Test ─────────────────────────────────
serve-protocol-test:
name: Serve protocol integration test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install package manager (from package.json)
run: |
corepack enable
corepack install
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Resolve yarn cache folder
id: yarn-config
run: echo "cacheFolder=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
- name: Restore yarn install cache (node_modules + cacheFolder + install-state)
uses: actions/cache@v4
with:
path: |
plugins/orchestrator/node_modules
${{ steps.yarn-config.outputs.cacheFolder }}
plugins/orchestrator/.yarn/install-state.gz
key: yarn-${{ runner.os }}-node-'20'-${{ hashFiles('plugins/orchestrator/yarn.lock') }}
restore-keys: |
yarn-${{ runner.os }}-node-'20'-
- run: yarn install --immutable
- run: yarn build
- name: Test all serve subcommands
run: |
COMMANDS=("list-resources" "list-workflow" "watch-workflow" "garbage-collect")
for cmd in "${COMMANDS[@]}"; do
echo "Testing: ${cmd}"
RESPONSE=$(echo "{\"command\":\"${cmd}\",\"params\":{}}" | \
node dist/cli.js serve --provider-strategy test 2>/dev/null | tail -1) || true
echo " ${RESPONSE}"
echo "${RESPONSE}" | node -e "
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8'));
if (!('success' in d)) process.exit(1);
" || { echo "FAIL: ${cmd}"; exit 1; }
done
- name: Test error handling
run: |
for input in "" "not json" '{"params":{}}'; do
RESPONSE=$(echo "${input}" | node dist/cli.js serve --provider-strategy test 2>/dev/null | tail -1) || true
echo "${RESPONSE}" | grep -q '"success":false' || { echo "FAIL for input: '${input}'"; exit 1; }
done
echo "Error handling OK"