Skip to content

Commit

Permalink
fix: Setting Android SDK filter (#1367)
Browse files Browse the repository at this point in the history
  • Loading branch information
bitsandfoxes authored Jun 23, 2023
1 parent 56cca6b commit bab6923
Show file tree
Hide file tree
Showing 21 changed files with 377 additions and 62 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Fixes

- Fixed an Android build issue where Sentry options would be cached with the first build until Editor restart ([#1379](https://github.com/getsentry/sentry-unity/pull/1379))
- Adding a remote repository filter to the gradle project ([#1367](https://github.com/getsentry/sentry-unity/pull/1367))
- Setting Android SDK version explicit to prevent version conflicts with remote repositories ([#1378](https://github.com/getsentry/sentry-unity/pull/1387))
- Set debug symbol upload logging to debug verbosity ([#1373](https://github.com/getsentry/sentry-unity/pull/1373))
- The SDK no longer causes an exception during initialiation on Android API level 32 and newer ([#1365](https://github.com/getsentry/sentry-unity/pull/1365))
Expand Down
15 changes: 11 additions & 4 deletions src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@
namespace Sentry.Unity.Editor.Android
{
// https://github.com/getsentry/sentry-java/blob/d3764bfc97eed22564a1e23ba96fa73ad2685498/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java#L83-L217
public class AndroidManifestConfiguration : IPostGenerateGradleAndroidProject
public class PostGenerateGradleAndroidProject : IPostGenerateGradleAndroidProject
{
public int callbackOrder { get; } = 1;
public void OnPostGenerateGradleAndroidProject(string basePath)
{
var androidManifestConfiguration = new AndroidManifestConfiguration();
androidManifestConfiguration.OnPostGenerateGradleAndroidProject(basePath);
}
}

public class AndroidManifestConfiguration
{
private readonly SentryUnityOptions? _options;
private readonly SentryCliOptions? _sentryCliOptions;
Expand All @@ -21,9 +31,6 @@ public class AndroidManifestConfiguration : IPostGenerateGradleAndroidProject
private readonly bool _isDevelopmentBuild;
private readonly ScriptingImplementation _scriptingImplementation;

// Lower levels are called first.
public int callbackOrder => 1;

public AndroidManifestConfiguration()
: this(
SentryScriptableObject.ConfiguredBuildTimeOptions,
Expand Down
108 changes: 73 additions & 35 deletions src/Sentry.Unity.Editor/Android/GradleSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ internal class GradleSetup
public const string RepositoryScopeName = "repositories";
public static readonly string SdkDependencies = $"implementation ('io.sentry:sentry-android:{GetAndroidSdkVersion()}') {{ exclude group: 'androidx.core' exclude group: 'androidx.lifecycle' }}";
public const string DependencyScopeName = "dependencies";
public const string MavenCentralWithoutFilter = "mavenCentral()";
public const string MavenCentralWithFilter = "mavenCentral { content { excludeGroupByRegex \"io\\\\.sentry.*\" } }";
public static readonly List<string> ScopesToSkip = new() { "buildscript", "pluginManagement" };

private readonly string _rootGradle;
Expand All @@ -39,19 +41,20 @@ public void UpdateGradleProject(IApplication? application = null)

// Starting with 2022.3.0f1 the root build.gradle updated to use the "new" way of importing plugins via `id`
// Instead, dependency repositories get handled in the `settings.gradle` at the root
var gradleFilePath = SentryUnityVersion.IsNewerOrEqualThan("2022.3", application)
? _settingsGradle
: _rootGradle;
var rootGradleFile = (SentryUnityVersion.IsNewerOrEqualThan("2022.3", application)) ? _settingsGradle : _rootGradle;

_logger.LogDebug("Updating the gradle file at '{0}'", gradleFilePath);
_logger.LogDebug("Updating the gradle file at '{0}'", rootGradleFile);

var gradleContent = LoadGradleScript(gradleFilePath);
var gradleContent = LoadGradleScript(rootGradleFile);
gradleContent = InsertIntoScope(gradleContent, RepositoryScopeName, LocalRepository);
File.WriteAllText(gradleFilePath, gradleContent);
gradleContent = ApplyMavenCentralFilter(gradleContent);
File.WriteAllText(rootGradleFile, gradleContent);

_logger.LogDebug("Updating the gradle file at '{0}'", _unityLibraryGradle);

var unityLibraryGradleContent = LoadGradleScript(_unityLibraryGradle);
unityLibraryGradleContent = InsertIntoScope(unityLibraryGradleContent, DependencyScopeName, SdkDependencies);
unityLibraryGradleContent = ApplyMavenCentralFilter(unityLibraryGradleContent);
File.WriteAllText(_unityLibraryGradle, unityLibraryGradleContent);
}

Expand All @@ -61,18 +64,19 @@ public void ClearGradleProject(IApplication? application = null)

// Starting with 2022.3.0f1 the root build.gradle updated to use the "new" way of importing plugins via `id`
// Instead, dependency repositories get handled in the `settings.gradle` at the root
var gradleFilePath = SentryUnityVersion.IsNewerOrEqualThan("2022.3", application)
? _settingsGradle
: _rootGradle;
var rootGradleFile = (SentryUnityVersion.IsNewerOrEqualThan("2022.3", application)) ? _settingsGradle : _rootGradle;

_logger.LogDebug("Removing modifications from '{0}'", rootGradleFile);

_logger.LogDebug("Removing modifications from '{0}'", gradleFilePath);
var gradleContent = LoadGradleScript(gradleFilePath);
var gradleContent = LoadGradleScript(rootGradleFile);
gradleContent = RemoveFromGradleContent(gradleContent, LocalRepository);
File.WriteAllText(gradleFilePath, gradleContent);
gradleContent = gradleContent.Replace(MavenCentralWithFilter, MavenCentralWithoutFilter);
File.WriteAllText(rootGradleFile, gradleContent);

_logger.LogDebug("Removing modifications from the 'build.gradle' file at {0}", _unityLibraryGradle);
var unityLibraryGradleContent = LoadGradleScript(_unityLibraryGradle);
unityLibraryGradleContent = RemoveFromGradleContent(unityLibraryGradleContent, SdkDependencies);
unityLibraryGradleContent = unityLibraryGradleContent.Replace(MavenCentralWithFilter, MavenCentralWithoutFilter);
File.WriteAllText(_unityLibraryGradle, unityLibraryGradleContent);
}

Expand All @@ -85,12 +89,65 @@ internal string InsertIntoScope(string gradleContent, string scope, string inser
}

var lines = gradleContent.Split('\n');
var scopeStart = -1;
var scopeStart = FindBeginningOfScope(lines, scope);
if (scopeStart == -1)
{
throw new BuildFailedException($"Failed to find scope '{scope}'.");
}

var modifiedLines = new List<string>(lines);

var lineToInsert = string.Empty;
var whiteSpaceCount = lines[scopeStart].IndexOf(scope, StringComparison.Ordinal);
for (var i = 0; i < whiteSpaceCount; i++)
{
lineToInsert += " ";
}

lineToInsert += " " + insertion;
var lineOffset = lines[scopeStart].Contains("{") ? 1 : 2; // to make sure we're inside the scope
modifiedLines.Insert(scopeStart + lineOffset, lineToInsert);

return string.Join("\n", modifiedLines.ToArray());
}

internal string ApplyMavenCentralFilter(string gradleContent)
{
_logger.LogDebug("Applying MavenFilter.");

if (gradleContent.Contains(MavenCentralWithFilter))
{
_logger.LogDebug("The filter for maven central has already been set. Skipping.");
return gradleContent;
}

var lines = gradleContent.Split('\n');

var scopeStart = FindBeginningOfScope(lines, RepositoryScopeName);
if (scopeStart == -1)
{
_logger.LogDebug($"Did not find the scope '{RepositoryScopeName}' to apply the filter for maven central. Skipping.");
return gradleContent;
}

for (var i = scopeStart; i < lines.Length; i++)
{
if (lines[i].Contains(MavenCentralWithoutFilter))
{
lines[i] = lines[i].Replace(MavenCentralWithoutFilter, MavenCentralWithFilter);
break;
}
}

return string.Join("\n", lines.ToArray());
}

private int FindBeginningOfScope(string[] lines, string scope)
{
for (var i = 0; i < lines.Length; i++)
{
var line = lines[i];
// There are potentially multiple, nested scopes. We cannot add ourselves to the ones within 'buildscript'
// There are potentially multiple, nested scopes. We cannot add ourselves to the ones listed in `ScopesToSkip`
if (ScopesToSkip.Any(line.Contains))
{
var startIndex = i;
Expand All @@ -105,30 +162,11 @@ internal string InsertIntoScope(string gradleContent, string scope, string inser
}
else if (lines[i].Contains(scope))
{
scopeStart = i;
break;
return i;
}
}

if (scopeStart == -1)
{
throw new BuildFailedException($"Failed to find scope '{scope}'.");
}

var modifiedLines = new List<string>(lines);

var lineToInsert = string.Empty;
var whiteSpaceCount = lines[scopeStart].IndexOf(scope, StringComparison.Ordinal);
for (var i = 0; i < whiteSpaceCount; i++)
{
lineToInsert += " ";
}

lineToInsert += " " + insertion;
var lineOffset = lines[scopeStart].Contains("{") ? 1 : 2; // to make sure we're inside the scope
modifiedLines.Insert(scopeStart + lineOffset, lineToInsert);

return string.Join("\n", modifiedLines.ToArray());
return -1;
}

private static int FindClosingBracket(string[] lines, int startIndex)
Expand Down
78 changes: 60 additions & 18 deletions test/Sentry.Unity.Editor.Tests/Android/GradleSetupTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Reflection;
using NUnit.Framework;
using Sentry.Unity.Editor.Android;
using Sentry.Unity.Integrations;
using Sentry.Unity.Tests.SharedClasses;
using Sentry.Unity.Tests.Stubs;

Expand Down Expand Up @@ -44,20 +43,37 @@ public void LoadGradleScript_FileNotFound_ThrowsFileNotFoundException()
}

[Test]
[TestCase("2019.3", "build.gradle")]
[TestCase("2020.3", "build.gradle")]
[TestCase("2021.3", "build.gradle")]
[TestCase("2022.3", "settings.gradle")]
public void UpdateGradleProject_ModifiesGradleFiles(string unityVersion, string rootGradleFileName)
[TestCase("2019.3")]
[TestCase("2020.3")]
[TestCase("2021.3")]
public void UpdateGradleProject_2021_AndOlder_ModifiesGradleFiles(string unityVersion)
{
var sut = new GradleSetup(Logger, GradleProjectPath);

sut.UpdateGradleProject(new TestApplication(unityVersion: unityVersion));

var rootGradleFilePath = Path.Combine(GradleProjectPath, rootGradleFileName);
var rootGradleFilePath = Path.Combine(GradleProjectPath, "build.gradle");
var rootGradleContent = File.ReadAllText(rootGradleFilePath);
StringAssert.Contains(GradleSetup.LocalRepository, rootGradleContent);

var unityLibraryGradleFilePath = Path.Combine(GradleProjectPath, "unityLibrary", "build.gradle");
var unityLibraryGradleContent = File.ReadAllText(unityLibraryGradleFilePath);
StringAssert.Contains(GradleSetup.SdkDependencies, unityLibraryGradleContent);
StringAssert.Contains(GradleSetup.MavenCentralWithFilter, unityLibraryGradleContent);
}

[Test]
public void UpdateGradleProject_2022_AndNewer_ModifiesGradleFiles()
{
var sut = new GradleSetup(Logger, GradleProjectPath);

sut.UpdateGradleProject(new TestApplication(unityVersion: "2022.3"));

var settingsGradleFilePath = Path.Combine(GradleProjectPath, "settings.gradle");
var settingsGradleContent = File.ReadAllText(settingsGradleFilePath);
StringAssert.Contains(GradleSetup.LocalRepository, settingsGradleContent);
StringAssert.Contains(GradleSetup.MavenCentralWithFilter, settingsGradleContent);

var unityLibraryGradleFilePath = Path.Combine(GradleProjectPath, "unityLibrary", "build.gradle");
var unityLibraryGradleContent = File.ReadAllText(unityLibraryGradleFilePath);
StringAssert.Contains(GradleSetup.SdkDependencies, unityLibraryGradleContent);
Expand All @@ -68,7 +84,8 @@ public void UpdateGradleProject_ModifiesGradleFiles(string unityVersion, string
[TestCase("2020.3", "build.gradle")]
[TestCase("2021.3", "build.gradle")]
[TestCase("2022.3", "settings.gradle")]
public void UpdateGradleProject_GradleAlreadyModified_LogsAndReturns(string unityVersion, string rootGradleFileName)
public void UpdateGradleProject_GradleAlreadyModified_LogsAndReturns(string unityVersion,
string rootGradleFileName)
{
var sut = new GradleSetup(Logger, GradleProjectPath);
sut.UpdateGradleProject(new TestApplication(unityVersion: unityVersion));
Expand All @@ -93,7 +110,8 @@ public void UpdateGradleProject_GradleAlreadyModified_LogsAndReturns(string unit
[TestCase("2020.3", "build.gradle")]
[TestCase("2021.3", "build.gradle")]
[TestCase("2022.3", "settings.gradle")]
public void ClearGradleProject_GradleFilesModified_RemovesModification(string unityVersion, string rootGradleFileName)
public void ClearGradleProject_GradleFilesModified_RemovesModification(string unityVersion,
string rootGradleFileName)
{
var sut = new GradleSetup(Logger, GradleProjectPath);
sut.UpdateGradleProject(new TestApplication(unityVersion: unityVersion));
Expand All @@ -110,28 +128,52 @@ public void ClearGradleProject_GradleFilesModified_RemovesModification(string un

rootGradleContent = File.ReadAllText(rootGradleFilePath);
StringAssert.DoesNotContain(GradleSetup.LocalRepository, rootGradleContent); // Sanity check
StringAssert.DoesNotContain(GradleSetup.MavenCentralWithFilter, rootGradleContent);

unityLibraryGradleContent = File.ReadAllText(unityLibraryGradleFilePath);
StringAssert.DoesNotContain(GradleSetup.SdkDependencies, unityLibraryGradleContent); // Sanity check
StringAssert.DoesNotContain(GradleSetup.MavenCentralWithFilter, unityLibraryGradleContent);
}

[Test]
[TestCase("InsertIntoScope/build.gradle_test_1")]
[TestCase("InsertIntoScope/build.gradle_test_2")]
[TestCase("InsertIntoScope/build.gradle_test_3")]
[TestCase("InsertIntoScope/build.gradle_test_4")]
[TestCase("InsertIntoScope/build.gradle_test_5")]
public void InsertIntoScope_ResultMatchesExpected(string testCaseFileName)
{
var assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var testCasePath = Path.Combine(assemblyPath, "TestFiles", "Android", testCaseFileName + ".txt");
var testCaseExpectedPath =
Path.Combine(assemblyPath, "TestFiles", "Android", testCaseFileName + "_expected.txt");
var expectedGradleContent = File.ReadAllText(testCaseExpectedPath);

var gradleContent = File.ReadAllText(testCasePath);
var sut = new GradleSetup(Logger, GradleProjectPath);

var actualResult = sut.InsertIntoScope(gradleContent, GradleSetup.RepositoryScopeName,
GradleSetup.LocalRepository);

StringAssert.AreEqualIgnoringCase(actualResult, expectedGradleContent);
}

[Test]
[TestCase("build.gradle_test_1.txt", "build.gradle_test_1_expected.txt")]
[TestCase("build.gradle_test_2.txt", "build.gradle_test_2_expected.txt")]
[TestCase("build.gradle_test_3.txt", "build.gradle_test_3_expected.txt")]
[TestCase("build.gradle_test_4.txt", "build.gradle_test_4_expected.txt")]
[TestCase("build.gradle_test_5.txt", "build.gradle_test_5_expected.txt")]
public void InsertIntoScope_ResultMatchesExpected(string testCaseFileName, string testCaseExpectedFileName)
[TestCase("ApplyMavenCentralFilter/build.gradle_test_1")]
[TestCase("ApplyMavenCentralFilter/build.gradle_test_2")]
[TestCase("ApplyMavenCentralFilter/build.gradle_test_3")]
public void ApplyMavenCentralFilter_ResultMatchesExpected(string testCaseFileName)
{
var assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var testCasePath = Path.Combine(assemblyPath, "TestFiles", "Android", testCaseFileName);
var testCaseExpectedPath = Path.Combine(assemblyPath, "TestFiles", "Android", testCaseExpectedFileName);
var testCasePath = Path.Combine(assemblyPath, "TestFiles", "Android", testCaseFileName + ".txt");
var testCaseExpectedPath =
Path.Combine(assemblyPath, "TestFiles", "Android", testCaseFileName + "_expected.txt");
var expectedGradleContent = File.ReadAllText(testCaseExpectedPath);

var gradleContent = File.ReadAllText(testCasePath);
var sut = new GradleSetup(Logger, GradleProjectPath);

var actualResult = sut.InsertIntoScope(gradleContent, GradleSetup.RepositoryScopeName, GradleSetup.LocalRepository);
var actualResult = sut.ApplyMavenCentralFilter(gradleContent);

StringAssert.AreEqualIgnoringCase(actualResult, expectedGradleContent);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
allprojects
{
buildscript
{
dependencies
{
// If you are changing the Android Gradle Plugin version, make sure it is compatible with the Gradle version preinstalled with Unity
// See which Gradle version is preinstalled with Unity here https://docs.unity3d.com/Manual/android-gradle-overview.html
// See official Gradle and Android Gradle Plugin compatibility table here https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
// To specify a custom Gradle version in Unity, go do "Preferences > External Tools", uncheck "Gradle Installed with Unity (recommended)" and specify a path to a custom Gradle version
classpath 'com.android.tools.build:gradle:4.0.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31'
}

repositories
{
google()
mavenCentral()
jcenter()
}
}

repositories
{
google()
mavenCentral()
jcenter()
flatDir
{
dirs "${project(':unityLibrary').projectDir}/libs"
}
}
}
Loading

0 comments on commit bab6923

Please sign in to comment.