Skip to content
Draft
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
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -355,11 +355,13 @@ jobs:
with:
unity-version: ${{ matrix.unity-version }}
init-type: ${{ matrix.init-type }}
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

test-run-ios:
name: Run iOS ${{ matrix.unity-version }} Integration Test
if: ${{ !startsWith(github.ref, 'refs/heads/release/') }}
needs: [test-compile-ios, create-unity-matrix]
needs: [test-build-ios, create-unity-matrix]
uses: ./.github/workflows/test-run-ios.yml
with:
unity-version: ${{ matrix.unity-version }}
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/test-build-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ jobs:

- name: Assert symbols and sources were uploaded (Runtime)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath samples/IntegrationTest/Logs/sentry-symbols-upload.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Compare build sizes (Runtime)
run: ./test/Scripts.Integration.Test/measure-build-size.ps1 -Path1 "samples/IntegrationTest/Build-NoSentry" -Path2 "samples/IntegrationTest/Build" -Platform "Android" -UnityVersion "$env:UNITY_VERSION"
Expand Down Expand Up @@ -147,6 +149,8 @@ jobs:

- name: Assert symbols and sources were uploaded (Build-Time)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath samples/IntegrationTest/Logs/sentry-symbols-upload.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Bundle build & symbol-upload logs with the APK (Build-Time)
run: |
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/test-build-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ jobs:

- name: Assert symbols and sources were uploaded (Breakpad backend)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath unity.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Compare build sizes
run: ./test/Scripts.Integration.Test/measure-build-size.ps1 -Path1 "samples/IntegrationTest/Build-NoSentry" -Path2 "samples/IntegrationTest/Build" -Platform Linux -UnityVersion "$env:UNITY_VERSION"
Expand Down Expand Up @@ -158,6 +160,8 @@ jobs:

- name: Assert symbols and sources were uploaded (Native backend)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath unity.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Create archive (Native backend)
run: |
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/test-build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ jobs:

- name: Assert symbols and sources were uploaded (Cocoa backend)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath unity.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Compare build sizes
run: ./test/Scripts.Integration.Test/measure-build-size.ps1 -Path1 "samples/IntegrationTest/Build-NoSentry" -Path2 "samples/IntegrationTest/Build" -Platform MacOS -UnityVersion "$env:UNITY_VERSION"
Expand Down Expand Up @@ -140,6 +142,8 @@ jobs:

- name: Assert symbols and sources were uploaded (Native backend)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath unity.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Create archive (Native backend)
run: |
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-build-windows-mono.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ jobs:

- name: Assert symbols and sources were uploaded
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath unity.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

# We create tar explicitly because upload-artifact is slow for many files.
- name: Create archive
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-build-windows-x86.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ jobs:

- name: Assert symbols and sources were uploaded
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath unity.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

# We create tar explicitly because upload-artifact is slow for many files.
- name: Create archive
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/test-build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ jobs:

- name: Assert symbols and sources were uploaded (Crashpad backend)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath unity.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Compare build sizes
run: ./test/Scripts.Integration.Test/measure-build-size.ps1 -Path1 "samples/IntegrationTest/Build-NoSentry" -Path2 "samples/IntegrationTest/Build" -Platform Windows -UnityVersion "$env:UNITY_VERSION"
Expand Down Expand Up @@ -140,6 +142,8 @@ jobs:

- name: Assert symbols and sources were uploaded (Native backend)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath unity.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Create archive (Native backend)
run: |
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/test-compile-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ on:
init-type:
required: true
type: string
secrets:
SENTRY_AUTH_TOKEN:
required: true

defaults:
run:
Expand Down Expand Up @@ -42,6 +45,8 @@ jobs:

- name: Assert symbols and sources were uploaded
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath samples/IntegrationTest/Build/sentry-symbols-upload.log
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Upload integration-test project on failure
if: ${{ failure() }}
Expand Down
29 changes: 21 additions & 8 deletions .github/workflows/test-run-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ defaults:

