From c668fb64f7ed38027c280fd565cc9c79477bdb30 Mon Sep 17 00:00:00 2001 From: Felix Angelov Date: Tue, 2 May 2023 14:54:31 -0500 Subject: [PATCH] feat(shorebird_cli): `app_id` in `shorebird.yaml` can be `String` or `Map` (#426) --- packages/shorebird_cli/build.yaml | 1 + .../commands/apps/delete_apps_command.dart | 2 +- .../channels/create_channels_command.dart | 3 +- .../channels/list_channels_command.dart | 3 +- .../lib/src/commands/init_command.dart | 4 +- .../lib/src/commands/patch_command.dart | 5 ++- .../lib/src/commands/release_command.dart | 5 ++- .../lib/src/config/shorebird_yaml.dart | 42 ++++++++++++++++++- .../lib/src/config/shorebird_yaml.g.dart | 4 +- .../lib/src/shorebird_config_mixin.dart | 2 +- .../test/src/config/shorebird_yaml_test.dart | 40 ++++++++++++++++++ 11 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 packages/shorebird_cli/test/src/config/shorebird_yaml_test.dart diff --git a/packages/shorebird_cli/build.yaml b/packages/shorebird_cli/build.yaml index 52cb55e6..799728c4 100644 --- a/packages/shorebird_cli/build.yaml +++ b/packages/shorebird_cli/build.yaml @@ -9,6 +9,7 @@ targets: - cast_nullable_to_non_nullable - lines_longer_than_80_chars - strict_raw_type + - unnecessary_lambdas json_serializable: options: field_rename: snake diff --git a/packages/shorebird_cli/lib/src/commands/apps/delete_apps_command.dart b/packages/shorebird_cli/lib/src/commands/apps/delete_apps_command.dart index 1a088d1f..4f627760 100644 --- a/packages/shorebird_cli/lib/src/commands/apps/delete_apps_command.dart +++ b/packages/shorebird_cli/lib/src/commands/apps/delete_apps_command.dart @@ -45,7 +45,7 @@ Defaults to the app_id in "shorebird.yaml".''', if (appIdArg == null) { String? defaultAppId; try { - defaultAppId = getShorebirdYaml()?.appId; + defaultAppId = getShorebirdYaml()?.appId.value; } catch (_) {} appId = logger.prompt( diff --git a/packages/shorebird_cli/lib/src/commands/channels/create_channels_command.dart b/packages/shorebird_cli/lib/src/commands/channels/create_channels_command.dart index cbd5aa8a..3c82b3eb 100644 --- a/packages/shorebird_cli/lib/src/commands/channels/create_channels_command.dart +++ b/packages/shorebird_cli/lib/src/commands/channels/create_channels_command.dart @@ -49,7 +49,8 @@ class CreateChannelsCommand extends ShorebirdCommand hostedUri: hostedUri, ); - final appId = results[_appIdOption] as String? ?? getShorebirdYaml()?.appId; + final appId = + results[_appIdOption] as String? ?? getShorebirdYaml()?.appId.value; if (appId == null) { logger.err( ''' diff --git a/packages/shorebird_cli/lib/src/commands/channels/list_channels_command.dart b/packages/shorebird_cli/lib/src/commands/channels/list_channels_command.dart index b2c3e4b3..e48d6b20 100644 --- a/packages/shorebird_cli/lib/src/commands/channels/list_channels_command.dart +++ b/packages/shorebird_cli/lib/src/commands/channels/list_channels_command.dart @@ -48,7 +48,8 @@ class ListChannelsCommand extends ShorebirdCommand hostedUri: hostedUri, ); - final appId = results[_appIdOption] as String? ?? getShorebirdYaml()?.appId; + final appId = + results[_appIdOption] as String? ?? getShorebirdYaml()?.appId.value; if (appId == null) { logger.err( ''' diff --git a/packages/shorebird_cli/lib/src/commands/init_command.dart b/packages/shorebird_cli/lib/src/commands/init_command.dart index 4e8ba461..c06c56bc 100644 --- a/packages/shorebird_cli/lib/src/commands/init_command.dart +++ b/packages/shorebird_cli/lib/src/commands/init_command.dart @@ -72,7 +72,9 @@ Please make sure you are running "shorebird init" from the root of your Flutter return ExitCode.software.code; } - final app = apps.firstWhereOrNull((a) => a.id == shorebirdYaml!.appId); + final app = apps.firstWhereOrNull( + (a) => a.id == shorebirdYaml!.appId.value, + ); appId = app?.id; } diff --git a/packages/shorebird_cli/lib/src/commands/patch_command.dart b/packages/shorebird_cli/lib/src/commands/patch_command.dart index 21f5b4ec..956eb06a 100644 --- a/packages/shorebird_cli/lib/src/commands/patch_command.dart +++ b/packages/shorebird_cli/lib/src/commands/patch_command.dart @@ -155,11 +155,12 @@ class PatchCommand extends ShorebirdCommand return ExitCode.software.code; } - final app = apps.firstWhereOrNull((a) => a.id == shorebirdYaml.appId); + final appId = shorebirdYaml.appId.value; + final app = apps.firstWhereOrNull((a) => a.id == appId); if (app == null) { logger.err( ''' -Could not find app with id: "${shorebirdYaml.appId}". +Could not find app with id: "$appId". Did you forget to run "shorebird init"?''', ); return ExitCode.software.code; diff --git a/packages/shorebird_cli/lib/src/commands/release_command.dart b/packages/shorebird_cli/lib/src/commands/release_command.dart index 0eeb9896..76842941 100644 --- a/packages/shorebird_cli/lib/src/commands/release_command.dart +++ b/packages/shorebird_cli/lib/src/commands/release_command.dart @@ -104,11 +104,12 @@ make smaller updates to your app. return ExitCode.software.code; } - final app = apps.firstWhereOrNull((a) => a.id == shorebirdYaml.appId); + final appId = shorebirdYaml.appId.value; + final app = apps.firstWhereOrNull((a) => a.id == appId); if (app == null) { logger.err( ''' -Could not find app with id: "${shorebirdYaml.appId}". +Could not find app with id: "$appId". Did you forget to run "shorebird init"?''', ); return ExitCode.software.code; diff --git a/packages/shorebird_cli/lib/src/config/shorebird_yaml.dart b/packages/shorebird_cli/lib/src/config/shorebird_yaml.dart index 37bea69d..b8e7b16b 100644 --- a/packages/shorebird_cli/lib/src/config/shorebird_yaml.dart +++ b/packages/shorebird_cli/lib/src/config/shorebird_yaml.dart @@ -2,17 +2,57 @@ import 'package:json_annotation/json_annotation.dart'; part 'shorebird_yaml.g.dart'; +/// {@template shorebird_yaml} +/// A Shorebird configuration file which contains metadata about the app. +/// {@endtemplate} @JsonSerializable( anyMap: true, disallowUnrecognizedKeys: true, createToJson: false, ) class ShorebirdYaml { + /// {@macro shorebird_yaml} const ShorebirdYaml({required this.appId, this.baseUrl}); factory ShorebirdYaml.fromJson(Map json) => _$ShorebirdYamlFromJson(json); - final String appId; + @JsonKey(fromJson: AppId.fromJson) + final AppId appId; final String? baseUrl; } + +/// {@template app_id} +/// The unique identifier for the app. Can be a single string or a map of +/// flavor names to ids for multi-flavor apps. +/// {@endtemplate} +class AppId { + /// {@macro app_id} + const AppId({this.value, this.values}); + + factory AppId.fromJson(dynamic json) { + if (json is String) return AppId(value: json); + return AppId(values: (json as Map).cast()); + } + + /// A single app id. + /// + /// Will be `null` for multi-flavor apps (if [values] is not `null`). + /// + /// Example: + /// `"8d3155a8-a048-4820-acca-824d26c29b71"` + final String? value; + + /// A map of flavor names to app ids. + /// + /// Will be `null` for apps with no flavors (if [value] is not `null`). + /// + /// Example: + /// ```json + /// { + /// "development": "8d3155a8-a048-4820-acca-824d26c29b71", + /// "production": "d458e87a-7362-4386-9eeb-629db2af413a" + /// } + /// ``` + final Map? values; +} diff --git a/packages/shorebird_cli/lib/src/config/shorebird_yaml.g.dart b/packages/shorebird_cli/lib/src/config/shorebird_yaml.g.dart index 7a8cb598..90c5273e 100644 --- a/packages/shorebird_cli/lib/src/config/shorebird_yaml.g.dart +++ b/packages/shorebird_cli/lib/src/config/shorebird_yaml.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: implicit_dynamic_parameter, require_trailing_commas, cast_nullable_to_non_nullable, lines_longer_than_80_chars, strict_raw_type +// ignore_for_file: implicit_dynamic_parameter, require_trailing_commas, cast_nullable_to_non_nullable, lines_longer_than_80_chars, strict_raw_type, unnecessary_lambdas part of 'shorebird_yaml.dart'; @@ -17,7 +17,7 @@ ShorebirdYaml _$ShorebirdYamlFromJson(Map json) => $checkedCreate( allowedKeys: const ['app_id', 'base_url'], ); final val = ShorebirdYaml( - appId: $checkedConvert('app_id', (v) => v as String), + appId: $checkedConvert('app_id', (v) => AppId.fromJson(v)), baseUrl: $checkedConvert('base_url', (v) => v as String?), ); return val; diff --git a/packages/shorebird_cli/lib/src/shorebird_config_mixin.dart b/packages/shorebird_cli/lib/src/shorebird_config_mixin.dart index cf670746..c414b866 100644 --- a/packages/shorebird_cli/lib/src/shorebird_config_mixin.dart +++ b/packages/shorebird_cli/lib/src/shorebird_config_mixin.dart @@ -63,7 +63,7 @@ mixin ShorebirdConfigMixin on ShorebirdCommand { app_id: $appId '''); - return ShorebirdYaml(appId: appId); + return ShorebirdYaml(appId: AppId(value: appId)); } void addShorebirdYamlToPubspecAssets() { diff --git a/packages/shorebird_cli/test/src/config/shorebird_yaml_test.dart b/packages/shorebird_cli/test/src/config/shorebird_yaml_test.dart new file mode 100644 index 00000000..bafb4b7c --- /dev/null +++ b/packages/shorebird_cli/test/src/config/shorebird_yaml_test.dart @@ -0,0 +1,40 @@ +import 'package:checked_yaml/checked_yaml.dart'; +import 'package:shorebird_cli/src/config/config.dart'; +import 'package:test/test.dart'; + +void main() { + group('ShorebirdYaml', () { + test('can be deserialized with single app_id', () { + const yaml = ''' +app_id: test_app_id +base_url: https://example.com +'''; + final shorebirdYaml = checkedYamlDecode( + yaml, + (m) => ShorebirdYaml.fromJson(m!), + ); + expect(shorebirdYaml.appId.value, 'test_app_id'); + expect(shorebirdYaml.appId.values, isNull); + expect(shorebirdYaml.baseUrl, 'https://example.com'); + }); + + test('can be deserialized with multiple app_id', () { + const yaml = ''' +app_id: + development: test_app_id1 + production: test_app_id2 +base_url: https://example.com +'''; + final shorebirdYaml = checkedYamlDecode( + yaml, + (m) => ShorebirdYaml.fromJson(m!), + ); + expect(shorebirdYaml.appId.value, isNull); + expect(shorebirdYaml.appId.values, { + 'development': 'test_app_id1', + 'production': 'test_app_id2', + }); + expect(shorebirdYaml.baseUrl, 'https://example.com'); + }); + }); +}