Skip to content

feat: Editor support for options configuration #569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- Config window support for programmatic options configuration ([#569](https://github.com/getsentry/sentry-unity/pull/569))
- Samples include programmatic options configuration snippet ([#568](https://github.com/getsentry/sentry-unity/pull/568))
- Support for programmatic options configuration ([#564](https://github.com/getsentry/sentry-unity/pull/564))

Expand Down
15 changes: 1 addition & 14 deletions src/Sentry.Unity.Editor/ConfigurationWindow/AdvancedTab.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.IO;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEngine;

namespace Sentry.Unity.Editor.ConfigurationWindow
Expand Down Expand Up @@ -64,19 +62,8 @@ internal static void Display(ScriptableSentryUnityOptions options)
new GUIContent("Windows Native Support", "Whether to enable Native Windows support to " +
"capture errors written in languages such as C and C++."),
options.WindowsNativeSupportEnabled);
}

EditorGUILayout.Space();
EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 1), Color.gray);
EditorGUILayout.Space();

GUILayout.Label("Programmatic Options Configuration", EditorStyles.boldLabel);

options.OptionsConfiguration = EditorGUILayout.ObjectField(
new GUIContent("Options Configuration", "A scriptable object that inherits from " +
"'ScriptableOptionsConfiguration' that allows you to " +
"programmatically modify Sentry options i.e. implement the " +
"'BeforeSend' callback."),
options.OptionsConfiguration, typeof(ScriptableOptionsConfiguration), false) as ScriptableOptionsConfiguration;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.IO;
using UnityEditor;
using UnityEngine;

namespace Sentry.Unity.Editor.ConfigurationWindow
{
internal static class OptionsConfigurationTab
{
private const string CreateScriptableObjectFlag = "CreateScriptableOptionsObject";
private const string ScriptNameKey = "ScriptableOptionsName";

public static void Display(ScriptableSentryUnityOptions options)
{
GUILayout.Label("Programmatic Options Configuration", EditorStyles.boldLabel);

options.OptionsConfiguration = EditorGUILayout.ObjectField(
new GUIContent("Options Configuration", "A scriptable object that inherits from " +
"'ScriptableOptionsConfiguration' that allows you to " +
"programmatically modify Sentry options i.e. implement " +
"the 'BeforeSend' callback."),
options.OptionsConfiguration, typeof(ScriptableOptionsConfiguration), false)
as ScriptableOptionsConfiguration;

EditorGUILayout.Space();
EditorGUILayout.HelpBox("The options configuration allows you to programmatically modify " +
"the Sentry options object during runtime initialization of the SDK. " +
"Clicking the button below will create a scriptable object template at your " +
"targeted location and create an instance at 'Assets/Resources/Sentry/'.", MessageType.Info);
EditorGUILayout.Space();

if (GUILayout.Button("Create options configuration"))
{
CreateOptionsConfigurationScript();
}
}

internal static void CreateOptionsConfigurationScript()
{
var scriptPath = EditorUtility.SaveFilePanel("Sentry Options Configuration", "Assets", "SentryOptionsConfiguration", "cs");
if (String.IsNullOrEmpty(scriptPath))
{
return;
}

if (scriptPath.StartsWith(Application.dataPath))
{
// AssetDatabase prefers a relative path
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.

// Your code here
}}
}}");

// 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 'ShouldCreateOptionsObject' 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);

var optionsConfigurationObject = ScriptableObject.CreateInstance(scriptName);
AssetDatabase.CreateAsset(optionsConfigurationObject, $"Assets/Resources/Sentry/{scriptName}.asset");
AssetDatabase.Refresh();

// Don't overwrite already set OptionsConfiguration
var options = SentryWindow.Instance.Options;
if (options.OptionsConfiguration == null)
{
options.OptionsConfiguration = (ScriptableOptionsConfiguration)optionsConfigurationObject;
}
}
}
}
16 changes: 14 additions & 2 deletions src/Sentry.Unity.Editor/ConfigurationWindow/SentryWindow.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.IO;
using Sentry.Extensibility;
using Sentry.Unity.Editor.ConfigurationWindow;
using Sentry.Unity.Json;
using UnityEditor;
using UnityEngine;
Expand All @@ -20,6 +19,8 @@ public static SentryWindow OpenSentryWindow()
return window;
}

public static SentryWindow Instance => GetWindow<SentryWindow>();

protected virtual string SentryOptionsAssetName { get; } = ScriptableSentryUnityOptions.ConfigName;

public ScriptableSentryUnityOptions Options { get; private set; } = null!; // Set by OnEnable()
Expand All @@ -28,7 +29,15 @@ public static SentryWindow OpenSentryWindow()
public event Action<ValidationError> OnValidationError = _ => { };

private int _currentTab = 0;
private string[] _tabs = new[] { "Core", "Enrichment", "Transport", "Advanced", "Debug Symbols" };
private readonly string[] _tabs =
{
"Core",
"Enrichment",
"Transport",
"Advanced",
"Options Config",
"Debug Symbols"
};

private void Awake()
{
Expand Down Expand Up @@ -135,6 +144,9 @@ private void OnGUI()
AdvancedTab.Display(Options);
break;
case 4:
OptionsConfigurationTab.Display(Options);
break;
case 5:
DebugSymbolsTab.Display(CliOptions);
break;
default:
Expand Down