jobs:
run:
timeout-minutes: 25
timeout-minutes: 45
name: ${{ inputs.unity-version }} ${{ inputs.ios-version }} ${{ inputs.init-type }}
runs-on: macos-15 # Pinning to get the oldest, supported version of iOS simulator
# Map the job outputs to step outputs
Expand All @@ -50,28 +50,41 @@ jobs:
run: git submodule update --init modules/app-runner
shell: bash

- name: Set Xcode for iOS version ${{ env.IOS_VERSION }}
if: ${{ env.IOS_VERSION != 'latest'}}
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
with:
xcode-version: '16.4' # to run iOS 18.5 we need Xcode 16.4

# A launch within ~2 minutes of the boot can stall past the run timeout, so boot while the app compiles.
- name: Boot simulator
timeout-minutes: 10
run: |
. ./modules/app-runner/import-modules.ps1
$target = if ($env:IOS_VERSION -match '^\d+\.\d+$') { "iOS $env:IOS_VERSION" } else { $env:IOS_VERSION }
Connect-Device -Platform "iOSSimulator" -Target $target | Out-Null
"SIMULATOR_BOOTED_AT=$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())" >> $env:GITHUB_ENV

- name: Download app artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
timeout-minutes: 20
uses: ./.github/actions/wait-for-artifact
with:
name: testapp-ios-compiled-${{ env.UNITY_VERSION }}-${{ env.INIT_TYPE }}
path: samples/IntegrationTest/Build
producer: Compile iOS ${{ env.UNITY_VERSION }} Test / ${{ env.UNITY_VERSION }} ${{ env.INIT_TYPE }}

- name: List downloaded files
run: |
Get-ChildItem -Path "samples/IntegrationTest/Build" -Recurse

- name: Set Xcode for iOS version ${{ env.IOS_VERSION }}
if: ${{ env.IOS_VERSION != 'latest'}}
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
with:
xcode-version: '16.4' # to run iOS 18.5 we need Xcode 16.4

