From 9da5fec86e1020e2845b7c9ef1a92eeb60573f65 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 1 Jul 2025 15:19:16 +0200 Subject: [PATCH 01/15] Update --- lib/sentry_dart_plugin.dart | 70 ++++++++++++++++++- lib/src/configuration.dart | 3 + lib/src/configuration_values.dart | 5 ++ .../utils/config-reader/config_reader.dart | 1 + .../config-reader/fallback_config_reader.dart | 6 ++ .../config-reader/no_op_config_reader.dart | 5 ++ .../properties_config_reader.dart | 11 +++ .../config-reader/yaml_config_reader.dart | 13 ++++ 8 files changed, 111 insertions(+), 3 deletions(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index a69463d7..9777ff8b 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -45,7 +45,10 @@ class SentryDartPlugin { if (_configuration.legacyWebSymbolication) { await _executeCliForLegacySourceMaps(release: release, dist: dist); } else { - await _executeCliForSourceMaps(release: release, dist: dist); + await _executeCliForSourceMaps( + release: release, + dist: dist, + ignoreSourcePaths: _configuration.ignoreWebSourcePaths); } } else { Log.info('uploadSourceMaps is disabled.'); @@ -226,7 +229,21 @@ class SentryDartPlugin { await for (final entity in webDir.list(recursive: true, followLinks: false)) { if (entity is File && entity.path.toLowerCase().endsWith('.js')) { - jsFiles.add(entity.path); + final relativePath = fs.path + .relative(entity.path, from: _configuration.webBuildFilesFolder); + + bool shouldIgnoreFile = false; + for (final ignorePattern in _configuration.ignoreWebSourcePaths) { + if (_matchesIgnorePattern(relativePath, ignorePattern)) { + shouldIgnoreFile = true; + } + } + + if (!shouldIgnoreFile) { + jsFiles.add(entity.path); + } else { + Log.info('Ignoring JS file: $relativePath'); + } } } } else { @@ -237,6 +254,46 @@ class SentryDartPlugin { return jsFiles; } + /// Matches a file path against an ignore pattern + /// Supports simple glob patterns with * and directory matching + bool _matchesIgnorePattern(String filePath, String pattern) { + // Normalize paths for comparison + final normalizedPath = filePath.replaceAll('\\', '/'); + final normalizedPattern = pattern.replaceAll('\\', '/'); + + // Handle exact matches + if (normalizedPath == normalizedPattern) { + return true; + } + + // Handle directory patterns (e.g., "packages/" matches any file in packages directory) + if (normalizedPattern.endsWith('/')) { + final dirPattern = + normalizedPattern.substring(0, normalizedPattern.length - 1); + if (normalizedPath.startsWith('$dirPattern/')) { + return true; + } + } + + // Handle wildcard patterns (e.g., "*.min.js" matches any file ending with .min.js) + if (normalizedPattern.contains('*')) { + final regexPattern = + normalizedPattern.replaceAll('.', r'\.').replaceAll('*', '.*'); + final regex = RegExp('^$regexPattern\$'); + if (regex.hasMatch(normalizedPath)) { + return true; + } + } + + // Handle substring matches for patterns that don't end with / + if (!normalizedPattern.endsWith('/') && + normalizedPath.contains(normalizedPattern)) { + return true; + } + + return false; + } + Future> _findAllSourceMapFiles() async { final List sourceMapFiles = []; final fs = injector.get(); @@ -301,6 +358,11 @@ class SentryDartPlugin { params.add('--ext'); params.add('map'); + for (final ignorePattern in _configuration.ignoreWebSourcePaths) { + params.add('--ignore'); + params.add(ignorePattern); + } + final sourceMapFiles = await _findAllSourceMapFiles(); final prefixesToStrip = await _extractPrefixesToStrip(sourceMapFiles); @@ -465,7 +527,9 @@ class SentryDartPlugin { } Future _executeCliForSourceMaps( - {required String release, required String? dist}) async { + {required String release, + required String? dist, + required List ignoreSourcePaths}) async { const taskName = 'uploading source maps'; Log.startingTask(taskName); diff --git a/lib/src/configuration.dart b/lib/src/configuration.dart index e0723502..1b23d4bb 100644 --- a/lib/src/configuration.dart +++ b/lib/src/configuration.dart @@ -106,6 +106,8 @@ class Configuration { /// Whether to use legacy web symbolication. Defaults to `false`. late bool legacyWebSymbolication; + late List ignoreWebSourcePaths; + /// Loads the configuration values Future getConfigValues(List cliArguments) async { const taskName = 'reading config values'; @@ -168,6 +170,7 @@ class Configuration { 'https://downloads.sentry-cdn.com/sentry-cli'; sentryCliVersion = configValues.sentryCliVersion; legacyWebSymbolication = configValues.legacyWebSymbolication ?? false; + ignoreWebSourcePaths = configValues.ignoreWebSourcePaths ?? []; } /// Validates the configuration values and log an error if required fields diff --git a/lib/src/configuration_values.dart b/lib/src/configuration_values.dart index 083a4aff..c8e5d691 100644 --- a/lib/src/configuration_values.dart +++ b/lib/src/configuration_values.dart @@ -27,6 +27,7 @@ class ConfigurationValues { final String? sentryCliCdnUrl; final String? sentryCliVersion; final bool? legacyWebSymbolication; + final List? ignoreWebSourcePaths; ConfigurationValues({ this.version, @@ -53,6 +54,7 @@ class ConfigurationValues { this.sentryCliCdnUrl, this.sentryCliVersion, this.legacyWebSymbolication, + this.ignoreWebSourcePaths, }); factory ConfigurationValues.fromArguments(List arguments) { @@ -108,6 +110,7 @@ class ConfigurationValues { legacyWebSymbolication: boolFromString( sentryArguments['legacy_web_symbolication'], ), + ignoreWebSourcePaths: sentryArguments['ignore_web_source_paths']?.split(',').map((e) => e.trim()).toList(), ); } @@ -143,6 +146,7 @@ class ConfigurationValues { sentryCliCdnUrl: configReader.getString('sentry_cli_cdn_url'), sentryCliVersion: configReader.getString('sentry_cli_version'), legacyWebSymbolication: configReader.getBool('legacy_web_symbolication'), + ignoreWebSourcePaths: configReader.getList('ignore_web_source_paths'), ); } @@ -201,6 +205,7 @@ class ConfigurationValues { sentryCliVersion: args.sentryCliVersion ?? file.sentryCliVersion, legacyWebSymbolication: args.legacyWebSymbolication ?? file.legacyWebSymbolication, + ignoreWebSourcePaths: args.ignoreWebSourcePaths ?? file.ignoreWebSourcePaths, ); } } diff --git a/lib/src/utils/config-reader/config_reader.dart b/lib/src/utils/config-reader/config_reader.dart index adbca101..192ed77c 100644 --- a/lib/src/utils/config-reader/config_reader.dart +++ b/lib/src/utils/config-reader/config_reader.dart @@ -12,6 +12,7 @@ import 'yaml_config_reader.dart'; abstract class ConfigReader { String? getString(String key, {String? deprecatedKey}); bool? getBool(String key, {String? deprecatedKey}); + List? getList(String key, {String? deprecatedKey}); bool contains(String key); /// This factory will try to load both pubspec.yaml and sentry.properties. diff --git a/lib/src/utils/config-reader/fallback_config_reader.dart b/lib/src/utils/config-reader/fallback_config_reader.dart index 7795f51e..015b2946 100644 --- a/lib/src/utils/config-reader/fallback_config_reader.dart +++ b/lib/src/utils/config-reader/fallback_config_reader.dart @@ -18,6 +18,12 @@ class FallbackConfigReader implements ConfigReader { _fallbackConfigReader?.getString(key, deprecatedKey: deprecatedKey); } + @override + List? getList(String key, {String? deprecatedKey}) { + return _configReader?.getList(key, deprecatedKey: deprecatedKey) ?? + _fallbackConfigReader?.getList(key, deprecatedKey: deprecatedKey); + } + @override bool contains(String key) { return _configReader?.contains(key) ?? diff --git a/lib/src/utils/config-reader/no_op_config_reader.dart b/lib/src/utils/config-reader/no_op_config_reader.dart index e792e28e..c5540a88 100644 --- a/lib/src/utils/config-reader/no_op_config_reader.dart +++ b/lib/src/utils/config-reader/no_op_config_reader.dart @@ -13,6 +13,11 @@ class NoOpConfigReader implements ConfigReader { return null; } + @override + List? getList(String key, {String? deprecatedKey}) { + return null; + } + @override bool contains(String key) { return false; diff --git a/lib/src/utils/config-reader/properties_config_reader.dart b/lib/src/utils/config-reader/properties_config_reader.dart index 22d25b10..05732975 100644 --- a/lib/src/utils/config-reader/properties_config_reader.dart +++ b/lib/src/utils/config-reader/properties_config_reader.dart @@ -17,6 +17,17 @@ class PropertiesConfigReader implements ConfigReader { return get(key, deprecatedKey, (key) => _properties.get((key))); } + @override + List? getList(String key, {String? deprecatedKey}) { + return get(key, deprecatedKey, (key) { + final value = _properties.get(key); + if (value != null && value.isNotEmpty) { + return value.split(',').map((e) => e.trim()).toList(); + } + return null; + }); + } + @override bool contains(String key) { return _properties.contains(key); diff --git a/lib/src/utils/config-reader/yaml_config_reader.dart b/lib/src/utils/config-reader/yaml_config_reader.dart index 5ae24313..b4aebc92 100644 --- a/lib/src/utils/config-reader/yaml_config_reader.dart +++ b/lib/src/utils/config-reader/yaml_config_reader.dart @@ -17,6 +17,19 @@ class YamlConfigReader implements ConfigReader { return get(key, deprecatedKey, (key) => (_yamlMap?[key]).toString()); } + @override + List? getList(String key, {String? deprecatedKey}) { + return get(key, deprecatedKey, (key) { + final value = _yamlMap?[key]; + if (value is YamlList) { + return value.map((e) => e.toString()).toList(); + } else if (value is List) { + return value.map((e) => e.toString()).toList(); + } + return null; + }); + } + @override bool contains(String key) { return _yamlMap?.containsKey(key) ?? false; From 138742ff51d4c406390c2562be720311c504e90e Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 1 Jul 2025 15:55:43 +0200 Subject: [PATCH 02/15] Update --- lib/sentry_dart_plugin.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index 9777ff8b..557bedd4 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -358,11 +358,6 @@ class SentryDartPlugin { params.add('--ext'); params.add('map'); - for (final ignorePattern in _configuration.ignoreWebSourcePaths) { - params.add('--ignore'); - params.add(ignorePattern); - } - final sourceMapFiles = await _findAllSourceMapFiles(); final prefixesToStrip = await _extractPrefixesToStrip(sourceMapFiles); @@ -383,6 +378,15 @@ class SentryDartPlugin { params.add('./'); params.add('--ext'); params.add('dart'); + params.add('--ignore'); + // we want to ignore the test folder by default + // TODO(buenaflor): the better way would be to get the paths from the sourcemaps and reference them directly instead of specifying the root dir + params.add('test/**/*.dart'); + } + + for (final ignorePattern in _configuration.ignoreWebSourcePaths) { + params.add('--ignore'); + params.add(ignorePattern); } params.addAll(_baseCliParams()); From 7e5da50f92c5087b5e1473a2e39aa6404c036799 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 1 Jul 2025 16:03:21 +0200 Subject: [PATCH 03/15] Add comment --- lib/sentry_dart_plugin.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index 557bedd4..ec8ad524 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -375,12 +375,12 @@ class SentryDartPlugin { // add the --url-prefix ~/lib however this would be applied to all files - even the source map - // and not only the dart source files meaning symbolication would not work correctly // TODO(buenaflor): revisit this approach when we can add --url-prefixes to specific files + // TODO(buenaflor): additionally the better way would be to get the paths from the sourcemaps and reference them directly instead of specifying the root dir params.add('./'); params.add('--ext'); params.add('dart'); params.add('--ignore'); // we want to ignore the test folder by default - // TODO(buenaflor): the better way would be to get the paths from the sourcemaps and reference them directly instead of specifying the root dir params.add('test/**/*.dart'); } From 653bb970bc2df6e4149a49f43cd5fc5bbf231b22 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 1 Jul 2025 16:06:37 +0200 Subject: [PATCH 04/15] Apply ignore --- lib/sentry_dart_plugin.dart | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index ec8ad524..62649282 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -303,7 +303,21 @@ class SentryDartPlugin { await for (final entity in webDir.list(recursive: true, followLinks: false)) { if (entity is File && entity.path.toLowerCase().endsWith('.js.map')) { - sourceMapFiles.add(entity.absolute); + final relativePath = fs.path + .relative(entity.path, from: _configuration.webBuildFilesFolder); + + bool shouldIgnoreFile = false; + for (final ignorePattern in _configuration.ignoreWebSourcePaths) { + if (_matchesIgnorePattern(relativePath, ignorePattern)) { + shouldIgnoreFile = true; + } + } + + if (!shouldIgnoreFile) { + sourceMapFiles.add(entity.absolute); + } else { + Log.info('Ignoring source map file: $relativePath'); + } } } } else { From b4f01c90154cd995d2a5ed831b616e0df2924ad8 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 1 Jul 2025 17:18:17 +0200 Subject: [PATCH 05/15] Update --- lib/sentry_dart_plugin.dart | 71 +++++++------------------------------ pubspec.yaml | 1 + 2 files changed, 14 insertions(+), 58 deletions(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index 62649282..902dfecf 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:file/file.dart'; +import 'package:glob/glob.dart'; import 'package:process/process.dart'; import 'package:sentry_dart_plugin/src/utils/extensions.dart'; @@ -232,17 +233,14 @@ class SentryDartPlugin { final relativePath = fs.path .relative(entity.path, from: _configuration.webBuildFilesFolder); - bool shouldIgnoreFile = false; - for (final ignorePattern in _configuration.ignoreWebSourcePaths) { - if (_matchesIgnorePattern(relativePath, ignorePattern)) { - shouldIgnoreFile = true; - } - } + final shouldIgnore = + _configuration.ignoreWebSourcePaths.any((pattern) { + final glob = Glob(pattern); + return glob.matches(relativePath); + }); - if (!shouldIgnoreFile) { + if (!shouldIgnore) { jsFiles.add(entity.path); - } else { - Log.info('Ignoring JS file: $relativePath'); } } } @@ -254,46 +252,6 @@ class SentryDartPlugin { return jsFiles; } - /// Matches a file path against an ignore pattern - /// Supports simple glob patterns with * and directory matching - bool _matchesIgnorePattern(String filePath, String pattern) { - // Normalize paths for comparison - final normalizedPath = filePath.replaceAll('\\', '/'); - final normalizedPattern = pattern.replaceAll('\\', '/'); - - // Handle exact matches - if (normalizedPath == normalizedPattern) { - return true; - } - - // Handle directory patterns (e.g., "packages/" matches any file in packages directory) - if (normalizedPattern.endsWith('/')) { - final dirPattern = - normalizedPattern.substring(0, normalizedPattern.length - 1); - if (normalizedPath.startsWith('$dirPattern/')) { - return true; - } - } - - // Handle wildcard patterns (e.g., "*.min.js" matches any file ending with .min.js) - if (normalizedPattern.contains('*')) { - final regexPattern = - normalizedPattern.replaceAll('.', r'\.').replaceAll('*', '.*'); - final regex = RegExp('^$regexPattern\$'); - if (regex.hasMatch(normalizedPath)) { - return true; - } - } - - // Handle substring matches for patterns that don't end with / - if (!normalizedPattern.endsWith('/') && - normalizedPath.contains(normalizedPattern)) { - return true; - } - - return false; - } - Future> _findAllSourceMapFiles() async { final List sourceMapFiles = []; final fs = injector.get(); @@ -306,17 +264,14 @@ class SentryDartPlugin { final relativePath = fs.path .relative(entity.path, from: _configuration.webBuildFilesFolder); - bool shouldIgnoreFile = false; - for (final ignorePattern in _configuration.ignoreWebSourcePaths) { - if (_matchesIgnorePattern(relativePath, ignorePattern)) { - shouldIgnoreFile = true; - } - } + final shouldIgnore = + _configuration.ignoreWebSourcePaths.any((pattern) { + final glob = Glob(pattern); + return glob.matches(relativePath); + }); - if (!shouldIgnoreFile) { + if (!shouldIgnore) { sourceMapFiles.add(entity.absolute); - } else { - Log.info('Ignoring source map file: $relativePath'); } } } diff --git a/pubspec.yaml b/pubspec.yaml index 2f747151..afdc5ff2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: convert: ^3.0.2 process: '>=4.2.4 <6.0.0' properties: ^2.1.0 + glob: ^2.1.3 dev_dependencies: lints: '>=3.0.0' From 83ab62290f77e15ffff978c0a29030e74223648a Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 1 Jul 2025 17:19:18 +0200 Subject: [PATCH 06/15] Update --- lib/sentry_dart_plugin.dart | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index 902dfecf..c1acc7d3 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -46,10 +46,7 @@ class SentryDartPlugin { if (_configuration.legacyWebSymbolication) { await _executeCliForLegacySourceMaps(release: release, dist: dist); } else { - await _executeCliForSourceMaps( - release: release, - dist: dist, - ignoreSourcePaths: _configuration.ignoreWebSourcePaths); + await _executeCliForSourceMaps(release: release, dist: dist); } } else { Log.info('uploadSourceMaps is disabled.'); @@ -500,9 +497,7 @@ class SentryDartPlugin { } Future _executeCliForSourceMaps( - {required String release, - required String? dist, - required List ignoreSourcePaths}) async { + {required String release, required String? dist}) async { const taskName = 'uploading source maps'; Log.startingTask(taskName); From 2fc2490e4635ac6069f3bc700e0381ffdcdfa432 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 2 Jul 2025 02:38:21 +0200 Subject: [PATCH 07/15] Update --- lib/sentry_dart_plugin.dart | 3 --- test/plugin_test.dart | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index c1acc7d3..105b8331 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -345,9 +345,6 @@ class SentryDartPlugin { params.add('./'); params.add('--ext'); params.add('dart'); - params.add('--ignore'); - // we want to ignore the test folder by default - params.add('test/**/*.dart'); } for (final ignorePattern in _configuration.ignoreWebSourcePaths) { diff --git a/test/plugin_test.dart b/test/plugin_test.dart index b2feb57f..bce05aa4 100644 --- a/test/plugin_test.dart +++ b/test/plugin_test.dart @@ -94,6 +94,8 @@ void main() { upload_source_maps: true log_level: debug ignore_missing: true + ignore_web_source_paths: + - "**/*.dart" '''; final commandLog = await runWith(version, config); const release = '$name@$version'; @@ -103,7 +105,7 @@ void main() { '$cli $args debug-files upload $orgAndProject --include-sources $buildDir/app/outputs', '$cli $args releases $orgAndProject new $release', '$cli sourcemaps inject $buildDir/web/file.js $orgAndProject', - '$cli $args sourcemaps upload --release $release $buildDir/web --ext js --ext map --strip-prefix ../../Documents --strip-prefix ../../../../ --strip-prefix ../../ --strip-prefix ../ ./ --ext dart $orgAndProject', + '$cli $args sourcemaps upload --release $release $buildDir/web --ext js --ext map --strip-prefix ../../Documents --strip-prefix ../../../../ --strip-prefix ../../ --strip-prefix ../ ./ --ext dart --ignore **/*.dart $orgAndProject', '$cli $args releases $orgAndProject set-commits $release --auto --ignore-missing', '$cli $args releases $orgAndProject finalize $release' ]); From 519866a1dfaed9dbb389e51b3807a2e7e1480fcc Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 2 Jul 2025 02:46:36 +0200 Subject: [PATCH 08/15] Fix test --- test/plugin_test.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/plugin_test.dart b/test/plugin_test.dart index bce05aa4..062ab557 100644 --- a/test/plugin_test.dart +++ b/test/plugin_test.dart @@ -94,8 +94,7 @@ void main() { upload_source_maps: true log_level: debug ignore_missing: true - ignore_web_source_paths: - - "**/*.dart" + ignore_web_source_paths: [test-dir] '''; final commandLog = await runWith(version, config); const release = '$name@$version'; @@ -105,7 +104,7 @@ void main() { '$cli $args debug-files upload $orgAndProject --include-sources $buildDir/app/outputs', '$cli $args releases $orgAndProject new $release', '$cli sourcemaps inject $buildDir/web/file.js $orgAndProject', - '$cli $args sourcemaps upload --release $release $buildDir/web --ext js --ext map --strip-prefix ../../Documents --strip-prefix ../../../../ --strip-prefix ../../ --strip-prefix ../ ./ --ext dart --ignore **/*.dart $orgAndProject', + '$cli $args sourcemaps upload --release $release $buildDir/web --ext js --ext map --strip-prefix ../../Documents --strip-prefix ../../../../ --strip-prefix ../../ --strip-prefix ../ ./ --ext dart --ignore test-dir $orgAndProject', '$cli $args releases $orgAndProject set-commits $release --auto --ignore-missing', '$cli $args releases $orgAndProject finalize $release' ]); From da88548629a014e214c4eedd4d6f7c592067c900 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 2 Jul 2025 02:53:58 +0200 Subject: [PATCH 09/15] update --- test/plugin_test.dart | 5 ++--- test/utils/config_formatter.dart | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/plugin_test.dart b/test/plugin_test.dart index 062ab557..f9e074f2 100644 --- a/test/plugin_test.dart +++ b/test/plugin_test.dart @@ -85,7 +85,6 @@ void main() { setUp(() { createJsFilesForTesting(); }); - test('works with all configuration files', () async { const version = '1.0.0'; final config = ''' @@ -94,7 +93,7 @@ void main() { upload_source_maps: true log_level: debug ignore_missing: true - ignore_web_source_paths: [test-dir] + ignore_web_source_paths: [testdir] '''; final commandLog = await runWith(version, config); const release = '$name@$version'; @@ -104,7 +103,7 @@ void main() { '$cli $args debug-files upload $orgAndProject --include-sources $buildDir/app/outputs', '$cli $args releases $orgAndProject new $release', '$cli sourcemaps inject $buildDir/web/file.js $orgAndProject', - '$cli $args sourcemaps upload --release $release $buildDir/web --ext js --ext map --strip-prefix ../../Documents --strip-prefix ../../../../ --strip-prefix ../../ --strip-prefix ../ ./ --ext dart --ignore test-dir $orgAndProject', + '$cli $args sourcemaps upload --release $release $buildDir/web --ext js --ext map --strip-prefix ../../Documents --strip-prefix ../../../../ --strip-prefix ../../ --strip-prefix ../ ./ --ext dart --ignore testdir $orgAndProject', '$cli $args releases $orgAndProject set-commits $release --auto --ignore-missing', '$cli $args releases $orgAndProject finalize $release' ]); diff --git a/test/utils/config_formatter.dart b/test/utils/config_formatter.dart index 9e777e76..9ae9505a 100644 --- a/test/utils/config_formatter.dart +++ b/test/utils/config_formatter.dart @@ -31,7 +31,9 @@ class ConfigFormatter { .replaceAll(': ', '=') .split('\n') .map((line) => line.trim()) - .join('\n'); + .join('\n') + .replaceAll('[', '') + .replaceAll(']', ''); // support for arrays } static String _formatPubspecYamlConfig(String config) { From 056a2a88bef75788122008826f9e53a0c0e4b1b2 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 2 Jul 2025 02:57:09 +0200 Subject: [PATCH 10/15] Update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b95ce227..474f32d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Unreleased + +### Features + +- Ignore path list for web ([#340](https://github.com/getsentry/sentry-dart-plugin/pull/340)) + - You can use the `ignore_web_source_paths` field: e.g `ignore_web_source_paths: [test/**/*.js]` + - This will ignore all specified files and directories from being uploaded + ## 3.1.0 ### Features From 3724753ca649e13524f92ab1f7de0baae3ca2d41 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 14 Jul 2025 16:50:30 +0200 Subject: [PATCH 11/15] Add test --- lib/sentry_dart_plugin.dart | 96 +++++++++++++++++------------------- test/configuration_test.dart | 6 +++ 2 files changed, 52 insertions(+), 50 deletions(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index 105b8331..0d525586 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -218,68 +218,64 @@ class SentryDartPlugin { await _executeAndLog('Failed to set commits', params); } - Future> _findAllJsFilePaths() async { - final List jsFiles = []; + /// Returns every file inside [_configuration.webBuildFilesFolder] whose + /// path ends with [extension] **and** is *not* matched by an ignore glob. + /// + /// The generic type `T` lets the caller decide what they want back + /// (e.g. `String` path vs. `File` object). + Future> _collectWebFiles({ + required String extension, + required T Function(File) builder, + }) async { final fs = injector.get(); final webDir = fs.directory(_configuration.webBuildFilesFolder); - if (await webDir.exists()) { - await for (final entity - in webDir.list(recursive: true, followLinks: false)) { - if (entity is File && entity.path.toLowerCase().endsWith('.js')) { - final relativePath = fs.path - .relative(entity.path, from: _configuration.webBuildFilesFolder); - - final shouldIgnore = - _configuration.ignoreWebSourcePaths.any((pattern) { - final glob = Glob(pattern); - return glob.matches(relativePath); - }); - - if (!shouldIgnore) { - jsFiles.add(entity.path); - } - } - } - } else { + // Fast-fail if the directory doesn’t exist. + if (!await webDir.exists()) { Log.warn( - 'Web build directory "${_configuration.webBuildFilesFolder}" does not exist, skipping JS file enumeration.', + 'Web build directory "${_configuration.webBuildFilesFolder}" does not exist, ' + 'skipping $extension enumeration.', ); + return []; } - return jsFiles; - } - Future> _findAllSourceMapFiles() async { - final List sourceMapFiles = []; - final fs = injector.get(); - final webDir = fs.directory(_configuration.webBuildFilesFolder); + // Compile ignore globs once instead of on every iteration. + final ignoreGlobs = + _configuration.ignoreWebSourcePaths.map((p) => Glob(p)).toList(); - if (await webDir.exists()) { - await for (final entity - in webDir.list(recursive: true, followLinks: false)) { - if (entity is File && entity.path.toLowerCase().endsWith('.js.map')) { - final relativePath = fs.path - .relative(entity.path, from: _configuration.webBuildFilesFolder); - - final shouldIgnore = - _configuration.ignoreWebSourcePaths.any((pattern) { - final glob = Glob(pattern); - return glob.matches(relativePath); - }); - - if (!shouldIgnore) { - sourceMapFiles.add(entity.absolute); - } - } + bool shouldIgnore(String relative) => + ignoreGlobs.any((g) => g.matches(relative)); + + final results = []; + + await for (final entity + in webDir.list(recursive: true, followLinks: false)) { + if (entity is! File) continue; + + final path = entity.path; + if (!path.toLowerCase().endsWith(extension)) continue; + + final relative = + fs.path.relative(path, from: _configuration.webBuildFilesFolder); + + if (!shouldIgnore(relative)) { + results.add(builder(entity)); } - } else { - Log.warn( - 'Web build directory "${_configuration.webBuildFilesFolder}" does not exist, skipping source map file enumeration.', - ); } - return sourceMapFiles; + + return results; } + Future> _findAllJsFilePaths() => _collectWebFiles( + extension: '.js', + builder: (file) => file.path, + ); + + Future> _findAllSourceMapFiles() => _collectWebFiles( + extension: '.js.map', + builder: (file) => file.absolute, + ); + Future _injectDebugIds() async { List params = []; params.add('sourcemaps'); diff --git a/test/configuration_test.dart b/test/configuration_test.dart index 10fe2df0..fde1f023 100644 --- a/test/configuration_test.dart +++ b/test/configuration_test.dart @@ -77,6 +77,7 @@ void main() { sentryCliCdnUrl: 'sentryCliCdnUrl-args-config', sentryCliVersion: '1.0.0-args-config', legacyWebSymbolication: true, + ignoreWebSourcePaths: ['some/', '**/*.js'], ); final fileConfig = ConfigurationValues( version: 'version-file-config', @@ -103,6 +104,7 @@ void main() { sentryCliCdnUrl: 'sentryCliCdnUrl-file-config', sentryCliVersion: '1.0.0-file-config', legacyWebSymbolication: false, + ignoreWebSourcePaths: ['some-other/'], ); final sut = fixture.getSut( @@ -141,6 +143,7 @@ void main() { expect(sut.sentryCliCdnUrl, 'sentryCliCdnUrl-args-config'); expect(sut.sentryCliVersion, '1.0.0-args-config'); expect(sut.legacyWebSymbolication, isTrue); + expect(sut.ignoreWebSourcePaths, ['some/', '**/*.js']); }); test("takes values from file config", () { @@ -171,6 +174,7 @@ void main() { sentryCliCdnUrl: 'sentryCliCdnUrl-file-config', sentryCliVersion: '1.0.0-file-config', legacyWebSymbolication: true, + ignoreWebSourcePaths: ['some/', '**/*.js'], ); final sut = fixture.getSut( @@ -208,6 +212,7 @@ void main() { expect(sut.sentryCliCdnUrl, 'sentryCliCdnUrl-file-config'); expect(sut.sentryCliVersion, '1.0.0-file-config'); expect(sut.legacyWebSymbolication, isTrue); + expect(sut.ignoreWebSourcePaths, ['some/', '**/*.js']); }); test("falls back to default values", () { @@ -240,6 +245,7 @@ void main() { 'https://downloads.sentry-cdn.com/sentry-cli', ); expect(sut.legacyWebSymbolication, isFalse); + expect(sut.ignoreWebSourcePaths, []); }); }); } From 4c12158312594bcc3697ffe8bdca020564fe8529 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 14 Jul 2025 17:03:24 +0200 Subject: [PATCH 12/15] Add mising tests --- test/configuration_values_test.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/configuration_values_test.dart b/test/configuration_values_test.dart index 59725141..ae4932a3 100644 --- a/test/configuration_values_test.dart +++ b/test/configuration_values_test.dart @@ -35,7 +35,8 @@ void main() { "--sentry-define=bin_dir=fixture-bin_dir", "--sentry-define=sentry_cli_cdn_url=fixture-sentry_cli_cdn_url", "--sentry-define=sentry_cli_version=1.0.0", - "--sentry-define=legacy_web_symbolication=true" + "--sentry-define=legacy_web_symbolication=true", + "--sentry-define=ignore_web_source_paths=some/, **/*.js" ]; final sut = ConfigurationValues.fromArguments(arguments); expect(sut.name, 'fixture-sentry-name'); @@ -60,6 +61,7 @@ void main() { expect(sut.sentryCliCdnUrl, 'fixture-sentry_cli_cdn_url'); expect(sut.sentryCliVersion, '1.0.0'); expect(sut.legacyWebSymbolication, isTrue); + expect(sut.ignoreWebSourcePaths, ['some/', '**/*.js']); }); test("fromArguments supports deprecated fields", () { @@ -103,6 +105,9 @@ void main() { sentry_cli_cdn_url: fixture-sentry_cli_cdn_url sentry_cli_version: 1.0.0 legacy_web_symbolication: true + ignore_web_source_paths: + - some/ + - **/*.js '''; FileSystem fs = MemoryFileSystem.test(); @@ -145,6 +150,7 @@ void main() { expect(sut.binDir, 'fixture-bin_dir'); expect(sut.sentryCliCdnUrl, 'fixture-sentry_cli_cdn_url'); expect(sut.legacyWebSymbolication, isTrue); + expect(sut.ignoreWebSourcePaths, ['some/', '**/*.js']); }); test('from config reader as properties', () { @@ -167,6 +173,7 @@ void main() { bin_dir=fixture-bin_dir sentry_cli_cdn_url=fixture-sentry_cli_cdn_url sentry_cli_version=1.0.0 + ignore_web_source_paths=[some/, **/*.js] '''; FileSystem fs = MemoryFileSystem.test(); @@ -209,6 +216,7 @@ void main() { expect(sut.binDir, 'fixture-bin_dir'); expect(sut.sentryCliCdnUrl, 'fixture-sentry_cli_cdn_url'); expect(sut.sentryCliVersion, '1.0.0'); + expect(sut.ignoreWebSourcePaths, ['some/', '**/*.js']); }); test('from config reader pubspec & properties', () { From 70000949ece388824e6e52ad26837ec0afaea6e8 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 14 Jul 2025 17:24:32 +0200 Subject: [PATCH 13/15] Update --- test/configuration_values_test.dart | 2 +- test/plugin_test.dart | 4 +- test/utils/config_formatter.dart | 78 +++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/test/configuration_values_test.dart b/test/configuration_values_test.dart index ae4932a3..c813a370 100644 --- a/test/configuration_values_test.dart +++ b/test/configuration_values_test.dart @@ -107,7 +107,7 @@ void main() { legacy_web_symbolication: true ignore_web_source_paths: - some/ - - **/*.js + - '**/*.js' '''; FileSystem fs = MemoryFileSystem.test(); diff --git a/test/plugin_test.dart b/test/plugin_test.dart index f9e074f2..33b533ff 100644 --- a/test/plugin_test.dart +++ b/test/plugin_test.dart @@ -93,7 +93,7 @@ void main() { upload_source_maps: true log_level: debug ignore_missing: true - ignore_web_source_paths: [testdir] + ignore_web_source_paths: [testdir/**/*.js] '''; final commandLog = await runWith(version, config); const release = '$name@$version'; @@ -103,7 +103,7 @@ void main() { '$cli $args debug-files upload $orgAndProject --include-sources $buildDir/app/outputs', '$cli $args releases $orgAndProject new $release', '$cli sourcemaps inject $buildDir/web/file.js $orgAndProject', - '$cli $args sourcemaps upload --release $release $buildDir/web --ext js --ext map --strip-prefix ../../Documents --strip-prefix ../../../../ --strip-prefix ../../ --strip-prefix ../ ./ --ext dart --ignore testdir $orgAndProject', + '$cli $args sourcemaps upload --release $release $buildDir/web --ext js --ext map --strip-prefix ../../Documents --strip-prefix ../../../../ --strip-prefix ../../ --strip-prefix ../ ./ --ext dart --ignore testdir/**/*.js $orgAndProject', '$cli $args releases $orgAndProject set-commits $release --auto --ignore-missing', '$cli $args releases $orgAndProject finalize $release' ]); diff --git a/test/utils/config_formatter.dart b/test/utils/config_formatter.dart index 9ae9505a..fc044c6a 100644 --- a/test/utils/config_formatter.dart +++ b/test/utils/config_formatter.dart @@ -2,41 +2,87 @@ import 'config_file_type.dart'; class ConfigFormatter { static String formatConfig( - String config, ConfigFileType fileType, String? url) { - // Add URL if provided - if (url != null) { - config = _addUrlPrefix(config, fileType, url); + String config, + ConfigFileType fileType, + String? url, + ) { + if (url?.isNotEmpty == true) { + config = _addUrlPrefix(config, fileType, url!); } - // Format config based on file type switch (fileType) { case ConfigFileType.sentryProperties: return _formatSentryPropertiesConfig(config); case ConfigFileType.pubspecYaml: return _formatPubspecYamlConfig(config); - default: - throw Exception('Unknown config file type: $fileType'); } } static String _addUrlPrefix( - String config, ConfigFileType fileType, String url) { + String config, + ConfigFileType fileType, + String url, + ) { final urlLine = fileType == ConfigFileType.sentryProperties ? 'url=$url' : 'url: $url'; return '$urlLine\n$config'; } static String _formatSentryPropertiesConfig(String config) { - return config - .replaceAll(': ', '=') - .split('\n') - .map((line) => line.trim()) - .join('\n') - .replaceAll('[', '') - .replaceAll(']', ''); // support for arrays + final lines = config.split('\n'); + final out = StringBuffer(); + + for (var i = 0; i < lines.length; i++) { + var line = lines[i].trim(); + if (line.isEmpty) continue; + + // 1) normalise key/value separator once + line = line.replaceFirst(RegExp(r':\s*'), '='); + + // 2) inline array + final mInline = RegExp(r'(.*)=\[(.*)\]').firstMatch(line); + if (mInline != null) { + final key = mInline.group(1)!.trim(); + final values = + mInline.group(2)!.split(',').map((v) => v.trim()).join(','); + out.writeln('$key=$values'); + continue; + } + + // 3) block-array start + if (RegExp(r'.*=').hasMatch(line) && line.endsWith('=')) { + final key = line.substring(0, line.length - 1).trim(); + final values = []; + + while (i + 1 < lines.length) { + final next = lines[i + 1].trim(); + if (next.startsWith('- ')) { + values.add(next.substring(2).trim()); + i++; // consume + } else if (next.isEmpty) { + i++; // skip blank + } else { + break; + } + } + + out.writeln('$key=${values.join(',')}'); + continue; + } + + // 4) plain key=value line + out.writeln(line); + } + + return out.toString().trimRight(); } static String _formatPubspecYamlConfig(String config) { - return config.split('\n').map((line) => ' ${line.trim()}').join('\n'); + return config + .split('\n') + .map((l) => + l.trim().startsWith('- ') ? ' ${l.trim()}' : ' ${l.trim()}') + .join('\n') + .trimRight(); } } From dc522939ccf0140aa4be4616803f211378716a21 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 14 Jul 2025 17:26:07 +0200 Subject: [PATCH 14/15] Remove todo --- lib/sentry_dart_plugin.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/sentry_dart_plugin.dart b/lib/sentry_dart_plugin.dart index 0d525586..32abf3e0 100644 --- a/lib/sentry_dart_plugin.dart +++ b/lib/sentry_dart_plugin.dart @@ -337,7 +337,6 @@ class SentryDartPlugin { // add the --url-prefix ~/lib however this would be applied to all files - even the source map - // and not only the dart source files meaning symbolication would not work correctly // TODO(buenaflor): revisit this approach when we can add --url-prefixes to specific files - // TODO(buenaflor): additionally the better way would be to get the paths from the sourcemaps and reference them directly instead of specifying the root dir params.add('./'); params.add('--ext'); params.add('dart'); From f7ec286f339cdf8241e988a0f37c8aef6ee24187 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Thu, 17 Jul 2025 23:57:50 +0200 Subject: [PATCH 15/15] Update test --- test/utils/config_formatter.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/utils/config_formatter.dart b/test/utils/config_formatter.dart index fc044c6a..52db56f3 100644 --- a/test/utils/config_formatter.dart +++ b/test/utils/config_formatter.dart @@ -37,7 +37,8 @@ class ConfigFormatter { if (line.isEmpty) continue; // 1) normalise key/value separator once - line = line.replaceFirst(RegExp(r':\s*'), '='); + line = line.replaceFirstMapped( + RegExp(r'^([^=:\s]+):\s*'), (m) => '${m.group(1)}='); // 2) inline array final mInline = RegExp(r'(.*)=\[(.*)\]').firstMatch(line);