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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@

## Unreleased

### Features

- The SDK now provides a dedicated sentry-cli scriptable config, available on the `Debug Symbols` tab. This allows for programmatic configuration of the used cli-options during build. ([#1887](https://github.com/getsentry/sentry-unity/pull/1887))

### Fixes

- The SDK no longer sends events when it fails to initialize the native SDK on Windows and Linux and logs those instead. It also suppresses `EntryPointNotFoundException` if sentry-native is not available at runtime. Native crashes won't get capture but it'll continue to capture C# errors. ([#1898](https://github.com/getsentry/sentry-unity/pull/1898))
- The SDK no longer closes the underlying native SDK during the games shutdown if native support has not been enabled. This allows the SDK to support and capture errors in case of building the game as a library on a mobile (Android or iOS) game. ([#1897](https://github.com/getsentry/sentry-unity/pull/1897))

### Features

- The SDK now provides a dedicated sentry-cli scriptable config, available on the `Debug Symbols` tab. This allows for programmatic configuration of the used cli-options during build. ([#1887](https://github.com/getsentry/sentry-unity/pull/1887))

### Dependencies

- Bump .NET SDK from v4.12.1 to v4.13.0 ([#1879](https://github.com/getsentry/sentry-unity/pull/1879), [#1885](https://github.com/getsentry/sentry-unity/pull/1885))
Expand Down
Original file line number Diff line number Diff line change
@@ -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: be9687ec81ccb4180b0ed8c055df62d8, type: 3}
m_Name: SentryCliConfiguration
m_EditorClassIdentifier:

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions samples/unity-of-bugs/Assets/Scripts/SentryCliConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using Sentry.Unity;
using UnityEngine;

public class SentryCliConfiguration : SentryCliOptionsConfiguration
{
public override void Configure(SentryCliOptions cliOptions)
{
var isDevMachineWithSymbolUpload = Environment.GetEnvironmentVariable("DEV_SYMBOL_UPLOAD") == "true";
if (isDevMachineWithSymbolUpload)
{
Debug.Log("'DEV_SYMBOL_UPLOAD' detected: Debug symbol upload has been enabled.");
cliOptions.UploadSymbols = true;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

185 changes: 185 additions & 0 deletions src/Sentry.Unity.Editor/ConfigurationWindow/ConfigurationCreator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
using System;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;

namespace Sentry.Unity.Editor.ConfigurationWindow;

internal static class OptionsConfigurationItem
{
private const string CreateScriptableObjectFlag = "Sentry/CreateScriptableOptionsObject";
private const string ScriptNameKey = "Sentry/ScriptableOptionsScript";

public static T? Display<T>(T? value, string fieldName, string scriptName, string toolTip) where T : ScriptableObject
{
GUILayout.BeginHorizontal();
var result = EditorGUILayout.ObjectField(
new GUIContent(fieldName, toolTip),
value,
typeof(T),
false
) as T;
if (GUILayout.Button("New", GUILayout.ExpandWidth(false)))
{
var t = typeof(T);
if (t == typeof(SentryRuntimeOptionsConfiguration) || t == typeof(SentryBuildTimeOptionsConfiguration))
{
CreateDeprecatedConfigurationScript<T>(fieldName, scriptName);
}
else if (t == typeof(SentryCliOptionsConfiguration))
{
CreateConfigurationScript(fieldName, SentryCliOptionsConfiguration.Template, scriptName);
}
else
{
throw new Exception("Attempting to create a new instance of unsupported type " + typeof(T).FullName);
}
}
GUILayout.EndHorizontal();
return result;
}

private static string SentryAssetPath(string scriptName) => $"Assets/Resources/Sentry/{scriptName}.asset";

private static void CreateDeprecatedConfigurationScript<T>(string fieldName, string scriptName)
{
const string directory = "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;
}

if (scriptPath.StartsWith(Application.dataPath))
{
// AssetDatabase prefers a relative path
scriptPath = "Assets" + scriptPath.Substring(Application.dataPath.Length);
}

scriptName = Path.GetFileNameWithoutExtension(scriptPath);

var template = new StringBuilder();
template.AppendLine("using UnityEngine;");
template.AppendLine("using Sentry.Unity;");
template.AppendLine();
template.AppendFormat("[CreateAssetMenu(fileName = \"{0}\", menuName = \"Sentry/{1}\", order = 999)]\n", SentryAssetPath(scriptName), scriptName);
template.AppendFormat("public class {0} : {1}\n", scriptName, typeof(T).FullName);
template.AppendLine("{");

if (typeof(T) == typeof(SentryBuildTimeOptionsConfiguration))
{
template.AppendLine(" /// Called during app build. Changes made here will affect build-time processing, symbol upload, etc.");
template.AppendLine(" /// Additionally, because iOS, macOS and Android native error handling is configured at build time,");
template.AppendLine(" /// you can make changes to these options here.");
}
else
{
template.AppendLine(" /// Called at the player startup by SentryInitialization.");
template.AppendLine(" /// You can alter configuration for the C# error handling and also");
template.AppendLine(" /// native error handling in platforms **other** than iOS, macOS and Android.");
}

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(SentryBuildTimeOptionsConfiguration) ? ", SentryCliOptions cliOptions" : "");
template.AppendLine(" {");
if (typeof(T) != typeof(SentryBuildTimeOptionsConfiguration))
{
template.AppendLine(" // Note that changes to the options here will **not** affect iOS, macOS and Android events. (i.e. environment and release)");
template.AppendLine(" // Take a look at `SentryBuildTimeOptionsConfiguration` instead.");
}
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
// trigger the creation after the scripts reloaded.
EditorPrefs.SetBool(CreateScriptableObjectFlag, true);
EditorPrefs.SetString(ScriptNameKey, scriptName);

AssetDatabase.ImportAsset(scriptPath);
Selection.activeObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(scriptPath);
}

private static void CreateConfigurationScript(string fieldName, string template, string scriptName)
{
const string directory = "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;
}

if (scriptPath.StartsWith(Application.dataPath))
{
// AssetDatabase prefers a relative path
scriptPath = "Assets" + scriptPath.Substring(Application.dataPath.Length);
}

scriptName = Path.GetFileNameWithoutExtension(scriptPath);
var script = template.Replace("{{ScriptName}}", scriptName);

File.WriteAllText(scriptPath, script);

// 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
// trigger the creation after the scripts reloaded.
EditorPrefs.SetBool(CreateScriptableObjectFlag, true);
EditorPrefs.SetString(ScriptNameKey, scriptName);

AssetDatabase.ImportAsset(scriptPath);
Selection.activeObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(scriptPath);
}

[UnityEditor.Callbacks.DidReloadScripts]
private static void OnScriptsReloaded()
{
if (!EditorPrefs.GetBool(CreateScriptableObjectFlag))
{
return;
}

var scriptName = EditorPrefs.GetString(ScriptNameKey);
EditorPrefs.DeleteKey(CreateScriptableObjectFlag);
EditorPrefs.DeleteKey(ScriptNameKey);

SetScript(scriptName);
}

internal static void SetScript(string scriptNameWithoutExtension)
{
var optionsConfigurationObject = ScriptableObject.CreateInstance(scriptNameWithoutExtension);
AssetDatabase.CreateAsset(optionsConfigurationObject, SentryAssetPath(scriptNameWithoutExtension));
AssetDatabase.Refresh();

var options = EditorWindow.GetWindow<SentryWindow>().Options;
var cliOptions = EditorWindow.GetWindow<SentryWindow>().CliOptions;

switch (optionsConfigurationObject)
{
case SentryRuntimeOptionsConfiguration runtimeConfiguration:
options.RuntimeOptionsConfiguration ??= runtimeConfiguration; // Don't overwrite if already set
break;
case SentryBuildTimeOptionsConfiguration buildTimeConfiguration:
options.BuildTimeOptionsConfiguration ??= buildTimeConfiguration; // Don't overwrite if already set
break;
case SentryCliOptionsConfiguration cliConfiguration:
cliOptions.CliOptionsConfiguration ??= cliConfiguration; // Don't overwrite if already set
break;
}
}
}
10 changes: 10 additions & 0 deletions src/Sentry.Unity.Editor/ConfigurationWindow/DebugSymbolsTab.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,15 @@ internal static void Display(SentryCliOptions cliOptions)
cliOptions.UploadSymbols && string.IsNullOrWhiteSpace(cliOptions.Project) ? SentryWindow.ErrorIcon : null,
"The project name in Sentry"),
cliOptions.Project);

EditorGUILayout.Space();

cliOptions.CliOptionsConfiguration = OptionsConfigurationItem.Display(
cliOptions.CliOptionsConfiguration,
"Sentry CLI Config Script",
"SentryCliConfiguration",
"A scriptable object that inherits from 'SentryCliOptionsConfiguration'." +
"It allows you to programmatically modify the options used during debug symbols upload."
);
}
}
Loading
Loading