Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ package-dev/alias-references.txt
# ignore integration test files
Samples/IntegrationTest*
unity.log
unity-test.log

# Ignore package release
test-package-release/
Expand Down
40 changes: 32 additions & 8 deletions Agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@ dotnet msbuild /t:DownloadNativeSDKs src/Sentry.Unity
# Build the Unity SDK
dotnet build

# Run all tests
./test.sh
# Run all tests (builds SDK first)
pwsh scripts/run-tests.ps1

# Run specific test targets
dotnet msbuild /t:UnityEditModeTest /p:Configuration=Release test/Sentry.Unity.Editor.Tests
dotnet msbuild /t:UnityPlayModeTest /p:Configuration=Release
# Run specific test types
pwsh scripts/run-tests.ps1 -PlayMode
pwsh scripts/run-tests.ps1 -EditMode

# Run filtered tests
pwsh scripts/run-tests.ps1 -Filter "TestClassName"
pwsh scripts/run-tests.ps1 -PlayMode -Filter "Throttler"

# Skip build for faster iteration
pwsh scripts/run-tests.ps1 -SkipBuild -Filter "MyTest"

# Integration testing (local)
./test/Scripts.Integration.Test/integration-test.ps1 -Platform "macOS" -UnityVersion "2021.3.45f2"
Expand Down Expand Up @@ -482,7 +489,14 @@ Key options:
### Running All Tests

```bash
./test.sh
# Run all tests (builds SDK first)
pwsh scripts/run-tests.ps1

# Run with filtering
pwsh scripts/run-tests.ps1 -Filter "TestClassName"

# Skip build for faster iteration
pwsh scripts/run-tests.ps1 -SkipBuild
```

### Integration Test Scripts
Expand Down Expand Up @@ -520,10 +534,20 @@ Supported platforms: `macOS`, `Windows`, `Linux`, `Android`, `iOS`, `WebGL`

### Development Workflow

**Prerequisites (first-time setup or after clean):**
```bash
# Download native SDKs - REQUIRED before building
dotnet msbuild /t:DownloadNativeSDKs src/Sentry.Unity
```

**Development cycle:**
1. Make changes to source code in `src/`
2. Run `dotnet build` to build and update `package-dev/`
3. Test changes using the sample project or integration tests
4. Run `pwsh scripts/repack.ps1` before creating releases
3. Run `pwsh scripts/run-tests.ps1` to build and run all tests
4. Test changes using the sample project or integration tests
5. Run `pwsh scripts/repack.ps1` before creating releases

> **Note:** The native SDKs in `package-dev/Plugins/` are not committed to the repository. You must run `DownloadNativeSDKs` before the first build or after cleaning the repository.

### Error Handling Patterns

Expand Down
124 changes: 5 additions & 119 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ Related: https://forum.unity.com/threads/6572-debugger-agent-unable-to-listen-on
<!-- Unity exits with a non-zero exit code when running tests. We ignore it and manually check the test results instead. -->
<Delete Files="$(UnityTestPlayModeResultFilePath)" />
<Exec EnvironmentVariables="IgnoreExitCode=true" Command="pwsh &quot;$(RepoRoot)scripts/unity.ps1&quot; $(UnityExec) -batchmode -nographics -runTests -testPlatform PlayMode -projectPath $(UnitySampleProjectPath) -testResults $(UnityTestPlayModeResultFilePath)" />
<UnityTestResults Path="$(UnityTestPlayModeResultFilePath)" />
<Exec Command="pwsh &quot;$(RepoRoot)scripts/report-test-results.ps1&quot; &quot;$(UnityTestPlayModeResultFilePath)&quot;" />
</Target>

<!-- Run EditMode tests with dotnet msbuild /t:UnityEditModeTest test/Sentry.Unity.Editor.Tests -->
Expand All @@ -411,7 +411,7 @@ Related: https://forum.unity.com/threads/6572-debugger-agent-unable-to-listen-on
<!-- IgnoreStandardErrorWarningFormat="true" because of the intentional compilation error printed in GenerateOptions_NewSentryOptionsGarbageAppended_FailsToCompile(). -->
<Delete Files="$(UnityTestEditModeResultFilePath)" />
<Exec EnvironmentVariables="IgnoreExitCode=true" IgnoreStandardErrorWarningFormat="true" Command="pwsh &quot;$(RepoRoot)scripts/unity.ps1&quot; $(UnityExec) -batchmode -nographics -runTests -testPlatform EditMode -projectPath $(UnitySampleProjectPath) -testResults $(UnityTestEditModeResultFilePath)"/>
<UnityTestResults Path="$(UnityTestEditModeResultFilePath)" />
<Exec Command="pwsh &quot;$(RepoRoot)scripts/report-test-results.ps1&quot; &quot;$(UnityTestEditModeResultFilePath)&quot;" />
</Target>

