From b37e98159bf94cc165d2a0ddb23e41771b59bff2 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos <6349682+vaind@users.noreply.github.com> Date: Thu, 10 Nov 2022 16:11:08 +0100 Subject: [PATCH] feat: seperate build & runtime scriptable options configure() (#1046) --- .github/workflows/ci.yml | 4 +- CHANGELOG.md | 2 + samples/unity-of-bugs/Assets/Editor.meta | 8 + .../SentryBuildtimeOptionsConfiguration.cs | 16 ++ ...ntryBuildtimeOptionsConfiguration.cs.meta} | 2 +- .../SentryBuildtimeOptionsConfiguration.asset | 14 ++ ...ryBuildtimeOptionsConfiguration.asset.meta | 8 + .../Resources/Sentry/SentryOptions.asset | 6 +- .../SentryRuntimeOptionsConfiguration.asset | 14 ++ ...ntryRuntimeOptionsConfiguration.asset.meta | 8 + .../Scripts/CustomOptionsConfiguration.cs | 25 --- .../SentryRuntimeOptionsConfiguration.cs | 28 ++++ .../SentryRuntimeOptionsConfiguration.cs.meta | 11 ++ .../ProjectSettings/GraphicsSettings.asset | 1 - .../ProjectSettings/ProjectSettings.asset | 2 +- scripts/pack.ps1 | 8 +- scripts/smoke-test-droid.ps1 | 20 ++- .../BuildPostProcess.cs | 20 ++- .../Android/AndroidManifestConfiguration.cs | 19 +-- .../SentryPerformanceAutoInstrumentation.cs | 30 ++-- .../ConfigurationWindow/AdvancedTab.cs | 2 +- .../ConfigurationWindow/CoreTab.cs | 4 +- .../OptionsConfigurationTab.cs | 144 ++++++++++++------ .../SentryEditorWindowInstrumentation.cs | 80 +--------- .../ConfigurationWindow/SentryWindow.cs | 2 + .../Il2CppBuildPreProcess.cs | 5 +- .../Native/BuildPostProcess.cs | 18 +-- .../ScriptableOptionsConfiguration.cs | 15 ++ src/Sentry.Unity.Editor/SentryCliOptions.cs | 6 +- .../SentryScriptableObject.cs | 22 +++ .../ScriptableOptionsConfiguration.cs | 6 + .../ScriptableSentryUnityOptions.cs | 24 ++- src/Sentry.Unity/SentryUnityOptions.cs | 5 + .../Editor/Builder.cs | 2 +- .../Editor/BuildtimeOptions.cs | 43 ++++++ .../Scripts/RuntimeOptions.cs | 45 ++++++ .../Scripts/SmokeTestOptions.cs | 16 -- .../Scripts/SmokeTester.cs | 29 +--- test/Scripts.Integration.Test/add-sentry.ps1 | 1 + .../configure-sentry.ps1 | 29 ++-- .../create-project.ps1 | 3 +- test/Scripts.Integration.Test/globals.ps1 | 13 -- .../integration-test.ps1 | 136 ++++++++++------- .../run-smoke-test.ps1 | 1 + .../package-release.zip.snapshot | 7 +- .../AndroidManifestConfigurationTests.cs | 16 +- .../ScriptableSentryUnityOptionsTests.cs | 2 +- 47 files changed, 555 insertions(+), 367 deletions(-) create mode 100644 samples/unity-of-bugs/Assets/Editor.meta create mode 100644 samples/unity-of-bugs/Assets/Editor/SentryBuildtimeOptionsConfiguration.cs rename samples/unity-of-bugs/Assets/{Scripts/CustomOptionsConfiguration.cs.meta => Editor/SentryBuildtimeOptionsConfiguration.cs.meta} (83%) create mode 100644 samples/unity-of-bugs/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset create mode 100644 samples/unity-of-bugs/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset.meta create mode 100644 samples/unity-of-bugs/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset create mode 100644 samples/unity-of-bugs/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset.meta delete mode 100644 samples/unity-of-bugs/Assets/Scripts/CustomOptionsConfiguration.cs create mode 100644 samples/unity-of-bugs/Assets/Scripts/SentryRuntimeOptionsConfiguration.cs create mode 100644 samples/unity-of-bugs/Assets/Scripts/SentryRuntimeOptionsConfiguration.cs.meta create mode 100644 src/Sentry.Unity.Editor/ScriptableOptionsConfiguration.cs create mode 100644 test/Scripts.Integration.Test/Editor/BuildtimeOptions.cs create mode 100644 test/Scripts.Integration.Test/Scripts/RuntimeOptions.cs delete mode 100644 test/Scripts.Integration.Test/Scripts/SmokeTestOptions.cs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 665262a39..94be3c5a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -474,7 +474,7 @@ jobs: disk-size: 4096M # Some runs have out of storage error when installing the smoke test. emulator-options: -no-snapshot-save -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -accel on disable-animations: true - script: pwsh ./scripts/smoke-test-droid.ps1 -IsIntegrationTest + script: pwsh ./scripts/smoke-test-droid.ps1 -IsIntegrationTest -WarnIfFlaky - name: Kill emulator if AVD failed. if: ${{ steps.smoke-test.outputs.status != 'success' }} @@ -527,7 +527,7 @@ jobs: path: samples/IntegrationTest/Build - name: Build iOS package - run: ./Scripts/smoke-test-ios.ps1 Build -IsIntegrationTest -UnityVersion "${{ matrix.unity-version }}" + run: ./scripts/smoke-test-ios.ps1 Build -IsIntegrationTest -UnityVersion "${{ matrix.unity-version }}" - name: Upload iOS test app for smoke test. uses: actions/upload-artifact@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 83776c877..286cfcc68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ ### Features - Added Unity version to event context ([#1072](https://github.com/getsentry/sentry-unity/pull/1072)) +- Add build-time `ScriptableOptionsConfiguration` scripting interface to support changing settings for native integrations and CLI ([#1046](https://github.com/getsentry/sentry-unity/pull/1046)) ### Fixes - Auto Instrumentation now correctly resolves prebuilt assemblies ([#1066](https://github.com/getsentry/sentry-unity/pull/1066)) +- Newly created `ScriptableOptionsConfiguration` script not being set in editor window UI ([#1046](https://github.com/getsentry/sentry-unity/pull/1046)) ### Dependencies diff --git a/samples/unity-of-bugs/Assets/Editor.meta b/samples/unity-of-bugs/Assets/Editor.meta new file mode 100644 index 000000000..f015e46ea --- /dev/null +++ b/samples/unity-of-bugs/Assets/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cd20b2f937c2a8f42941ebf4c691803f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/unity-of-bugs/Assets/Editor/SentryBuildtimeOptionsConfiguration.cs b/samples/unity-of-bugs/Assets/Editor/SentryBuildtimeOptionsConfiguration.cs new file mode 100644 index 000000000..f1ccae2c2 --- /dev/null +++ b/samples/unity-of-bugs/Assets/Editor/SentryBuildtimeOptionsConfiguration.cs @@ -0,0 +1,16 @@ +using System; +using UnityEngine; +using Sentry.Unity; +using Sentry.Unity.Editor; + +[CreateAssetMenu(fileName = "Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset", menuName = "Sentry/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset", order = 999)] +public class SentryBuildtimeOptionsConfiguration : Sentry.Unity.Editor.ScriptableOptionsConfiguration +{ + /// See base class for documentation. + /// Learn more at https://docs.sentry.io/platforms/unity/configuration/options/#programmatic-configuration + public override void Configure(SentryUnityOptions options, SentryCliOptions cliOptions) + { + Debug.Log("SentryBuildtimeOptionsConfiguration::Configure() called"); + Debug.Log("SentryBuildtimeOptionsConfiguration::Configure() finished"); + } +} diff --git a/samples/unity-of-bugs/Assets/Scripts/CustomOptionsConfiguration.cs.meta b/samples/unity-of-bugs/Assets/Editor/SentryBuildtimeOptionsConfiguration.cs.meta similarity index 83% rename from samples/unity-of-bugs/Assets/Scripts/CustomOptionsConfiguration.cs.meta rename to samples/unity-of-bugs/Assets/Editor/SentryBuildtimeOptionsConfiguration.cs.meta index 0a41e4581..6720c826a 100644 --- a/samples/unity-of-bugs/Assets/Scripts/CustomOptionsConfiguration.cs.meta +++ b/samples/unity-of-bugs/Assets/Editor/SentryBuildtimeOptionsConfiguration.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: cf00f463fb8394bd4aaa371f7db39685 +guid: 59bc41c2bf823704a9122d2a5995ffcf MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/samples/unity-of-bugs/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset b/samples/unity-of-bugs/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset new file mode 100644 index 000000000..6fc31a0d1 --- /dev/null +++ b/samples/unity-of-bugs/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59bc41c2bf823704a9122d2a5995ffcf, type: 3} + m_Name: SentryBuildtimeOptionsConfiguration + m_EditorClassIdentifier: diff --git a/samples/unity-of-bugs/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset.meta b/samples/unity-of-bugs/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset.meta new file mode 100644 index 000000000..c1978f6f7 --- /dev/null +++ b/samples/unity-of-bugs/Assets/Plugins/Sentry/SentryBuildtimeOptionsConfiguration.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6bcc81a646c08ce439ab03805d477458 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset index 3728b6532..e3b9a6324 100644 --- a/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset +++ b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryOptions.asset @@ -17,7 +17,7 @@ MonoBehaviour: k__BackingField: 1 k__BackingField: 0 k__BackingField: 0 - k__BackingField: 0 + k__BackingField: 1 k__BackingField: 1 k__BackingField: 30000 k__BackingField: @@ -47,7 +47,9 @@ MonoBehaviour: k__BackingField: 1 k__BackingField: 1 k__BackingField: 1 - k__BackingField: {fileID: 11400000, guid: bda1a724b0875436aade31393b0129c0, + k__BackingField: {fileID: 11400000, guid: 407b4d5f2fef2c845bf2a3dcdf6b00fb, + type: 2} + k__BackingField: {fileID: 11400000, guid: 6bcc81a646c08ce439ab03805d477458, type: 2} k__BackingField: 1 k__BackingField: 0 diff --git a/samples/unity-of-bugs/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset new file mode 100644 index 000000000..cc941560d --- /dev/null +++ b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 91e386628575c034e89d0f7632eb69b8, type: 3} + m_Name: SentryRuntimeOptionsConfiguration + m_EditorClassIdentifier: diff --git a/samples/unity-of-bugs/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset.meta b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset.meta new file mode 100644 index 000000000..f53ac3afe --- /dev/null +++ b/samples/unity-of-bugs/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 407b4d5f2fef2c845bf2a3dcdf6b00fb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/unity-of-bugs/Assets/Scripts/CustomOptionsConfiguration.cs b/samples/unity-of-bugs/Assets/Scripts/CustomOptionsConfiguration.cs deleted file mode 100644 index 88acb31c2..000000000 --- a/samples/unity-of-bugs/Assets/Scripts/CustomOptionsConfiguration.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Sentry.Unity; -using UnityEngine; - -[CreateAssetMenu(fileName = "Assets/Resources/Sentry/CustomOptionsConfiguration", menuName = "Sentry/CustomOptionsConfiguration", order = 999)] -public class CustomOptionsConfiguration : ScriptableOptionsConfiguration -{ - // This method gets called when you instantiated the scriptable object and added it to the configuration window - public override void Configure(SentryUnityOptions options) - { - // NOTE: Changes to the options object done here will not affect native crashes. The native SDKs only take - // options defined in the Sentry editor configuration window. - // Learn more at: https://docs.sentry.io/platforms/unity/native-support/configuration/ - - options.BeforeSend = sentryEvent => - { - if (sentryEvent.Tags.ContainsKey("SomeTag")) - { - // Don't send events with a tag SomeTag to Sentry - return null; - } - - return sentryEvent; - }; - } -} diff --git a/samples/unity-of-bugs/Assets/Scripts/SentryRuntimeOptionsConfiguration.cs b/samples/unity-of-bugs/Assets/Scripts/SentryRuntimeOptionsConfiguration.cs new file mode 100644 index 000000000..1f31c36f0 --- /dev/null +++ b/samples/unity-of-bugs/Assets/Scripts/SentryRuntimeOptionsConfiguration.cs @@ -0,0 +1,28 @@ +using System; +using UnityEngine; +using Sentry.Unity; + +[CreateAssetMenu(fileName = "Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset", menuName = "Sentry/Assets/Resources/Sentry/SentryRuntimeOptionsConfiguration.asset", order = 999)] +public class SentryRuntimeOptionsConfiguration : Sentry.Unity.ScriptableOptionsConfiguration +{ + /// See base class for documentation. + /// Learn more at https://docs.sentry.io/platforms/unity/configuration/options/#programmatic-configuration + public override void Configure(SentryUnityOptions options) + { + Debug.Log("SentryRuntimeOptionsConfiguration::Configure() called"); + + /// BeforeSend is only relevant at runtime. It wouldn't hurt to be set at build time, just wouldn't do anything. + options.BeforeSend = sentryEvent => + { + if (sentryEvent.Tags.ContainsKey("SomeTag")) + { + // Don't send events with a tag SomeTag to Sentry + return null; + } + + return sentryEvent; + }; + + Debug.Log("SentryRuntimeOptionsConfiguration::Configure() finished"); + } +} diff --git a/samples/unity-of-bugs/Assets/Scripts/SentryRuntimeOptionsConfiguration.cs.meta b/samples/unity-of-bugs/Assets/Scripts/SentryRuntimeOptionsConfiguration.cs.meta new file mode 100644 index 000000000..be1e4f4cd --- /dev/null +++ b/samples/unity-of-bugs/Assets/Scripts/SentryRuntimeOptionsConfiguration.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91e386628575c034e89d0f7632eb69b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/unity-of-bugs/ProjectSettings/GraphicsSettings.asset b/samples/unity-of-bugs/ProjectSettings/GraphicsSettings.asset index 71c9e0f54..4654e1330 100644 --- a/samples/unity-of-bugs/ProjectSettings/GraphicsSettings.asset +++ b/samples/unity-of-bugs/ProjectSettings/GraphicsSettings.asset @@ -34,7 +34,6 @@ GraphicsSettings: - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} - - {fileID: 16003, guid: 0000000000000000f000000000000000, type: 0} m_PreloadedShaders: [] m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} diff --git a/samples/unity-of-bugs/ProjectSettings/ProjectSettings.asset b/samples/unity-of-bugs/ProjectSettings/ProjectSettings.asset index b4ff3070e..947982551 100644 --- a/samples/unity-of-bugs/ProjectSettings/ProjectSettings.asset +++ b/samples/unity-of-bugs/ProjectSettings/ProjectSettings.asset @@ -794,7 +794,7 @@ PlayerSettings: incrementalIl2cppBuild: {} suppressCommonWarnings: 1 allowUnsafeCode: 0 - additionalIl2CppArgs: + additionalIl2CppArgs: ' --emit-source-mapping' scriptingRuntimeVersion: 1 gcIncremental: 0 assemblyVersionValidation: 1 diff --git a/scripts/pack.ps1 b/scripts/pack.ps1 index 5cd63662d..7bf828043 100644 --- a/scripts/pack.ps1 +++ b/scripts/pack.ps1 @@ -1,4 +1,4 @@ -Remove-Item "package-release" -Recurse -ErrorAction SilentlyContinue +Remove-Item "package-release" -Recurse -ErrorAction SilentlyContinue New-Item "package-release" -ItemType Directory $exclude = @( @@ -22,9 +22,9 @@ Copy-Item "CHANGELOG.md" -Destination "package-release/CHANGELOG.md" Copy-Item "LICENSE.md" -Destination "package-release/LICENSE.md" # Copy samples -Copy-Item "samples/unity-of-bugs/Assets/Scenes" -Destination "package-release/Samples~/unity-of-bugs/Scenes" -Recurse -Copy-Item "samples/unity-of-bugs/Assets/Scripts" -Destination "package-release/Samples~/unity-of-bugs/Scripts" -Recurse ` - -Exclude "SmokeTestOptions.cs*" +Copy-Item "samples/unity-of-bugs/Assets/Scenes*" -Destination "package-release/Samples~/unity-of-bugs/" -Recurse +Copy-Item "samples/unity-of-bugs/Assets/Editor*" -Destination "package-release/Samples~/unity-of-bugs/" -Recurse +Copy-Item "samples/unity-of-bugs/Assets/Scripts*" -Destination "package-release/Samples~/unity-of-bugs/" -Recurse # Create zip Compress-Archive "package-release/*" -DestinationPath "package-release.zip" -Force diff --git a/scripts/smoke-test-droid.ps1 b/scripts/smoke-test-droid.ps1 index 359924dcf..3f3ddf9ea 100644 --- a/scripts/smoke-test-droid.ps1 +++ b/scripts/smoke-test-droid.ps1 @@ -1,6 +1,7 @@ param ( [Parameter(Position = 0)] - [Switch] $IsIntegrationTest + [Switch] $IsIntegrationTest, + [Switch] $WarnIfFlaky ) . $PSScriptRoot/../test/Scripts.Integration.Test/common.ps1 @@ -216,7 +217,7 @@ function ExitNow([string] $status, [string] $message) { Write-Host $message -ForegroundColor Green } - elseif ($status -ieq "flaky") + elseif ($status -ieq "flaky" -and $WarnIfFlaky) { Write-Warning $message } @@ -259,6 +260,8 @@ If (-not (Test-Path -Path "$ApkPath/$ApkFileName" )) # Test foreach ($device in $DeviceList) { + adb -s $device logcat -c + $deviceApi = "$(adb -s $device shell getprop ro.build.version.sdk)".Trim() $deviceSdk = "$(adb -s $device shell getprop ro.build.version.release)".Trim() Write-Host "`nChecking device $device with SDK '$deviceSdk' and API '$deviceApi'" @@ -283,7 +286,7 @@ foreach ($device in $DeviceList) do { Write-Host "Installing test app..." - $stdout = (adb -s $device install -r $ApkPath/$ApkFileName) + $stdout = (adb -s $device install -r $ApkPath/$ApkFileName 2>&1) if ($stdout.Contains("Broken pipe")) { @@ -299,12 +302,15 @@ foreach ($device in $DeviceList) ExitNow "failed" "Failed to Install APK: $stdout." } - function RunTest([string] $Name, [string] $SuccessString, [string] $FailureString) + function RunTest([string] $Name, [string] $SuccessString, [string] $FailureString, [switch] $PreserveLogcat) { Write-Host "::group::Test: '$name'" - Write-Host "Clearing logcat from $device." - adb -s $device logcat -c + if (!$PreserveLogcat) + { + Write-Host "Clearing logcat from $device." + adb -s $device logcat -c + } adb -s $device shell am start -n $TestActivityName -e test $Name #despite calling start, the app might not be started yet. @@ -411,7 +417,7 @@ foreach ($device in $DeviceList) # Note: mobile apps post the crash on the second app launch, so we must run both as part of the "CrashTestWithServer" CrashTestWithServer -SuccessString "POST /api/12345/envelope/ HTTP/1.1`" 200 -b'1f8b08000000000000" -CrashTestCallback { RunTest -Name "crash" -SuccessString "CRASH TEST: Issuing a native crash" -FailureString "CRASH TEST: FAIL" - RunTest -Name "has-crashed" + RunTest -Name "has-crashed" -PreserveLogcat } } catch diff --git a/src/Sentry.Unity.Editor.iOS/BuildPostProcess.cs b/src/Sentry.Unity.Editor.iOS/BuildPostProcess.cs index a14541a2d..16d62edf4 100644 --- a/src/Sentry.Unity.Editor.iOS/BuildPostProcess.cs +++ b/src/Sentry.Unity.Editor.iOS/BuildPostProcess.cs @@ -1,6 +1,7 @@ using System; using System.IO; using Sentry.Extensibility; +using Sentry.Unity.Editor.ConfigurationWindow; using UnityEditor; using UnityEditor.Callbacks; @@ -16,9 +17,7 @@ public static void OnPostProcessBuild(BuildTarget target, string pathToProject) return; } - var options = SentryScriptableObject - .Load(ScriptableSentryUnityOptions.GetConfigPath()) - ?.ToSentryUnityOptions(BuildPipeline.isBuildingPlayer); + var (options, cliOptions) = SentryScriptableObject.ConfiguredBuildtimeOptions(); var logger = options?.DiagnosticLogger ?? new UnityLogger(new SentryUnityOptions()); try @@ -37,32 +36,31 @@ public static void OnPostProcessBuild(BuildTarget target, string pathToProject) if (options is null) { - logger.LogWarning("Native support disabled. " + - "Sentry has not been configured. You can do that through the editor: Tools -> Sentry"); + logger.LogWarning("iOS native support disabled because Sentry has not been configured. " + + "You can do that through the editor: {0}", SentryWindow.EditorMenuPath); return; } if (!options.IsValid()) { - logger.LogWarning("Native support disabled."); + logger.LogWarning("iOS native support disabled."); return; } if (!options.IosNativeSupportEnabled) { - logger.LogDebug("iOS Native support disabled through the options."); + logger.LogDebug("iOS native support disabled through the options."); return; } sentryXcodeProject.AddNativeOptions(options); sentryXcodeProject.AddSentryToMain(options); - var sentryCliOptions = SentryScriptableObject.CreateOrLoad(SentryCliOptions.GetConfigPath()); - if (sentryCliOptions.IsValid(logger)) + if (cliOptions?.IsValid(logger, EditorUserBuildSettings.development) is true) { - SentryCli.CreateSentryProperties(pathToProject, sentryCliOptions, options); + SentryCli.CreateSentryProperties(pathToProject, cliOptions, options); SentryCli.AddExecutableToXcodeProject(pathToProject, logger); - sentryXcodeProject.AddBuildPhaseSymbolUpload(logger, sentryCliOptions); + sentryXcodeProject.AddBuildPhaseSymbolUpload(logger, cliOptions); } else if (options.Il2CppLineNumberSupportEnabled) { diff --git a/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs b/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs index 1e2e49871..72591b65a 100644 --- a/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs +++ b/src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs @@ -4,6 +4,7 @@ using System.Text; using System.Xml; using Sentry.Extensibility; +using Sentry.Unity.Editor.ConfigurationWindow; using UnityEditor; using UnityEditor.Android; using UnityEngine; @@ -25,9 +26,7 @@ public class AndroidManifestConfiguration : IPostGenerateGradleAndroidProject public AndroidManifestConfiguration() : this( - () => SentryScriptableObject.Load(ScriptableSentryUnityOptions.GetConfigPath()) - ?.ToSentryUnityOptions(BuildPipeline.isBuildingPlayer), - () => SentryScriptableObject.Load(SentryCliOptions.GetConfigPath()), + () => SentryScriptableObject.ConfiguredBuildtimeOptions(), isDevelopmentBuild: EditorUserBuildSettings.development, scriptingImplementation: PlayerSettings.GetScriptingBackend(BuildTargetGroup.Android)) { @@ -35,14 +34,12 @@ public AndroidManifestConfiguration() // Testing internal AndroidManifestConfiguration( - Func getOptions, - Func getSentryCliOptions, + Func<(SentryUnityOptions?, SentryCliOptions?)> getOptions, bool isDevelopmentBuild, ScriptingImplementation scriptingImplementation, IUnityLoggerInterceptor? interceptor = null) { - _options = getOptions(); - _sentryCliOptions = getSentryCliOptions(); + (_options, _sentryCliOptions) = getOptions(); _logger = _options?.DiagnosticLogger ?? new UnityLogger(_options ?? new SentryUnityOptions(), interceptor); _isDevelopmentBuild = isDevelopmentBuild; @@ -71,18 +68,18 @@ internal void ModifyManifest(string basePath) var disableAutoInit = false; if (_options is null) { - _logger.LogWarning("Android Native support disabled. " + - "Sentry has not been configured. You can do that through the editor: Tools -> Sentry"); + _logger.LogWarning("Android native support disabled because Sentry has not been configured. " + + "You can do that through the editor: {0}", SentryWindow.EditorMenuPath); disableAutoInit = true; } else if (!_options.IsValid()) { - _logger.LogDebug("Native support disabled."); + _logger.LogDebug("Android native support disabled."); disableAutoInit = true; } else if (!_options.AndroidNativeSupportEnabled) { - _logger.LogDebug("Android Native support disabled through the options."); + _logger.LogDebug("Android native support disabled through the options."); disableAutoInit = true; } diff --git a/src/Sentry.Unity.Editor/AutoInstrumentation/SentryPerformanceAutoInstrumentation.cs b/src/Sentry.Unity.Editor/AutoInstrumentation/SentryPerformanceAutoInstrumentation.cs index 3f7989273..2d20711eb 100644 --- a/src/Sentry.Unity.Editor/AutoInstrumentation/SentryPerformanceAutoInstrumentation.cs +++ b/src/Sentry.Unity.Editor/AutoInstrumentation/SentryPerformanceAutoInstrumentation.cs @@ -15,20 +15,20 @@ public class SentryPerformanceAutoInstrumentation : IPostBuildPlayerScriptDLLs public int callbackOrder { get; } public void OnPostBuildPlayerScriptDLLs(BuildReport report) { - var options = SentryScriptableObject.Load(ScriptableSentryUnityOptions.GetConfigPath()); + var (options, cliOptions) = SentryScriptableObject.ConfiguredBuildtimeOptions(); if (options == null) { return; } - var logger = options.ToSentryUnityOptions(isBuilding: true).DiagnosticLogger; - if (options.TracesSampleRate <= 0.0f || !options.PerformanceAutoInstrumentation) + var logger = options.DiagnosticLogger ?? new UnityLogger(options); + if (options.TracesSampleRate <= 0.0f || !options.PerformanceAutoInstrumentationEnabled) { - logger?.LogInfo("Performance Auto Instrumentation has been disabled."); + logger.LogInfo("Performance Auto Instrumentation has been disabled."); return; } - logger?.LogInfo("Running Performance Auto Instrumentation in PostBuildScriptPhase."); + logger.LogInfo("Running Performance Auto Instrumentation in PostBuildScriptPhase."); var stopwatch = Stopwatch.StartNew(); @@ -40,15 +40,15 @@ public void OnPostBuildPlayerScriptDLLs(BuildReport report) } catch (Exception e) { - logger?.LogError("Failed to add the performance auto instrumentation. " + + logger.LogError("Failed to add the performance auto instrumentation. " + "The assembly has not been modified.", e); } stopwatch.Stop(); - logger?.LogInfo("Auto Instrumentation finished in {0} seconds.", stopwatch.Elapsed.Seconds); + logger.LogInfo("Auto Instrumentation finished in {0} seconds.", stopwatch.Elapsed.Seconds); } - private static void ModifyPlayerAssembly(IDiagnosticLogger? logger, SentryPlayerReaderWriter playerReaderWriter) + private static void ModifyPlayerAssembly(IDiagnosticLogger logger, SentryPlayerReaderWriter playerReaderWriter) { var getInstanceMethod = playerReaderWriter.ImportSentryMonoBehaviourMethod("get_Instance"); var startAwakeSpanMethod = playerReaderWriter.ImportSentryMonoBehaviourMethod("StartAwakeSpan", new[] { typeof(MonoBehaviour) }); @@ -63,25 +63,25 @@ private static void ModifyPlayerAssembly(IDiagnosticLogger? logger, SentryPlayer continue; } - logger?.LogDebug("\tChecking: '{0}'", type.FullName); + logger.LogDebug("\tChecking: '{0}'", type.FullName); foreach (var method in type.Methods.Where(method => method.Name == "Awake")) { - logger?.LogDebug("\tDetected 'Awake' method."); + logger.LogDebug("\tDetected 'Awake' method."); if (method.Body is null) { - logger?.LogDebug("\tMethod body is null. Skipping."); + logger.LogDebug("\tMethod body is null. Skipping."); continue; } if (method.Body.Instructions is null) { - logger?.LogDebug("\tInstructions are null. Skipping."); + logger.LogDebug("\tInstructions are null. Skipping."); continue; } - logger?.LogDebug("\t\tAdding 'Start Awake Span'."); + logger.LogDebug("\t\tAdding 'Start Awake Span'."); var processor = method.Body.GetILProcessor(); @@ -90,7 +90,7 @@ private static void ModifyPlayerAssembly(IDiagnosticLogger? logger, SentryPlayer processor.InsertBefore(method.Body.Instructions[0], processor.Create(OpCodes.Ldarg_0)); processor.InsertBefore(method.Body.Instructions[0], processor.Create(OpCodes.Call, getInstanceMethod)); - logger?.LogDebug("\t\tAdding 'Finish Awake Span'."); + logger.LogDebug("\t\tAdding 'Finish Awake Span'."); // We're checking the instructions for OpCode.Ret so we can insert the finish span instruction before it. // Iterating over the collection backwards because we're modifying it's length @@ -105,7 +105,7 @@ private static void ModifyPlayerAssembly(IDiagnosticLogger? logger, SentryPlayer } } - logger?.LogInfo("Applying Auto Instrumentation."); + logger.LogInfo("Applying Auto Instrumentation."); playerReaderWriter.Write(); } } diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/AdvancedTab.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/AdvancedTab.cs index e4ba57c18..4eb696357 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/AdvancedTab.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/AdvancedTab.cs @@ -85,7 +85,7 @@ internal static void Display(ScriptableSentryUnityOptions options, SentryCliOpti { EditorGUILayout.HelpBox("The IL2CPP line number feature is supported from Unity version 2020.3 or newer and 2021.3 or newer onwards", MessageType.Warning); } - else if (cliOptions is not null && !cliOptions.IsValid(null)) + else if (cliOptions is not null && !cliOptions.IsValid(null, EditorUserBuildSettings.development)) { EditorGUILayout.HelpBox("The IL2CPP line number support relies on the Debug Symbol Upload to be properly set up.", MessageType.Error); } diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/CoreTab.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/CoreTab.cs index 2def8f059..82901b556 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/CoreTab.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/CoreTab.cs @@ -43,10 +43,10 @@ internal static void Display(ScriptableSentryUnityOptions options) EditorGUI.BeginDisabledGroup(options.TracesSampleRate <= 0); GUILayout.Label("Experimental", EditorStyles.boldLabel); - options.PerformanceAutoInstrumentation = EditorGUILayout.Toggle( + options.PerformanceAutoInstrumentationEnabled = EditorGUILayout.Toggle( new GUIContent("Auto Instrumentation", "To create transaction and spans automatically, " + "the SDK will modify the compiled assembly during a post build step."), - options.PerformanceAutoInstrumentation); + options.PerformanceAutoInstrumentationEnabled); EditorGUI.EndDisabledGroup(); } diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/OptionsConfigurationTab.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/OptionsConfigurationTab.cs index f6ffd001b..fe434ba7a 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/OptionsConfigurationTab.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/OptionsConfigurationTab.cs @@ -1,7 +1,10 @@ using System; using System.IO; +using System.Text; using UnityEditor; using UnityEngine; +using RuntimeConfiguration = Sentry.Unity.ScriptableOptionsConfiguration; +using BuildtimeConfiguration = Sentry.Unity.Editor.ScriptableOptionsConfiguration; namespace Sentry.Unity.Editor.ConfigurationWindow { @@ -13,50 +16,75 @@ public static void Display(ScriptableSentryUnityOptions options) EditorGUILayout.Space(); - EditorGUILayout.HelpBox("The scriptable options configuration allows you to programmatically " + - "modify the Sentry options at runtime, right before the SDK gets initialized." + - "This allows you to override configuration otherwise unavailable from the " + - "Editor UI, e.g. set a custom BeforeSend callback.", - MessageType.Info); + EditorGUILayout.HelpBox( + "The scriptable options configuration allows you to programmatically modify Sentry options." + + "\n" + + "\n" + + "You can use 'Runtime Options Script' to modify options just before Sentry SDK gets initialized. " + + "This allows you to change configuration otherwise unavailable from the Editor UI, e.g. set a custom BeforeSend callback." + + "\n" + + "\n" + + "Use 'Buildtime Options Script' in case you need to change build-time behavior, e.g. specify custom Sentry-CLI options " + + "or change settings for native SDKs that start before the managed layer does (such as Android, iOS, macOS).", + MessageType.Info); EditorGUILayout.HelpBox("Clicking the 'New' button will prompt you with selecting a location for " + - "your custom 'ScriptableSentryConfiguration' script and automatically " + - "create a new instance at 'Assets/Resources/Sentry/'", - // TODO other platforms - // "Because Sentry Unity integration includes both managed C# Unity SDK and a " + - // "platform specific one, you can specify the respective overrides separately.\n\n" + - MessageType.Info); + "your custom 'ScriptableOptionsConfiguration' script and automatically " + + "create a new asset instance.", MessageType.Info); EditorGUILayout.Space(); - OptionsConfigurationDotNet.Display(options); + options.OptionsConfiguration = OptionsConfigurationItem.Display( + options.OptionsConfiguration, + "Runtime Options Script", + "SentryRuntimeOptionsConfiguration" + ); + + options.BuildtimeOptionsConfiguration = OptionsConfigurationItem.Display( + options.BuildtimeOptionsConfiguration as BuildtimeConfiguration, + "Buildtime Options Script", + "SentryBuildtimeOptionsConfiguration" + ) as ScriptableObject; } } - internal static class OptionsConfigurationDotNet + internal static class OptionsConfigurationItem { - private const string CreateScriptableObjectFlag = "CreateScriptableOptionsObject"; - private const string ScriptNameKey = "ScriptableOptionsName"; + private const string CreateScriptableObjectFlag = "Sentry/CreateScriptableOptionsObject"; + private const string ScriptNameKey = "Sentry/ScriptableOptionsScript"; - public static void Display(ScriptableSentryUnityOptions options) + public static T? Display(T? value, string fieldName, string scriptName) where T : ScriptableObject { GUILayout.BeginHorizontal(); - options.OptionsConfiguration = EditorGUILayout.ObjectField( - new GUIContent(".NET (C#)", "A scriptable object that inherits from " + - "'ScriptableOptionsConfiguration' and allows you to " + - "programmatically modify Sentry options."), - options.OptionsConfiguration, typeof(ScriptableOptionsConfiguration), false) - as ScriptableOptionsConfiguration; + var result = EditorGUILayout.ObjectField( + new GUIContent(fieldName, "A scriptable object that inherits from 'ScriptableOptionsConfiguration' " + + "and allows you to programmatically modify Sentry options."), + value, + typeof(T), + false + ) as T; if (GUILayout.Button("New", GUILayout.ExpandWidth(false))) { - CreateScript(); + CreateScript(fieldName, scriptName); } GUILayout.EndHorizontal(); + return result; } - internal static void CreateScript() + private static string SentryAssetPath(string scriptName, bool isEditorScript) => + string.Format("Assets/{0}/Sentry/{1}.asset", isEditorScript ? "Plugins" : "Resources", scriptName); + + private static void CreateScript(string fieldName, string scriptName) { - var scriptPath = EditorUtility.SaveFilePanel("Sentry Options Configuration", "Assets", "SentryOptionsConfiguration", "cs"); + var isEditorScript = typeof(T) == typeof(BuildtimeConfiguration); + var directory = isEditorScript ? "Assets/Editor" : "Assets/Scripts"; + + if (!AssetDatabase.IsValidFolder(directory)) + { + AssetDatabase.CreateFolder(Path.GetDirectoryName(directory), Path.GetFileName(directory)); + } + + var scriptPath = EditorUtility.SaveFilePanel(fieldName, directory, scriptName, "cs"); if (String.IsNullOrEmpty(scriptPath)) { return; @@ -68,23 +96,30 @@ internal static void CreateScript() scriptPath = "Assets" + scriptPath.Substring(Application.dataPath.Length); } - var scriptName = Path.GetFileNameWithoutExtension(scriptPath); - - File.WriteAllText(scriptPath, $@"using Sentry.Unity; -using UnityEngine; - -[CreateAssetMenu(fileName = ""Assets/Resources/Sentry/{scriptName}.cs"", menuName = ""Sentry/{scriptName}"", order = 999)] -public class {scriptName} : ScriptableOptionsConfiguration -{{ - // This method gets called when you instantiated the scriptable object and added it to the configuration window - public override void Configure(SentryUnityOptions options) - {{ - // NOTE: Native support is already initialized by the time this method runs, so Unity bugs are captured. - // That means changes done to the 'options' here will only affect events from C# scripts. + scriptName = Path.GetFileNameWithoutExtension(scriptPath); - // Your code here - }} -}}"); + var template = new StringBuilder(); + template.AppendLine("using System;"); + template.AppendLine("using UnityEngine;"); + template.AppendLine("using Sentry.Unity;"); + if (isEditorScript) + { + template.AppendLine("using Sentry.Unity.Editor;"); + } + template.AppendLine(); + template.AppendFormat("[CreateAssetMenu(fileName = \"{0}\", menuName = \"Sentry/{0}\", order = 999)]\n", SentryAssetPath(scriptName, isEditorScript)); + template.AppendFormat("public class {0} : {1}\n", scriptName, typeof(T).FullName); + template.AppendLine("{"); + template.AppendLine(" /// See base class for documentation."); + template.AppendLine(" /// Learn more at https://docs.sentry.io/platforms/unity/configuration/options/#programmatic-configuration"); + template.AppendFormat(" public override void Configure(SentryUnityOptions options{0})\n", + typeof(T) == typeof(BuildtimeConfiguration) ? ", SentryCliOptions cliOptions" : ""); + template.AppendLine(" {"); + template.AppendLine(" // TODO implement"); + template.AppendLine(" }"); + template.AppendLine("}"); + + File.WriteAllText(scriptPath, template.ToString().Replace("\r\n", "\n")); // The created script has to be compiled and the scriptable object can't immediately be instantiated. // So instead we work around this by setting a 'CreateScriptableObjectFlag' flag in the EditorPrefs to @@ -111,17 +146,30 @@ private static void OnScriptsReloaded() SetScript(scriptName); } - internal static void SetScript(String scriptName) + internal static void SetScript(String scriptNameWithoutExtension) { - var optionsConfigurationObject = ScriptableObject.CreateInstance(scriptName); - AssetDatabase.CreateAsset(optionsConfigurationObject, $"Assets/Resources/Sentry/{scriptName}.asset"); + var optionsConfigurationObject = ScriptableObject.CreateInstance(scriptNameWithoutExtension); + var isEditorScript = optionsConfigurationObject is BuildtimeConfiguration; + AssetDatabase.CreateAsset(optionsConfigurationObject, SentryAssetPath(scriptNameWithoutExtension, isEditorScript)); AssetDatabase.Refresh(); - // Don't overwrite already set OptionsConfiguration - var options = SentryWindow.Instance!.Options; - if (options.OptionsConfiguration == null) + var options = EditorWindow.GetWindow().Options; + + if (isEditorScript) + { + // Don't overwrite already set OptionsConfiguration + if (options.BuildtimeOptionsConfiguration is null) + { + options.BuildtimeOptionsConfiguration = optionsConfigurationObject; + } + } + else { - options.OptionsConfiguration = (ScriptableOptionsConfiguration)optionsConfigurationObject; + // Don't overwrite already set OptionsConfiguration + if (options.OptionsConfiguration is null) + { + options.OptionsConfiguration = optionsConfigurationObject as RuntimeConfiguration; + } } } } diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/SentryEditorWindowInstrumentation.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/SentryEditorWindowInstrumentation.cs index 92e0258d7..870def2e9 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/SentryEditorWindowInstrumentation.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/SentryEditorWindowInstrumentation.cs @@ -17,9 +17,9 @@ private static void ConfigureOptions(Dictionary args, [CallerMem { Debug.LogFormat("{0}: Invoking SentryOptions", functionName); - if (!EditorApplication.ExecuteMenuItem("Tools/Sentry")) + if (!EditorApplication.ExecuteMenuItem(SentryWindow.EditorMenuPath.Replace(" -> ", "/"))) { - throw new Exception($"{functionName} failed: Menu item 'Tools -> Sentry' not found. Was the Sentry UPM package installed?"); + throw new Exception($"{functionName} failed: Menu item '{SentryWindow.EditorMenuPath}' not found. Was the Sentry UPM package installed?"); } var optionsWindow = EditorWindow.GetWindow(); @@ -33,74 +33,16 @@ private static void ConfigureOptions(Dictionary args, [CallerMem Debug.LogFormat("{0}: Found SentryOptions", functionName); var value = ""; - bool boolValue; - if (args.TryGetValue("sentryOptions.Dsn", out value)) + if (args.TryGetValue("runtimeOptionsScript", out value)) { - Debug.LogFormat("{0}: Configuring DSN to {1}", functionName, value); - options.Dsn = value; + Debug.LogFormat("{0}: Configuring Runtime Options Script to {1}", functionName, value); + OptionsConfigurationItem.SetScript(value); } - if (args.TryGetValue("sentryOptionsScript", out value)) + if (args.TryGetValue("buildtimeOptionsScript", out value)) { - Debug.LogFormat("{0}: Configuring Options Script to {1}", functionName, value); - OptionsConfigurationDotNet.SetScript(value); - } - - if (args.TryGetValue("attachScreenshot", out boolValue)) - { - Debug.LogFormat("{0}: Configuring AttachScreenshot to {1}", functionName, boolValue); - options.AttachScreenshot = boolValue; - } - - if (args.TryGetValue("diagnosticLevel", out value)) - { - Debug.LogFormat("{0}: Configuring DiagnosticLevel to {1}", functionName, value); - options.DebugOnlyInEditor = false; - options.DiagnosticLevel = value switch - { - "debug" => SentryLevel.Debug, - "info" => SentryLevel.Info, - "warning" => SentryLevel.Warning, - "error" => SentryLevel.Error, - "fatal" => SentryLevel.Fatal, - _ => throw new ArgumentException($"Invalid DiagnosticLevel value: {value}") - }; - } - - if (args.TryGetValue("il2cppLineNumbers", out boolValue)) - { - Debug.LogFormat("{0}: Configuring Il2CppLineNumberSupportEnabled to {1}", functionName, boolValue); - options.Il2CppLineNumberSupportEnabled = boolValue; - } - - if (args.TryGetValue("traceSampleRate", out boolValue)) - { - Debug.LogFormat("{0}: Configuring TraceSampleRate to {1}", functionName, boolValue ? 1.0f : 0.0f); - options.TracesSampleRate = boolValue ? 1.0d : 0.0d; - } - - if (args.TryGetValue("performanceAutoInstrumentation", out boolValue)) - { - Debug.LogFormat("{0}: Configuring Performance Auto Instrumentation to {1}", functionName, boolValue); - options.PerformanceAutoInstrumentation = boolValue; - } - - if (args.TryGetValue("cliOptions.Org", out value)) - { - Debug.LogFormat("{0}: Configuring symbol-upload organization to {1}", functionName, value); - cliOptions.Organization = value; - } - - if (args.TryGetValue("cliOptions.Project", out value)) - { - Debug.LogFormat("{0}: Configuring symbol-upload project to {1}", functionName, value); - cliOptions.Project = value; - } - - if (args.TryGetValue("cliOptions.Auth", out value)) - { - Debug.LogFormat("{0}: Configuring symbol-upload auth token", functionName); - cliOptions.Auth = value; + Debug.LogFormat("{0}: Configuring Buildtime Options Script to {1}", functionName, value); + OptionsConfigurationItem.SetScript(value); } if (args.TryGetValue("cliOptions.UrlOverride", out value)) @@ -109,12 +51,6 @@ private static void ConfigureOptions(Dictionary args, [CallerMem cliOptions.UrlOverride = value; } - if (args.TryGetValue("cliOptions.UploadSources", out boolValue)) - { - Debug.LogFormat("{0}: Configuring symbol-upload UploadSources to {1}", functionName, boolValue); - cliOptions.UploadSources = boolValue; - } - optionsWindow.Close(); Debug.LogFormat("{0}: SUCCESS", functionName); } diff --git a/src/Sentry.Unity.Editor/ConfigurationWindow/SentryWindow.cs b/src/Sentry.Unity.Editor/ConfigurationWindow/SentryWindow.cs index 88368f9bb..81a07c800 100644 --- a/src/Sentry.Unity.Editor/ConfigurationWindow/SentryWindow.cs +++ b/src/Sentry.Unity.Editor/ConfigurationWindow/SentryWindow.cs @@ -11,6 +11,8 @@ public class SentryWindow : EditorWindow { private const string LinkXmlPath = "Assets/Plugins/Sentry/link.xml"; + public const string EditorMenuPath = "Tools -> Sentry"; + [MenuItem("Tools/Sentry")] public static void OnMenuClick() { diff --git a/src/Sentry.Unity.Editor/Il2CppBuildPreProcess.cs b/src/Sentry.Unity.Editor/Il2CppBuildPreProcess.cs index f03a6cfd3..3d51e14d1 100644 --- a/src/Sentry.Unity.Editor/Il2CppBuildPreProcess.cs +++ b/src/Sentry.Unity.Editor/Il2CppBuildPreProcess.cs @@ -20,9 +20,8 @@ public void OnPreprocessBuild(BuildReport report) return; } - var options = SentryScriptableObject - .Load(ScriptableSentryUnityOptions.GetConfigPath()) - ?.ToSentryUnityOptions(BuildPipeline.isBuildingPlayer); + + var (options, cliOptions) = SentryScriptableObject.ConfiguredBuildtimeOptions(); if (options is null) { diff --git a/src/Sentry.Unity.Editor/Native/BuildPostProcess.cs b/src/Sentry.Unity.Editor/Native/BuildPostProcess.cs index cafa410b2..97f926f61 100644 --- a/src/Sentry.Unity.Editor/Native/BuildPostProcess.cs +++ b/src/Sentry.Unity.Editor/Native/BuildPostProcess.cs @@ -1,6 +1,7 @@ using System; using System.IO; using Sentry.Extensibility; +using Sentry.Unity.Editor.ConfigurationWindow; using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Build; @@ -20,18 +21,16 @@ public static void OnPostProcessBuild(BuildTarget target, string executablePath) return; } - var options = SentryScriptableObject - .Load(ScriptableSentryUnityOptions.GetConfigPath()) - ?.ToSentryUnityOptions(BuildPipeline.isBuildingPlayer); + var (options, cliOptions) = SentryScriptableObject.ConfiguredBuildtimeOptions(); var logger = options?.DiagnosticLogger ?? new UnityLogger(options ?? new SentryUnityOptions()); var isMono = PlayerSettings.GetScriptingBackend(targetGroup) == ScriptingImplementation.Mono2x; try { - if (options?.IsValid() is not true) + if (options is null) { - logger.LogWarning("Native support disabled. " + - "Sentry has not been configured. You can do that through the editor: Tools -> Sentry"); + logger.LogWarning("Native support disabled because Sentry has not been configured. " + + "You can do that through the editor: {0}", SentryWindow.EditorMenuPath); return; } @@ -52,7 +51,7 @@ public static void OnPostProcessBuild(BuildTarget target, string executablePath) var projectDir = Path.GetDirectoryName(executablePath); var executableName = Path.GetFileName(executablePath); AddCrashHandler(logger, target, projectDir, executableName); - UploadDebugSymbols(logger, target, projectDir, executableName, options, isMono); + UploadDebugSymbols(logger, target, projectDir, executableName, options, cliOptions, isMono); } catch (Exception e) { @@ -97,10 +96,9 @@ private static void AddCrashHandler(IDiagnosticLogger logger, BuildTarget target File.Copy(crashpadPath, targetPath, true); } - private static void UploadDebugSymbols(IDiagnosticLogger logger, BuildTarget target, string projectDir, string executableName, SentryUnityOptions options, bool isMono) + private static void UploadDebugSymbols(IDiagnosticLogger logger, BuildTarget target, string projectDir, string executableName, SentryUnityOptions options, SentryCliOptions? cliOptions, bool isMono) { - var cliOptions = SentryScriptableObject.CreateOrLoad(SentryCliOptions.GetConfigPath()); - if (!cliOptions.IsValid(logger)) + if (cliOptions?.IsValid(logger, EditorUserBuildSettings.development) is not true) { if (options.Il2CppLineNumberSupportEnabled) { diff --git a/src/Sentry.Unity.Editor/ScriptableOptionsConfiguration.cs b/src/Sentry.Unity.Editor/ScriptableOptionsConfiguration.cs new file mode 100644 index 000000000..8a2e57c6f --- /dev/null +++ b/src/Sentry.Unity.Editor/ScriptableOptionsConfiguration.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace Sentry.Unity.Editor +{ + public abstract class ScriptableOptionsConfiguration : ScriptableObject + { + /// + /// Called during app build. Changes made here will affect build-time processing, symbol upload, etc. + /// Additionally, because iOS, macOS and Android native error handling is configured at build time, + /// you can make changes to these options here. + /// + /// + public abstract void Configure(SentryUnityOptions options, SentryCliOptions cliOptions); + } +} diff --git a/src/Sentry.Unity.Editor/SentryCliOptions.cs b/src/Sentry.Unity.Editor/SentryCliOptions.cs index e1b38b447..3d8657ab5 100644 --- a/src/Sentry.Unity.Editor/SentryCliOptions.cs +++ b/src/Sentry.Unity.Editor/SentryCliOptions.cs @@ -1,7 +1,5 @@ using System; -using System.IO; using Sentry.Extensibility; -using UnityEditor; using UnityEngine; namespace Sentry.Unity.Editor @@ -30,7 +28,7 @@ internal static string GetConfigPath(string? notDefaultConfigName = null) private static void MissingFieldWarning(IDiagnosticLogger? logger, string name) => logger?.LogWarning("{0} missing. Please set it under {1}", name, EditorMenuPath); - public bool IsValid(IDiagnosticLogger? logger, bool? isDevelopmentBuild = null) + public bool IsValid(IDiagnosticLogger? logger, bool isDevelopmentBuild) { if (!UploadSymbols) { @@ -38,7 +36,7 @@ public bool IsValid(IDiagnosticLogger? logger, bool? isDevelopmentBuild = null) return false; } - if ((isDevelopmentBuild ?? EditorUserBuildSettings.development) && !UploadDevelopmentSymbols) + if (isDevelopmentBuild && !UploadDevelopmentSymbols) { logger?.LogDebug("Automated symbols upload for development builds has been disabled."); return false; diff --git a/src/Sentry.Unity.Editor/SentryScriptableObject.cs b/src/Sentry.Unity.Editor/SentryScriptableObject.cs index b123068be..d9b825e8c 100644 --- a/src/Sentry.Unity.Editor/SentryScriptableObject.cs +++ b/src/Sentry.Unity.Editor/SentryScriptableObject.cs @@ -23,5 +23,27 @@ internal static T CreateOrLoad(string path) where T : ScriptableObject } internal static T? Load(string path) where T : ScriptableObject => AssetDatabase.LoadAssetAtPath(path); + + private static SentryCliOptions? LoadCliOptions() => Load(SentryCliOptions.GetConfigPath()); + private static ScriptableSentryUnityOptions? LoadOptions() => + Load(ScriptableSentryUnityOptions.GetConfigPath()); + + internal static (SentryUnityOptions?, SentryCliOptions?) ConfiguredBuildtimeOptions() + { + var scriptableOptions = LoadOptions(); + var cliOptions = LoadCliOptions(); + + SentryUnityOptions? options = null; + if (scriptableOptions is not null) + { + options = scriptableOptions.ToSentryUnityOptions(isBuilding: true); + /// Must be non-nullable in the interface otherwise Unity script compilation fails... + cliOptions ??= ScriptableObject.CreateInstance(); + var setupScript = scriptableOptions.BuildtimeOptionsConfiguration as Sentry.Unity.Editor.ScriptableOptionsConfiguration; + setupScript?.Configure(options, cliOptions); + } + + return (options, cliOptions); + } } } diff --git a/src/Sentry.Unity/ScriptableOptionsConfiguration.cs b/src/Sentry.Unity/ScriptableOptionsConfiguration.cs index fa3b160f6..5645efa5a 100644 --- a/src/Sentry.Unity/ScriptableOptionsConfiguration.cs +++ b/src/Sentry.Unity/ScriptableOptionsConfiguration.cs @@ -4,6 +4,12 @@ namespace Sentry.Unity { public abstract class ScriptableOptionsConfiguration : ScriptableObject { + /// + /// Called at the player startup by SentryInitialization. + /// You can alter configuration for the C# error handling and also + /// native error handling in platforms other than iOS, macOS and Android. + /// + /// public abstract void Configure(SentryUnityOptions options); } } diff --git a/src/Sentry.Unity/ScriptableSentryUnityOptions.cs b/src/Sentry.Unity/ScriptableSentryUnityOptions.cs index 1981534b5..cfbe57379 100644 --- a/src/Sentry.Unity/ScriptableSentryUnityOptions.cs +++ b/src/Sentry.Unity/ScriptableSentryUnityOptions.cs @@ -29,7 +29,8 @@ public static string GetConfigPath(string? notDefaultConfigName = null) [field: SerializeField] public bool CaptureInEditor { get; set; } = true; [field: SerializeField] public bool EnableLogDebouncing { get; set; } = false; [field: SerializeField] public double TracesSampleRate { get; set; } = 0; - [field: SerializeField] public bool PerformanceAutoInstrumentation { get; set; } = false; + + [field: SerializeField] public bool PerformanceAutoInstrumentationEnabled { get; set; } = false; [field: SerializeField] public bool AutoSessionTracking { get; set; } = true; @@ -74,7 +75,10 @@ public static string GetConfigPath(string? notDefaultConfigName = null) [field: SerializeField] public bool LinuxNativeSupportEnabled { get; set; } = true; [field: SerializeField] public bool Il2CppLineNumberSupportEnabled { get; set; } = true; - [field: SerializeField] public ScriptableOptionsConfiguration? OptionsConfiguration { get; set; } + [field: SerializeField] public Sentry.Unity.ScriptableOptionsConfiguration? OptionsConfiguration { get; set; } + + /// Actual type is `Sentry.Unity.Editor.ScriptableOptionsConfiguration` but we can't reference it here because we don't depend on the editor Assembly. + [field: SerializeField] public ScriptableObject? BuildtimeOptionsConfiguration { get; set; } [field: SerializeField] public bool Debug { get; set; } = true; [field: SerializeField] public bool DebugOnlyInEditor { get; set; } = true; @@ -133,7 +137,8 @@ internal SentryUnityOptions ToSentryUnityOptions(bool isBuilding, ISentryUnityIn WindowsNativeSupportEnabled = WindowsNativeSupportEnabled, MacosNativeSupportEnabled = MacosNativeSupportEnabled, LinuxNativeSupportEnabled = LinuxNativeSupportEnabled, - Il2CppLineNumberSupportEnabled = Il2CppLineNumberSupportEnabled + Il2CppLineNumberSupportEnabled = Il2CppLineNumberSupportEnabled, + PerformanceAutoInstrumentationEnabled = PerformanceAutoInstrumentationEnabled, }; if (!string.IsNullOrWhiteSpace(ReleaseOverride)) @@ -181,12 +186,15 @@ internal SentryUnityOptions ToSentryUnityOptions(bool isBuilding, ISentryUnityIn } } - OptionsConfiguration?.Configure(options); - - // Doing this after the configure callback to allow users to programmatically opt out - if (!isBuilding && options.Il2CppLineNumberSupportEnabled && unityInfo is not null) + if (!isBuilding) { - options.AddIl2CppExceptionProcessor(unityInfo); + OptionsConfiguration?.Configure(options); + + // Doing this after the configure callback to allow users to programmatically opt out + if (options.Il2CppLineNumberSupportEnabled && unityInfo is not null) + { + options.AddIl2CppExceptionProcessor(unityInfo); + } } return options; diff --git a/src/Sentry.Unity/SentryUnityOptions.cs b/src/Sentry.Unity/SentryUnityOptions.cs index 744453249..f7752a293 100644 --- a/src/Sentry.Unity/SentryUnityOptions.cs +++ b/src/Sentry.Unity/SentryUnityOptions.cs @@ -122,6 +122,11 @@ public sealed class SentryUnityOptions : SentryOptions /// public bool Il2CppLineNumberSupportEnabled { get; set; } = true; + /// + /// Enable automatic performance transaction tracking. + /// + public bool PerformanceAutoInstrumentationEnabled { get; set; } = false; + // This option is hidden due to incompatibility between IL2CPP and Enhanced mode. private new StackTraceMode StackTraceMode { get; set; } diff --git a/test/Scripts.Integration.Test/Editor/Builder.cs b/test/Scripts.Integration.Test/Editor/Builder.cs index d78890519..54a1e776a 100644 --- a/test/Scripts.Integration.Test/Editor/Builder.cs +++ b/test/Scripts.Integration.Test/Editor/Builder.cs @@ -27,7 +27,7 @@ public static void BuildIl2CPPPlayer(BuildTarget target, BuildTargetGroup group) options = BuildOptions.StrictMode, }; - if(File.Exists("Assets/Scenes/SmokeTest.unity")) + if (File.Exists("Assets/Scenes/SmokeTest.unity")) { buildPlayerOptions.scenes = new[] { "Assets/Scenes/SmokeTest.unity" }; } diff --git a/test/Scripts.Integration.Test/Editor/BuildtimeOptions.cs b/test/Scripts.Integration.Test/Editor/BuildtimeOptions.cs new file mode 100644 index 000000000..d0d2425a3 --- /dev/null +++ b/test/Scripts.Integration.Test/Editor/BuildtimeOptions.cs @@ -0,0 +1,43 @@ +using Sentry; +using Sentry.Unity; +using Sentry.Unity.Editor; +using UnityEngine; +using UnityEditor; + +[CreateAssetMenu(fileName = "Assets/Resources/Sentry/BuildtimeOptions.cs", menuName = "Sentry/BuildtimeOptions", order = 999)] +public class BuildtimeOptions : Sentry.Unity.Editor.ScriptableOptionsConfiguration +{ + public override void Configure(SentryUnityOptions options, SentryCliOptions cliOptions) + { + Debug.Log("Sentry: BuildtimeOptions::Configure() called"); + + switch (EditorUserBuildSettings.selectedBuildTargetGroup) + { + case BuildTargetGroup.Android: + options.Dsn = "http://publickey@10.0.2.2:8000/12345"; + break; + case BuildTargetGroup.WebGL: + options.Dsn = "http://publickey@127.0.0.1:8000/12345"; + break; + default: + options.Dsn = "http://publickey@localhost:8000/12345"; + break; + } + + Debug.LogFormat("Sentry: Setting options.Dsn = {0}", options.Dsn); + + options.Il2CppLineNumberSupportEnabled = true; + options.Debug = true; + options.DiagnosticLevel = SentryLevel.Debug; + options.TracesSampleRate = 1.0d; + options.PerformanceAutoInstrumentationEnabled = true; + + cliOptions.UploadSymbols = !string.IsNullOrEmpty(cliOptions.UrlOverride); + cliOptions.UploadSources = cliOptions.UploadSymbols; + cliOptions.Organization = "sentry-sdks"; + cliOptions.Project = "sentry-unity"; + cliOptions.Auth = "dummy-token"; + + Debug.Log("Sentry: BuildtimeOptions::Configure() finished"); + } +} diff --git a/test/Scripts.Integration.Test/Scripts/RuntimeOptions.cs b/test/Scripts.Integration.Test/Scripts/RuntimeOptions.cs new file mode 100644 index 000000000..8a3d01f2a --- /dev/null +++ b/test/Scripts.Integration.Test/Scripts/RuntimeOptions.cs @@ -0,0 +1,45 @@ +using Sentry; +using Sentry.Unity; +using UnityEngine; + +[CreateAssetMenu(fileName = "Assets/Resources/Sentry/RuntimeOptions.cs", menuName = "Sentry/RuntimeOptions", order = 999)] +public class RuntimeOptions : ScriptableOptionsConfiguration +{ + public override void Configure(SentryUnityOptions options) + { + Debug.Log("Sentry: RuntimeOptions::Configure() called"); + + options.Dsn = string.Format("http://publickey@{0}:8000/12345", +#if UNITY_ANDROID + "10.0.2.2"); +#elif UNITY_WEBGL + "127.0.0.1"); +#else + "localhost"); +#endif + + Debug.LogFormat("Sentry: Setting options.Dsn = {0}", options.Dsn); + + options.AttachScreenshot = true; + options.Il2CppLineNumberSupportEnabled = true; + options.Debug = true; + options.DiagnosticLevel = SentryLevel.Debug; + options.TracesSampleRate = 1.0d; + options.PerformanceAutoInstrumentationEnabled = true; + + options.CreateHttpClientHandler = () => SmokeTester.t; + SmokeTester.CrashedLastRun = () => + { + if (options.CrashedLastRun != null) + { + return options.CrashedLastRun() ? 1 : 0; + } + return -2; + }; + + // If an ANR triggers while the smoke test runs, the test would fail because we expect exact order of events. + options.DisableAnrIntegration(); + + Debug.Log("Sentry: RuntimeOptions::Configure() finished"); + } +} diff --git a/test/Scripts.Integration.Test/Scripts/SmokeTestOptions.cs b/test/Scripts.Integration.Test/Scripts/SmokeTestOptions.cs deleted file mode 100644 index 79f5a3a1f..000000000 --- a/test/Scripts.Integration.Test/Scripts/SmokeTestOptions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Sentry.Unity; -using UnityEngine; - -[CreateAssetMenu(fileName = "Assets/Resources/Sentry/SmokeTestOptions.cs", menuName = "Sentry/SmokeTestOptions", order = 999)] -public class SmokeTestOptions : ScriptableOptionsConfiguration -{ - // This method gets called when you instantiated the scriptable object and added it to the configuration window - public override void Configure(SentryUnityOptions options) - { - // NOTE: Native support is already initialized by the time this method runs, so Unity bugs are captured. - // That means changes done to the 'options' here will only affect events from C# scripts. - - Debug.Log("Sentry: SmokeTestOptions - Configure called"); - SmokeTester.Configure(options); - } -} \ No newline at end of file diff --git a/test/Scripts.Integration.Test/Scripts/SmokeTester.cs b/test/Scripts.Integration.Test/Scripts/SmokeTester.cs index ba0e6cb92..979e35e9d 100644 --- a/test/Scripts.Integration.Test/Scripts/SmokeTester.cs +++ b/test/Scripts.Integration.Test/Scripts/SmokeTester.cs @@ -80,33 +80,16 @@ private static string GetTestArg() } #endif - private static TestHandler t = new TestHandler(); + internal static TestHandler t = new TestHandler(); - private static Func _crashedLastRun = () => -1; - - // Forwarded from SmokeTestOptions.Configure() - public static void Configure(SentryUnityOptions options) - { - Debug.Log("SmokeTester.Configure() running"); - options.CreateHttpClientHandler = () => t; - _crashedLastRun = () => - { - if (options.CrashedLastRun != null) - { - return options.CrashedLastRun() ? 1 : 0; - } - return -2; - }; - // If an ANR triggers while the smoke test runs, the test would fail because we expect exact order of events. - options.DisableAnrIntegration(); - } + internal static Func CrashedLastRun = () => -1; public static void SmokeTest() { t.Start("SMOKE"); try { - int crashed = _crashedLastRun(); + int crashed = CrashedLastRun(); t.Expect($"options.CrashedLastRun ({crashed}) == false (0)", crashed == 0); var currentMessage = 0; @@ -189,7 +172,7 @@ public static void CrashTest() public static void HasntCrashedTest() { t.Start("HASNT-CRASHED"); - int crashed = _crashedLastRun(); + int crashed = CrashedLastRun(); t.Expect($"options.CrashedLastRun ({crashed}) == false (0)", crashed == 0); t.Pass(); } @@ -197,7 +180,7 @@ public static void HasntCrashedTest() public static void HasCrashedTest() { t.Start("HAS-CRASHED"); - int crashed = _crashedLastRun(); + int crashed = CrashedLastRun(); t.Expect($"options.CrashedLastRun ({crashed}) == true (1)", crashed == 1); t.Pass(); } @@ -225,7 +208,7 @@ private static void AddContext() [DllImport("__Internal")] private static extern void throw_cpp(); - private class TestHandler : HttpClientHandler + internal class TestHandler : HttpClientHandler { private String name; diff --git a/test/Scripts.Integration.Test/add-sentry.ps1 b/test/Scripts.Integration.Test/add-sentry.ps1 index 0bef1a93c..219c2592c 100644 --- a/test/Scripts.Integration.Test/add-sentry.ps1 +++ b/test/Scripts.Integration.Test/add-sentry.ps1 @@ -13,3 +13,4 @@ RunUnityAndExpect $UnityPath "AddSentryPackage" "Sentry Package Installation: SU Write-Host -NoNewline "Copying Integration Test Files" New-Item -Path "$NewProjectAssetsPath" -Name "Scripts" -ItemType "directory" Copy-Item -Recurse "$IntegrationScriptsPath/Scripts/*" -Destination "$NewProjectAssetsPath/Scripts/" +Copy-Item -Recurse "$IntegrationScriptsPath/Editor/BuildtimeOptions.cs" -Destination "$NewProjectAssetsPath/Editor/" diff --git a/test/Scripts.Integration.Test/configure-sentry.ps1 b/test/Scripts.Integration.Test/configure-sentry.ps1 index 714a2fb3e..81bc2f050 100644 --- a/test/Scripts.Integration.Test/configure-sentry.ps1 +++ b/test/Scripts.Integration.Test/configure-sentry.ps1 @@ -12,22 +12,21 @@ $UnityPath = FormatUnityPath $UnityPath $unityArgs = @( ` "-quit", "-batchmode", "-nographics", "-projectPath ", $NewProjectPath, ` "-executeMethod", "Sentry.Unity.Editor.ConfigurationWindow.SentryEditorWindowInstrumentation.ConfigureOptions", ` - "-sentryOptions.Dsn", (TestDsnFor $Platform), ` - "-sentryOptionsScript", "SmokeTestOptions", ` - "-attachScreenshot", "true", ` - "-il2cppLineNumbers", "true", ` - "-diagnosticLevel", "debug", - "-traceSampleRate", "true", - "-performanceAutoInstrumentation", "true") + "-buildtimeOptionsScript", "BuildtimeOptions", ` + "-runtimeOptionsScript", "RuntimeOptions", ` + "-cliOptions.UrlOverride", ($CheckSymbols ? (SymbolServerUrlFor $UnityPath $Platform) : "") ) -if ($CheckSymbols) +RunUnityAndExpect $UnityPath "ConfigureSentryOptions" "ConfigureOptions: SUCCESS" $unityArgs + +function AssertPathExists([string] $Path) { - $unityArgs += @( ` - "-cliOptions.UploadSources", "true", ` - "-cliOptions.Org", "sentry-sdks", ` - "-cliOptions.Project", "sentry-unity", ` - "-cliOptions.Auth", "dummy-token", ` - "-cliOptions.UrlOverride", (SymbolServerUrlFor $UnityPath $Platform)) + if (!(Test-Path $Path)) + { + Write-Error "Path is expected to exist but it doesn't: '$Path'" + } } -RunUnityAndExpect $UnityPath "ConfigureSentryOptions" "ConfigureOptions: SUCCESS" $unityArgs +AssertPathExists "$NewProjectAssetsPath/Plugins/Sentry/SentryCliOptions.asset" +AssertPathExists "$NewProjectAssetsPath/Plugins/Sentry/BuildtimeOptions.asset" +AssertPathExists "$NewProjectAssetsPath/Resources/Sentry/SentryOptions.asset" +AssertPathExists "$NewProjectAssetsPath/Resources/Sentry/RuntimeOptions.asset" diff --git a/test/Scripts.Integration.Test/create-project.ps1 b/test/Scripts.Integration.Test/create-project.ps1 index 2106db172..fa9eec0ed 100644 --- a/test/Scripts.Integration.Test/create-project.ps1 +++ b/test/Scripts.Integration.Test/create-project.ps1 @@ -23,7 +23,8 @@ RunUnityCustom $UnityPath @("-batchmode", "-createProject", "$NewProjectPath", " Write-Host "Copying Editor scripts to integration project:" New-Item -Path "$NewProjectAssetsPath" -Name "Editor" -ItemType "directory" -Copy-Item -Recurse "$IntegrationScriptsPath/Editor/*" -Destination "$NewProjectAssetsPath/Editor/" +Copy-Item -Recurse "$IntegrationScriptsPath/Editor/*" -Destination "$NewProjectAssetsPath/Editor/" ` + -Exclude "BuildtimeOptions.cs" New-Item -Path "$NewProjectAssetsPath" -Name "Scenes" -ItemType "directory" Copy-Item -Recurse "$IntegrationScriptsPath/Scenes/*" -Destination "$NewProjectAssetsPath/Scenes/" Write-Host " OK" diff --git a/test/Scripts.Integration.Test/globals.ps1 b/test/Scripts.Integration.Test/globals.ps1 index c14498bcc..23dcfee36 100644 --- a/test/Scripts.Integration.Test/globals.ps1 +++ b/test/Scripts.Integration.Test/globals.ps1 @@ -144,19 +144,6 @@ function BuildMethodFor([string] $platform) } } -function TestDsnFor([string] $platform) -{ - $dsn = "http://publickey@" - switch ("$platform") - { - "Android" { $dsn += "10.0.2.2"; break; } - "WebGL" { $dsn += "127.0.0.1"; break; } - Default { $dsn += "localhost" } - } - $dsn += ":8000/12345" - return $dsn -} - function RunUnityCustom([string] $unityPath, [string[]] $arguments, [switch] $ReturnLogOutput) { If ($unityPath.StartsWith("docker ")) diff --git a/test/Scripts.Integration.Test/integration-test.ps1 b/test/Scripts.Integration.Test/integration-test.ps1 index 3be6520fd..5429942c8 100644 --- a/test/Scripts.Integration.Test/integration-test.ps1 +++ b/test/Scripts.Integration.Test/integration-test.ps1 @@ -4,81 +4,103 @@ # └───────────────────────────────────────────────────┘ # param( - [string] $UnityVersion, - [string] $Platform, - [switch] $Clean, - [switch] $Repack, - [switch] $Recreate, - [switch] $Rebuild + [string] $UnityVersion, + [string] $Platform, + [switch] $Clean, + [switch] $Repack, + [switch] $Recreate, + [switch] $Rebuild ) . ./test/Scripts.Integration.Test/globals.ps1 $UnityPath = $null -If ($IsMacOS) { - $UnityPath = "/Applications/Unity/Hub/Editor/$UnityVersion*/Unity.app/" -} elseif ($IsWindows) { - $UnityPath = "C:/Program Files/Unity/Hub/Editor/$UnityVersion/Editor/Unity.exe" +If ($IsMacOS) +{ + $UnityPath = "/Applications/Unity/Hub/Editor/$UnityVersion*/Unity.app/" } - -If (-not(Test-Path -Path $UnityPath)) { - Throw "Failed to find Unity at '$UnityPath'" +elseif ($IsWindows) +{ + $UnityPath = "C:/Program Files/Unity/Hub/Editor/$UnityVersion/Editor/Unity.exe" } -If($Clean) { - Write-Host "Cleanup" - If(Test-Path -Path "package-release.zip") { - Remove-Item -Path "package-release.zip" -Recurse -Force -Confirm:$false - } - If(Test-Path -Path "package-release") { - Remove-Item -Path "package-release" -Recurse -Force -Confirm:$false - } - If(Test-Path -Path $PackageReleaseOutput) { - Remove-Item -Path $PackageReleaseOutput -Recurse -Force -Confirm:$false - } - If(Test-Path -Path $NewProjectPath) { - Remove-Item -Path $NewProjectPath -Recurse -Force -Confirm:$false - } +If (-not(Test-Path -Path $UnityPath)) +{ + Throw "Failed to find Unity at '$UnityPath'" } -If (-not(Test-Path -Path $PackageReleaseOutput) -Or $Repack) { - Write-Host "Creating Package" - ./scripts/pack.ps1 - Write-Host "Extracting Package" - ./test/Scripts.Integration.Test/extract-package.ps1 +If ($Clean) +{ + Write-Host "Cleanup" + If (Test-Path -Path "package-release.zip") + { + Remove-Item -Path "package-release.zip" -Recurse -Force -Confirm:$false + } + If (Test-Path -Path "package-release") + { + Remove-Item -Path "package-release" -Recurse -Force -Confirm:$false + } + If (Test-Path -Path $PackageReleaseOutput) + { + Remove-Item -Path $PackageReleaseOutput -Recurse -Force -Confirm:$false + } + If (Test-Path -Path $NewProjectPath) + { + Remove-Item -Path $NewProjectPath -Recurse -Force -Confirm:$false + } } -If (-not(Test-Path -Path "$NewProjectPath") -Or $Recreate) { - Write-Host "Creating Project" - ./test/Scripts.Integration.Test/create-project.ps1 "$UnityPath" - Write-Host "Adding Sentry" - ./test/Scripts.Integration.Test/add-sentry.ps1 "$UnityPath" - Write-Host "Configuring Sentry" - ./test/Scripts.Integration.Test/configure-sentry.ps1 "$UnityPath" -Platform $Platform +If (-not(Test-Path -Path $PackageReleaseOutput) -Or $Repack) +{ + dotnet build + Write-Host "Creating Package" + ./scripts/pack.ps1 + Write-Host "Extracting Package" + ./test/Scripts.Integration.Test/extract-package.ps1 } -# If ($Platform -eq "Android") { -# ./test/Scripts.Integration.Test/build-project.ps1 "$UnityPath" -Platform "Android" -# ./scripts/smoke-test-droid.ps1 -IsIntegrationTest -# } +If (-not(Test-Path -Path "$NewProjectPath") -Or $Recreate) +{ + Write-Host "Creating Project" + ./test/Scripts.Integration.Test/create-project.ps1 "$UnityPath" + Write-Host "Adding Sentry" + ./test/Scripts.Integration.Test/add-sentry.ps1 "$UnityPath" + Write-Host "Configuring Sentry" + ./test/Scripts.Integration.Test/configure-sentry.ps1 "$UnityPath" -Platform $Platform +} -# If ($Platform -eq "iOS") { -# ./test/Scripts.Integration.Test/build-project.ps1 "$UnityPath" -Platform "iOS" -# ./Scripts/smoke-test-ios.ps1 Build -UnityVersion "2022" -# ./Scripts/smoke-test-ios.ps1 Test "iOS 12.4" -IsIntegrationTest -# } +$buildDir = "Samples/IntegrationTest/Build" -If(-not(Test-Path -Path "Samples/IntegrationTest/Build") -Or $Rebuild) { - Write-Host "Building Project" - ./test/Scripts.Integration.Test/build-project.ps1 -UnityPath "$UnityPath" -UnityVersion $UnityVersion -Platform $Platform +if ($Rebuild -or -not(Test-Path -Path $buildDir)) +{ + Write-Host "Building Project" + ./test/Scripts.Integration.Test/build-project.ps1 -UnityPath "$UnityPath" -UnityVersion $UnityVersion -Platform $Platform + if ($Platform -eq "iOS") + { + ./scripts/smoke-test-ios.ps1 Build -IsIntegrationTest -UnityVersion $UnityVersion + } } -Write-Host "Running Smoke Test" -If ($Platform -eq "macOS") { - ./test/Scripts.Integration.Test/run-smoke-test.ps1 -Smoke -} +Write-Host "Running tests" -If ($Platform -eq "WebGL") { - Start-Process "python3" -ArgumentList @("./Scripts/smoke-test-webgl.py", "Samples/IntegrationTest/Build") +switch -Regex ($Platform) +{ + "^(Windows|MacOS|Linux)$" + { + ./test/Scripts.Integration.Test/run-smoke-test.ps1 -Smoke -Crash + } + "^Android$" + { + ./scripts/smoke-test-droid.ps1 -IsIntegrationTest + } + "^iOS$" + { + ./scripts/smoke-test-ios.ps1 Test "latest" -IsIntegrationTest + } + "^WebGL$" + { + python3 scripts/smoke-test-webgl.py $buildDir + } + Default { Write-Warning "No test run for platform: '$platform'" } } diff --git a/test/Scripts.Integration.Test/run-smoke-test.ps1 b/test/Scripts.Integration.Test/run-smoke-test.ps1 index 8c7d6cb39..39bb0caf9 100644 --- a/test/Scripts.Integration.Test/run-smoke-test.ps1 +++ b/test/Scripts.Integration.Test/run-smoke-test.ps1 @@ -107,6 +107,7 @@ function RunTest([string] $type) { Write-Host "$type test: Player.log contents:" -ForegroundColor Yellow $appLog = Get-Content "$AppDataDir/Player.log" + $appLog Write-Host "================================================================================" -ForegroundColor Yellow Write-Host "$type test: Player.log contents END" -ForegroundColor Yellow } diff --git a/test/Scripts.Tests/package-release.zip.snapshot b/test/Scripts.Tests/package-release.zip.snapshot index 6d8fcb2d1..1a19309a8 100644 --- a/test/Scripts.Tests/package-release.zip.snapshot +++ b/test/Scripts.Tests/package-release.zip.snapshot @@ -235,6 +235,9 @@ Runtime/SentryInitialization.cs Runtime/SentryInitialization.cs.meta Runtime/SentryIntegrations.cs Runtime/SentryIntegrations.cs.meta +Samples~/unity-of-bugs/Editor.meta +Samples~/unity-of-bugs/Editor/SentryBuildtimeOptionsConfiguration.cs +Samples~/unity-of-bugs/Editor/SentryBuildtimeOptionsConfiguration.cs.meta Samples~/unity-of-bugs/Scenes.meta Samples~/unity-of-bugs/Scripts.meta Samples~/unity-of-bugs/Scenes/1_Bugfarm.unity @@ -249,8 +252,8 @@ Samples~/unity-of-bugs/Scripts/AdditionalButtons.cs Samples~/unity-of-bugs/Scripts/AdditionalButtons.cs.meta Samples~/unity-of-bugs/Scripts/BugFarmButtons.cs Samples~/unity-of-bugs/Scripts/BugFarmButtons.cs.meta -Samples~/unity-of-bugs/Scripts/CustomOptionsConfiguration.cs -Samples~/unity-of-bugs/Scripts/CustomOptionsConfiguration.cs.meta +Samples~/unity-of-bugs/Scripts/SentryRuntimeOptionsConfiguration.cs +Samples~/unity-of-bugs/Scripts/SentryRuntimeOptionsConfiguration.cs.meta Samples~/unity-of-bugs/Scripts/NativeSupport.meta Samples~/unity-of-bugs/Scripts/SceneButtons.cs Samples~/unity-of-bugs/Scripts/SceneButtons.cs.meta diff --git a/test/Sentry.Unity.Editor.Tests/Android/AndroidManifestConfigurationTests.cs b/test/Sentry.Unity.Editor.Tests/Android/AndroidManifestConfigurationTests.cs index ec968dae4..9787dc9ec 100644 --- a/test/Sentry.Unity.Editor.Tests/Android/AndroidManifestConfigurationTests.cs +++ b/test/Sentry.Unity.Editor.Tests/Android/AndroidManifestConfigurationTests.cs @@ -13,9 +13,7 @@ public class AndroidManifestTests private class Fixture { public SentryUnityOptions? SentryUnityOptions { get; set; } - public Func GetSentryUnityOptions { get; set; } public SentryCliOptions? SentryCliOptions { get; set; } - public Func GetSentryCliOptions { get; set; } public TestUnityLoggerInterceptor LoggerInterceptor { get; set; } public bool IsDevelopmentBuild { get; set; } public ScriptingImplementation ScriptingImplementation { get; set; } = ScriptingImplementation.IL2CPP; @@ -37,14 +35,10 @@ public Fixture() SentryCliOptions.Auth = "test_auth_token"; SentryCliOptions.Organization = "test_organization"; SentryCliOptions.Project = "test_project"; - - GetSentryUnityOptions = () => SentryUnityOptions; - GetSentryCliOptions = () => SentryCliOptions; } public AndroidManifestConfiguration GetSut() => - new(GetSentryUnityOptions, - GetSentryCliOptions, + new(() => (SentryUnityOptions, SentryCliOptions), IsDevelopmentBuild, ScriptingImplementation, LoggerInterceptor); @@ -77,8 +71,10 @@ public void ModifyManifest_LoadSentryUnityOptions_NullOptions_LogWarningAndDisab var sut = _fixture.GetSut(); var manifest = WithAndroidManifest(basePath => sut.ModifyManifest(basePath)); - _fixture.LoggerInterceptor.AssertLogContains(SentryLevel.Warning, "Android Native support disabled. " + - "Sentry has not been configured. You can do that through the editor: Tools -> Sentry"); + _fixture.LoggerInterceptor.AssertLogContains( + SentryLevel.Warning, + "Android native support disabled because Sentry has not been configured. " + + "You can do that through the editor: Tools -> Sentry"); Assert.True(manifest.Contains( ""), @@ -123,7 +119,7 @@ public void ModifyManifest_UnityOptions_AndroidNativeSupportEnabledFalse_LogDebu var sut = _fixture.GetSut(); var manifest = WithAndroidManifest(basePath => sut.ModifyManifest(basePath)); - _fixture.LoggerInterceptor.AssertLogContains(SentryLevel.Debug, "Android Native support disabled through the options."); + _fixture.LoggerInterceptor.AssertLogContains(SentryLevel.Debug, "Android native support disabled through the options."); Assert.True(manifest.Contains( ""), diff --git a/test/Sentry.Unity.Tests/ScriptableSentryUnityOptionsTests.cs b/test/Sentry.Unity.Tests/ScriptableSentryUnityOptionsTests.cs index 7bb93d56e..6bc1c4727 100644 --- a/test/Sentry.Unity.Tests/ScriptableSentryUnityOptionsTests.cs +++ b/test/Sentry.Unity.Tests/ScriptableSentryUnityOptionsTests.cs @@ -118,7 +118,7 @@ public void ToSentryUnityOptions_HasOptionsConfiguration_GetsCalled(bool isBuild scriptableOptions.ToSentryUnityOptions(isBuilding); - Assert.IsTrue(optionsConfiguration.GotCalled); + Assert.AreEqual(optionsConfiguration.GotCalled, !isBuilding); } [Test]