Workflow cleanup (#568)
* Remove unused GitHub workflow files * Allow Unity workflows to run in forks Also adjust Claude NL suite licensing checks so it can run in the top-level repo.main
parent
10e93b8548
commit
a4f74dab43
|
|
@ -1,637 +0,0 @@
|
|||
name: Claude GameObject API Tests (Unity live)
|
||||
|
||||
on: [workflow_dispatch]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
UNITY_IMAGE: unityci/editor:ubuntu-2021.3.45f2-linux-il2cpp-3
|
||||
|
||||
jobs:
|
||||
go-suite:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
JUNIT_OUT: reports/junit-go-suite.xml
|
||||
MD_OUT: reports/junit-go-suite.md
|
||||
|
||||
steps:
|
||||
# ---------- Secrets check ----------
|
||||
- name: Detect secrets (outputs)
|
||||
id: detect
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
run: |
|
||||
set -e
|
||||
if [ -n "$ANTHROPIC_API_KEY" ]; then echo "anthropic_ok=true" >> "$GITHUB_OUTPUT"; else echo "anthropic_ok=false" >> "$GITHUB_OUTPUT"; fi
|
||||
if [ -n "$UNITY_LICENSE" ] || { [ -n "$UNITY_EMAIL" ] && [ -n "$UNITY_PASSWORD" ]; }; then
|
||||
echo "unity_ok=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "unity_ok=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# ---------- Python env for MCP server (uv) ----------
|
||||
- uses: astral-sh/setup-uv@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install MCP server
|
||||
run: |
|
||||
set -eux
|
||||
uv venv
|
||||
echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/.venv" >> "$GITHUB_ENV"
|
||||
echo "$GITHUB_WORKSPACE/.venv/bin" >> "$GITHUB_PATH"
|
||||
if [ -f Server/pyproject.toml ]; then
|
||||
uv pip install -e Server
|
||||
elif [ -f Server/requirements.txt ]; then
|
||||
uv pip install -r Server/requirements.txt
|
||||
else
|
||||
echo "No MCP Python deps found (skipping)"
|
||||
fi
|
||||
|
||||
# --- Licensing ---
|
||||
- name: Decide license sources
|
||||
id: lic
|
||||
shell: bash
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
run: |
|
||||
set -eu
|
||||
use_ulf=false; use_ebl=false
|
||||
[[ -n "${UNITY_LICENSE:-}" ]] && use_ulf=true
|
||||
[[ -n "${UNITY_EMAIL:-}" && -n "${UNITY_PASSWORD:-}" ]] && use_ebl=true
|
||||
echo "use_ulf=$use_ulf" >> "$GITHUB_OUTPUT"
|
||||
echo "use_ebl=$use_ebl" >> "$GITHUB_OUTPUT"
|
||||
echo "has_serial=$([[ -n "${UNITY_SERIAL:-}" ]] && echo true || echo false)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Stage Unity .ulf license (from secret)
|
||||
if: steps.lic.outputs.use_ulf == 'true'
|
||||
id: ulf
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
mkdir -p "$RUNNER_TEMP/unity-license-ulf" "$RUNNER_TEMP/unity-local/Unity"
|
||||
f="$RUNNER_TEMP/unity-license-ulf/Unity_lic.ulf"
|
||||
if printf "%s" "$UNITY_LICENSE" | base64 -d - >/dev/null 2>&1; then
|
||||
printf "%s" "$UNITY_LICENSE" | base64 -d - > "$f"
|
||||
else
|
||||
printf "%s" "$UNITY_LICENSE" > "$f"
|
||||
fi
|
||||
chmod 600 "$f" || true
|
||||
if head -c 100 "$f" | grep -qi '<\?xml'; then
|
||||
mkdir -p "$RUNNER_TEMP/unity-config/Unity/licenses"
|
||||
mv "$f" "$RUNNER_TEMP/unity-config/Unity/licenses/UnityEntitlementLicense.xml"
|
||||
echo "ok=false" >> "$GITHUB_OUTPUT"
|
||||
elif grep -qi '<Signature>' "$f"; then
|
||||
cp -f "$f" "$RUNNER_TEMP/unity-local/Unity/Unity_lic.ulf"
|
||||
echo "ok=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "ok=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Activate Unity (EBL via container - host-mount)
|
||||
if: steps.lic.outputs.use_ebl == 'true'
|
||||
shell: bash
|
||||
env:
|
||||
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$RUNNER_TEMP/unity-config" "$RUNNER_TEMP/unity-local"
|
||||
docker run --rm --network host \
|
||||
-e HOME=/root \
|
||||
-e UNITY_EMAIL -e UNITY_PASSWORD -e UNITY_SERIAL \
|
||||
-v "$RUNNER_TEMP/unity-config:/root/.config/unity3d" \
|
||||
-v "$RUNNER_TEMP/unity-local:/root/.local/share/unity3d" \
|
||||
"$UNITY_IMAGE" bash -lc '
|
||||
set -euxo pipefail
|
||||
if [[ -n "${UNITY_SERIAL:-}" ]]; then
|
||||
/opt/unity/Editor/Unity -batchmode -nographics -logFile - \
|
||||
-username "$UNITY_EMAIL" -password "$UNITY_PASSWORD" -serial "$UNITY_SERIAL" -quit || true
|
||||
else
|
||||
/opt/unity/Editor/Unity -batchmode -nographics -logFile - \
|
||||
-username "$UNITY_EMAIL" -password "$UNITY_PASSWORD" -quit || true
|
||||
fi
|
||||
ls -la /root/.config/unity3d/Unity/licenses || true
|
||||
'
|
||||
|
||||
if ! find "$RUNNER_TEMP/unity-config" -type f -iname "*.xml" | grep -q .; then
|
||||
if [[ "${{ steps.ulf.outputs.ok }}" == "true" ]]; then
|
||||
echo "EBL entitlement not found; proceeding with ULF-only (ok=true)."
|
||||
else
|
||||
echo "No entitlement produced and no valid ULF; cannot continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------- Warm up project ----------
|
||||
- name: Warm up project (import Library once)
|
||||
if: steps.detect.outputs.anthropic_ok == 'true' && (steps.lic.outputs.use_ulf == 'true' || steps.lic.outputs.use_ebl == 'true')
|
||||
shell: bash
|
||||
env:
|
||||
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
|
||||
ULF_OK: ${{ steps.ulf.outputs.ok }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
manual_args=()
|
||||
if [[ "${ULF_OK:-false}" == "true" ]]; then
|
||||
manual_args=(-manualLicenseFile "/root/.local/share/unity3d/Unity/Unity_lic.ulf")
|
||||
fi
|
||||
docker run --rm --network host \
|
||||
-e HOME=/root \
|
||||
-v "${{ github.workspace }}:${{ github.workspace }}" -w "${{ github.workspace }}" \
|
||||
-v "$RUNNER_TEMP/unity-config:/root/.config/unity3d" \
|
||||
-v "$RUNNER_TEMP/unity-local:/root/.local/share/unity3d" \
|
||||
-v "$RUNNER_TEMP/unity-cache:/root/.cache/unity3d" \
|
||||
"$UNITY_IMAGE" /opt/unity/Editor/Unity -batchmode -nographics -logFile - \
|
||||
-projectPath "${{ github.workspace }}/TestProjects/UnityMCPTests" \
|
||||
"${manual_args[@]}" \
|
||||
-quit
|
||||
|
||||
# ---------- Clean old MCP status ----------
|
||||
- name: Clean old MCP status
|
||||
run: |
|
||||
set -eux
|
||||
mkdir -p "$GITHUB_WORKSPACE/.unity-mcp"
|
||||
rm -f "$GITHUB_WORKSPACE/.unity-mcp"/unity-mcp-status-*.json || true
|
||||
|
||||
# ---------- Start headless Unity ----------
|
||||
- name: Start Unity (persistent bridge)
|
||||
if: steps.detect.outputs.anthropic_ok == 'true' && (steps.lic.outputs.use_ulf == 'true' || steps.lic.outputs.use_ebl == 'true')
|
||||
shell: bash
|
||||
env:
|
||||
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
|
||||
ULF_OK: ${{ steps.ulf.outputs.ok }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
manual_args=()
|
||||
if [[ "${ULF_OK:-false}" == "true" ]]; then
|
||||
manual_args=(-manualLicenseFile "/root/.local/share/unity3d/Unity/Unity_lic.ulf")
|
||||
fi
|
||||
|
||||
mkdir -p "$GITHUB_WORKSPACE/.unity-mcp"
|
||||
docker rm -f unity-mcp >/dev/null 2>&1 || true
|
||||
docker run -d --name unity-mcp --network host \
|
||||
-e HOME=/root \
|
||||
-e UNITY_MCP_ALLOW_BATCH=1 \
|
||||
-e UNITY_MCP_STATUS_DIR="${{ github.workspace }}/.unity-mcp" \
|
||||
-e UNITY_MCP_BIND_HOST=127.0.0.1 \
|
||||
-v "${{ github.workspace }}:${{ github.workspace }}" -w "${{ github.workspace }}" \
|
||||
-v "$RUNNER_TEMP/unity-config:/root/.config/unity3d" \
|
||||
-v "$RUNNER_TEMP/unity-local:/root/.local/share/unity3d" \
|
||||
-v "$RUNNER_TEMP/unity-cache:/root/.cache/unity3d" \
|
||||
"$UNITY_IMAGE" /opt/unity/Editor/Unity -batchmode -nographics -logFile /root/.config/unity3d/Editor.log \
|
||||
-stackTraceLogType Full \
|
||||
-projectPath "${{ github.workspace }}/TestProjects/UnityMCPTests" \
|
||||
"${manual_args[@]}" \
|
||||
-executeMethod MCPForUnity.Editor.McpCiBoot.StartStdioForCi
|
||||
|
||||
# ---------- Wait for Unity bridge ----------
|
||||
- name: Wait for Unity bridge (robust)
|
||||
if: steps.detect.outputs.anthropic_ok == 'true' && (steps.lic.outputs.use_ulf == 'true' || steps.lic.outputs.use_ebl == 'true')
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
deadline=$((SECONDS+600))
|
||||
fatal_after=$((SECONDS+120))
|
||||
ok_pat='(Bridge|MCP(For)?Unity|AutoConnect).*(listening|ready|started|port|bound)'
|
||||
license_fatal='No valid Unity|License is not active|cannot load ULF|Signature element not found|Token not found|0 entitlement|Entitlement.*(failed|denied)|License (activation|return|renewal).*(failed|expired|denied)'
|
||||
|
||||
while [ $SECONDS -lt $deadline ]; do
|
||||
logs="$(docker logs unity-mcp 2>&1 || true)"
|
||||
port="$(jq -r '.unity_port // empty' "$GITHUB_WORKSPACE"/.unity-mcp/unity-mcp-status-*.json 2>/dev/null | head -n1 || true)"
|
||||
if [[ -n "${port:-}" ]] && timeout 1 bash -lc "exec 3<>/dev/tcp/127.0.0.1/$port"; then
|
||||
echo "Bridge ready on port $port"
|
||||
docker exec unity-mcp chmod -R a+rwx "$GITHUB_WORKSPACE/.unity-mcp" || chmod -R a+rwx "$GITHUB_WORKSPACE/.unity-mcp" || true
|
||||
exit 0
|
||||
fi
|
||||
if echo "$logs" | grep -qiE "$ok_pat"; then
|
||||
echo "Bridge ready (log markers)"
|
||||
docker exec unity-mcp chmod -R a+rwx "$GITHUB_WORKSPACE/.unity-mcp" || chmod -R a+rwx "$GITHUB_WORKSPACE/.unity-mcp" || true
|
||||
exit 0
|
||||
fi
|
||||
if [ $SECONDS -ge $fatal_after ] && echo "$logs" | grep -qiE "$license_fatal"; then
|
||||
echo "::error::Fatal licensing signal detected after warm-up"
|
||||
echo "$logs" | tail -n 200 | sed -E 's/((email|serial|license|password|token)[^[:space:]]*)/[REDACTED]/Ig'
|
||||
exit 1
|
||||
fi
|
||||
st="$(docker inspect -f '{{.State.Status}}' unity-mcp 2>/dev/null || true)"
|
||||
if [[ "$st" != "running" ]]; then
|
||||
echo "::error::Unity container exited during wait"; docker logs unity-mcp --tail 200 | sed -E 's/((email|serial|license|password|token)[^[:space:]]*)/[REDACTED]/Ig'
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "::error::Bridge not ready before deadline"
|
||||
docker logs unity-mcp --tail 200 | sed -E 's/((email|serial|license|password|token)[^[:space:]]*)/[REDACTED]/Ig'
|
||||
exit 1
|
||||
|
||||
- name: Pin Claude tool permissions
|
||||
run: |
|
||||
set -eux
|
||||
mkdir -p .claude
|
||||
cat > .claude/settings.json <<'JSON'
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"mcp__unity",
|
||||
"Edit(reports/**)",
|
||||
"MultiEdit(reports/**)"
|
||||
],
|
||||
"deny": [
|
||||
"Bash",
|
||||
"WebFetch",
|
||||
"WebSearch",
|
||||
"Task",
|
||||
"TodoWrite",
|
||||
"NotebookEdit",
|
||||
"NotebookRead"
|
||||
]
|
||||
}
|
||||
}
|
||||
JSON
|
||||
|
||||
- name: Prepare reports
|
||||
run: |
|
||||
set -eux
|
||||
rm -f reports/*.xml reports/*.md || true
|
||||
mkdir -p reports
|
||||
|
||||
- name: Create report skeletons
|
||||
run: |
|
||||
set -eu
|
||||
cat > "$JUNIT_OUT" <<'XML'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites><testsuite name="UnityMCP.GO-T" tests="1" failures="1" errors="0" skipped="0" time="0">
|
||||
<testcase name="GO-Suite.Bootstrap" classname="UnityMCP.GO-T">
|
||||
<failure message="bootstrap">Bootstrap placeholder; suite will append real tests.</failure>
|
||||
</testcase>
|
||||
</testsuite></testsuites>
|
||||
XML
|
||||
printf '# Unity GameObject API Test Results\n\n' > "$MD_OUT"
|
||||
|
||||
- name: Verify Unity bridge status
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
shopt -s nullglob
|
||||
status_files=("$GITHUB_WORKSPACE"/.unity-mcp/unity-mcp-status-*.json)
|
||||
if ((${#status_files[@]})); then
|
||||
first_status="${status_files[0]}"
|
||||
fname="$(basename "$first_status")"
|
||||
hash_part="${fname%.json}"; hash_part="${hash_part#unity-mcp-status-}"
|
||||
proj="$(jq -r '.project_name // empty' "$first_status" || true)"
|
||||
if [[ -n "${proj:-}" && -n "${hash_part:-}" ]]; then
|
||||
echo "UNITY_MCP_DEFAULT_INSTANCE=${proj}@${hash_part}" >> "$GITHUB_ENV"
|
||||
echo "Default instance set to ${proj}@${hash_part}"
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Write MCP config
|
||||
run: |
|
||||
set -eux
|
||||
mkdir -p .claude
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
workspace = os.environ["GITHUB_WORKSPACE"]
|
||||
default_inst = os.environ.get("UNITY_MCP_DEFAULT_INSTANCE", "").strip()
|
||||
|
||||
cfg = {
|
||||
"mcpServers": {
|
||||
"unity": {
|
||||
"args": [
|
||||
"run",
|
||||
"--active",
|
||||
"--directory",
|
||||
"Server",
|
||||
"mcp-for-unity",
|
||||
"--transport",
|
||||
"stdio",
|
||||
],
|
||||
"transport": {"type": "stdio"},
|
||||
"env": {
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
"MCP_LOG_LEVEL": "debug",
|
||||
"UNITY_PROJECT_ROOT": f"{workspace}/TestProjects/UnityMCPTests",
|
||||
"UNITY_MCP_STATUS_DIR": f"{workspace}/.unity-mcp",
|
||||
"UNITY_MCP_HOST": "127.0.0.1",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unity = cfg["mcpServers"]["unity"]
|
||||
if default_inst:
|
||||
unity["env"]["UNITY_MCP_DEFAULT_INSTANCE"] = default_inst
|
||||
if "--default-instance" not in unity["args"]:
|
||||
unity["args"] += ["--default-instance", default_inst]
|
||||
|
||||
runner_script = Path(".claude/run-unity-mcp.sh")
|
||||
workspace_path = Path(workspace)
|
||||
uv_candidate = workspace_path / ".venv" / "bin" / "uv"
|
||||
uv_cmd = uv_candidate.as_posix() if uv_candidate.exists() else "uv"
|
||||
script = textwrap.dedent(f"""\
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
LOG="{workspace}/.unity-mcp/mcp-server-startup-debug.log"
|
||||
mkdir -p "$(dirname "$LOG")"
|
||||
echo "" >> "$LOG"
|
||||
echo "[ $(date -Iseconds) ] Starting unity MCP server" >> "$LOG"
|
||||
exec {uv_cmd} "$@" 2>> "$LOG"
|
||||
""")
|
||||
runner_script.write_text(script)
|
||||
runner_script.chmod(0o755)
|
||||
|
||||
unity["command"] = runner_script.resolve().as_posix()
|
||||
|
||||
path = Path(".claude/mcp.json")
|
||||
path.write_text(json.dumps(cfg, indent=2) + "\n")
|
||||
print(f"Wrote {path} and {runner_script}")
|
||||
PY
|
||||
|
||||
# ---------- Run Claude GO pass ----------
|
||||
- name: Run Claude GO pass
|
||||
uses: anthropics/claude-code-base-action@beta
|
||||
if: steps.detect.outputs.anthropic_ok == 'true' && steps.detect.outputs.unity_ok == 'true'
|
||||
continue-on-error: true
|
||||
env:
|
||||
UNITY_MCP_DEFAULT_INSTANCE: ${{ env.UNITY_MCP_DEFAULT_INSTANCE }}
|
||||
with:
|
||||
use_node_cache: false
|
||||
prompt_file: .claude/prompts/nl-gameobject-suite.md
|
||||
mcp_config: .claude/mcp.json
|
||||
settings: .claude/settings.json
|
||||
allowed_tools: "mcp__unity,Edit(reports/**),MultiEdit(reports/**)"
|
||||
disallowed_tools: "Bash,WebFetch,WebSearch,Task,TodoWrite,NotebookEdit,NotebookRead"
|
||||
model: claude-haiku-4-5-20251001
|
||||
fallback_model: claude-sonnet-4-5-20250929
|
||||
append_system_prompt: |
|
||||
You are running the GameObject API tests.
|
||||
- Emit exactly GO-0, GO-1, GO-2, GO-3, GO-4, GO-5.
|
||||
- Write each to reports/${ID}_results.xml.
|
||||
- Stop after GO-5_results.xml is written.
|
||||
timeout_minutes: "25"
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
|
||||
# ---------- Backfill missing tests ----------
|
||||
- name: Backfill missing GO tests
|
||||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
import re
|
||||
|
||||
DESIRED = ["GO-0","GO-1","GO-2","GO-3","GO-4","GO-5"]
|
||||
seen = set()
|
||||
|
||||
def id_from_filename(p: Path):
|
||||
n = p.name
|
||||
m = re.match(r'GO-?(\d+)_results\.xml$', n, re.I)
|
||||
if m:
|
||||
return f"GO-{int(m.group(1))}"
|
||||
return None
|
||||
|
||||
for p in Path("reports").glob("*_results.xml"):
|
||||
fid = id_from_filename(p)
|
||||
if fid in DESIRED:
|
||||
seen.add(fid)
|
||||
|
||||
Path("reports").mkdir(parents=True, exist_ok=True)
|
||||
for d in DESIRED:
|
||||
if d in seen:
|
||||
continue
|
||||
frag = Path(f"reports/{d}_results.xml")
|
||||
tc = ET.Element("testcase", {"classname":"UnityMCP.GO-T", "name": d})
|
||||
fail = ET.SubElement(tc, "failure", {"message":"not produced"})
|
||||
fail.text = "The agent did not emit a fragment for this test."
|
||||
ET.ElementTree(tc).write(frag, encoding="utf-8", xml_declaration=False)
|
||||
print(f"backfill: {d}")
|
||||
PY
|
||||
|
||||
# ---------- Merge fragments into JUnit ----------
|
||||
- name: Assemble JUnit
|
||||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
import re, os
|
||||
|
||||
def localname(tag: str) -> str:
|
||||
return tag.rsplit('}', 1)[-1] if '}' in tag else tag
|
||||
|
||||
src = Path(os.environ.get('JUNIT_OUT', 'reports/junit-go-suite.xml'))
|
||||
if not src.exists():
|
||||
raise SystemExit(0)
|
||||
|
||||
tree = ET.parse(src)
|
||||
root = tree.getroot()
|
||||
suite = root.find('./*') if localname(root.tag) == 'testsuites' else root
|
||||
if suite is None:
|
||||
raise SystemExit(0)
|
||||
|
||||
def id_from_filename(p: Path):
|
||||
n = p.name
|
||||
m = re.match(r'GO-?(\d+)_results\.xml$', n, re.I)
|
||||
if m:
|
||||
return f"GO-{int(m.group(1))}"
|
||||
return None
|
||||
|
||||
fragments = sorted(Path('reports').glob('GO-*_results.xml'))
|
||||
added = 0
|
||||
|
||||
for frag in fragments:
|
||||
try:
|
||||
froot = ET.parse(frag).getroot()
|
||||
if localname(froot.tag) == 'testcase':
|
||||
suite.append(froot)
|
||||
added += 1
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not parse fragment {frag}: {e}")
|
||||
|
||||
if added:
|
||||
for tc in list(suite.findall('.//testcase')):
|
||||
if (tc.get('name') or '') == 'GO-Suite.Bootstrap':
|
||||
suite.remove(tc)
|
||||
testcases = suite.findall('.//testcase')
|
||||
failures_cnt = sum(1 for tc in testcases if (tc.find('failure') is not None or tc.find('error') is not None))
|
||||
suite.set('tests', str(len(testcases)))
|
||||
suite.set('failures', str(failures_cnt))
|
||||
suite.set('errors', '0')
|
||||
suite.set('skipped', '0')
|
||||
tree.write(src, encoding='utf-8', xml_declaration=True)
|
||||
print(f"Appended {added} testcase(s).")
|
||||
PY
|
||||
|
||||
# ---------- Build markdown summary ----------
|
||||
- name: Build markdown summary
|
||||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
import os, html, re
|
||||
|
||||
def localname(tag: str) -> str:
|
||||
return tag.rsplit('}', 1)[-1] if '}' in tag else tag
|
||||
|
||||
src = Path(os.environ.get('JUNIT_OUT', 'reports/junit-go-suite.xml'))
|
||||
md_out = Path(os.environ.get('MD_OUT', 'reports/junit-go-suite.md'))
|
||||
md_out.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if not src.exists():
|
||||
md_out.write_text("# Unity GameObject API Test Results\n\n(No JUnit found)\n", encoding='utf-8')
|
||||
raise SystemExit(0)
|
||||
|
||||
tree = ET.parse(src)
|
||||
root = tree.getroot()
|
||||
suite = root.find('./*') if localname(root.tag) == 'testsuites' else root
|
||||
cases = [] if suite is None else list(suite.findall('.//testcase'))
|
||||
|
||||
desired = ['GO-0','GO-1','GO-2','GO-3','GO-4','GO-5']
|
||||
default_titles = {
|
||||
'GO-0': 'Hierarchy with ComponentTypes',
|
||||
'GO-1': 'Find GameObjects Tool',
|
||||
'GO-2': 'GameObject Resource Read',
|
||||
'GO-3': 'Components Resource Read',
|
||||
'GO-4': 'Manage Components Tool',
|
||||
'GO-5': 'Deprecation Warnings',
|
||||
}
|
||||
|
||||
def id_from_case(tc):
|
||||
n = (tc.get('name') or '')
|
||||
m = re.match(r'\s*(GO-\d+)\b', n)
|
||||
if m:
|
||||
return m.group(1)
|
||||
return None
|
||||
|
||||
id_status = {}
|
||||
for tc in cases:
|
||||
tid = id_from_case(tc)
|
||||
if not tid or tid not in desired or tid in id_status:
|
||||
continue
|
||||
ok = (tc.find('failure') is None and tc.find('error') is None)
|
||||
id_status[tid] = ok
|
||||
|
||||
total = len(cases)
|
||||
failures = sum(1 for tc in cases if (tc.find('failure') is not None or tc.find('error') is not None))
|
||||
passed = total - failures
|
||||
|
||||
lines = [
|
||||
'# Unity GameObject API Test Results',
|
||||
'',
|
||||
f'Totals: {passed} passed, {failures} failed, {total} total',
|
||||
'',
|
||||
'## Test Checklist'
|
||||
]
|
||||
for p in desired:
|
||||
st = id_status.get(p, None)
|
||||
label = f"{p} — {default_titles.get(p, '')}"
|
||||
lines.append(f"- [x] {label}" if st is True else (f"- [ ] {label} (fail)" if st is False else f"- [ ] {label} (not run)"))
|
||||
lines.append('')
|
||||
|
||||
lines.append('## Test Details')
|
||||
for tc in cases:
|
||||
tid = id_from_case(tc)
|
||||
if not tid:
|
||||
continue
|
||||
title = tc.get('name') or tid
|
||||
ok = (tc.find('failure') is None and tc.find('error') is None)
|
||||
badge = "PASS" if ok else "FAIL"
|
||||
lines.append(f"### {title} — {badge}")
|
||||
so = tc.find('system-out')
|
||||
text = '' if so is None or so.text is None else html.unescape(so.text.strip())
|
||||
if text:
|
||||
lines += ['```', text[:2000], '```']
|
||||
else:
|
||||
lines.append('(no system-out)')
|
||||
node = tc.find('failure') or tc.find('error')
|
||||
if node is not None:
|
||||
msg = (node.get('message') or '').strip()
|
||||
if msg:
|
||||
lines.append(f"- Message: {msg}")
|
||||
lines.append('')
|
||||
|
||||
md_out.write_text('\n'.join(lines), encoding='utf-8')
|
||||
PY
|
||||
|
||||
- name: GO details -> Job Summary
|
||||
if: always()
|
||||
run: |
|
||||
echo "## Unity GameObject API Tests — Summary" >> $GITHUB_STEP_SUMMARY
|
||||
python3 - <<'PY' >> $GITHUB_STEP_SUMMARY
|
||||
from pathlib import Path
|
||||
p = Path('reports/junit-go-suite.md')
|
||||
if p.exists():
|
||||
text = p.read_bytes().decode('utf-8', 'replace')
|
||||
print(text[:65000])
|
||||
else:
|
||||
print("_No markdown report found._")
|
||||
PY
|
||||
|
||||
- name: Publish JUnit report
|
||||
if: always()
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
with:
|
||||
report_paths: "${{ env.JUNIT_OUT }}"
|
||||
include_passed: true
|
||||
detailed_summary: true
|
||||
annotate_notice: true
|
||||
require_tests: false
|
||||
fail_on_parse_error: true
|
||||
|
||||
- name: Upload artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: claude-go-suite-artifacts
|
||||
path: |
|
||||
${{ env.JUNIT_OUT }}
|
||||
${{ env.MD_OUT }}
|
||||
reports/*_results.xml
|
||||
retention-days: 7
|
||||
|
||||
# ---------- Cleanup ----------
|
||||
- name: Stop Unity
|
||||
if: always()
|
||||
run: |
|
||||
docker logs --tail 400 unity-mcp | sed -E 's/((email|serial|license|password|token)[^[:space:]]*)/[REDACTED]/ig' || true
|
||||
docker rm -f unity-mcp || true
|
||||
|
||||
- name: Return Pro license (if used)
|
||||
if: always() && steps.lic.outputs.use_ebl == 'true' && steps.lic.outputs.has_serial == 'true'
|
||||
uses: game-ci/unity-return-license@v2
|
||||
continue-on-error: true
|
||||
env:
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
name: Claude MCP Preflight (no Unity)
|
||||
|
||||
on: [workflow_dispatch]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
mcp-preflight:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: astral-sh/setup-uv@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install MCP server deps
|
||||
run: |
|
||||
set -eux
|
||||
uv venv
|
||||
echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/.venv" >> "$GITHUB_ENV"
|
||||
echo "$GITHUB_WORKSPACE/.venv/bin" >> "$GITHUB_PATH"
|
||||
if [ -f Server/pyproject.toml ]; then
|
||||
uv pip install -e Server
|
||||
elif [ -f Server/requirements.txt ]; then
|
||||
uv pip install -r Server/requirements.txt
|
||||
else
|
||||
echo "No MCP Python deps found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Preflight MCP server (stdio)
|
||||
env:
|
||||
PYTHONUNBUFFERED: "1"
|
||||
MCP_LOG_LEVEL: debug
|
||||
UNITY_PROJECT_ROOT: ${{ github.workspace }}/TestProjects/UnityMCPTests
|
||||
UNITY_MCP_STATUS_DIR: ${{ github.workspace }}/.unity-mcp-dummy
|
||||
UNITY_MCP_HOST: 127.0.0.1
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
mkdir -p "$UNITY_MCP_STATUS_DIR"
|
||||
# Create a dummy status file with an unreachable port; help should not require it
|
||||
cat > "$UNITY_MCP_STATUS_DIR/unity-mcp-status-dummy.json" <<JSON
|
||||
{ "unity_port": 0, "reason": "dummy", "reloading": false, "project_path": "$UNITY_PROJECT_ROOT/Assets" }
|
||||
JSON
|
||||
uv run --active --directory Server mcp-for-unity --transport stdio --help \
|
||||
> /tmp/mcp-preflight.log 2>&1 || { cat /tmp/mcp-preflight.log; exit 1; }
|
||||
cat /tmp/mcp-preflight.log
|
||||
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ jobs:
|
|||
run: |
|
||||
set -e
|
||||
if [ -n "$ANTHROPIC_API_KEY" ]; then echo "anthropic_ok=true" >> "$GITHUB_OUTPUT"; else echo "anthropic_ok=false" >> "$GITHUB_OUTPUT"; fi
|
||||
if [ -n "$UNITY_LICENSE" ] || { [ -n "$UNITY_EMAIL" ] && [ -n "$UNITY_PASSWORD" ]; }; then
|
||||
if [ -n "$UNITY_LICENSE" ] || { [ -n "$UNITY_EMAIL" ] && [ -n "$UNITY_PASSWORD" ] && [ -n "$UNITY_SERIAL" ]; }; then
|
||||
echo "unity_ok=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "unity_ok=false" >> "$GITHUB_OUTPUT"
|
||||
|
|
@ -76,7 +76,7 @@ jobs:
|
|||
set -eu
|
||||
use_ulf=false; use_ebl=false
|
||||
[[ -n "${UNITY_LICENSE:-}" ]] && use_ulf=true
|
||||
[[ -n "${UNITY_EMAIL:-}" && -n "${UNITY_PASSWORD:-}" ]] && use_ebl=true
|
||||
[[ -n "${UNITY_EMAIL:-}" && -n "${UNITY_PASSWORD:-}" && -n "${UNITY_SERIAL:-}" ]] && use_ebl=true
|
||||
echo "use_ulf=$use_ulf" >> "$GITHUB_OUTPUT"
|
||||
echo "use_ebl=$use_ebl" >> "$GITHUB_OUTPUT"
|
||||
echo "has_serial=$([[ -n "${UNITY_SERIAL:-}" ]] && echo true || echo false)" >> "$GITHUB_OUTPUT"
|
||||
|
|
|
|||
|
|
@ -1,199 +0,0 @@
|
|||
name: Unity Tests (fork)
|
||||
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
UNITY_IMAGE: unityci/editor:ubuntu-2021.3.45f2-linux-il2cpp-3
|
||||
|
||||
jobs:
|
||||
test-editmode:
|
||||
# Guard: run only on the fork owner's repo
|
||||
if: github.repository_owner == 'dsarno'
|
||||
name: Test in editmode (fork)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
|
||||
steps:
|
||||
# ---------- Secrets check ----------
|
||||
- name: Detect Unity credentials (outputs)
|
||||
id: detect
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
run: |
|
||||
set -e
|
||||
if [ -n "$UNITY_LICENSE" ]; then echo "unity_ok=true" >> "$GITHUB_OUTPUT"; else echo "unity_ok=false" >> "$GITHUB_OUTPUT"; fi
|
||||
if [ -n "$UNITY_EMAIL" ] && [ -n "$UNITY_PASSWORD" ]; then echo "ebl_ok=true" >> "$GITHUB_OUTPUT"; else echo "ebl_ok=false" >> "$GITHUB_OUTPUT"; fi
|
||||
if [ -n "$UNITY_SERIAL" ]; then echo "has_serial=true" >> "$GITHUB_OUTPUT"; else echo "has_serial=false" >> "$GITHUB_OUTPUT"; fi
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Prepare reports
|
||||
run: |
|
||||
set -eux
|
||||
rm -f reports/*.xml || true
|
||||
mkdir -p reports
|
||||
|
||||
# ---------- Licensing: allow both ULF and EBL ----------
|
||||
- name: Decide license sources
|
||||
id: lic
|
||||
shell: bash
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
run: |
|
||||
set -eu
|
||||
use_ulf=false; use_ebl=false
|
||||
[[ -n "${UNITY_LICENSE:-}" ]] && use_ulf=true
|
||||
[[ -n "${UNITY_EMAIL:-}" && -n "${UNITY_PASSWORD:-}" ]] && use_ebl=true
|
||||
echo "use_ulf=$use_ulf" >> "$GITHUB_OUTPUT"
|
||||
echo "use_ebl=$use_ebl" >> "$GITHUB_OUTPUT"
|
||||
echo "has_serial=$([[ -n "${UNITY_SERIAL:-}" ]] && echo true || echo false)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Stage Unity .ulf license (from secret)
|
||||
if: steps.lic.outputs.use_ulf == 'true'
|
||||
id: ulf
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
mkdir -p "$RUNNER_TEMP/unity-license-ulf" "$RUNNER_TEMP/unity-local/Unity"
|
||||
f="$RUNNER_TEMP/unity-license-ulf/Unity_lic.ulf"
|
||||
if printf "%s" "$UNITY_LICENSE" | base64 -d - >/dev/null 2>&1; then
|
||||
printf "%s" "$UNITY_LICENSE" | base64 -d - > "$f"
|
||||
else
|
||||
printf "%s" "$UNITY_LICENSE" > "$f"
|
||||
fi
|
||||
chmod 600 "$f" || true
|
||||
# If someone pasted an entitlement XML into UNITY_LICENSE by mistake, re-home it:
|
||||
if head -c 100 "$f" | grep -qi '<\?xml'; then
|
||||
mkdir -p "$RUNNER_TEMP/unity-config/Unity/licenses"
|
||||
mv "$f" "$RUNNER_TEMP/unity-config/Unity/licenses/UnityEntitlementLicense.xml"
|
||||
echo "ok=false" >> "$GITHUB_OUTPUT"
|
||||
elif grep -qi '<Signature>' "$f"; then
|
||||
# provide it in the standard local-share path too
|
||||
cp -f "$f" "$RUNNER_TEMP/unity-local/Unity/Unity_lic.ulf"
|
||||
echo "ok=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "ok=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Activate Unity (EBL via container - host-mount)
|
||||
if: steps.lic.outputs.use_ebl == 'true'
|
||||
shell: bash
|
||||
env:
|
||||
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
mkdir -p "$RUNNER_TEMP/unity-config" "$RUNNER_TEMP/unity-local"
|
||||
|
||||
# Try Pro first if serial is present, otherwise named-user EBL.
|
||||
docker run --rm --network host \
|
||||
-e HOME=/root \
|
||||
-e UNITY_EMAIL -e UNITY_PASSWORD -e UNITY_SERIAL \
|
||||
-v "$RUNNER_TEMP/unity-config:/root/.config/unity3d" \
|
||||
-v "$RUNNER_TEMP/unity-local:/root/.local/share/unity3d" \
|
||||
"$UNITY_IMAGE" bash -lc '
|
||||
set -euxo pipefail
|
||||
if [[ -n "${UNITY_SERIAL:-}" ]]; then
|
||||
/opt/unity/Editor/Unity -batchmode -nographics -logFile - \
|
||||
-username "$UNITY_EMAIL" -password "$UNITY_PASSWORD" -serial "$UNITY_SERIAL" -quit || true
|
||||
else
|
||||
/opt/unity/Editor/Unity -batchmode -nographics -logFile - \
|
||||
-username "$UNITY_EMAIL" -password "$UNITY_PASSWORD" -quit || true
|
||||
fi
|
||||
ls -la /root/.config/unity3d/Unity/licenses || true
|
||||
'
|
||||
|
||||
# Verify entitlement written to host mount; allow ULF-only runs to proceed
|
||||
if ! find "$RUNNER_TEMP/unity-config" -type f -iname "*.xml" | grep -q .; then
|
||||
if [[ "${{ steps.ulf.outputs.ok }}" == "true" ]]; then
|
||||
echo "EBL entitlement not found; proceeding with ULF-only (ok=true)."
|
||||
else
|
||||
echo "No entitlement produced and no valid ULF; cannot continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------- Warm up project (import Library once) ----------
|
||||
- name: Warm up project (import Library once)
|
||||
if: steps.lic.outputs.use_ulf == 'true' || steps.lic.outputs.use_ebl == 'true'
|
||||
shell: bash
|
||||
env:
|
||||
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
|
||||
ULF_OK: ${{ steps.ulf.outputs.ok }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
manual_args=()
|
||||
if [[ "${ULF_OK:-false}" == "true" ]]; then
|
||||
manual_args=(-manualLicenseFile "/root/.local/share/unity3d/Unity/Unity_lic.ulf")
|
||||
fi
|
||||
docker run --rm --network host \
|
||||
-e HOME=/root \
|
||||
-v "${{ github.workspace }}:/workspace" -w /workspace \
|
||||
-v "$RUNNER_TEMP/unity-config:/root/.config/unity3d" \
|
||||
-v "$RUNNER_TEMP/unity-local:/root/.local/share/unity3d" \
|
||||
"$UNITY_IMAGE" /opt/unity/Editor/Unity -batchmode -nographics -logFile - \
|
||||
-projectPath /workspace/TestProjects/UnityMCPTests \
|
||||
"${manual_args[@]}" \
|
||||
-quit
|
||||
|
||||
# ---------- Run editmode tests ----------
|
||||
- name: Run editmode tests (Unity CLI)
|
||||
if: steps.lic.outputs.use_ulf == 'true' || steps.lic.outputs.use_ebl == 'true'
|
||||
shell: bash
|
||||
env:
|
||||
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
|
||||
ULF_OK: ${{ steps.ulf.outputs.ok }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
manual_args=()
|
||||
if [[ "${ULF_OK:-false}" == "true" ]]; then
|
||||
manual_args=(-manualLicenseFile "/root/.local/share/unity3d/Unity/Unity_lic.ulf")
|
||||
fi
|
||||
docker run --rm --network host \
|
||||
-e HOME=/root \
|
||||
-v "${{ github.workspace }}:/workspace" -w /workspace \
|
||||
-v "$RUNNER_TEMP/unity-config:/root/.config/unity3d" \
|
||||
-v "$RUNNER_TEMP/unity-local:/root/.local/share/unity3d" \
|
||||
"$UNITY_IMAGE" /opt/unity/Editor/Unity -batchmode -nographics -logFile - \
|
||||
-projectPath /workspace/TestProjects/UnityMCPTests \
|
||||
-runTests \
|
||||
-testPlatform editmode \
|
||||
-testResults /workspace/reports/editmode-results.xml \
|
||||
-testResultsFormatter NUnit \
|
||||
"${manual_args[@]}" \
|
||||
-quit
|
||||
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: unity-editmode-results
|
||||
path: reports
|
||||
|
||||
- name: License diagnostics when missing
|
||||
if: steps.lic.outputs.use_ulf != 'true' && steps.lic.outputs.use_ebl != 'true'
|
||||
run: |
|
||||
echo "::error::No Unity credentials were supplied. Set UNITY_LICENSE or UNITY_EMAIL/UNITY_PASSWORD (and optionally UNITY_SERIAL) secrets in this fork."
|
||||
|
||||
|
|
@ -11,8 +11,6 @@ on:
|
|||
|
||||
jobs:
|
||||
testAllModes:
|
||||
# Guard: only run on upstream repo; skip on forks
|
||||
if: github.repository_owner == 'CoplayDev'
|
||||
name: Test in ${{ matrix.testMode }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
|
|
@ -30,6 +28,26 @@ jobs:
|
|||
with:
|
||||
lfs: true
|
||||
|
||||
- name: Detect Unity license secrets
|
||||
id: detect
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
run: |
|
||||
set -e
|
||||
if [ -n "$UNITY_LICENSE" ] || { [ -n "$UNITY_EMAIL" ] && [ -n "$UNITY_PASSWORD" ] && [ -n "$UNITY_SERIAL" ]; }; then
|
||||
echo "unity_ok=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "unity_ok=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Skip Unity tests (missing license secrets)
|
||||
if: steps.detect.outputs.unity_ok != 'true'
|
||||
run: |
|
||||
echo "Unity license secrets missing; skipping Unity tests."
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ matrix.projectPath }}/Library
|
||||
|
|
@ -40,12 +58,14 @@ jobs:
|
|||
|
||||
# Run domain reload tests first (they're [Explicit] so need explicit category)
|
||||
- name: Run domain reload tests
|
||||
if: steps.detect.outputs.unity_ok == 'true'
|
||||
uses: game-ci/unity-test-runner@v4
|
||||
id: domain-tests
|
||||
env:
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
|
|
@ -53,19 +73,21 @@ jobs:
|
|||
customParameters: -testCategory domain_reload
|
||||
|
||||
- name: Run tests
|
||||
if: steps.detect.outputs.unity_ok == 'true'
|
||||
uses: game-ci/unity-test-runner@v4
|
||||
id: tests
|
||||
env:
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
testMode: ${{ matrix.testMode }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
if: always() && steps.detect.outputs.unity_ok == 'true'
|
||||
with:
|
||||
name: Test results for ${{ matrix.testMode }}
|
||||
path: ${{ steps.tests.outputs.artifactsPath }}
|
||||
|
|
|
|||
Loading…
Reference in New Issue