- name: Run iOS Integration Tests
id: integration-test
timeout-minutes: 20
env:
SENTRY_IOS_VERSION: ${{ inputs.ios-version }}
run: |
# A rerun finds the app at once; keep its first launch out of the settle window too.
Start-Sleep -Seconds ([Math]::Max(0, [int]$env:SIMULATOR_BOOTED_AT + 150 - [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()))
$env:SENTRY_TEST_PLATFORM = "iOS"
$env:SENTRY_TEST_APP = "samples/IntegrationTest/Build/IntegrationTest.app"
Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixes

- Running `SentryEditorWindowInstrumentation.ConfigureOptions` again on a configured project no longer clears the options and CLI options configuration ([#2911](https://github.com/getsentry/sentry-unity/pull/2911))

## 4.11.0

### Fixes
Expand Down
5 changes: 3 additions & 2 deletions scripts/unity-utils.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function GetUnityRetrySignature([string] $unityPath, [string[]] $arguments, [int
return $null
}

# Unity 6.6 on Linux intermittently gets SIGKILLed during startup.
# Unity 6.6 kills the PID in a stale Library/burst.pid at startup, which in a fresh container can be its own xvfb-run.
if ($exitCode -eq 137)
{
return 'killed'
Expand Down Expand Up @@ -48,7 +48,8 @@ function GetUnityRetrySignature([string] $unityPath, [string[]] $arguments, [int
return 'tool-segfault'
}

if (($stdout -match 'Batchmode quit successfully invoked') -and ($stdout -match 'Caught fatal signal'))
# A trap after a long shutdown stall (exit 133, SIGTRAP) can kill Unity before it logs the signal.
if (($stdout -match 'Batchmode quit successfully invoked') -and (($stdout -match 'Caught fatal signal') -or $exitCode -eq 133))
{
return 'shutdown-crash'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,39 @@ private static void OnScriptsReloaded()

internal static void SetScript(string scriptNameWithoutExtension)
{
var optionsConfigurationObject = ScriptableObject.CreateInstance(scriptNameWithoutExtension);
var window = EditorWindow.GetWindow<SentryWindow>();
SetScript(scriptNameWithoutExtension, window.Options, window.CliOptions);
}

var options = EditorWindow.GetWindow<SentryWindow>().Options;
var cliOptions = EditorWindow.GetWindow<SentryWindow>().CliOptions;
internal static void SetScript(string scriptNameWithoutExtension, ScriptableSentryUnityOptions options, SentryCliOptions cliOptions)
{
var optionsConfigurationObject = ScriptableObject.CreateInstance(scriptNameWithoutExtension);

switch (optionsConfigurationObject)
{
case SentryOptionsConfiguration configuration:
AssetDatabase.CreateAsset(optionsConfigurationObject, SentryOptionsConfiguration.GetAssetPath(scriptNameWithoutExtension));
AssetDatabase.Refresh();
configuration = LoadOrCreateAsset(configuration, SentryOptionsConfiguration.GetAssetPath(scriptNameWithoutExtension));
options.OptionsConfiguration ??= configuration; // Don't overwrite if already set
break;
case SentryCliOptionsConfiguration cliConfiguration:
AssetDatabase.CreateAsset(optionsConfigurationObject, SentryCliOptionsConfiguration.GetAssetPath(scriptNameWithoutExtension));
AssetDatabase.Refresh();
cliConfiguration = LoadOrCreateAsset(cliConfiguration, SentryCliOptionsConfiguration.GetAssetPath(scriptNameWithoutExtension));
cliOptions.CliOptionsConfiguration ??= cliConfiguration; // Don't overwrite if already set
break;
}
}

// Recreating the asset would leave the options referencing an object that is no longer it.
private static T LoadOrCreateAsset<T>(T instance, string path) where T : ScriptableObject
{
var existing = AssetDatabase.LoadAssetAtPath<T>(path);
if (existing != null)
{
UnityEngine.Object.DestroyImmediate(instance);
return existing;
}

AssetDatabase.CreateAsset(instance, path);
AssetDatabase.Refresh();
return instance;
}
}
13 changes: 13 additions & 0 deletions test/IntegrationTest/Integration.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ BeforeAll {
}

$runResult = Invoke-App -Action $Action
$sendResult = $null

# On Xbox, console output is not available in non-development builds.
# Retrieve the log file the app writes directly to disk.
Expand Down Expand Up @@ -324,11 +325,23 @@ BeforeAll {
$runResult.Output | ForEach-Object { Write-Host $_ }
Write-Host "::endgroup::"

# sentry-cocoa sends the crash report on crash-send and deletes the envelope if sentry.io answers with a 5xx. Rerun once per job.
$ingest5xx = $Action -eq "crash-capture" -and [bool]($sendResult.Output -match "Received response status code: 5\d\d")
if ($ingest5xx -and $script:Ingest5xxRetried) {
Write-Host "::warning::sentry.io answered the crash report with a 5xx again (signature: ingest-5xx). Not running $Action a third time."
}
elseif ($ingest5xx) {
$script:Ingest5xxRetried = $true
Write-Host "::warning::sentry.io answered the crash report with a 5xx and the SDK dropped it (signature: ingest-5xx). Running $Action again."
return Invoke-TestAction -Action $Action
}

return $runResult
}

$script:AndroidUninitialisedLaunches = 0
$script:FlushTimeoutRelaunched = $false
$script:Ingest5xxRetried = $false

$script:Platform = $env:SENTRY_TEST_PLATFORM
if ([string]::IsNullOrEmpty($script:Platform)) {
Expand Down
84 changes: 81 additions & 3 deletions test/Scripts.Integration.Test/assert-symbol-upload.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,20 @@ if ($log -notmatch "--include-sources")

# Confirm the upload reached a terminal success state rather than erroring out.
# "Uploaded N missing debug information files" on first upload; "Nothing to upload"
# when the artifacts are already on the server (idempotent re-run / cache hit).
# when the artifacts are already on the server (idempotent re-run / cache hit);
# only "File upload/processing complete" when a rebuild's chunks are all on the server already.
$uploadSucceeded = $log -match "Uploaded \d+ missing debug information file" `
-or $log -match "Nothing to upload"
-or $log -match "Nothing to upload" `
-or $log -match "File (upload|processing) complete"
if (-not $uploadSucceeded)
{
throw "Symbol-upload assertion failed: sentry-cli upload did not reach a success state in '$LogPath'. " +
"Expected 'Uploaded N missing debug information files' or 'Nothing to upload'."
"Expected 'Uploaded N missing debug information files', 'Nothing to upload' or 'File upload/processing complete'."
}

if ($log -match "some symbols did not process correctly")
{
throw "Symbol-upload assertion failed: sentry.io failed to process a debug file in '$LogPath'."
}

$retries = [regex]::Matches($log, "retry number \d+ failed due to request failed with retryable status code (\d+)")
Expand All @@ -77,3 +84,74 @@ if ($retries.Count -gt 0)
}

Write-Host "Symbol-upload assertion passed: sentry-cli uploaded debug symbols and sources ('$LogPath')." -ForegroundColor Green

# sentry-cli returns before sentry.io has processed the upload, and a large debug companion can take
# minutes. An event that arrives earlier is symbolicated without it and never reprocessed, so wait
# until the server lists each uploaded debug companion, IL2CPP mapping and source bundle.
$pending = [regex]::Matches($log, "UPLOADED (\S+) \([^;)]+;\s*(?:\w+ )?(debug companion|il2cpp|sources)\)") |
ForEach-Object { "$($_.Groups[1].Value) $($_.Groups[2].Value)" } | Sort-Object -Unique
function Test-ProcessedFile($files, [string] $kind)
{
foreach ($file in $files)
{
$processed = switch ($kind)
{
'debug companion' { ($file.data | Select-Object -ExpandProperty features -ErrorAction Ignore) -contains 'debug' }
'il2cpp' { $file.symbolType -eq 'il2cpp' }
# A portable PDB embeds its sources instead of getting a source bundle.
'sources' { $file.symbolType -eq 'sourcebundle' -or ($file.data | Select-Object -ExpandProperty features -ErrorAction Ignore) -contains 'sources' }
}
if ($processed) { return $true }
}
return $false
}

if ($pending -and -not $env:SENTRY_AUTH_TOKEN)
{
Write-Host "::warning::Not waiting for sentry.io to process the debug files: SENTRY_AUTH_TOKEN is not set (signature: symbols-processing-skipped)."
}
elseif ($pending)
{
# The project CliConfiguration.cs uploads to.
$uriBase = "https://sentry.io/api/0/projects/sentry-sdks/sentry-unity-integration-tests/files/dsyms/"
$timeoutSeconds = 300
$headers = @{ Authorization = "Bearer $env:SENTRY_AUTH_TOKEN" }
# Deterministic builds reuse debug IDs, so only a file the server processed for this build counts.
$since = [DateTime]::UtcNow.AddMinutes(-30)
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
foreach ($debugId in ($pending | ForEach-Object { $_.Split(' ')[0] } | Sort-Object -Unique))
{
$kinds = $pending | Where-Object { $_.StartsWith("$debugId ") } | ForEach-Object { $_.Substring($debugId.Length + 1) }
while ($true)
{
try
{
$files = Invoke-RestMethod -Uri "$uriBase`?debug_id=$debugId" -Headers $headers -TimeoutSec 30
}
catch
{
$status = if ($_.Exception -is [Microsoft.PowerShell.Commands.HttpResponseException]) { [int]$_.Exception.Response.StatusCode } else { 0 }
if ($status -in 401, 403)
{
Write-Host "::warning::Not waiting for sentry.io to process the debug files: the token can't list them (HTTP $status, signature: symbols-processing-skipped)."
return
}
Write-Host "Querying debug files of $debugId failed: $_"
$files = @()
}
$files = @($files | Where-Object { ([DateTime]$_.dateCreated).ToUniversalTime() -ge $since })
$missing = $kinds | Where-Object { -not (Test-ProcessedFile $files $_) }
if (-not $missing)
{
break
}
if ($stopwatch.Elapsed.TotalSeconds -gt $timeoutSeconds)
{
Write-Host "::warning::sentry.io has not processed $($missing -join ', ') of $debugId after $timeoutSeconds s (signature: symbols-processing-timeout). Events may stay unsymbolicated."
return
}
Start-Sleep -Seconds 10
}
}
Write-Host "sentry.io processed the uploaded debug files after $([int]$stopwatch.Elapsed.TotalSeconds) s."
}
Loading
Loading