<!-- Locate the TestRunner.dlls by filling the wildcard with the template version number. 3d is the default template -->
Expand Down Expand Up @@ -465,104 +465,6 @@ File.WriteAllLines(PackageManifestFile, lines);
</Task>
</UsingTask>

<!-- Parse test results -->
<UsingTask TaskName="UnityTestResults" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<Path ParameterType="System.String" Required="true" />
</ParameterGroup>

<Task>
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Using Namespace="System.Linq" />
<Using Namespace="System.Xml.Linq" />
<Code Type="Fragment" Language="cs">
<![CDATA[

if (!File.Exists(Path))
{
Log.LogError("Test results file not found at " + Path);
return false;
}

var document = XDocument.Load(Path);
var testRun = document.Descendants("test-run").First();

var total = testRun.Attribute("total").Value;
if (total == "0")
{
Log.LogError("Unity test results is empty.");
return false;
}

var result = testRun.Attribute("result").Value;

Log.LogCriticalMessage("UnityTestResults", null, null, null, 0, 0, 0, 0, "{0} in {1}s", result.Replace("(Child)", ""), testRun.Attribute("duration").Value);
Log.LogCriticalMessage("UnityTestResults", null, null, null, 0, 0, 0, 0, " Passed: {0,3}", testRun.Attribute("passed").Value);
Log.LogCriticalMessage("UnityTestResults", null, null, null, 0, 0, 0, 0, " Failed: {0,3}", testRun.Attribute("failed").Value);
Log.LogCriticalMessage("UnityTestResults", null, null, null, 0, 0, 0, 0, " Skipped: {0,3}", testRun.Attribute("skipped").Value);
Log.LogCriticalMessage("UnityTestResults", null, null, null, 0, 0, 0, 0, " Inconclusive: {0,3}", testRun.Attribute("inconclusive").Value);

if (result == "Passed")
{
return true;
}

PrintFailedTests(testRun);

var failed = testRun.Attribute("failed").Value;
var errorMessage = $"Test run completed with {failed} failing test{(int.Parse(failed) > 1 ? "s" : "")}.";
Log.LogError(errorMessage);

Success = false;

void PrintFailedTests(XElement element)
{
foreach (var descendant in element.Descendants())
{
if (descendant.Name != "test-case"
|| descendant.Attribute("result")?.Value != "Failed")
{
continue;
}

if (descendant.Descendants().Any(d => d.Name == "test-case"))
{
PrintFailedTests(descendant);
}
else
{
var sb = new StringBuilder()
.Append("Test ")
.Append(descendant.Attribute("id")?.Value)
.Append(": ")
.AppendLine(descendant.Attribute("name")?.Value);

var failure = descendant.Descendants("failure")
.Descendants("message")
.FirstOrDefault()
?.Value;

var stack = descendant.Descendants("failure")
.Descendants("stack-trace")
.FirstOrDefault()
?.Value;

sb.AppendLine(failure)
.Append("Test StackTrace: ")
.AppendLine(stack);

// MSBuild is breaking each line as if it was an error per line and not a single error.
// So Log.LogError got replaced by Console.WriteLine for now.
Console.WriteLine(sb.ToString());
}
}
}
]]>
</Code>
</Task>
</UsingTask>

<!-- Checks if the environment variable 'SENTRY_AUTH_TOKEN' has been set and creates the SentryCliOptions.asset for the sample project
This is meant for developers - so they don't have to configure the CLI options after each clean checkout (or git clean).
Gets automatically run after 'DownloadNativeSDKs'
Expand All @@ -582,27 +484,11 @@ void PrintFailedTests(XElement element)
</Target>

<!-- Downloads native SDKs from the latest successful GitHub Actions workflow run.
Only downloads SDKs that are not already present.
This is meant for developers - so that they don't have to compile the native SDK after each clean checkout (or git clean).
Depends on your a GH CLI installation - https://cli.github.com/
Depends on a GH CLI installation - https://cli.github.com/
dotnet msbuild /t:DownloadNativeSDKs src/Sentry.Unity -->
<Target Name="DownloadNativeSDKs" Condition="'$(MSBuildProjectName)' == 'Sentry.Unity'">
<Message Importance="High" Text="Downloading pre-compiled native SDKs from GitHub Actions artifacts." />
<Exec ConsoleToMSBuild="true" Command="gh run list --branch main --workflow CI --json &quot;conclusion,databaseId&quot; --jq &quot;first(.[] | select(.conclusion == \&quot;success\&quot;) | .databaseId)&quot;">
<Output TaskParameter="ConsoleOutput" PropertyName="LastSuccessfulRunId" />
</Exec>
<Error Condition="!('$(LastSuccessfulRunId)' > 0)" Text="Failed to find a successful run" />

