Skip to content

Commit

Permalink
feat: sentry.properties (#191)
Browse files Browse the repository at this point in the history
* Add sentry properties reader
  • Loading branch information
buenaflor authored Jan 30, 2024
1 parent 387c3a3 commit 1795b48
Show file tree
Hide file tree
Showing 11 changed files with 381 additions and 178 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Features

- Support reading config from sentry.properties file ([#191](https://github.com/getsentry/sentry-dart-plugin/pull/191))

### Dependencies

- Bump CLI from v2.21.2 to v2.22.3 ([#180](https://github.com/getsentry/sentry-dart-plugin/pull/180))
Expand Down
80 changes: 29 additions & 51 deletions lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import 'dart:io';
import 'package:file/file.dart';
import 'package:process/process.dart';
import 'package:system_info2/system_info2.dart';
import 'package:yaml/yaml.dart';

import 'cli/host_platform.dart';
import 'cli/setup.dart';
import 'utils/config-reader/config_reader.dart';
import 'utils/extensions.dart';
import 'utils/injector.dart';
import 'utils/log.dart';
Expand Down Expand Up @@ -80,57 +80,51 @@ class Configuration {
/// https://docs.sentry.io/product/cli/releases/#dealing-with-missing-commits
late bool ignoreMissing;

dynamic _getPubspec() {
final file = injector.get<FileSystem>().file("pubspec.yaml");
if (!file.existsSync()) {
Log.error("Pubspec not found: ${file.absolute.path}");
return {};
}
final pubspecString = file.readAsStringSync();
final pubspec = loadYaml(pubspecString);
return pubspec;
}

/// Loads the configuration values
Future<void> getConfigValues(List<String> arguments) async {
final environments = Platform.environment;
const taskName = 'reading config values';
Log.startingTask(taskName);

await _findAndSetCliPath();
final pubspec = _getPubspec();
final config = pubspec['sentry'] as YamlMap?;

release = config?['release']?.toString() ?? environments['SENTRY_RELEASE'];
dist = config?['dist']?.toString() ?? environments['SENTRY_DIST'];
final reader = ConfigReader();
loadConfig(reader);

Log.taskCompleted(taskName);
}

void loadConfig(ConfigReader reader) {
final environments = Platform.environment;
final pubspec = ConfigReader.getPubspec();

release = reader.getString('release') ?? environments['SENTRY_RELEASE'];
dist = reader.getString('dist') ?? environments['SENTRY_DIST'];
version = pubspec['version'].toString();
name = pubspec['name'].toString();

uploadDebugSymbols =
config?.get('upload_debug_symbols', 'upload_native_symbols') ?? true;
uploadSourceMaps = config?['upload_source_maps'] ?? false;
uploadSources =
config?.get('upload_sources', 'include_native_sources') ?? false;
commits = (config?['commits'] ?? 'auto').toString();
ignoreMissing = config?['ignore_missing'] ?? false;
uploadDebugSymbols = reader.getBool('upload_debug_symbols',
deprecatedKey: 'upload_native_symbols') ??
true;
uploadSourceMaps = reader.getBool('upload_source_maps') ?? false;
uploadSources = reader.getBool('upload_sources',
deprecatedKey: 'include_native_sources') ??
false;
commits = (reader.getString('commits') ?? 'auto').toString();
ignoreMissing = reader.getBool('ignore_missing') ?? false;

// uploading JS and Map files need to have the correct folder structure
// otherwise symbolication fails, the default path for the web build folder is build/web
// but can be customized so making it flexible.
final webBuildPath =
config?['web_build_path']?.toString() ?? _fs.path.join('build', 'web');
reader.getString('web_build_path') ?? _fs.path.join('build', 'web');
webBuildFilesFolder = _fs.path.join(buildFilesFolder, webBuildPath);

project = config?['project']?.toString(); // or env. var. SENTRY_PROJECT
org = config?['org']?.toString(); // or env. var. SENTRY_ORG
waitForProcessing = config?['wait_for_processing'] ?? false;
project = reader.getString('project'); // or env. var. SENTRY_PROJECT
org = reader.getString('org'); // or env. var. SENTRY_ORG
waitForProcessing = reader.getBool('wait_for_processing') ?? false;
authToken =
config?['auth_token']?.toString(); // or env. var. SENTRY_AUTH_TOKEN
url = config?['url']?.toString(); // or env. var. SENTRY_URL
logLevel =
config?['log_level']?.toString(); // or env. var. SENTRY_LOG_LEVEL

Log.taskCompleted(taskName);
reader.getString('auth_token'); // or env. var. SENTRY_AUTH_TOKEN
url = reader.getString('url'); // or env. var. SENTRY_URL
logLevel = reader.getString('log_level'); // or env. var. SENTRY_LOG_LEVEL
}

/// Validates the configuration values and log an error if required fields
Expand Down Expand Up @@ -227,19 +221,3 @@ class Configuration {
'Trying to fallback to preinstalled Sentry CLI, if available on PATH: $cliPath');
}
}

extension _Config on YamlMap {
T? get<T>(String name, String? deprecatedName) {
if (deprecatedName != null && containsKey(deprecatedName)) {
Log.warn(
'Your pubspec.yaml contains `$deprecatedName` which is deprecated. Consider switching to `$name`.');
}
if (containsKey(name)) {
return this[name];
} else if (deprecatedName != null && containsKey(deprecatedName)) {
return this[deprecatedName];
} else {
return null;
}
}
}
70 changes: 70 additions & 0 deletions lib/src/utils/config-reader/config_reader.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import 'package:properties/properties.dart';
import 'package:yaml/yaml.dart';
import 'package:file/file.dart';

import '../injector.dart';
import '../log.dart';
import 'no_op_config_reader.dart';
import 'properties_config_reader.dart';
import 'yaml_config_reader.dart';

abstract class ConfigReader {
String? getString(String key, {String? deprecatedKey});
bool? getBool(String key, {String? deprecatedKey});
bool contains(String key);

/// By default this ConfigReader factory will try to load pubspec.yaml first.
/// If the sentry config doesn't exist on pubspec.yaml it will use sentry.properties as fallback.
factory ConfigReader() {
// Attempt to retrieve the config from pubspec.yaml first
final pubspec = getPubspec();
final sentryConfig = pubspec['sentry'] as YamlMap?;
if (sentryConfig != null) {
Log.info('retrieving config from pubspec.yaml');
return YamlConfigReader(sentryConfig);
} else {
Log.info('sentry config not found in pubspec.yaml');
}

// If sentry config is not found in pubspec.yaml, try loading from sentry.properties
final propertiesFile = injector.get<FileSystem>().file("sentry.properties");
if (propertiesFile.existsSync()) {
Log.info('retrieving config from sentry.properties');
// Loads properties class via string as there are issues loading the file
// from path if run in the test suite
final properties =
Properties.fromString(propertiesFile.readAsStringSync());
return PropertiesConfigReader(properties);
}
Log.error('no config found, please use sentry.properties or pubspec.yaml.');
return NoOpConfigReader();
}

static dynamic getPubspec() {
final file = injector.get<FileSystem>().file("pubspec.yaml");
if (!file.existsSync()) {
Log.error("Pubspec not found: ${file.absolute.path}");
return {};
}
final pubspecString = file.readAsStringSync();
final pubspec = loadYaml(pubspecString);
return pubspec;
}
}

extension Config on ConfigReader {
T? get<T>(
String name, String? deprecatedName, T? Function(String key) resolve) {
if (deprecatedName != null && contains(deprecatedName)) {
Log.warn(
'Your config contains `$deprecatedName` which is deprecated. Consider switching to `$name`.');
}
if (contains(name)) {
return resolve(name);
} else if (deprecatedName != null && contains(deprecatedName)) {
return resolve(deprecatedName);
} else {
return null;
}
}
}
20 changes: 20 additions & 0 deletions lib/src/utils/config-reader/no_op_config_reader.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'config_reader.dart';

class NoOpConfigReader implements ConfigReader {
NoOpConfigReader();

@override
bool? getBool(String key, {String? deprecatedKey}) {
return null;
}

@override
String? getString(String key, {String? deprecatedKey}) {
return null;
}

@override
bool contains(String key) {
return false;
}
}
24 changes: 24 additions & 0 deletions lib/src/utils/config-reader/properties_config_reader.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:properties/properties.dart';

import 'config_reader.dart';

class PropertiesConfigReader implements ConfigReader {
final Properties _properties;

PropertiesConfigReader(Properties properties) : _properties = properties;

@override
bool? getBool(String key, {String? deprecatedKey}) {
return get(key, deprecatedKey, (key) => _properties.getBool((key)));
}

@override
String? getString(String key, {String? deprecatedKey}) {
return get(key, deprecatedKey, (key) => _properties.get((key)));
}

@override
bool contains(String key) {
return _properties.contains(key);
}
}
24 changes: 24 additions & 0 deletions lib/src/utils/config-reader/yaml_config_reader.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:yaml/yaml.dart';

import 'config_reader.dart';

class YamlConfigReader implements ConfigReader {
final YamlMap? _yamlMap;

YamlConfigReader(YamlMap? yamlMap) : _yamlMap = yamlMap;

@override
bool? getBool(String key, {String? deprecatedKey}) {
return get(key, deprecatedKey, (key) => _yamlMap?[key] as bool?);
}

@override
String? getString(String key, {String? deprecatedKey}) {
return get(key, deprecatedKey, (key) => (_yamlMap?[key]).toString());
}

@override
bool contains(String key) {
return _yamlMap?.containsKey(key) ?? false;
}
}
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies:
crypto: ^3.0.2
convert: ^3.0.2
process: ^4.2.4
properties: ^2.1.0

dev_dependencies:
lints: ^3.0.0
Expand Down
Loading

0 comments on commit 1795b48

Please sign in to comment.