diff --git a/packages/shorebird_cli/lib/src/command.dart b/packages/shorebird_cli/lib/src/command.dart index 5c05f9c9..bb4eaa7f 100644 --- a/packages/shorebird_cli/lib/src/command.dart +++ b/packages/shorebird_cli/lib/src/command.dart @@ -5,10 +5,12 @@ import 'package:args/command_runner.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:meta/meta.dart'; import 'package:shorebird_cli/src/auth/auth.dart'; +import 'package:shorebird_cli/src/command_runner.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; typedef CodePushClientBuilder = CodePushClient Function({ required String apiKey, + Uri? hostedUri, }); typedef StartProcess = Future Function( @@ -17,12 +19,6 @@ typedef StartProcess = Future Function( bool runInShell, }); -typedef RunProcess = Future Function( - String executable, - List arguments, { - bool runInShell, -}); - abstract class ShorebirdCommand extends Command { ShorebirdCommand({ required this.logger, diff --git a/packages/shorebird_cli/lib/src/commands/apps/create_apps_command.dart b/packages/shorebird_cli/lib/src/commands/apps/create_apps_command.dart index a77f320d..aca2a236 100644 --- a/packages/shorebird_cli/lib/src/commands/apps/create_apps_command.dart +++ b/packages/shorebird_cli/lib/src/commands/apps/create_apps_command.dart @@ -55,7 +55,10 @@ Defaults to the app_id in "shorebird.yaml".''', appId = appIdArg; } - final client = buildCodePushClient(apiKey: session.apiKey); + final client = buildCodePushClient( + apiKey: session.apiKey, + hostedUri: hostedUri, + ); try { await client.createApp(appId: appId); 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 460dbdf2..e3c81bfc 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 @@ -55,7 +55,10 @@ Defaults to the app_id in "shorebird.yaml".''', appId = appIdArg; } - final client = buildCodePushClient(apiKey: session.apiKey); + final client = buildCodePushClient( + apiKey: session.apiKey, + hostedUri: hostedUri, + ); final confirm = logger.confirm('Deleting an app is permanent. Continue?'); if (!confirm) { diff --git a/packages/shorebird_cli/lib/src/commands/apps/list_apps_command.dart b/packages/shorebird_cli/lib/src/commands/apps/list_apps_command.dart index 4a360080..9dba9f47 100644 --- a/packages/shorebird_cli/lib/src/commands/apps/list_apps_command.dart +++ b/packages/shorebird_cli/lib/src/commands/apps/list_apps_command.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:mason_logger/mason_logger.dart'; import 'package:shorebird_cli/src/command.dart'; +import 'package:shorebird_cli/src/shorebird_config_mixin.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; /// {@template list_apps_command} @@ -9,7 +10,7 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; /// `shorebird apps list` /// List all apps using Shorebird. /// {@endtemplate} -class ListAppsCommand extends ShorebirdCommand { +class ListAppsCommand extends ShorebirdCommand with ShorebirdConfigMixin { /// {@macro list_apps_command} ListAppsCommand({ required super.logger, @@ -34,7 +35,10 @@ class ListAppsCommand extends ShorebirdCommand { return ExitCode.noUser.code; } - final client = buildCodePushClient(apiKey: session.apiKey); + final client = buildCodePushClient( + apiKey: session.apiKey, + hostedUri: hostedUri, + ); late final List apps; try { diff --git a/packages/shorebird_cli/lib/src/commands/build_command.dart b/packages/shorebird_cli/lib/src/commands/build_command.dart index f362bb5b..149d6662 100644 --- a/packages/shorebird_cli/lib/src/commands/build_command.dart +++ b/packages/shorebird_cli/lib/src/commands/build_command.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:mason_logger/mason_logger.dart'; import 'package:shorebird_cli/src/command.dart'; +import 'package:shorebird_cli/src/shorebird_config_mixin.dart'; import 'package:shorebird_cli/src/shorebird_engine_mixin.dart'; typedef RunProcess = Future Function( @@ -15,7 +16,8 @@ typedef RunProcess = Future Function( /// `shorebird build` /// Build a new release of your application. /// {@endtemplate} -class BuildCommand extends ShorebirdCommand with ShorebirdEngineMixin { +class BuildCommand extends ShorebirdCommand + with ShorebirdConfigMixin, ShorebirdEngineMixin { /// {@macro build_command} BuildCommand({ required super.logger, diff --git a/packages/shorebird_cli/lib/src/commands/publish_command.dart b/packages/shorebird_cli/lib/src/commands/publish_command.dart index 411b7800..1fe0a757 100644 --- a/packages/shorebird_cli/lib/src/commands/publish_command.dart +++ b/packages/shorebird_cli/lib/src/commands/publish_command.dart @@ -68,7 +68,10 @@ class PublishCommand extends ShorebirdCommand with ShorebirdConfigMixin { try { final pubspecYaml = getPubspecYaml()!; final shorebirdYaml = getShorebirdYaml()!; - final codePushClient = buildCodePushClient(apiKey: session.apiKey); + final codePushClient = buildCodePushClient( + apiKey: session.apiKey, + hostedUri: hostedUri, + ); logger.detail( '''Deploying ${artifact.path} to ${shorebirdYaml.appId} (${pubspecYaml.version})''', ); diff --git a/packages/shorebird_cli/lib/src/commands/run_command.dart b/packages/shorebird_cli/lib/src/commands/run_command.dart index bfa0bcdc..6d1354b1 100644 --- a/packages/shorebird_cli/lib/src/commands/run_command.dart +++ b/packages/shorebird_cli/lib/src/commands/run_command.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:mason_logger/mason_logger.dart'; import 'package:shorebird_cli/src/command.dart'; +import 'package:shorebird_cli/src/shorebird_config_mixin.dart'; import 'package:shorebird_cli/src/shorebird_engine_mixin.dart'; typedef StartProcess = Future Function( @@ -16,7 +17,8 @@ typedef StartProcess = Future Function( /// `shorebird run` /// Run the Flutter application. /// {@endtemplate} -class RunCommand extends ShorebirdCommand with ShorebirdEngineMixin { +class RunCommand extends ShorebirdCommand + with ShorebirdConfigMixin, ShorebirdEngineMixin { /// {@macro run_command} RunCommand({ required super.logger, diff --git a/packages/shorebird_cli/lib/src/config/shorebird_yaml.dart b/packages/shorebird_cli/lib/src/config/shorebird_yaml.dart index 768b86c1..37bea69d 100644 --- a/packages/shorebird_cli/lib/src/config/shorebird_yaml.dart +++ b/packages/shorebird_cli/lib/src/config/shorebird_yaml.dart @@ -8,10 +8,11 @@ part 'shorebird_yaml.g.dart'; createToJson: false, ) class ShorebirdYaml { - const ShorebirdYaml({required this.appId}); + const ShorebirdYaml({required this.appId, this.baseUrl}); factory ShorebirdYaml.fromJson(Map json) => _$ShorebirdYamlFromJson(json); final String appId; + final String? baseUrl; } 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 5e1eabfc..7a8cb598 100644 --- a/packages/shorebird_cli/lib/src/config/shorebird_yaml.g.dart +++ b/packages/shorebird_cli/lib/src/config/shorebird_yaml.g.dart @@ -14,12 +14,13 @@ ShorebirdYaml _$ShorebirdYamlFromJson(Map json) => $checkedCreate( ($checkedConvert) { $checkKeys( json, - allowedKeys: const ['app_id'], + allowedKeys: const ['app_id', 'base_url'], ); final val = ShorebirdYaml( appId: $checkedConvert('app_id', (v) => v as String), + baseUrl: $checkedConvert('base_url', (v) => v as String?), ); return val; }, - fieldKeyMap: const {'appId': 'app_id'}, + fieldKeyMap: const {'appId': 'app_id', 'baseUrl': 'base_url'}, ); diff --git a/packages/shorebird_cli/lib/src/shorebird_config_mixin.dart b/packages/shorebird_cli/lib/src/shorebird_config_mixin.dart index 18278c89..c2aaf570 100644 --- a/packages/shorebird_cli/lib/src/shorebird_config_mixin.dart +++ b/packages/shorebird_cli/lib/src/shorebird_config_mixin.dart @@ -16,6 +16,15 @@ mixin ShorebirdConfigMixin on ShorebirdCommand { return hasShorebirdYaml && pubspecContainsShorebirdYaml; } + Uri? get hostedUri { + try { + final baseUrl = getShorebirdYaml()?.baseUrl; + return baseUrl == null ? null : Uri.tryParse(baseUrl); + } catch (_) { + return null; + } + } + bool get pubspecContainsShorebirdYaml { final file = File(p.join(Directory.current.path, 'pubspec.yaml')); final pubspecContents = file.readAsStringSync(); diff --git a/packages/shorebird_cli/lib/src/shorebird_engine_mixin.dart b/packages/shorebird_cli/lib/src/shorebird_engine_mixin.dart index 6d925bc3..6c90d6bf 100644 --- a/packages/shorebird_cli/lib/src/shorebird_engine_mixin.dart +++ b/packages/shorebird_cli/lib/src/shorebird_engine_mixin.dart @@ -5,9 +5,10 @@ import 'dart:isolate'; import 'package:archive/archive_io.dart'; import 'package:path/path.dart' as p; import 'package:shorebird_cli/src/command.dart'; +import 'package:shorebird_cli/src/shorebird_config_mixin.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; -mixin ShorebirdEngineMixin on ShorebirdCommand { +mixin ShorebirdEngineMixin on ShorebirdConfigMixin { String get shorebirdEnginePath { return p.join( Directory.current.path, @@ -31,6 +32,7 @@ mixin ShorebirdEngineMixin on ShorebirdCommand { try { final codePushClient = buildCodePushClient( apiKey: auth.currentSession!.apiKey, + hostedUri: hostedUri, ); await _downloadShorebirdEngine( codePushClient, diff --git a/packages/shorebird_cli/test/src/commands/apps/create_apps_command_test.dart b/packages/shorebird_cli/test/src/commands/apps/create_apps_command_test.dart index a5da7873..315ae709 100644 --- a/packages/shorebird_cli/test/src/commands/apps/create_apps_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/apps/create_apps_command_test.dart @@ -34,7 +34,9 @@ void main() { codePushClient = _MockCodePushClient(); command = CreateAppCommand( auth: auth, - buildCodePushClient: ({required String apiKey}) => codePushClient, + buildCodePushClient: ({required String apiKey, Uri? hostedUri}) { + return codePushClient; + }, logger: logger, )..testArgResults = argResults; diff --git a/packages/shorebird_cli/test/src/commands/apps/delete_apps_command_test.dart b/packages/shorebird_cli/test/src/commands/apps/delete_apps_command_test.dart index 325961ed..24165887 100644 --- a/packages/shorebird_cli/test/src/commands/apps/delete_apps_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/apps/delete_apps_command_test.dart @@ -34,7 +34,9 @@ void main() { codePushClient = _MockCodePushClient(); command = DeleteAppCommand( auth: auth, - buildCodePushClient: ({required String apiKey}) => codePushClient, + buildCodePushClient: ({required String apiKey, Uri? hostedUri}) { + return codePushClient; + }, logger: logger, )..testArgResults = argResults; diff --git a/packages/shorebird_cli/test/src/commands/apps/list_apps_command_test.dart b/packages/shorebird_cli/test/src/commands/apps/list_apps_command_test.dart index 88b944cc..dc5a970f 100644 --- a/packages/shorebird_cli/test/src/commands/apps/list_apps_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/apps/list_apps_command_test.dart @@ -28,7 +28,9 @@ void main() { logger = _MockLogger(); command = ListAppsCommand( auth: auth, - buildCodePushClient: ({required String apiKey}) => codePushClient, + buildCodePushClient: ({required String apiKey, Uri? hostedUri}) { + return codePushClient; + }, logger: logger, ); diff --git a/packages/shorebird_cli/test/src/commands/build_command_test.dart b/packages/shorebird_cli/test/src/commands/build_command_test.dart index 98ac8249..ac0b21c8 100644 --- a/packages/shorebird_cli/test/src/commands/build_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/build_command_test.dart @@ -41,7 +41,9 @@ void main() { processResult = _MockProcessResult(); buildCommand = BuildCommand( auth: auth, - buildCodePushClient: ({required String apiKey}) => codePushClient, + buildCodePushClient: ({required String apiKey, Uri? hostedUri}) { + return codePushClient; + }, logger: logger, runProcess: (executable, arguments, {bool runInShell = false}) async { return processResult; diff --git a/packages/shorebird_cli/test/src/commands/publish_command_test.dart b/packages/shorebird_cli/test/src/commands/publish_command_test.dart index a7eb94fe..adae89f6 100644 --- a/packages/shorebird_cli/test/src/commands/publish_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/publish_command_test.dart @@ -46,6 +46,7 @@ flutter: late Logger logger; late CodePushClient codePushClient; late PublishCommand command; + late Uri? capturedHostedUri; Directory setUpTempDir() { final tempDir = Directory.systemTemp.createTempSync(); @@ -65,7 +66,10 @@ flutter: codePushClient = _MockCodePushClient(); command = PublishCommand( auth: auth, - buildCodePushClient: ({required String apiKey}) => codePushClient, + buildCodePushClient: ({required String apiKey, Uri? hostedUri}) { + capturedHostedUri = hostedUri; + return codePushClient; + }, logger: logger, ) ..testArgResults = argResults @@ -191,6 +195,26 @@ flutter: ), ).called(1); expect(exitCode, ExitCode.success.code); + expect(capturedHostedUri, isNull); + }); + + test('succeeds when publish is successful using custom base_url', () async { + final tempDir = setUpTempDir(); + const baseUrl = 'https://example.com'; + File( + p.join(tempDir.path, 'shorebird.yaml'), + ).writeAsStringSync( + ''' +app_id: $appId +base_url: $baseUrl''', + ); + final artifact = File(p.join(tempDir.path, 'patch.txt'))..createSync(); + when(() => argResults.rest).thenReturn([artifact.path]); + await IOOverrides.runZoned( + command.run, + getCurrentDirectory: () => tempDir, + ); + expect(capturedHostedUri, equals(Uri.parse(baseUrl))); }); }); } diff --git a/packages/shorebird_cli/test/src/commands/run_command_test.dart b/packages/shorebird_cli/test/src/commands/run_command_test.dart index 8efd20a3..fcfbca8a 100644 --- a/packages/shorebird_cli/test/src/commands/run_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/run_command_test.dart @@ -46,7 +46,7 @@ void main() { runCommand = RunCommand( auth: auth, logger: logger, - buildCodePushClient: ({required String apiKey}) { + buildCodePushClient: ({required String apiKey, Uri? hostedUri}) { return codePushClient; }, startProcess: (executable, arguments, {bool runInShell = false}) async {