diff --git a/.github/scripts/audience/check-package-meta.sh b/.github/scripts/audience/check-package-meta.sh new file mode 100755 index 000000000..44ea7385e --- /dev/null +++ b/.github/scripts/audience/check-package-meta.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# +# Guards the published shape of the com.immutable.audience package. +# +# When the package is installed from a git URL, Unity copies the folder into an +# immutable PackageCache verbatim. Every asset there must have a .meta companion +# or the asset is dropped, which turns into a fatal error on device builds. +# Non-Unity tooling files (csproj, props, sln) have no place in the package and +# trip the same failure because their .meta files are intentionally gitignored. +# +# This check fails the build if either problem is reintroduced. + +set -euo pipefail + +PKG="src/Packages/Audience" +status=0 + +# Files that should never ship inside the package. +forbidden=$(git ls-files "$PKG" \ + | grep -E '\.(csproj|sln)$|/Directory\.Build\.(props|targets)$' || true) +if [ -n "$forbidden" ]; then + echo "ERROR: non-Unity tooling files tracked inside $PKG (move them out of the package):" + while IFS= read -r f; do + printf ' %s\n' "$f" + done <<< "$forbidden" + status=1 +fi + +# Every tracked asset must have a tracked .meta companion. Dotfiles and dot +# folders are ignored by Unity, so they are exempt. +missing="" +while IFS= read -r f; do + case "$f" in + *.meta) continue ;; + */.*) continue ;; + .*) continue ;; + esac + if ! git ls-files --error-unmatch "$f.meta" >/dev/null 2>&1; then + missing="$missing $f"$'\n' + fi +done < <(git ls-files "$PKG") + +if [ -n "$missing" ]; then + echo "ERROR: assets in $PKG are missing a committed .meta companion:" + printf '%s' "$missing" + status=1 +fi + +# Every tracked .meta must have a matching asset. The asset is either a tracked +# file or, for Unity folder metas, a directory that holds tracked files. An +# orphan meta left behind by `git rm`-ing an asset keeps a stale GUID around. +orphan="" +while IFS= read -r m; do + base="${m%.meta}" + if git ls-files --error-unmatch "$base" >/dev/null 2>&1; then + continue + fi + if [ -n "$(git ls-files "$base/")" ]; then + continue + fi + orphan="$orphan $m"$'\n' +done < <(git ls-files "$PKG" | grep -E '\.meta$' || true) + +if [ -n "$orphan" ]; then + echo "ERROR: orphan .meta files in $PKG (no matching asset, stale GUID):" + printf '%s' "$orphan" + status=1 +fi + +if [ "$status" -eq 0 ]; then + echo "OK: $PKG is meta-complete and free of non-Unity tooling files." +fi +exit "$status" diff --git a/.github/workflows/test-audience-sdk.yml b/.github/workflows/test-audience-sdk.yml index 9bbf8230a..843307ddb 100644 --- a/.github/workflows/test-audience-sdk.yml +++ b/.github/workflows/test-audience-sdk.yml @@ -4,22 +4,26 @@ on: push: branches: [main] paths: - - 'src/Packages/Audience/Runtime/**' - - 'src/Packages/Audience/Tests/**' - - 'src/Packages/Audience/package.json' - - 'src/Packages/Audience/Directory.Build.props' - - 'src/Packages/Audience/link.xml' + - 'src/Packages/Audience/**' + - 'src/Audience.Build/**' - '.github/workflows/test-audience-sdk.yml' + - '.github/scripts/audience/check-package-meta.sh' pull_request: paths: - - 'src/Packages/Audience/Runtime/**' - - 'src/Packages/Audience/Tests/**' - - 'src/Packages/Audience/package.json' - - 'src/Packages/Audience/Directory.Build.props' - - 'src/Packages/Audience/link.xml' + - 'src/Packages/Audience/**' + - 'src/Audience.Build/**' - '.github/workflows/test-audience-sdk.yml' + - '.github/scripts/audience/check-package-meta.sh' jobs: + package-shape: + name: Package shape (meta completeness) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check package meta files + run: ./.github/scripts/audience/check-package-meta.sh + test: name: Unit Tests (.NET) runs-on: ubuntu-latest @@ -33,14 +37,14 @@ jobs: dotnet-version: '8.0.x' - name: Restore dependencies - run: dotnet restore src/Packages/Audience/Tests/Audience.Tests.csproj + run: dotnet restore src/Audience.Build/Audience.Tests/Audience.Tests.csproj - name: Build - run: dotnet build src/Packages/Audience/Tests/Audience.Tests.csproj --no-restore --configuration Release + run: dotnet build src/Audience.Build/Audience.Tests/Audience.Tests.csproj --no-restore --configuration Release - name: Run tests run: > - dotnet test src/Packages/Audience/Tests/Audience.Tests.csproj + dotnet test src/Audience.Build/Audience.Tests/Audience.Tests.csproj --no-build --configuration Release --logger "trx;LogFileName=test-results.trx" --logger "console;verbosity=normal" diff --git a/.gitignore b/.gitignore index 74e2a2fea..18d0e6361 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,6 @@ *.DotSettings.user.meta Directory.Build.props.meta Directory.Build.targets.meta -src/Packages/Audience/README.md.meta # MemoryCaptures can get excessive in size. # They also could contain extremely sensitive data @@ -54,6 +53,11 @@ ExportedObj/ *.unityproj *.sln *.sln.meta + +# Hand-maintained headless dotnet build projects for the Audience package. +# These live outside the Unity package so they never ship to consumers; keep +# them tracked despite the blanket *.csproj rule above. +!src/Audience.Build/**/*.csproj *.suo *.tmp *.user diff --git a/src/Audience.Build/Audience.Runtime/Audience.Runtime.csproj b/src/Audience.Build/Audience.Runtime/Audience.Runtime.csproj new file mode 100644 index 000000000..6e49886f6 --- /dev/null +++ b/src/Audience.Build/Audience.Runtime/Audience.Runtime.csproj @@ -0,0 +1,25 @@ + + + netstandard2.1 + 9.0 + disable + + Immutable.Audience.Runtime + true + + false + $(MSBuildThisFileDirectory)../../Packages/Audience + + + + + + diff --git a/src/Packages/Audience/Tests/Audience.Tests.csproj b/src/Audience.Build/Audience.Tests/Audience.Tests.csproj similarity index 50% rename from src/Packages/Audience/Tests/Audience.Tests.csproj rename to src/Audience.Build/Audience.Tests/Audience.Tests.csproj index 10a750d73..ea3621573 100644 --- a/src/Packages/Audience/Tests/Audience.Tests.csproj +++ b/src/Audience.Build/Audience.Tests/Audience.Tests.csproj @@ -4,8 +4,10 @@ 9.0 disable false - + Immutable.Audience.Runtime.Tests + false + $(MSBuildThisFileDirectory)../../Packages/Audience @@ -13,18 +15,16 @@ - + - - - + diff --git a/src/Audience.Build/Directory.Build.props b/src/Audience.Build/Directory.Build.props new file mode 100644 index 000000000..4a8414701 --- /dev/null +++ b/src/Audience.Build/Directory.Build.props @@ -0,0 +1,17 @@ + + + + $(MSBuildThisFileDirectory)../../artifacts/$(MSBuildProjectName)/bin/ + $(MSBuildThisFileDirectory)../../artifacts/$(MSBuildProjectName)/obj/ + + diff --git a/src/Packages/Audience/Directory.Build.props b/src/Packages/Audience/Directory.Build.props deleted file mode 100644 index 7a4d7a676..000000000 --- a/src/Packages/Audience/Directory.Build.props +++ /dev/null @@ -1,21 +0,0 @@ - - - - $(MSBuildThisFileDirectory)../../../artifacts/$(MSBuildProjectName)/bin/ - $(MSBuildThisFileDirectory)../../../artifacts/$(MSBuildProjectName)/obj/ - - diff --git a/src/Packages/Audience/README.md.meta b/src/Packages/Audience/README.md.meta new file mode 100644 index 000000000..1f680a643 --- /dev/null +++ b/src/Packages/Audience/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0c6db6545a39045358bc1316ec7cce59 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Packages/Audience/Runtime/Audience.Runtime.csproj b/src/Packages/Audience/Runtime/Audience.Runtime.csproj deleted file mode 100644 index 8a7e3eb4a..000000000 --- a/src/Packages/Audience/Runtime/Audience.Runtime.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - netstandard2.1 - 9.0 - disable - - Immutable.Audience.Runtime - - true - - - - - -