Skip to content

Commit

Permalink
Support configuration arguments via --sentry-define (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
denrase authored Apr 15, 2024
1 parent a9260fc commit b5dce98
Show file tree
Hide file tree
Showing 6 changed files with 575 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Update env/config `release` and `dist` behaviour ([#217](https://github.com/getsentry/sentry-dart-plugin/pull/217))
- This is a breaking change, please check if the `release` and `dist` values are as you expect them.
- Add option to provide alternative binary directory ([#214](https://github.com/getsentry/sentry-dart-plugin/pull/214))
- Support configuration arguments via `--sentry-define` ([#198](https://github.com/getsentry/sentry-dart-plugin/pull/198))

### Dependencies

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ sentry:
ignore_missing: true
```

You can also override or extend your file based configuration by passing the parameters as arguments
in the format `--sentry-define=<KEY>=<VALUE>`. They take precedence over your file based parameters,
but not over the alternative environment variables.

```bash
flutter packages pub run sentry_dart_plugin --sentry-define=release=app-internal-test@0.0.1
```

### sentry.properties

Create a `sentry.properties` file at the root of your project:
Expand Down
80 changes: 39 additions & 41 deletions lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:system_info2/system_info2.dart';

import 'cli/host_platform.dart';
import 'cli/setup.dart';
import 'configuration_values.dart';
import 'utils/config-reader/config_reader.dart';
import 'utils/extensions.dart';
import 'utils/injector.dart';
Expand Down Expand Up @@ -48,13 +49,13 @@ class Configuration {
// the Sentry CLI path, defaults to the assets folder
late String? cliPath;

/// The Apps release name, defaults to 'name@version+buildNumber' from pubspec or set via env. var. SENTRY_RELEASE
/// The Apps release name, defaults to 'name@version+buildNumber' from SENTRY_RELEASE env. variable, arguments or pubspec.
/// Example, name: 'my_app', version: 2.0.0+1, in this case the release is my_app@2.0.0+1
/// This field has precedence over the [name] from pubspec
/// If this field has a build number, it has precedence over the [version]'s build number from pubspec
late String? release;

/// The Apps dist/build number, taken from pubspec dist or SENTRY_DIST env. variable
/// The Apps dist/build number, taken from SENTRY_DIST env. variable, arguments or pubspec.
/// If provided, it will override the build number from [version]
late String? dist;

Expand Down Expand Up @@ -85,63 +86,60 @@ class Configuration {
late String binDir;

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

final reader = ConfigReader();
loadConfig(reader);
loadConfig(
argsConfig: ConfigurationValues.fromArguments(cliArguments),
fileConfig: ConfigurationValues.fromReader(ConfigReader()),
platformEnvConfig: ConfigurationValues.fromPlatformEnvironment(
Platform.environment,
),
);

await _findAndSetCliPath();

Log.taskCompleted(taskName);
}

void loadConfig(ConfigReader reader) {
final environments = Platform.environment;
void loadConfig({
required ConfigurationValues platformEnvConfig,
required ConfigurationValues argsConfig,
required ConfigurationValues fileConfig,
}) {
final pubspec = ConfigReader.getPubspec();

String? envRelease = environments['SENTRY_RELEASE'];
if (envRelease?.isEmpty ?? false) {
envRelease = null;
}

String? envDist = environments['SENTRY_DIST'];
if (envDist?.isEmpty ?? false) {
envDist = null;
}

release = envRelease ?? reader.getString('release');
dist = envDist ?? reader.getString('dist');
version = pubspec['version'].toString();
name = pubspec['name'].toString();

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;
final configValues = ConfigurationValues.merged(
args: argsConfig,
file: fileConfig,
platformEnv: platformEnvConfig,
);

release = configValues.release;
dist = configValues.dist;
version = configValues.version ?? pubspec['version'].toString();
name = configValues.name ?? pubspec['name'].toString();
uploadDebugSymbols = configValues.uploadDebugSymbols ?? true;
uploadSourceMaps = configValues.uploadSourceMaps ?? false;
uploadSources = configValues.uploadSources ?? false;
commits = configValues.commits ?? 'auto';
ignoreMissing = configValues.ignoreMissing ?? 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 =
reader.getString('web_build_path') ?? _fs.path.join('build', 'web');
configValues.webBuildPath ?? _fs.path.join('build', 'web');
webBuildFilesFolder = _fs.path.join(buildFilesFolder, webBuildPath);

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 =
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
binDir =
reader.getString('bin_dir') ?? '.dart_tool/pub/bin/sentry_dart_plugin';
project = configValues.project; // or env. var. SENTRY_PROJECT
org = configValues.org; // or env. var. SENTRY_ORG
waitForProcessing = configValues.waitForProcessing ?? false;
authToken = configValues.authToken; // or env. var. SENTRY_AUTH_TOKEN
url = configValues.url; // or env. var. SENTRY_URL
logLevel = configValues.logLevel; // or env. var. SENTRY_LOG_LEVEL
binDir = configValues.binDir ?? '.dart_tool/pub/bin/sentry_dart_plugin';
}

/// Validates the configuration values and log an error if required fields
Expand Down
161 changes: 161 additions & 0 deletions lib/src/configuration_values.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// https://stackoverflow.com/a/73564526
import 'package:sentry_dart_plugin/src/utils/config-reader/config_reader.dart';

class ConfigurationValues {
final String? version;
final String? name;

final bool? uploadDebugSymbols;
final bool? uploadSourceMaps;
final bool? uploadSources;
final String? project;
final String? org;
final String? authToken;
final String? url;
final bool? waitForProcessing;
final String? logLevel;
final String? release;
final String? dist;
final String? webBuildPath;
final String? commits;
final bool? ignoreMissing;
final String? binDir;

ConfigurationValues({
this.version,
this.name,
this.uploadDebugSymbols,
this.uploadSourceMaps,
this.uploadSources,
this.project,
this.org,
this.authToken,
this.url,
this.waitForProcessing,
this.logLevel,
this.release,
this.dist,
this.webBuildPath,
this.commits,
this.ignoreMissing,
this.binDir,
});

factory ConfigurationValues.fromArguments(List<String> arguments) {
Map<String, String> sentryArguments = {};
for (final arg in arguments) {
final components = arg.split("=");
if (components.length < 3) {
continue;
}
if (components[0] != "--sentry-define") {
continue;
}
sentryArguments[components[1]] = components.sublist(2).join('=');
}
boolFromString(String? value) {
return value == "true"
? true
: value == "false"
? false
: null;
}

return ConfigurationValues(
version: sentryArguments['version'],
name: sentryArguments['name'],
uploadDebugSymbols: boolFromString(
sentryArguments['upload_debug_symbols'] ??
sentryArguments['upload_native_symbols'],
),
uploadSourceMaps: boolFromString(sentryArguments['upload_source_maps']),
uploadSources: boolFromString(
sentryArguments['upload_sources'] ??
sentryArguments['include_native_sources'],
),
project: sentryArguments['project'],
org: sentryArguments['org'],
authToken: sentryArguments['auth_token'],
url: sentryArguments['url'],
waitForProcessing:
boolFromString(sentryArguments['wait_for_processing']),
logLevel: sentryArguments['log_level'],
release: sentryArguments['release'],
dist: sentryArguments['dist'],
webBuildPath: sentryArguments['web_build_path'],
commits: sentryArguments['commits'],
ignoreMissing: boolFromString(sentryArguments['ignore_missing']),
binDir: sentryArguments['bin_dir']);
}

factory ConfigurationValues.fromReader(ConfigReader configReader) {
return ConfigurationValues(
version: configReader.getString('version'),
name: configReader.getString('name'),
uploadDebugSymbols: configReader.getBool(
'upload_debug_symbols',
deprecatedKey: 'upload_native_symbols',
),
uploadSourceMaps: configReader.getBool('upload_source_maps'),
uploadSources: configReader.getBool(
'upload_sources',
deprecatedKey: 'include_native_sources',
),
project: configReader.getString('project'),
org: configReader.getString('org'),
authToken: configReader.getString('auth_token'),
url: configReader.getString('url'),
waitForProcessing: configReader.getBool('wait_for_processing'),
logLevel: configReader.getString('log_level'),
release: configReader.getString('release'),
dist: configReader.getString('dist'),
webBuildPath: configReader.getString('web_build_path'),
commits: configReader.getString('commits'),
ignoreMissing: configReader.getBool('ignore_missing'),
binDir: configReader.getString('bin_dir'),
);
}

factory ConfigurationValues.fromPlatformEnvironment(
Map<String, String> environment,
) {
String? envRelease = environment['SENTRY_RELEASE'];
if (envRelease?.isEmpty ?? false) {
envRelease = null;
}
String? envDist = environment['SENTRY_DIST'];
if (envDist?.isEmpty ?? false) {
envDist = null;
}
return ConfigurationValues(
release: envRelease,
dist: envDist,
);
}

factory ConfigurationValues.merged({
required ConfigurationValues platformEnv,
required ConfigurationValues args,
required ConfigurationValues file,
}) {
return ConfigurationValues(
version: args.version ?? file.version,
name: args.name ?? file.name,
uploadDebugSymbols: args.uploadDebugSymbols ?? file.uploadDebugSymbols,
uploadSourceMaps: args.uploadSourceMaps ?? file.uploadSourceMaps,
uploadSources: args.uploadSources ?? file.uploadSources,
project: args.project ?? file.project,
org: args.org ?? file.org,
authToken: args.authToken ?? file.authToken,
url: args.url ?? file.url,
waitForProcessing: args.waitForProcessing ?? file.waitForProcessing,
logLevel: args.logLevel ?? file.logLevel,
release: platformEnv.release ?? args.release ?? file.release,
dist: platformEnv.dist ?? args.dist ?? file.dist,
webBuildPath: args.webBuildPath ?? file.webBuildPath,
commits: args.commits ?? file.commits,
ignoreMissing: args.ignoreMissing ?? file.ignoreMissing,
binDir: args.binDir ?? file.binDir,
);
}
}
Loading

0 comments on commit b5dce98

Please sign in to comment.