feat(asset-gen): add MiniMax music cover support #123
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: E2E Bridge Smoke (deterministic, no LLM) | |
| # Boots a headless Unity Editor, starts the Python MCP server's wire path, and | |
| # drives a fixed sequence of real tool calls with exact assertions | |
| # (Server/tests/e2e/bridge_smoke.py). Unlike claude-nl-suite.yml this needs | |
| # NO Anthropic API key -- it is deterministic and cheap, so it can gate PRs and | |
| # releases. It still needs Unity license secrets to boot the Editor. | |
| on: | |
| workflow_dispatch: | |
| pull_request: | |
| paths: | |
| - "MCPForUnity/Editor/**" | |
| - "MCPForUnity/Runtime/**" | |
| - "Server/src/**" | |
| - "Server/tests/e2e/**" | |
| - "tools/local_harness.py" | |
| - ".github/workflows/e2e-bridge.yml" | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| UNITY_IMAGE: unityci/editor:ubuntu-2021.3.45f2-linux-il2cpp-3 | |
| jobs: | |
| e2e-bridge: | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 40 | |
| steps: | |
| - 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" | |
| echo "::warning::E2E bridge smoke SKIPPED - no license secrets in scope (normal for fork PRs). This check is NOT a pass: nothing was booted or exercised." | |
| # Every step below is gated on unity_ok, so the job reports a green check | |
| # having run nothing at all. Say so plainly on the run page. | |
| { | |
| echo "## :warning: E2E bridge smoke was SKIPPED" | |
| echo | |
| echo "No Unity license secrets were in scope, so **no Editor was booted and no tool call was exercised**." | |
| echo "The green check means the job exited cleanly - **not** that the bridge works." | |
| echo | |
| echo "GitHub withholds repository secrets from workflow runs triggered by a fork's pull request." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| - uses: actions/checkout@v4 | |
| if: steps.detect.outputs.unity_ok == 'true' | |
| with: | |
| fetch-depth: 0 | |
| - uses: astral-sh/setup-uv@v4 | |
| if: steps.detect.outputs.unity_ok == 'true' | |
| with: | |
| python-version: "3.11" | |
| - name: Install MCP server | |
| if: steps.detect.outputs.unity_ok == 'true' | |
| run: | | |
| set -eux | |
| uv venv | |
| echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/.venv" >> "$GITHUB_ENV" | |
| echo "$GITHUB_WORKSPACE/.venv/bin" >> "$GITHUB_PATH" | |
| uv pip install -e Server | |
| # --- License staging (mirrors claude-nl-suite.yml) --- | |
| - name: Decide license sources | |
| if: steps.detect.outputs.unity_ok == 'true' | |
| 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:-}" && -n "${UNITY_SERIAL:-}" ]] && use_ebl=true | |
| echo "use_ulf=$use_ulf" >> "$GITHUB_OUTPUT" | |
| echo "use_ebl=$use_ebl" >> "$GITHUB_OUTPUT" | |
| - name: Stage Unity .ulf license (from secret) | |
| if: steps.detect.outputs.unity_ok == 'true' && 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 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) | |
| if: steps.detect.outputs.unity_ok == 'true' && 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 | |
| /opt/unity/Editor/Unity -batchmode -nographics -logFile - \ | |
| -username "$UNITY_EMAIL" -password "$UNITY_PASSWORD" -serial "$UNITY_SERIAL" -quit || true | |
| ' | |
| - name: Warm up project (import Library once) | |
| if: steps.detect.outputs.unity_ok == '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 | |
| - name: Clean old MCP status | |
| if: steps.detect.outputs.unity_ok == 'true' | |
| run: | | |
| set -eux | |
| mkdir -p "$GITHUB_WORKSPACE/.unity-mcp" | |
| rm -f "$GITHUB_WORKSPACE/.unity-mcp"/unity-mcp-status-*.json || true | |
| - name: Run headless bridge harness (boot + wait + smoke/editmode/playmode) | |
| if: steps.detect.outputs.unity_ok == 'true' | |
| shell: bash | |
| env: | |
| UNITY_IMAGE: ${{ env.UNITY_IMAGE }} | |
| ULF_OK: ${{ steps.ulf.outputs.ok }} | |
| run: | | |
| set -euxo pipefail | |
| # In --ci mode the harness drives the DockerLauncher: it runs the same | |
| # docker container (repo .unity-mcp status dir, docker liveness/teardown, | |
| # log redaction), waits on the status file, derives the instance, then | |
| # runs the smoke + EditMode + PlayMode legs over the bridge. | |
| license_args=() | |
| if [[ "${ULF_OK:-false}" == "true" ]]; then | |
| license_args=(--editor-arg -manualLicenseFile \ | |
| --editor-arg "/root/.local/share/unity3d/Unity/Unity_lic.ulf") | |
| fi | |
| python3 tools/local_harness.py --ci \ | |
| --legs smoke,editmode,playmode \ | |
| --project-path TestProjects/UnityMCPTests \ | |
| --reports reports \ | |
| "${license_args[@]}" | |
| - name: Unity logs on failure | |
| if: failure() && steps.detect.outputs.unity_ok == 'true' | |
| run: docker logs unity-mcp --tail 200 | sed -E 's/((email|serial|license|password|token)[^[:space:]]*)/[REDACTED]/Ig' || true | |
| - name: Upload E2E report | |
| if: always() && steps.detect.outputs.unity_ok == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-bridge-report | |
| path: reports/junit-*.xml | |
| if-no-files-found: ignore |