Skip to content

Commit 12ae4a1

Browse files
nattb8claude
andcommitted
fix(audience): keep package meta-complete for git-URL installs
When the Audience package is installed from a git URL, Unity copies the folder into an immutable PackageCache verbatim. Any file without a .meta companion is dropped, which is a fatal error on device builds. The package shipped four non-Unity files (Directory.Build.props, two .csproj, README.md) whose .meta files are intentionally gitignored, so iOS builds failed. Move the headless dotnet build projects to src/Audience.Build so they never ship to consumers, and commit README.md.meta so the README keeps its meta. A CI check now fails any PR that reintroduces a missing meta or a non-Unity tooling file under the package. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6a3eba5 commit 12ae4a1

9 files changed

Lines changed: 154 additions & 73 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Guards the published shape of the com.immutable.audience package.
4+
#
5+
# When the package is installed from a git URL, Unity copies the folder into an
6+
# immutable PackageCache verbatim. Every asset there must have a .meta companion
7+
# or the asset is dropped, which turns into a fatal error on device builds.
8+
# Non-Unity tooling files (csproj, props, sln) have no place in the package and
9+
# trip the same failure because their .meta files are intentionally gitignored.
10+
#
11+
# This check fails the build if either problem is reintroduced.
12+
13+
set -euo pipefail
14+
15+
PKG="src/Packages/Audience"
16+
status=0
17+
18+
# Files that should never ship inside the package.
19+
forbidden=$(git ls-files "$PKG" \
20+
| grep -E '\.(csproj|sln)$|/Directory\.Build\.(props|targets)$' || true)
21+
if [ -n "$forbidden" ]; then
22+
echo "ERROR: non-Unity tooling files tracked inside $PKG (move them out of the package):"
23+
while IFS= read -r f; do
24+
printf ' %s\n' "$f"
25+
done <<< "$forbidden"
26+
status=1
27+
fi
28+
29+
# Every tracked asset must have a tracked .meta companion. Dotfiles and dot
30+
# folders are ignored by Unity, so they are exempt.
31+
missing=""
32+
while IFS= read -r f; do
33+
case "$f" in
34+
*.meta) continue ;;
35+
*/.*) continue ;;
36+
.*) continue ;;
37+
esac
38+
if ! git ls-files --error-unmatch "$f.meta" >/dev/null 2>&1; then
39+
missing="$missing $f"$'\n'
40+
fi
41+
done < <(git ls-files "$PKG")
42+
43+
if [ -n "$missing" ]; then
44+
echo "ERROR: assets in $PKG are missing a committed .meta companion:"
45+
printf '%s' "$missing"
46+
status=1
47+
fi
48+
49+
# Every tracked .meta must have a matching asset. The asset is either a tracked
50+
# file or, for Unity folder metas, a directory that holds tracked files. An
51+
# orphan meta left behind by `git rm`-ing an asset keeps a stale GUID around.
52+
orphan=""
53+
while IFS= read -r m; do
54+
base="${m%.meta}"
55+
if git ls-files --error-unmatch "$base" >/dev/null 2>&1; then
56+
continue
57+
fi
58+
if [ -n "$(git ls-files "$base/")" ]; then
59+
continue
60+
fi
61+
orphan="$orphan $m"$'\n'
62+
done < <(git ls-files "$PKG" | grep -E '\.meta$' || true)
63+
64+
if [ -n "$orphan" ]; then
65+
echo "ERROR: orphan .meta files in $PKG (no matching asset, stale GUID):"
66+
printf '%s' "$orphan"
67+
status=1
68+
fi
69+
70+
if [ "$status" -eq 0 ]; then
71+
echo "OK: $PKG is meta-complete and free of non-Unity tooling files."
72+
fi
73+
exit "$status"

