diff --git a/README.md b/README.md index 0028f46..41ab9c5 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ sentry: dist: ... build_path: ... web_build_path: ... + symbols_path: ... commits: auto ignore_missing: true ``` @@ -91,6 +92,7 @@ release=... dist=... build_path: ... web_build_path=... +symbols_path=... commits=auto ignore_missing=true ``` @@ -113,6 +115,7 @@ ignore_missing=true | dist | The dist/build number for source maps, it should match the dist set by the SDK | the number after the '+' char from 'version' pubspec (string) | no | SENTRY_DIST | | build_path | The build folder of debug files for upload | `build` (string) | no | - | | web_build_path | The web build folder of debug files for upload relative to build_path | `web` (string) | no | - | +| symbols_path | The directory containing debug symbols (i.e. the `--split-debug-info=` parameter value you pass to `flutter build`) | `.` (string) | no | - | | commits | Release commits integration | auto (string) | no | - | | ignore_missing | Ignore missing commits previously used in the release | false (boolean) | no | - | | bin_dir | The folder where the plugin downloads the sentry-cli binary | .dart_tool/pub/bin/sentry_dart_plugin (string) | no | - | diff --git a/example/README.md b/example/README.md index 2fcdf08..b3fb0e7 100644 --- a/example/README.md +++ b/example/README.md @@ -43,6 +43,9 @@ sentry: # default 'web' #web_build_path: ... + # default '.' + #symbols_path: ... + # default to name@version from pubspec #release: ... ``` diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index 0294c42..bc24a81 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -1,6 +1,8 @@ import 'dart:convert'; +import 'package:file/file.dart'; import 'package:process/process.dart'; +import 'package:sentry_dart_plugin/src/utils/extensions.dart'; import 'src/configuration.dart'; import 'src/utils/injector.dart'; @@ -75,15 +77,57 @@ class SentryDartPlugin { Log.info('includeSources is disabled, not uploading sources.'); } - params.add(_configuration.buildFilesFolder); - _addWait(params); - await _executeAndLog('Failed to upload symbols', params); + final buildDirs = _enumerateBuildDirectories(); + final fs = injector.get(); + await for (final path in buildDirs) { + if (await fs.directory(path).exists()) { + await _executeAndLog('Failed to upload symbols', [...params, path]); + } + } + + if (_configuration.symbolsFolder.isNotEmpty) { + final symbolsRootDir = fs.directory(_configuration.symbolsFolder); + if (await symbolsRootDir.exists()) { + final symbolFileRegexp = RegExp(r'[/\\]app[^/\\]+.*\.(dSYM|symbols)$'); + await for (final entry in symbolsRootDir.find(symbolFileRegexp)) { + await _executeAndLog( + 'Failed to upload symbols', [...params, entry.path]); + } + } + } Log.taskCompleted(taskName); } + Stream _enumerateBuildDirectories() async* { + final buildDir = _configuration.buildFilesFolder; + + // Android + yield '$buildDir/app/outputs'; + yield '$buildDir/app/intermediates'; + + // Windows + for (final subdir in ['', '/x64', '/arm64']) { + yield '$buildDir/windows$subdir/runner/Release'; + } + + // Linux + for (final subdir in ['/x64', '/arm64']) { + yield '$buildDir/linux$subdir/release/bundle'; + } + + // macOS + // TODO + + // iOS + // TODO + + // web + // TODO + } + List _releasesCliParams() { final params = []; _setUrlAndTokenAndLog(params); diff --git a/lib/src/configuration.dart b/lib/src/configuration.dart index 54ca298..fb32ebf 100644 --- a/lib/src/configuration.dart +++ b/lib/src/configuration.dart @@ -69,6 +69,9 @@ class Configuration { /// the Web Build folder, defaults to `web` late String webBuildFilesFolder; + /// The directory passed to `--split-debug-info`, defaults to '.' + late String symbolsFolder; + /// The URL prefix, defaults to null late String? urlPrefix; @@ -146,6 +149,7 @@ class Configuration { // but can be customized so making it flexible. final webBuildPath = configValues.webBuildPath ?? 'web'; webBuildFilesFolder = _fs.path.join(buildFilesFolder, webBuildPath); + symbolsFolder = configValues.symbolsPath ?? '.'; project = configValues.project; // or env. var. SENTRY_PROJECT org = configValues.org; // or env. var. SENTRY_ORG diff --git a/lib/src/configuration_values.dart b/lib/src/configuration_values.dart index 3cc3898..13546f4 100644 --- a/lib/src/configuration_values.dart +++ b/lib/src/configuration_values.dart @@ -19,6 +19,7 @@ class ConfigurationValues { final String? dist; final String? buildPath; final String? webBuildPath; + final String? symbolsPath; final String? commits; final bool? ignoreMissing; final String? binDir; @@ -43,6 +44,7 @@ class ConfigurationValues { this.dist, this.buildPath, this.webBuildPath, + this.symbolsPath, this.commits, this.ignoreMissing, this.binDir, @@ -94,6 +96,7 @@ class ConfigurationValues { dist: sentryArguments['dist'], buildPath: sentryArguments['build_path'], webBuildPath: sentryArguments['web_build_path'], + symbolsPath: sentryArguments['symbols_path'], commits: sentryArguments['commits'], ignoreMissing: boolFromString(sentryArguments['ignore_missing']), binDir: sentryArguments['bin_dir'], @@ -127,6 +130,7 @@ class ConfigurationValues { dist: configReader.getString('dist'), buildPath: configReader.getString('build_path'), webBuildPath: configReader.getString('web_build_path'), + symbolsPath: configReader.getString('symbols_path'), commits: configReader.getString('commits'), ignoreMissing: configReader.getBool('ignore_missing'), binDir: configReader.getString('bin_dir'), @@ -180,6 +184,7 @@ class ConfigurationValues { dist: platformEnv.dist ?? args.dist ?? file.dist, buildPath: args.buildPath ?? file.buildPath, webBuildPath: args.webBuildPath ?? file.webBuildPath, + symbolsPath: args.symbolsPath ?? file.symbolsPath, commits: args.commits ?? file.commits, ignoreMissing: args.ignoreMissing ?? file.ignoreMissing, binDir: args.binDir ?? file.binDir, diff --git a/lib/src/utils/extensions.dart b/lib/src/utils/extensions.dart index d6aa4c6..6d6e74c 100644 --- a/lib/src/utils/extensions.dart +++ b/lib/src/utils/extensions.dart @@ -1,4 +1,16 @@ +import 'package:file/file.dart'; + /// Checks if the given String == null extension StringValidations on String? { bool get isNull => this == null; } + +extension DirectorySearch on Directory { + Stream find(RegExp regexp) async* { + await for (final entity in list(recursive: true)) { + if (regexp.hasMatch(entity.path)) { + yield entity; + } + } + } +} diff --git a/test/configuration_test.dart b/test/configuration_test.dart index 93f4224..42bcb99 100644 --- a/test/configuration_test.dart +++ b/test/configuration_test.dart @@ -69,6 +69,7 @@ void main() { dist: 'dist-args-config', buildPath: 'build_path-args-config', webBuildPath: 'web_build_path-args-config', + symbolsPath: 'symbols_path-args-config', commits: 'commits-args-config', ignoreMissing: true, binDir: 'binDir-args-config', @@ -93,6 +94,7 @@ void main() { dist: 'dist-file-config', buildPath: 'build_path-file-config', webBuildPath: 'web_build_path-file-config', + symbolsPath: 'symbols_path-args-config', commits: 'commits-file-config', ignoreMissing: false, binDir: 'binDir-file-config', @@ -122,6 +124,7 @@ void main() { expect(sut.release, 'release-args-config'); expect(sut.dist, 'dist-args-config'); expect(sut.buildFilesFolder, 'build_path-args-config'); + expect(sut.symbolsFolder, 'symbols_path-args-config'); expect( sut.webBuildFilesFolder, fixture.fs.path.join( @@ -157,6 +160,7 @@ void main() { dist: 'dist-file-config', buildPath: 'build_path-file-config', webBuildPath: 'web_build_path-file-config', + symbolsPath: 'symbols_path-args-config', commits: 'commits-file-config', ignoreMissing: true, binDir: 'binDir-file-config', @@ -187,6 +191,7 @@ void main() { expect(sut.release, 'release-file-config'); expect(sut.dist, 'dist-file-config'); expect(sut.buildFilesFolder, 'build_path-file-config'); + expect(sut.symbolsFolder, 'symbols_path-args-config'); expect( sut.webBuildFilesFolder, fixture.fs.path diff --git a/test/configureation_values_test.dart b/test/configureation_values_test.dart index d951e42..6afce69 100644 --- a/test/configureation_values_test.dart +++ b/test/configureation_values_test.dart @@ -29,6 +29,7 @@ void main() { "--sentry-define=dist=fixture-dist", "--sentry-define=build_path=fixture-build_path", "--sentry-define=web_build_path=fixture-web_build_path", + "--sentry-define=symbols_path=fixture-symbols_path", "--sentry-define=commits=fixture-commits", "--sentry-define=ignore_missing=true", "--sentry-define=bin_dir=fixture-bin_dir", @@ -51,6 +52,7 @@ void main() { expect(sut.dist, 'fixture-dist'); expect(sut.buildPath, 'fixture-build_path'); expect(sut.webBuildPath, 'fixture-web_build_path'); + expect(sut.symbolsPath, 'fixture-symbols_path'); expect(sut.commits, 'fixture-commits'); expect(sut.ignoreMissing, true); expect(sut.binDir, 'fixture-bin_dir'); @@ -81,7 +83,7 @@ void main() { test('from config reader as pubspec', () { final sentryPubspec = ''' version: fixture-sentry-version - name: fixture-sentry-name + name: fixture-sentry-name upload_debug_symbols: true upload_source_maps: true upload_sources: true @@ -92,6 +94,7 @@ void main() { dist: fixture-dist build_path: fixture-build_path web_build_path: fixture-web_build_path + symbols_path: fixture-symbols_path commits: fixture-commits ignore_missing: true bin_dir: fixture-bin_dir @@ -133,6 +136,7 @@ void main() { expect(sut.dist, 'fixture-dist'); expect(sut.buildPath, 'fixture-build_path'); expect(sut.webBuildPath, 'fixture-web_build_path'); + expect(sut.symbolsPath, 'fixture-symbols_path'); expect(sut.commits, 'fixture-commits'); expect(sut.ignoreMissing, true); expect(sut.binDir, 'fixture-bin_dir'); @@ -142,7 +146,7 @@ void main() { test('from config reader as properties', () { final sentryProperties = ''' version=fixture-sentry-version - name=fixture-sentry-name + name=fixture-sentry-name upload_debug_symbols=true upload_source_maps=true upload_sources=true @@ -153,6 +157,7 @@ void main() { dist=fixture-dist build_path=fixture-build_path web_build_path=fixture-web_build_path + symbols_path: fixture-symbols_path commits=fixture-commits ignore_missing=true bin_dir=fixture-bin_dir @@ -194,6 +199,7 @@ void main() { expect(sut.dist, 'fixture-dist'); expect(sut.buildPath, 'fixture-build_path'); expect(sut.webBuildPath, 'fixture-web_build_path'); + expect(sut.symbolsPath, 'fixture-symbols_path'); expect(sut.commits, 'fixture-commits'); expect(sut.ignoreMissing, true); expect(sut.binDir, 'fixture-bin_dir'); diff --git a/test/plugin_test.dart b/test/plugin_test.dart index 58281f2..6ff8078 100644 --- a/test/plugin_test.dart +++ b/test/plugin_test.dart @@ -37,7 +37,7 @@ void main() { pm = MockProcessManager(); injector.registerSingleton(() => pm, override: true); fs = MemoryFileSystem.test(); - fs.currentDirectory = fs.directory(buildDir)..createSync(); + fs.directory('$buildDir/app/outputs').createSync(recursive: true); injector.registerSingleton(() => fs, override: true); injector.registerSingleton(() => MockCLI(), override: true); configWriter = ConfigWriter(fs, name); @@ -82,7 +82,7 @@ void main() { final args = '$commonArgs --log-level debug'; expect(commandLog, [ - '$cli $args debug-files upload $orgAndProject --include-sources $buildDir', + '$cli $args debug-files upload $orgAndProject --include-sources $buildDir/app/outputs', '$cli $args releases $orgAndProject new $release', '$cli $args releases $orgAndProject files $release upload-sourcemaps $buildDir/web --ext map --ext js', '$cli $args releases $orgAndProject files $release upload-sourcemaps $buildDir --ext dart', @@ -108,7 +108,7 @@ void main() { const release = '$name@$version'; expect(commandLog, [ - '$cli $commonArgs debug-files upload $orgAndProject $buildDir', + '$cli $commonArgs debug-files upload $orgAndProject $buildDir/app/outputs', '$cli $commonArgs releases $orgAndProject new $release', '$cli $commonArgs releases $orgAndProject set-commits $release --auto', '$cli $commonArgs releases $orgAndProject finalize $release' @@ -129,7 +129,7 @@ void main() { const release = '$name@$version'; expect(commandLog, [ - '$customCliPath $commonArgs debug-files upload $orgAndProject $buildDir', + '$customCliPath $commonArgs debug-files upload $orgAndProject $buildDir/app/outputs', '$customCliPath $commonArgs releases $orgAndProject new $release', '$customCliPath $commonArgs releases $orgAndProject set-commits $release --auto', '$customCliPath $commonArgs releases $orgAndProject finalize $release' @@ -157,7 +157,7 @@ void main() { const release = '$name@$version'; expect(commandLog, [ - '$cli $commonArgs debug-files upload $orgAndProject $buildDir', + '$cli $commonArgs debug-files upload $orgAndProject $buildDir/app/outputs', '$cli $commonArgs releases $orgAndProject new $release', '$cli $commonArgs releases $orgAndProject set-commits $release $expectedArgs', '$cli $commonArgs releases $orgAndProject finalize $release' @@ -172,7 +172,7 @@ void main() { const release = '$name@$version'; expect(commandLog, [ - '$cli $commonArgs debug-files upload $orgAndProject $buildDir', + '$cli $commonArgs debug-files upload $orgAndProject $buildDir/app/outputs', '$cli $commonArgs releases $orgAndProject new $release', '$cli $commonArgs releases $orgAndProject finalize $release' ]);