<ItemGroup>
<SDK Include="Windows"/>
<SDK Include="Android"/>
<SDK Include="Linux"/>
</ItemGroup>
<Message Importance="High" Text="Replacing $(SentryArtifactsDestination)%(SDK.Identity)" />
<RemoveDir Directories="$(SentryArtifactsDestination)%(SDK.Identity)" />
<Exec Command="gh run download $(LastSuccessfulRunId) -n &quot;%(SDK.Identity)-sdk&quot; -D &quot;$(SentryArtifactsDestination)%(SDK.Identity)&quot;" />

<!-- Download overwrites some files that then show up as changed in the IDE, even though there are no changes, e.g. only whitespace -->
<Message Importance="High" Text="Restoring package-dev/Plugins to the latest git commit" />
<Exec WorkingDirectory="$(RepoRoot)" Command="git restore package-dev/Plugins" />
<Exec Command="pwsh &quot;$(RepoRoot)scripts/download-native-sdks.ps1&quot; -RepoRoot &quot;$(RepoRoot)&quot;" />
</Target>
</Project>
136 changes: 136 additions & 0 deletions scripts/download-native-sdks.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env pwsh

param(
[Parameter()]
[string]$RepoRoot = "$PSScriptRoot/.."
)

Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $true

$ArtifactsDestination = Join-Path $RepoRoot "package-dev/Plugins"

# SDK definitions with their existence checks
$SDKs = @(
@{
Name = "Windows"
Destination = Join-Path $ArtifactsDestination "Windows"
CheckFile = "Sentry/sentry.dll"
},
@{
Name = "Linux"
Destination = Join-Path $ArtifactsDestination "Linux"
CheckFile = "Sentry/libsentry.so"
},
@{
Name = "Android"
Destination = Join-Path $ArtifactsDestination "Android"
CheckDir = "Sentry~"
ExpectedFileCount = 4
}
)

function Test-SDKPresent {
param($SDK)

if ($SDK.ContainsKey('CheckFile')) {
$checkPath = Join-Path $SDK.Destination $SDK.CheckFile
return Test-Path $checkPath
}
elseif ($SDK.ContainsKey('CheckDir')) {
$checkPath = Join-Path $SDK.Destination $SDK.CheckDir
if (-not (Test-Path $checkPath)) {
return $false
}
$fileCount = (Get-ChildItem -Path $checkPath -File).Count
return $fileCount -ge $SDK.ExpectedFileCount
}
return $false
}

function Get-LatestSuccessfulRunId {
Write-Host "Fetching latest successful CI run ID..." -ForegroundColor Yellow

$result = gh run list --branch main --workflow CI --json "conclusion,databaseId" --jq 'first(.[] | select(.conclusion == "success") | .databaseId)'

if (-not $result -or $result -eq "null") {
Write-Error "Failed to find a successful CI run on main branch"
exit 1
}

Write-Host "Found run ID: $result" -ForegroundColor Green
return $result
}

function Download-SDK {
param(
[Parameter(Mandatory)]
[string]$Name,
[Parameter(Mandatory)]
[string]$Destination,
[Parameter(Mandatory)]
[string]$RunId
)

Write-Host "Downloading $Name SDK..." -ForegroundColor Yellow

# Remove existing directory if present (partial download)
if (Test-Path $Destination) {
Write-Host " Removing existing directory..." -ForegroundColor Gray
Remove-Item -Path $Destination -Recurse -Force
}

$artifactName = "$Name-sdk"
gh run download $RunId -n $artifactName -D $Destination

if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to download $Name SDK"
exit 1
}

Write-Host " Downloaded $Name SDK successfully" -ForegroundColor Green
}

# Main logic
Write-Host "Checking native SDK status..." -ForegroundColor Cyan
Write-Host ""

$sdksToDownload = @()

foreach ($sdk in $SDKs) {
if (Test-SDKPresent $sdk) {
Write-Host "$($sdk.Name) SDK already present, skipping download." -ForegroundColor Green
}
else {
Write-Host "$($sdk.Name) SDK not found, will download." -ForegroundColor Yellow
$sdksToDownload += $sdk
}
}

Write-Host ""

if ($sdksToDownload.Count -eq 0) {
Write-Host "All native SDKs are already present." -ForegroundColor Green
exit 0
}

# Fetch run ID only if we need to download something
$runId = Get-LatestSuccessfulRunId

foreach ($sdk in $sdksToDownload) {
Download-SDK -Name $sdk.Name -Destination $sdk.Destination -RunId $runId
}

Write-Host ""
Write-Host "Restoring package-dev/Plugins to latest git commit..." -ForegroundColor Yellow
Push-Location $RepoRoot
try {
git restore package-dev/Plugins
}
finally {
Pop-Location
}

Write-Host ""
Write-Host "Native SDK download completed successfully!" -ForegroundColor Green
Loading
Loading