.github/workflows/test-audience-sdk.yml

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,26 @@ on:
44
push:
55
branches: [main]
66
paths:
7-
- 'src/Packages/Audience/Runtime/**'
8-
- 'src/Packages/Audience/Tests/**'
9-
- 'src/Packages/Audience/package.json'
10-
- 'src/Packages/Audience/Directory.Build.props'
11-
- 'src/Packages/Audience/link.xml'
7+
- 'src/Packages/Audience/**'
8+
- 'src/Audience.Build/**'
129
- '.github/workflows/test-audience-sdk.yml'
10+
- '.github/scripts/audience/check-package-meta.sh'
1311
pull_request:
1412
paths:
15-
- 'src/Packages/Audience/Runtime/**'
16-
- 'src/Packages/Audience/Tests/**'
17-
- 'src/Packages/Audience/package.json'
18-
- 'src/Packages/Audience/Directory.Build.props'
19-
- 'src/Packages/Audience/link.xml'
13+
- 'src/Packages/Audience/**'
14+
- 'src/Audience.Build/**'
2015
- '.github/workflows/test-audience-sdk.yml'
16+
- '.github/scripts/audience/check-package-meta.sh'
2117

2218
jobs:
19+
package-shape:
20+
name: Package shape (meta completeness)
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
- name: Check package meta files
25+
run: ./.github/scripts/audience/check-package-meta.sh
26+
2327
test:
2428
name: Unit Tests (.NET)
2529
runs-on: ubuntu-latest
@@ -33,14 +37,14 @@ jobs:
3337
dotnet-version: '8.0.x'
3438

3539
- name: Restore dependencies
36-
run: dotnet restore src/Packages/Audience/Tests/Audience.Tests.csproj
40+
run: dotnet restore src/Audience.Build/Audience.Tests/Audience.Tests.csproj
3741

3842
- name: Build
39-
run: dotnet build src/Packages/Audience/Tests/Audience.Tests.csproj --no-restore --configuration Release
43+
run: dotnet build src/Audience.Build/Audience.Tests/Audience.Tests.csproj --no-restore --configuration Release
4044

4145
- name: Run tests
4246
run: >
43-
dotnet test src/Packages/Audience/Tests/Audience.Tests.csproj
47+
dotnet test src/Audience.Build/Audience.Tests/Audience.Tests.csproj
4448
--no-build --configuration Release
4549
--logger "trx;LogFileName=test-results.trx"
4650
--logger "console;verbosity=normal"

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
*.DotSettings.user.meta
2020
Directory.Build.props.meta
2121
Directory.Build.targets.meta
22-
src/Packages/Audience/README.md.meta
2322

2423
# MemoryCaptures can get excessive in size.
2524
# They also could contain extremely sensitive data
@@ -54,6 +53,11 @@ ExportedObj/
5453
*.unityproj
5554
*.sln
5655
*.sln.meta
56+
57+
# Hand-maintained headless dotnet build projects for the Audience package.
58+
# These live outside the Unity package so they never ship to consumers; keep
59+
# them tracked despite the blanket *.csproj rule above.
60+
!src/Audience.Build/**/*.csproj
5761
*.suo
5862
*.tmp
5963
*.user
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>netstandard2.1</TargetFramework>
4+
<LangVersion>9.0</LangVersion>
5+
<Nullable>disable</Nullable>
6+
<!-- Match the Unity asmdef assembly name so InternalsVisibleTo works in both contexts -->
7+
<AssemblyName>Immutable.Audience.Runtime</AssemblyName>
8+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
9+
<!-- Sources live in the package folder, not next to this project -->
10+
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
11+
<PackageRoot>$(MSBuildThisFileDirectory)../../Packages/Audience</PackageRoot>
12+
</PropertyGroup>
13+
<!--
14+
The Unity/ subtree belongs to the sibling Immutable.Audience.Unity asmdef.
15+
It references UnityEngine, so it cannot build under the headless .NET SDK.
16+
Excluding it here mirrors the noEngineReferences:true portability guard on
17+
com.immutable.audience.asmdef, catching stray UnityEngine usage in Core/,
18+
Events/, Transport/ and Utility/.
19+
-->
20+
<ItemGroup>
21+
<Compile Include="$(PackageRoot)/Runtime/**/*.cs"
22+
Exclude="$(PackageRoot)/Runtime/Unity/**/*.cs"
23+
LinkBase="Runtime" />
24+
</ItemGroup>
25+
</Project>

