Build Unity SpaceCraft #14
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
| ################################################################################################### | |
| # Build Unity SpaceCraft – GitHub Actions (Ubuntu runner) | |
| # | |
| # Overview | |
| # - Builds the Unity SpaceCraft project for WebGL on GitHub-hosted Linux runners. | |
| # - Auto-detects Unity version from ProjectVersion.txt (override via input). | |
| # - Supports Production/Development profiles or a fully custom build method. | |
| # - Caches the Unity Library folder for faster imports/compiles between runs. | |
| # - Downloads real LFS asset blobs for the checked-out commit (required for Unity). | |
| # - Uploads build artifacts for later download/deploy. | |
| # | |
| # Requirements (repo secrets) | |
| # - UNITY_LICENSE: Unity license file contents (game-ci format) or ULF text. | |
| # - UNITY_EMAIL: Unity account email (for legacy activation flows in builder). | |
| # - UNITY_PASSWORD: Unity account password (for legacy activation flows in builder). | |
| # | |
| # Inputs (workflow_dispatch) | |
| # - unityVersion: Unity Editor version (e.g., 2022.3.45f1). Use 'auto' to parse ProjectVersion.txt. | |
| # - projectPath: Path to the Unity project. Defaults to Unity/SpaceCraft. | |
| # - targetPlatform: Build target (WebGL). Extendable if needed. | |
| # - buildProfile: Convenience selector mapping to build methods (Production/Development). | |
| # - buildMethod: Explicit Unity C# method string, overrides buildProfile. Example: | |
| # SpaceCraft.Editor.Builds.BuildWebGLProduction | |
| # | |
| # Build method expectations (Unity side) | |
| # - The selected build method should be a static C# function callable by Unity with: | |
| # - No arguments (or signature supported by Unity batchmode). | |
| # - It should configure build options and write the WebGL build output into the project Build/ path | |
| # or another deterministic directory consumed by artifact upload below. | |
| # - Example namespace/class/method naming is provided here as a convention; implement accordingly. | |
| # | |
| # Caching strategy | |
| # - Caches the Library/ folder per (OS, Unity version, Packages/manifest.json hash) to reduce reimport. | |
| # - On cache hits, compilations and imports should be much faster. | |
| # - We intentionally do not cache Temp/ or final Build/ outputs; those are uploaded as artifacts. | |
| # | |
| # LFS and checkout | |
| # - actions/checkout is configured with lfs: true and fetch-depth: 1 | |
| # - Ensures real LFS blobs for the current commit are available to the build. | |
| # - Uses shallow history for speed (no need for full Git history in CI). | |
| # | |
| # Artifacts | |
| # - Uploads the default game-ci build/ directory and the project Build/ directory. | |
| # - Adjust artifact paths if your build method writes to a different location. | |
| # | |
| # Invocation examples | |
| # - Production (auto-detect Unity, default project path): | |
| # unityVersion: auto | |
| # buildProfile: WebGLProductionBuild | |
| # - Development: | |
| # unityVersion: auto | |
| # buildProfile: WebGLDevelopmentBuild | |
| # - Explicit method (overrides profile mapping): | |
| # buildMethod: SpaceCraft.Editor.Builds.BuildWebGLProduction | |
| # | |
| # Notes | |
| # - This workflow focuses on GitHub-hosted runners (no self-hosted required). | |
| # - For further speed-ups, consider enabling editor caching in the action if appropriate and supported | |
| # by your environment, or splitting content generation into a separate, cacheable step. | |
| ################################################################################################### | |
| name: Build Unity SpaceCraft | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| unityVersion: | |
| description: "Unity Editor version (e.g. 2022.3.45f1). Use 'auto' to detect from ProjectVersion.txt" | |
| required: false | |
| default: "auto" | |
| type: string | |
| projectPath: | |
| description: "Unity project path" | |
| required: false | |
| default: "Unity/SpaceCraft" | |
| type: string | |
| targetPlatform: | |
| description: "Unity target platform" | |
| required: false | |
| default: "WebGL" | |
| type: choice | |
| options: | |
| - WebGL | |
| buildProfile: | |
| description: "Build profile token (maps to a Unity build method)" | |
| required: false | |
| default: "WebGLProductionBuild" | |
| type: choice | |
| options: | |
| - WebGLProductionBuild | |
| - WebGLDevelopmentBuild | |
| buildMethod: | |
| description: "Explicit Unity build method (overrides buildProfile). Example: SpaceCraft.Editor.Builds.BuildWebGLProduction" | |
| required: false | |
| default: "" | |
| type: string | |
| jobs: | |
| build: | |
| name: Build ${{ inputs.targetPlatform }} (${{ inputs.buildProfile }}) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 90 | |
| env: | |
| PROJECT_PATH: ${{ inputs.projectPath }} | |
| TARGET_PLATFORM: ${{ inputs.targetPlatform }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| lfs: true | |
| fetch-depth: 1 | |
| - name: Ensure LFS files are materialized (smudged) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "[lfs] git lfs version:" && git lfs version || true | |
| echo "[lfs] Pulling LFS objects (broad)" | |
| git lfs pull --exclude="" --include="" || true | |
| echo "[lfs] Forcing checkout (smudge) of LFS pointers" | |
| git lfs checkout || true | |
| - name: Detect Unity version and resolve project path | |
| id: detect | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "[detect] GITHUB_WORKSPACE=${{ github.workspace }}" | |
| echo "[detect] inputs.projectPath='${{ inputs.projectPath }}' inputs.unityVersion='${{ inputs.unityVersion }}'" | |
| echo "[detect] Workspace root listing:" | |
| ls -la "${{ github.workspace }}" || true | |
| # If version provided, honor it and still resolve project path for later steps | |
| REQ_VER="${{ inputs.unityVersion }}" | |
| PROJ_PATH_IN="${{ inputs.projectPath }}" | |
| CANDIDATE_FILE="${{ github.workspace }}/${PROJ_PATH_IN}/ProjectSettings/ProjectVersion.txt" | |
| echo "[detect] Initial candidate file: $CANDIDATE_FILE" | |
| echo "[detect] Listing input project path: '${PROJ_PATH_IN}'" | |
| ls -la "${{ github.workspace }}/${PROJ_PATH_IN}" || true | |
| if [[ ! -f "$CANDIDATE_FILE" ]]; then | |
| echo "[detect] Input projectPath not found: $CANDIDATE_FILE" >&2 | |
| echo "[detect] Searching for ProjectVersion.txt under workspace..." | |
| MAPFILE -t FOUND < <(find "${{ github.workspace }}" -type f -path "*/ProjectSettings/ProjectVersion.txt" | sort) | |
| echo "[detect] Found ${#FOUND[@]} candidates" | |
| if [[ ${#FOUND[@]} -eq 0 ]]; then | |
| echo "[detect] No ProjectVersion.txt found in repository" >&2 | |
| exit 1 | |
| fi | |
| CANDIDATE_FILE="${FOUND[0]}" | |
| echo "[detect] Using detected ProjectVersion.txt: $CANDIDATE_FILE" | |
| echo "[detect] Candidates (up to 10):" && printf '%s\n' "${FOUND[@]:0:10}" | |
| fi | |
| # Derive resolved project path (folder containing ProjectSettings) | |
| RESOLVED_PROJECT_PATH="$(cd "$(dirname "$CANDIDATE_FILE")/.." && pwd)" | |
| # Convert to path relative to workspace for downstream steps | |
| RESOLVED_PROJECT_PATH_REL="${RESOLVED_PROJECT_PATH#"${{ github.workspace }}/"}" | |
| echo "projectPath=$RESOLVED_PROJECT_PATH_REL" >> "$GITHUB_OUTPUT" | |
| echo "[detect] RESOLVED_PROJECT_PATH=$RESOLVED_PROJECT_PATH" | |
| echo "[detect] RESOLVED_PROJECT_PATH_REL=$RESOLVED_PROJECT_PATH_REL" | |
| echo "[detect] ProjectSettings listing:" && ls -la "$RESOLVED_PROJECT_PATH/ProjectSettings" || true | |
| echo "[detect] cat ProjectVersion.txt (pre-smudge):" && cat "$CANDIDATE_FILE" || true | |
| # If file still looks like an LFS pointer, try to smudge just this file and re-check | |
| if head -n 1 "$CANDIDATE_FILE" | grep -q '^version https://git-lfs.github.com/spec/v1'; then | |
| echo "[detect] ProjectVersion.txt appears to be an LFS pointer; attempting smudge" | |
| git lfs checkout -- "$CANDIDATE_FILE" || true | |
| git lfs pull --include="$RESOLVED_PROJECT_PATH_REL/ProjectSettings/ProjectVersion.txt" --exclude="" || true | |
| echo "[detect] cat ProjectVersion.txt (post-smudge):" && cat "$CANDIDATE_FILE" || true | |
| fi | |
| if [[ "$REQ_VER" != "auto" && -n "$REQ_VER" ]]; then | |
| echo "[detect] Using provided unityVersion: $REQ_VER" | |
| echo "version=$REQ_VER" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| VERSION=$(grep -E "^m_EditorVersion:\s*" "$CANDIDATE_FILE" | sed -E 's/^m_EditorVersion:\s*([^[:space:]]+).*/\1/') | |
| if [[ -z "$VERSION" ]]; then | |
| echo "[detect] Failed to parse Unity version from ProjectVersion.txt" >&2 | |
| exit 1 | |
| fi | |
| echo "[detect] Detected Unity version: $VERSION" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Log build configuration | |
| shell: bash | |
| run: | | |
| echo "[config] projectPath='${{ steps.detect.outputs.projectPath }}'" | |
| echo "[config] unityVersion='${{ steps.detect.outputs.version }}'" | |
| echo "[config] targetPlatform='${{ inputs.targetPlatform }}'" | |
| echo "[config] buildProfile='${{ inputs.buildProfile }}'" | |
| - name: Validate Unity activation secrets | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| missing=0 | |
| if [[ -z "${{ secrets.UNITY_LICENSE }}" ]]; then echo "[secrets] UNITY_LICENSE is missing" >&2; missing=1; fi | |
| if [[ -z "${{ secrets.UNITY_EMAIL }}" ]]; then echo "[secrets] UNITY_EMAIL is missing" >&2; missing=1; fi | |
| if [[ -z "${{ secrets.UNITY_PASSWORD }}" ]]; then echo "[secrets] UNITY_PASSWORD is missing" >&2; missing=1; fi | |
| if [[ "$missing" -ne 0 ]]; then | |
| echo "[secrets] One or more required secrets are missing. Per GameCI v4 Personal license activation, provide UNITY_LICENSE, UNITY_EMAIL, UNITY_PASSWORD." >&2 | |
| exit 1 | |
| fi | |
| - name: Cache Unity Library (project import cache) | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ${{ steps.detect.outputs.projectPath }}/Library | |
| key: ${{ runner.os }}-unity-library-${{ steps.detect.outputs.version }}-${{ hashFiles(format('{0}/Packages/manifest.json', steps.detect.outputs.projectPath)) }} | |
| restore-keys: | | |
| ${{ runner.os }}-unity-library-${{ steps.detect.outputs.version }}- | |
| - name: Compute build method | |
| id: compute | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ -n "${{ inputs.buildMethod }}" ]]; then | |
| METHOD="${{ inputs.buildMethod }}" | |
| else | |
| case "${{ inputs.buildProfile }}" in | |
| WebGLProductionBuild) | |
| METHOD="Build.WebGL_Prod" | |
| ;; | |
| WebGLDevelopmentBuild) | |
| METHOD="Build.WebGL_Dev" | |
| ;; | |
| *) | |
| echo "Unknown buildProfile: ${{ inputs.buildProfile }}" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| fi | |
| echo "buildMethod=$METHOD" >> "$GITHUB_OUTPUT" | |
| echo "[compute] Selected build method: $METHOD" | |
| - name: Prepare logs directory | |
| shell: bash | |
| run: | | |
| mkdir -p Logs | |
| mkdir -p "${{ steps.detect.outputs.projectPath }}/Logs" | |
| - name: Unity - Builder | |
| uses: game-ci/unity-builder@v4 | |
| env: | |
| UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} | |
| UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} | |
| UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} | |
| with: | |
| projectPath: ${{ steps.detect.outputs.projectPath }} | |
| targetPlatform: ${{ inputs.targetPlatform }} | |
| unityVersion: ${{ steps.detect.outputs.version }} | |
| buildMethod: ${{ steps.compute.outputs.buildMethod }} | |
| customParameters: -logFile Logs/Editor.log -stackTraceLogType Full | |
| # Optional: enable Unity editor cache inside action (requires action support) | |
| # cacheUnity: true | |
| # cacheVersioning: semantic | |
| - name: Upload build artifacts | |
| if: success() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: SpaceCraft-${{ inputs.targetPlatform }}-${{ inputs.buildProfile }} | |
| path: | | |
| ${{ steps.detect.outputs.projectPath }}/Builds/SpaceCraft | |
| - name: Upload Unity logs (always) | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: Unity-Logs | |
| path: | | |
| Logs | |
| ${{ steps.detect.outputs.projectPath }}/Logs | |