src/Packages/Audience/Tests/Audience.Tests.csproj renamed to src/Audience.Build/Audience.Tests/Audience.Tests.csproj

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,27 @@
44
<LangVersion>9.0</LangVersion>
55
<Nullable>disable</Nullable>
66
<IsPackable>false</IsPackable>
7-
<!-- Match the Unity asmdef assembly name so InternalsVisibleTo("Immutable.Audience.Runtime.Tests") resolves correctly -->
7+
<!-- Match the Unity asmdef assembly name so InternalsVisibleTo("Immutable.Audience.Runtime.Tests") resolves -->
88
<AssemblyName>Immutable.Audience.Runtime.Tests</AssemblyName>
9+
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
10+
<PackageRoot>$(MSBuildThisFileDirectory)../../Packages/Audience</PackageRoot>
911
</PropertyGroup>
1012
<ItemGroup>
1113
<PackageReference Include="NUnit" Version="3.14.0" />
1214
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
1315
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
1416
</ItemGroup>
1517
<ItemGroup>
16-
<ProjectReference Include="../Runtime/Audience.Runtime.csproj" />
18+
<ProjectReference Include="../Audience.Runtime/Audience.Runtime.csproj" />
1719
</ItemGroup>
1820
<!--
19-
Exclude Tests/Editor/ from the headless dotnet build. Those tests reference
20-
Unity-only types (MonoBehaviour, VisualElement, SampleApp MonoBehaviour)
21-
and run inside the Unity Test Framework in-editor.
21+
Editor/ and Runtime/Unity/ tests reference Unity-only types and run inside
22+
the Unity Test Framework in-editor, so they are excluded from the headless
23+
dotnet build.
2224
-->
2325
<ItemGroup>
24-
<Compile Remove="Editor/**/*.cs" />
25-
<!-- DeviceCollectorTests references Immutable.Audience.Unity which wraps
26-
UnityEngine APIs unavailable in the headless dotnet build. These tests
27-
run inside the Unity Test Framework via the asmdef instead. -->
28-
<Compile Remove="Runtime/Unity/**/*.cs" />
26+
<Compile Include="$(PackageRoot)/Tests/**/*.cs"
27+
Exclude="$(PackageRoot)/Tests/Editor/**/*.cs;$(PackageRoot)/Tests/Runtime/Unity/**/*.cs"
28+
LinkBase="Tests" />
2929
</ItemGroup>
3030
</Project>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project>
2+
<!--
3+
Redirect dotnet build outputs to a repo-root artifacts/ folder.
4+
5+
These projects build the Audience package sources headlessly for unit tests.
6+
They live outside src/Packages/Audience so they are never copied into a
7+
consumer's PackageCache (git-URL installs ship the package folder verbatim,
8+
and non-Unity files there break device builds when they lack .meta files).
9+
10+
$(MSBuildThisFileDirectory) = src/Audience.Build/
11+
../../artifacts/ = <repo-root>/artifacts/
12+
-->
13+
<PropertyGroup>
14+
<BaseOutputPath>$(MSBuildThisFileDirectory)../../artifacts/$(MSBuildProjectName)/bin/</BaseOutputPath>
15+
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory)../../artifacts/$(MSBuildProjectName)/obj/</BaseIntermediateOutputPath>
16+
</PropertyGroup>
17+
</Project>

src/Packages/Audience/Directory.Build.props

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/Packages/Audience/README.md.meta

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Packages/Audience/Runtime/Audience.Runtime.csproj

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)