diff --git a/packages/shorebird_cli/lib/src/code_push_client_wrapper.dart b/packages/shorebird_cli/lib/src/code_push_client_wrapper.dart index 95d0a653..e1f8e28a 100644 --- a/packages/shorebird_cli/lib/src/code_push_client_wrapper.dart +++ b/packages/shorebird_cli/lib/src/code_push_client_wrapper.dart @@ -363,6 +363,7 @@ Please create a release using "shorebird release" and try again. required String appId, required int releaseId, required ReleasePlatform platform, + required String projectRoot, required String aabPath, required Map architectures, String? flavor, @@ -370,7 +371,7 @@ Please create a release using "shorebird release" and try again. final createArtifactProgress = logger.progress('Creating artifacts'); for (final archMetadata in architectures.values) { final artifactPath = p.join( - Directory.current.path, + projectRoot, 'build', 'app', 'intermediates', diff --git a/packages/shorebird_cli/lib/src/commands/init_command.dart b/packages/shorebird_cli/lib/src/commands/init_command.dart index ba725dd8..b7cc24fa 100644 --- a/packages/shorebird_cli/lib/src/commands/init_command.dart +++ b/packages/shorebird_cli/lib/src/commands/init_command.dart @@ -52,7 +52,7 @@ class InitCommand extends ShorebirdCommand { if (!shorebirdEnv.hasPubspecYaml) { logger.err(''' Could not find a "pubspec.yaml". -Please make sure you are running "shorebird init" from the root of your Flutter project. +Please make sure you are running "shorebird init" from within your Flutter project. '''); return ExitCode.noInput.code; } @@ -66,11 +66,12 @@ Please make sure you are running "shorebird init" from the root of your Flutter Set? androidFlavors; Set? iosFlavors; var productFlavors = {}; + final projectRoot = shorebirdEnv.getFlutterProjectRoot()!; final detectFlavorsProgress = logger.progress('Detecting product flavors'); try { final flavors = await Future.wait([ - _maybeGetAndroidFlavors(Directory.current.path), - _maybeGetiOSFlavors(Directory.current.path), + _maybeGetAndroidFlavors(projectRoot.path), + _maybeGetiOSFlavors(projectRoot.path), ]); androidFlavors = flavors[0]; iosFlavors = flavors[1]; @@ -133,7 +134,8 @@ Please make sure you are running "shorebird init" from the root of your Flutter flavorsToAppIds[flavor] = app.id; } _addShorebirdYamlToProject( - shorebirdYaml.appId, + projectRoot: projectRoot, + appId: shorebirdYaml.appId, flavors: flavorsToAppIds, ); updateShorebirdYamlProgress.complete('Flavors added to shorebird.yaml'); @@ -201,10 +203,16 @@ Please make sure you are running "shorebird init" from the root of your Flutter return ExitCode.software.code; } - _addShorebirdYamlToProject(appId, flavors: flavors); + _addShorebirdYamlToProject( + projectRoot: projectRoot, + appId: appId, + flavors: flavors, + ); if (!shorebirdEnv.pubspecContainsShorebirdYaml) { - _addShorebirdYamlToPubspecAssets(); + _addShorebirdYamlToPubspecAssets( + shorebirdEnv.getPubspecYamlFile(cwd: projectRoot), + ); } logger.info( @@ -274,8 +282,9 @@ For more information about Shorebird, visit ${link(uri: Uri.parse('https://shore } } - ShorebirdYaml _addShorebirdYamlToProject( - String appId, { + ShorebirdYaml _addShorebirdYamlToProject({ + required String appId, + required Directory projectRoot, Map? flavors, }) { const content = ''' @@ -299,13 +308,14 @@ app_id: if (flavors != null) editor.update(['flavors'], flavors); - shorebirdEnv.getShorebirdYamlFile().writeAsStringSync(editor.toString()); + shorebirdEnv + .getShorebirdYamlFile(cwd: projectRoot) + .writeAsStringSync(editor.toString()); return ShorebirdYaml(appId: appId); } - void _addShorebirdYamlToPubspecAssets() { - final pubspecFile = shorebirdEnv.getPubspecYamlFile(); + void _addShorebirdYamlToPubspecAssets(File pubspecFile) { final pubspecContents = pubspecFile.readAsStringSync(); final yaml = loadYaml(pubspecContents, sourceUrl: pubspecFile.uri) as Map; final editor = YamlEditor(pubspecContents); diff --git a/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart b/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart index 3c618403..34db966e 100644 --- a/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart +++ b/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart @@ -128,9 +128,18 @@ If this option is not provided, the version number will be determined from the p return ExitCode.software.code; } + final projectRoot = shorebirdEnv.getShorebirdProjectRoot()!; + + final bundleDirPath = p.join( + projectRoot.path, + 'build', + 'app', + 'outputs', + 'bundle', + ); final bundlePath = flavor != null - ? './build/app/outputs/bundle/${flavor}Release/app-$flavor-release.aab' - : './build/app/outputs/bundle/release/app-release.aab'; + ? p.join(bundleDirPath, '${flavor}Release', 'app-$flavor-release.aab') + : p.join(bundleDirPath, 'release', 'app-release.aab'); final String releaseVersion; final argReleaseVersion = results['release-version'] as String?; @@ -251,7 +260,7 @@ Current Flutter Revision: $originalFlutterRevision for (final releaseArtifactPath in releaseArtifactPaths.entries) { final archMetadata = architectures[releaseArtifactPath.key]!; final patchArtifactPath = p.join( - Directory.current.path, + projectRoot.path, 'build', 'app', 'intermediates', diff --git a/packages/shorebird_cli/lib/src/commands/patch/patch_ios_command.dart b/packages/shorebird_cli/lib/src/commands/patch/patch_ios_command.dart index d7f69166..32ae6e34 100644 --- a/packages/shorebird_cli/lib/src/commands/patch/patch_ios_command.dart +++ b/packages/shorebird_cli/lib/src/commands/patch/patch_ios_command.dart @@ -278,8 +278,11 @@ ${summary.join('\n')} return ExitCode.success.code; } - String get _aotOutputPath => - p.join(Directory.current.path, 'build', 'out.aot'); + String get _aotOutputPath => p.join( + shorebirdEnv.getShorebirdProjectRoot()!.path, + 'build', + 'out.aot', + ); Future _buildPatch() async { final target = results['target'] as String?; diff --git a/packages/shorebird_cli/lib/src/commands/patch/patch_ios_framework_command.dart b/packages/shorebird_cli/lib/src/commands/patch/patch_ios_framework_command.dart index 186482bf..fe3a1bfa 100644 --- a/packages/shorebird_cli/lib/src/commands/patch/patch_ios_framework_command.dart +++ b/packages/shorebird_cli/lib/src/commands/patch/patch_ios_framework_command.dart @@ -158,7 +158,11 @@ Please re-run the release command for this version or create a new release.'''); final newestDillFile = newestAppDill(); aotFile = await buildElfAotSnapshot( appDillPath: newestDillFile.path, - outFilePath: p.join(Directory.current.path, 'build', 'out.aot'), + outFilePath: p.join( + shorebirdEnv.getShorebirdProjectRoot()!.path, + 'build', + 'out.aot', + ), ); } catch (error) { buildProgress.fail('$error'); diff --git a/packages/shorebird_cli/lib/src/commands/release/release_aar_command.dart b/packages/shorebird_cli/lib/src/commands/release/release_aar_command.dart index 81b6ed53..61ac6d99 100644 --- a/packages/shorebird_cli/lib/src/commands/release/release_aar_command.dart +++ b/packages/shorebird_cli/lib/src/commands/release/release_aar_command.dart @@ -156,13 +156,10 @@ ${summary.join('\n')} // Copy release AAR to a new directory to avoid overwriting with subsequent // patch builds. - final sourceLibraryDirectory = Directory( - aarLibraryPath( - packageName: shorebirdEnv.androidPackageName!, - ), + final sourceLibraryDirectory = Directory(aarLibraryPath); + final targetLibraryDirectory = Directory( + p.join(shorebirdEnv.getShorebirdProjectRoot()!.path, 'release'), ); - final targetLibraryDirectory = - Directory(p.join(Directory.current.path, 'release')); await copyPath(sourceLibraryDirectory.path, targetLibraryDirectory.path); final extractAarProgress = logger.progress('Creating artifacts'); @@ -209,7 +206,7 @@ dependencyResolutionManagement { google() mavenCentral() + maven { -+ url '../${p.basename(Directory.current.path)}/${p.relative(targetLibraryDirectory.path)}' ++ url '../${p.basename(shorebirdEnv.getShorebirdProjectRoot()!.path)}/${p.relative(targetLibraryDirectory.path)}' + } + maven { - url 'https://storage.googleapis.com/download.flutter.io' diff --git a/packages/shorebird_cli/lib/src/commands/release/release_android_command.dart b/packages/shorebird_cli/lib/src/commands/release/release_android_command.dart index cd78ed77..5d0d7d43 100644 --- a/packages/shorebird_cli/lib/src/commands/release/release_android_command.dart +++ b/packages/shorebird_cli/lib/src/commands/release/release_android_command.dart @@ -110,15 +110,28 @@ Please comment and upvote ${link(uri: Uri.parse('https://github.com/shorebirdtec return ExitCode.software.code; } + final projectRoot = shorebirdEnv.getShorebirdProjectRoot()!; final shorebirdYaml = shorebirdEnv.getShorebirdYaml()!; final appId = shorebirdYaml.getAppId(flavor: flavor); final app = await codePushClientWrapper.getApp(appId: appId); - final bundleDirPath = p.join('build', 'app', 'outputs', 'bundle'); + final bundleDirPath = p.join( + projectRoot.path, + 'build', + 'app', + 'outputs', + 'bundle', + ); + final apkDirPath = p.join( + projectRoot.path, + 'build', + 'app', + 'outputs', + 'apk', + ); final bundlePath = flavor != null ? p.join(bundleDirPath, '${flavor}Release', 'app-$flavor-release.aab') : p.join(bundleDirPath, 'release', 'app-release.aab'); - final apkDirPath = p.join('build', 'app', 'outputs', 'apk'); final apkPath = flavor != null ? p.join(apkDirPath, flavor, 'release', 'app-$flavor-release.apk') : p.join(apkDirPath, 'release', 'app-release.apk'); @@ -194,6 +207,7 @@ ${summary.join('\n')} await codePushClientWrapper.createAndroidReleaseArtifacts( appId: app.appId, releaseId: release.id, + projectRoot: projectRoot.path, aabPath: bundlePath, platform: platform, architectures: architectures, diff --git a/packages/shorebird_cli/lib/src/shorebird_artifact_mixin.dart b/packages/shorebird_cli/lib/src/shorebird_artifact_mixin.dart index ed3d05c1..93eb4a23 100644 --- a/packages/shorebird_cli/lib/src/shorebird_artifact_mixin.dart +++ b/packages/shorebird_cli/lib/src/shorebird_artifact_mixin.dart @@ -4,22 +4,26 @@ import 'package:collection/collection.dart'; import 'package:path/path.dart' as p; import 'package:shorebird_cli/src/command.dart'; import 'package:shorebird_cli/src/logger.dart'; +import 'package:shorebird_cli/src/shorebird_env.dart'; mixin ShorebirdArtifactMixin on ShorebirdCommand { - String aarLibraryPath({required String packageName}) => p.joinAll([ - Directory.current.path, - 'build', - 'host', - 'outputs', - 'repo', - ]); + String get aarLibraryPath { + final projectRoot = shorebirdEnv.getShorebirdProjectRoot()!; + return p.joinAll([ + projectRoot.path, + 'build', + 'host', + 'outputs', + 'repo', + ]); + } String aarArtifactDirectory({ required String packageName, required String buildNumber, }) => p.joinAll([ - aarLibraryPath(packageName: packageName), + aarLibraryPath, ...packageName.split('.'), 'flutter_release', buildNumber, @@ -69,18 +73,17 @@ mixin ShorebirdArtifactMixin on ShorebirdCommand { /// Returns the .xcarchive directory generated by `flutter build ipa`. This /// was traditionally named `Runner.xcarchive`, but can now be renamed. Directory? getXcarchiveDirectory() { + final projectRoot = shorebirdEnv.getShorebirdProjectRoot()!; final archiveDirectory = Directory( p.join( - Directory.current.path, + projectRoot.path, 'build', 'ios', 'archive', ), ); - if (!archiveDirectory.existsSync()) { - return null; - } + if (!archiveDirectory.existsSync()) return null; return archiveDirectory .listSync() @@ -118,9 +121,10 @@ mixin ShorebirdArtifactMixin on ShorebirdCommand { /// an exception if there is not exactly one .ipa file in the build directory, /// or if there is no build directory. String getIpaPath() { + final projectRoot = shorebirdEnv.getShorebirdProjectRoot()!; final ipaBuildDirectory = Directory( p.join( - Directory.current.path, + projectRoot.path, 'build', 'ios', 'ipa', @@ -161,23 +165,27 @@ mixin ShorebirdArtifactMixin on ShorebirdCommand { /// Returns the [Directory] containing the App.xcframework generated by /// `shorebird release ios-framework-alpha` or /// `shorebird patch ios-framework-alpha`. - Directory getAppXcframeworkDirectory() => Directory( - p.join( - Directory.current.path, - 'build', - 'ios', - 'framework', - 'Release', - ), - ); + Directory getAppXcframeworkDirectory() { + final projectRoot = shorebirdEnv.getShorebirdProjectRoot()!; + return Directory( + p.join( + projectRoot.path, + 'build', + 'ios', + 'framework', + 'Release', + ), + ); + } /// Finds the most recently-edited app.dill file in the .dart_tool directory. // TODO(bryanoltman): This is an enormous hack – we don't know that this is // the correct file. File newestAppDill() { + final projectRoot = shorebirdEnv.getShorebirdProjectRoot()!; final dartToolBuildDir = Directory( p.join( - Directory.current.path, + projectRoot.path, '.dart_tool', 'flutter_build', ), diff --git a/packages/shorebird_cli/lib/src/shorebird_env.dart b/packages/shorebird_cli/lib/src/shorebird_env.dart index be8f47d0..4326da00 100644 --- a/packages/shorebird_cli/lib/src/shorebird_env.dart +++ b/packages/shorebird_cli/lib/src/shorebird_env.dart @@ -7,7 +7,6 @@ import 'package:scoped/scoped.dart'; import 'package:shorebird_cli/src/config/shorebird_yaml.dart'; import 'package:shorebird_cli/src/platform.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; -import 'package:yaml/yaml.dart'; /// A reference to a [ShorebirdEnv] instance. final shorebirdEnvRef = create(ShorebirdEnv.new); @@ -94,13 +93,48 @@ class ShorebirdEnv { } /// The `shorebird.yaml` file for this project. - File getShorebirdYamlFile() { - return File(p.join(Directory.current.path, 'shorebird.yaml')); + File getShorebirdYamlFile({required Directory cwd}) { + return File(p.join(cwd.path, 'shorebird.yaml')); } /// The `pubspec.yaml` file for this project. - File getPubspecYamlFile() { - return File(p.join(Directory.current.path, 'pubspec.yaml')); + File getPubspecYamlFile({required Directory cwd}) { + return File(p.join(cwd.path, 'pubspec.yaml')); + } + + /// Finds nearest ancestor file + /// relative to the [cwd] that satisfies [where]. + File? findNearestAncestor({ + required File? Function(String path) where, + Directory? cwd, + }) { + Directory? prev; + var dir = cwd ?? Directory.current; + while (prev?.path != dir.path) { + final file = where(dir.path); + if (file?.existsSync() ?? false) return file; + prev = dir; + dir = dir.parent; + } + return null; + } + + /// Returns the root directory of the nearest Shorebird project. + Directory? getShorebirdProjectRoot() { + final file = findNearestAncestor( + where: (path) => getShorebirdYamlFile(cwd: Directory(path)), + ); + if (file == null || !file.existsSync()) return null; + return Directory(p.dirname(file.path)); + } + + /// Returns the root directory of the nearest Flutter project. + Directory? getFlutterProjectRoot() { + final file = findNearestAncestor( + where: (path) => getPubspecYamlFile(cwd: Directory(path)), + ); + if (file == null || !file.existsSync()) return null; + return Directory(p.dirname(file.path)); } /// The `shorebird.yaml` file for this project, parsed into a [ShorebirdYaml] @@ -109,9 +143,9 @@ class ShorebirdEnv { /// Returns `null` if the file does not exist. /// Throws a [ParsedYamlException] if the file exists but is invalid. ShorebirdYaml? getShorebirdYaml() { - final file = getShorebirdYamlFile(); - if (!file.existsSync()) return null; - final yaml = file.readAsStringSync(); + final root = getShorebirdProjectRoot(); + if (root == null) return null; + final yaml = getShorebirdYamlFile(cwd: root).readAsStringSync(); return checkedYamlDecode(yaml, (m) => ShorebirdYaml.fromJson(m!)); } @@ -120,10 +154,14 @@ class ShorebirdEnv { /// Returns `null` if the file does not exist. /// Throws a [ParsedYamlException] if the file exists but is invalid. Pubspec? getPubspecYaml() { - final file = getPubspecYamlFile(); - if (!file.existsSync()) return null; - final yaml = file.readAsStringSync(); - return Pubspec.parse(yaml); + final root = getFlutterProjectRoot(); + if (root == null) return null; + final yaml = getPubspecYamlFile(cwd: root).readAsStringSync(); + try { + return Pubspec.parse(yaml); + } catch (_) { + return null; + } } /// Whether `shorebird init` has been run in the current project. @@ -132,7 +170,7 @@ class ShorebirdEnv { } /// Whether the current project has a `shorebird.yaml` file. - bool get hasShorebirdYaml => getShorebirdYamlFile().existsSync(); + bool get hasShorebirdYaml => getShorebirdYaml() != null; /// Whether the current project has a `pubspec.yaml` file. bool get hasPubspecYaml => getPubspecYaml() != null; @@ -140,13 +178,11 @@ class ShorebirdEnv { /// Whether the current project's `pubspec.yaml` file contains a reference to /// `shorebird.yaml` in its `assets` section. bool get pubspecContainsShorebirdYaml { - final file = File(p.join(Directory.current.path, 'pubspec.yaml')); - final pubspecContents = file.readAsStringSync(); - final yaml = loadYaml(pubspecContents, sourceUrl: file.uri) as Map; - if (!yaml.containsKey('flutter')) return false; - if (yaml['flutter'] is! Map) return false; - if (!(yaml['flutter'] as Map).containsKey('assets')) return false; - final assets = (yaml['flutter'] as Map)['assets'] as List; + final pubspec = getPubspecYaml(); + if (pubspec == null) return false; + if (pubspec.flutter == null) return false; + if (pubspec.flutter!['assets'] == null) return false; + final assets = pubspec.flutter!['assets'] as List; return assets.contains('shorebird.yaml'); } diff --git a/packages/shorebird_cli/lib/src/validators/android_internet_permission_validator.dart b/packages/shorebird_cli/lib/src/validators/android_internet_permission_validator.dart index 70d6f239..7a96842f 100644 --- a/packages/shorebird_cli/lib/src/validators/android_internet_permission_validator.dart +++ b/packages/shorebird_cli/lib/src/validators/android_internet_permission_validator.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:path/path.dart' as p; +import 'package:shorebird_cli/src/shorebird_env.dart'; import 'package:shorebird_cli/src/validators/validators.dart'; import 'package:xml/xml.dart'; @@ -22,20 +23,20 @@ class AndroidInternetPermissionValidator extends Validator { 'AndroidManifest.xml files contain INTERNET permission'; @override - bool canRunInCurrentContext() => _androidSrcDirectory.existsSync(); + bool canRunInCurrentContext() => _androidSrcDirectory?.existsSync() ?? false; // coverage:ignore-start @override String get incorrectContextMessage => ''' -The ${_androidSrcDirectory.path} directory does not exist. +The ${_androidSrcDirectory?.path ?? 'android/app/src'} directory does not exist. -The command you are running must be run at the root of a Flutter app project that supports the Android platform. If you are releasing a Flutter module, use 'aar' in place of 'android' in your shorebird command.'''; +The command you are running must be run within a Flutter app project that supports the Android platform. If you are releasing a Flutter module, use 'aar' in place of 'android' in your shorebird command.'''; // coverage:ignore-end @override Future> validate() async { final manifestFilePath = p.join( - _androidSrcDirectory.path, + _androidSrcDirectory!.path, 'main', 'AndroidManifest.xml', ); @@ -63,14 +64,18 @@ The command you are running must be run at the root of a Flutter app project tha return []; } - Directory get _androidSrcDirectory => Directory( - p.join( - Directory.current.path, - 'android', - 'app', - 'src', - ), - ); + Directory? get _androidSrcDirectory { + final root = shorebirdEnv.getFlutterProjectRoot(); + if (root == null) return null; + return Directory( + p.join( + root.path, + 'android', + 'app', + 'src', + ), + ); + } bool _androidManifestHasInternetPermission(String path) { final xmlDocument = XmlDocument.parse(File(path).readAsStringSync()); diff --git a/packages/shorebird_cli/test/src/code_push_client_wrapper_test.dart b/packages/shorebird_cli/test/src/code_push_client_wrapper_test.dart index e2522f38..3ea49810 100644 --- a/packages/shorebird_cli/test/src/code_push_client_wrapper_test.dart +++ b/packages/shorebird_cli/test/src/code_push_client_wrapper_test.dart @@ -119,6 +119,7 @@ void main() { late Progress progress; late CodePushClientWrapper codePushClientWrapper; late Platform platform; + late Directory projectRoot; R runWithOverrides(R Function() body) { return runScoped( @@ -143,6 +144,7 @@ void main() { logger = MockLogger(); platform = MockPlatform(); progress = MockProgress(); + projectRoot = Directory.systemTemp.createTempSync(); codePushClientWrapper = runWithOverrides( () => CodePushClientWrapper(codePushClient: codePushClient), @@ -720,7 +722,7 @@ Please bump your version number and try again.''', platform: any(named: 'platform'), status: any(named: 'status'), ), - ).thenAnswer((_) async => {}); + ).thenAnswer((_) async {}); final result = await runWithOverrides( () async => codePushClientWrapper.createRelease( @@ -989,13 +991,12 @@ Please bump your version number and try again.''', group('createAndroidReleaseArtifacts', () { final aabPath = p.join('path', 'to', 'app.aab'); - Directory setUpTempDir({String? flavor}) { - final tempDir = Directory.systemTemp.createTempSync(); - File(p.join(tempDir.path, aabPath)).createSync(recursive: true); + void setUpProjectRoot({String? flavor}) { + File(p.join(projectRoot.path, aabPath)).createSync(recursive: true); for (final archMetadata in ShorebirdBuildMixin.allAndroidArchitectures.values) { final artifactPath = p.join( - tempDir.path, + projectRoot.path, 'build', 'app', 'intermediates', @@ -1008,7 +1009,6 @@ Please bump your version number and try again.''', ); File(artifactPath).createSync(recursive: true); } - return tempDir; } setUp(() { @@ -1022,7 +1022,7 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); + ).thenAnswer((_) async {}); }); test('exits with code 70 when artifact creation fails', () async { @@ -1038,22 +1038,20 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(error); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () async => expectLater( - () async => runWithOverrides( - () async => codePushClientWrapper.createAndroidReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aabPath: p.join(tempDir.path, aabPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), + await expectLater( + () async => runWithOverrides( + () async => codePushClientWrapper.createAndroidReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + projectRoot: projectRoot.path, + aabPath: p.join(projectRoot.path, aabPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), - exitsWithCode(ExitCode.software), ), - getCurrentDirectory: () => tempDir, + exitsWithCode(ExitCode.software), ); verify(() => progress.fail(any(that: contains(error)))).called(1); @@ -1072,22 +1070,20 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(error); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () async => expectLater( - () async => runWithOverrides( - () async => codePushClientWrapper.createAndroidReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aabPath: p.join(tempDir.path, aabPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), + await expectLater( + () async => runWithOverrides( + () async => codePushClientWrapper.createAndroidReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + projectRoot: projectRoot.path, + aabPath: p.join(projectRoot.path, aabPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), - exitsWithCode(ExitCode.software), ), - getCurrentDirectory: () => tempDir, + exitsWithCode(ExitCode.software), ); verify(() => progress.fail(any(that: contains(error)))).called(1); @@ -1107,18 +1103,16 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(const CodePushConflictException(message: error)); - final tempDir = setUpTempDir(); + setUpProjectRoot(); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => codePushClientWrapper.createAndroidReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aabPath: p.join(tempDir.path, aabPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), - getCurrentDirectory: () => tempDir, + () => codePushClientWrapper.createAndroidReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + projectRoot: projectRoot.path, + aabPath: p.join(projectRoot.path, aabPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), ); @@ -1144,18 +1138,16 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(const CodePushConflictException(message: error)); - final tempDir = setUpTempDir(); + setUpProjectRoot(); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => codePushClientWrapper.createAndroidReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aabPath: p.join(tempDir.path, aabPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), - getCurrentDirectory: () => tempDir, + () async => codePushClientWrapper.createAndroidReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + projectRoot: projectRoot.path, + aabPath: p.join(projectRoot.path, aabPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), ); @@ -1178,19 +1170,17 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); - final tempDir = setUpTempDir(); + ).thenAnswer((_) async {}); + setUpProjectRoot(); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => codePushClientWrapper.createAndroidReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aabPath: p.join(tempDir.path, aabPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), - getCurrentDirectory: () => tempDir, + () async => codePushClientWrapper.createAndroidReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + projectRoot: projectRoot.path, + aabPath: p.join(projectRoot.path, aabPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), ); @@ -1210,20 +1200,18 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); - final tempDir = setUpTempDir(flavor: flavorName); + ).thenAnswer((_) async {}); + setUpProjectRoot(flavor: flavorName); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => codePushClientWrapper.createAndroidReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aabPath: p.join(tempDir.path, aabPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - flavor: flavorName, - ), - getCurrentDirectory: () => tempDir, + () async => codePushClientWrapper.createAndroidReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + projectRoot: projectRoot.path, + aabPath: p.join(projectRoot.path, aabPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, + flavor: flavorName, ), ); @@ -1263,12 +1251,11 @@ Please bump your version number and try again.''', final aarPath = p.join(aarDir, 'flutter_release-$buildNumber.aar'); final extractedAarPath = p.join(aarDir, 'flutter_release-$buildNumber'); - Directory setUpTempDir({String? flavor}) { - final tempDir = Directory.systemTemp.createTempSync(); + void setUpProjectRoot({String? flavor}) { for (final archMetadata in ShorebirdBuildMixin.allAndroidArchitectures.values) { final artifactPath = p.join( - tempDir.path, + projectRoot.path, extractedAarPath, 'jni', archMetadata.path, @@ -1276,8 +1263,7 @@ Please bump your version number and try again.''', ); File(artifactPath).createSync(recursive: true); } - File(p.join(tempDir.path, aarPath)).createSync(recursive: true); - return tempDir; + File(p.join(projectRoot.path, aarPath)).createSync(recursive: true); } setUp(() { @@ -1291,7 +1277,7 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); + ).thenAnswer((_) async {}); }); test('exits with code 70 when artifact creation fails', () async { @@ -1307,24 +1293,21 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(error); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () async => expectLater( - () async => runWithOverrides( - () async => - codePushClientWrapper.createAndroidArchiveReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aarPath: p.join(tempDir.path, aarPath), - extractedAarDir: p.join(tempDir.path, extractedAarPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), + await expectLater( + () async => runWithOverrides( + () async => + codePushClientWrapper.createAndroidArchiveReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + aarPath: p.join(projectRoot.path, aarPath), + extractedAarDir: p.join(projectRoot.path, extractedAarPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), - exitsWithCode(ExitCode.software), ), - getCurrentDirectory: () => tempDir, + exitsWithCode(ExitCode.software), ); verify(() => progress.fail(any(that: contains(error)))).called(1); @@ -1343,24 +1326,21 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(error); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () async => expectLater( - () async => runWithOverrides( - () async => - codePushClientWrapper.createAndroidArchiveReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aarPath: p.join(tempDir.path, aarPath), - extractedAarDir: p.join(tempDir.path, extractedAarPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), + await expectLater( + () async => runWithOverrides( + () async => + codePushClientWrapper.createAndroidArchiveReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + aarPath: p.join(projectRoot.path, aarPath), + extractedAarDir: p.join(projectRoot.path, extractedAarPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), - exitsWithCode(ExitCode.software), ), - getCurrentDirectory: () => tempDir, + exitsWithCode(ExitCode.software), ); verify(() => progress.fail(any(that: contains(error)))).called(1); @@ -1380,20 +1360,17 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(const CodePushConflictException(message: error)); - final tempDir = setUpTempDir(); + setUpProjectRoot(); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => - codePushClientWrapper.createAndroidArchiveReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aarPath: p.join(tempDir.path, aarPath), - extractedAarDir: p.join(tempDir.path, extractedAarPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), - getCurrentDirectory: () => tempDir, + () async => + codePushClientWrapper.createAndroidArchiveReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + aarPath: p.join(projectRoot.path, aarPath), + extractedAarDir: p.join(projectRoot.path, extractedAarPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), ); @@ -1419,20 +1396,17 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(const CodePushConflictException(message: error)); - final tempDir = setUpTempDir(); + setUpProjectRoot(); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => - codePushClientWrapper.createAndroidArchiveReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aarPath: p.join(tempDir.path, aarPath), - extractedAarDir: p.join(tempDir.path, extractedAarPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), - getCurrentDirectory: () => tempDir, + () async => + codePushClientWrapper.createAndroidArchiveReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + aarPath: p.join(projectRoot.path, aarPath), + extractedAarDir: p.join(projectRoot.path, extractedAarPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), ); @@ -1455,21 +1429,18 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); - final tempDir = setUpTempDir(); + ).thenAnswer((_) async {}); + setUpProjectRoot(); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => - codePushClientWrapper.createAndroidArchiveReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aarPath: p.join(tempDir.path, aarPath), - extractedAarDir: p.join(tempDir.path, extractedAarPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), - getCurrentDirectory: () => tempDir, + () async => + codePushClientWrapper.createAndroidArchiveReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + aarPath: p.join(projectRoot.path, aarPath), + extractedAarDir: p.join(projectRoot.path, extractedAarPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), ); @@ -1489,21 +1460,18 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); - final tempDir = setUpTempDir(flavor: flavorName); + ).thenAnswer((_) async {}); + setUpProjectRoot(flavor: flavorName); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => - codePushClientWrapper.createAndroidArchiveReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - platform: releasePlatform, - aarPath: p.join(tempDir.path, aarPath), - extractedAarDir: p.join(tempDir.path, extractedAarPath), - architectures: ShorebirdBuildMixin.allAndroidArchitectures, - ), - getCurrentDirectory: () => tempDir, + () async => + codePushClientWrapper.createAndroidArchiveReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + platform: releasePlatform, + aarPath: p.join(projectRoot.path, aarPath), + extractedAarDir: p.join(projectRoot.path, extractedAarPath), + architectures: ShorebirdBuildMixin.allAndroidArchitectures, ), ); @@ -1528,12 +1496,13 @@ Please bump your version number and try again.''', final xcarchivePath = p.join('path', 'to', 'app.xcarchive'); final runnerPath = p.join('path', 'to', 'runner.app'); - Directory setUpTempDir({String? flavor}) { - final tempDir = Directory.systemTemp.createTempSync(); - Directory(p.join(tempDir.path, xcarchivePath)) - .createSync(recursive: true); - Directory(p.join(tempDir.path, runnerPath)).createSync(recursive: true); - return tempDir; + void setUpProjectRoot({String? flavor}) { + Directory( + p.join(projectRoot.path, xcarchivePath), + ).createSync(recursive: true); + Directory( + p.join(projectRoot.path, runnerPath), + ).createSync(recursive: true); } setUp(() { @@ -1547,7 +1516,7 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); + ).thenAnswer((_) async {}); }); test('exits with code 70 when xcarchive artifact creation fails', @@ -1565,22 +1534,19 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(error); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () async => expectLater( - () async => runWithOverrides( - () async => codePushClientWrapper.createIosReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - xcarchivePath: p.join(tempDir.path, xcarchivePath), - runnerPath: p.join(tempDir.path, runnerPath), - isCodesigned: true, - ), + await expectLater( + () async => runWithOverrides( + () async => codePushClientWrapper.createIosReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + xcarchivePath: p.join(projectRoot.path, xcarchivePath), + runnerPath: p.join(projectRoot.path, runnerPath), + isCodesigned: true, ), - exitsWithCode(ExitCode.software), ), - getCurrentDirectory: () => tempDir, + exitsWithCode(ExitCode.software), ); verify(() => progress.fail(any(that: contains(error)))).called(1); @@ -1592,8 +1558,10 @@ Please bump your version number and try again.''', when( () => codePushClient.createReleaseArtifact( appId: any(named: 'appId'), - artifactPath: - any(named: 'artifactPath', that: endsWith('.xcarchive.zip')), + artifactPath: any( + named: 'artifactPath', + that: endsWith('.xcarchive.zip'), + ), releaseId: any(named: 'releaseId'), arch: any(named: 'arch'), platform: any(named: 'platform'), @@ -1601,22 +1569,19 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(const CodePushConflictException(message: error)); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () async => expectLater( - () async => runWithOverrides( - () async => codePushClientWrapper.createIosReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - xcarchivePath: p.join(tempDir.path, xcarchivePath), - runnerPath: p.join(tempDir.path, runnerPath), - isCodesigned: false, - ), + await expectLater( + () async => runWithOverrides( + () async => codePushClientWrapper.createIosReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + xcarchivePath: p.join(projectRoot.path, xcarchivePath), + runnerPath: p.join(projectRoot.path, runnerPath), + isCodesigned: false, ), - exitsWithCode(ExitCode.software), ), - getCurrentDirectory: () => tempDir, + exitsWithCode(ExitCode.software), ); verify(() => progress.fail(any(that: contains(error)))).called(1); @@ -1639,22 +1604,19 @@ Please bump your version number and try again.''', canSideload: any(named: 'canSideload'), ), ).thenThrow(error); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () async => expectLater( - () async => runWithOverrides( - () async => codePushClientWrapper.createIosReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - xcarchivePath: p.join(tempDir.path, xcarchivePath), - runnerPath: p.join(tempDir.path, runnerPath), - isCodesigned: false, - ), + await expectLater( + () async => runWithOverrides( + () async => codePushClientWrapper.createIosReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + xcarchivePath: p.join(projectRoot.path, xcarchivePath), + runnerPath: p.join(projectRoot.path, runnerPath), + isCodesigned: false, ), - exitsWithCode(ExitCode.software), ), - getCurrentDirectory: () => tempDir, + exitsWithCode(ExitCode.software), ); verify(() => progress.fail(any(that: contains(error)))).called(1); @@ -1671,19 +1633,16 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); - final tempDir = setUpTempDir(); + ).thenAnswer((_) async {}); + setUpProjectRoot(); await runWithOverrides( - () async => IOOverrides.runZoned( - () async => codePushClientWrapper.createIosReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - xcarchivePath: p.join(tempDir.path, xcarchivePath), - runnerPath: p.join(tempDir.path, runnerPath), - isCodesigned: true, - ), - getCurrentDirectory: () => tempDir, + () async => codePushClientWrapper.createIosReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + xcarchivePath: p.join(projectRoot.path, xcarchivePath), + runnerPath: p.join(projectRoot.path, runnerPath), + isCodesigned: true, ), ); @@ -1695,11 +1654,10 @@ Please bump your version number and try again.''', group('createIosFrameworkReleaseArtifacts', () { final frameworkPath = p.join('path', 'to', 'App.xcframework'); - Directory setUpTempDir({String? flavor}) { - final tempDir = Directory.systemTemp.createTempSync(); - Directory(p.join(tempDir.path, frameworkPath)) - .createSync(recursive: true); - return tempDir; + void setUpProjectRoot({String? flavor}) { + Directory( + p.join(projectRoot.path, frameworkPath), + ).createSync(recursive: true); } test( @@ -1715,17 +1673,15 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenThrow( - Exception('oh no'), - ); - final tempDir = setUpTempDir(); + ).thenThrow(Exception('oh no')); + setUpProjectRoot(); await expectLater( () async => runWithOverrides( () => codePushClientWrapper.createIosFrameworkReleaseArtifacts( appId: app.appId, releaseId: releaseId, - appFrameworkPath: p.join(tempDir.path, frameworkPath), + appFrameworkPath: p.join(projectRoot.path, frameworkPath), ), ), exitsWithCode(ExitCode.software), @@ -1744,21 +1700,18 @@ Please bump your version number and try again.''', hash: any(named: 'hash'), canSideload: any(named: 'canSideload'), ), - ).thenAnswer((_) async => {}); - final tempDir = setUpTempDir(); + ).thenAnswer((_) async {}); + setUpProjectRoot(); - await IOOverrides.runZoned( - () async => expectLater( - runWithOverrides( - () => codePushClientWrapper.createIosFrameworkReleaseArtifacts( - appId: app.appId, - releaseId: releaseId, - appFrameworkPath: p.join(tempDir.path, frameworkPath), - ), + await expectLater( + runWithOverrides( + () => codePushClientWrapper.createIosFrameworkReleaseArtifacts( + appId: app.appId, + releaseId: releaseId, + appFrameworkPath: p.join(projectRoot.path, frameworkPath), ), - completes, ), - getCurrentDirectory: () => tempDir, + completes, ); }); }); @@ -1798,7 +1751,7 @@ Please bump your version number and try again.''', platform: any(named: 'platform'), status: any(named: 'status'), ), - ).thenAnswer((_) async => {}); + ).thenAnswer((_) async {}); await runWithOverrides( () => codePushClientWrapper.updateReleaseStatus( diff --git a/packages/shorebird_cli/test/src/commands/build/build_apk_command_test.dart b/packages/shorebird_cli/test/src/commands/build/build_apk_command_test.dart index 934a3fbf..ae0fed4f 100644 --- a/packages/shorebird_cli/test/src/commands/build/build_apk_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/build/build_apk_command_test.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:args/args.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; @@ -124,14 +122,10 @@ void main() { test('exits with code 70 when building apk fails', () async { when(() => buildProcessResult.exitCode).thenReturn(1); when(() => buildProcessResult.stderr).thenReturn('oops'); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.software.code)); + expect(exitCode, equals(ExitCode.software.code)); verify( () => shorebirdProcess.run( 'flutter', @@ -143,13 +137,9 @@ void main() { test('exits with code 0 when building apk succeeds', () async { when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdProcess.run( @@ -170,12 +160,8 @@ ${lightCyan.wrap(p.join('build', 'app', 'outputs', 'apk', 'release', 'app-releas test('runs flutter pub get with system flutter after successful build', () async { when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -195,13 +181,9 @@ ${lightCyan.wrap(p.join('build', 'app', 'outputs', 'apk', 'release', 'app-releas when(() => argResults['flavor']).thenReturn(flavor); when(() => argResults['target']).thenReturn(target); when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdProcess.run( diff --git a/packages/shorebird_cli/test/src/commands/build/build_app_bundle_command_test.dart b/packages/shorebird_cli/test/src/commands/build/build_app_bundle_command_test.dart index 6adea3e4..3a7790b6 100644 --- a/packages/shorebird_cli/test/src/commands/build/build_app_bundle_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/build/build_app_bundle_command_test.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:args/args.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; @@ -125,14 +123,10 @@ void main() { test('exits with code 70 when building appbundle fails', () async { when(() => buildProcessResult.exitCode).thenReturn(1); when(() => buildProcessResult.stderr).thenReturn('oops'); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.software.code)); + expect(exitCode, equals(ExitCode.software.code)); verify( () => shorebirdProcess.run( 'flutter', @@ -144,13 +138,9 @@ void main() { test('exits with code 0 when building appbundle succeeds', () async { when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdProcess.run( 'flutter', @@ -176,13 +166,9 @@ ${lightCyan.wrap(p.join('build', 'app', 'outputs', 'bundle', 'release', 'app-rel when(() => argResults['flavor']).thenReturn(flavor); when(() => argResults['target']).thenReturn(target); when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdProcess.run( 'flutter', @@ -247,12 +233,8 @@ ${lightCyan.wrap(p.join('build', 'app', 'outputs', 'bundle', '${flavor}Release', test('runs flutter pub get with system flutter after successful build', () async { when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( diff --git a/packages/shorebird_cli/test/src/commands/build/build_ipa_command_test.dart b/packages/shorebird_cli/test/src/commands/build/build_ipa_command_test.dart index 0e7825f1..9bbc3b8c 100644 --- a/packages/shorebird_cli/test/src/commands/build/build_ipa_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/build/build_ipa_command_test.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:args/args.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; @@ -123,14 +121,10 @@ void main() { test('exits with code 70 when building ipa fails', () async { when(() => buildProcessResult.exitCode).thenReturn(1); when(() => buildProcessResult.stderr).thenReturn('oops'); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.software.code)); + expect(exitCode, equals(ExitCode.software.code)); verify( () => shorebirdProcess.run( 'flutter', @@ -146,13 +140,9 @@ void main() { test('exits with code 0 when building ipa succeeds', () async { when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdProcess.run( @@ -183,12 +173,8 @@ ${lightCyan.wrap(p.join('build', 'ios', 'ipa', 'Runner.ipa'))}''', test('runs flutter pub get with system flutter after successful build', () async { when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -208,13 +194,9 @@ ${lightCyan.wrap(p.join('build', 'ios', 'ipa', 'Runner.ipa'))}''', when(() => argResults['flavor']).thenReturn(flavor); when(() => argResults['target']).thenReturn(target); when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdProcess.run( @@ -253,13 +235,9 @@ ${lightCyan.wrap(p.join('build', 'ios', 'ipa', 'Runner.ipa'))}''', 'with --no-codesign', () async { when(() => argResults['codesign']).thenReturn(false); when(() => buildProcessResult.exitCode).thenReturn(ExitCode.success.code); - final tempDir = Directory.systemTemp.createTempSync(); - final result = await IOOverrides.runZoned( - () async => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdProcess.run( diff --git a/packages/shorebird_cli/test/src/commands/init_command_test.dart b/packages/shorebird_cli/test/src/commands/init_command_test.dart index 392740eb..cbdda741 100644 --- a/packages/shorebird_cli/test/src/commands/init_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/init_command_test.dart @@ -40,6 +40,7 @@ environment: late CodePushClientWrapper codePushClientWrapper; late File shorebirdYamlFile; late ShorebirdYaml shorebirdYaml; + late Directory projectRoot; late File pubspecYamlFile; late Logger logger; late Platform platform; @@ -66,6 +67,10 @@ environment: ); } + setUpAll(() { + registerFallbackValue(MockDirectory()); + }); + setUp(() { argResults = MockArgResults(); doctor = MockDoctor(); @@ -74,6 +79,7 @@ environment: shorebirdYaml = MockShorebirdYaml(); shorebirdYamlFile = MockFile(); pubspecYamlFile = MockFile(); + projectRoot = Directory.systemTemp.createTempSync(); logger = MockLogger(); platform = MockPlatform(); progress = MockProgress(); @@ -89,9 +95,12 @@ environment: ).thenAnswer((_) async => {}); when(() => doctor.allValidators).thenReturn([]); when( - () => shorebirdEnv.getShorebirdYamlFile(), + () => shorebirdEnv.getShorebirdYamlFile(cwd: any(named: 'cwd')), ).thenReturn(shorebirdYamlFile); - when(() => shorebirdEnv.getPubspecYamlFile()).thenReturn(pubspecYamlFile); + when( + () => shorebirdEnv.getPubspecYamlFile(cwd: any(named: 'cwd')), + ).thenReturn(pubspecYamlFile); + when(() => shorebirdEnv.getFlutterProjectRoot()).thenReturn(projectRoot); when( () => pubspecYamlFile.readAsStringSync(), ).thenReturn(pubspecYamlContent); @@ -148,7 +157,7 @@ environment: () => logger.err( ''' Could not find a "pubspec.yaml". -Please make sure you are running "shorebird init" from the root of your Flutter project. +Please make sure you are running "shorebird init" from within your Flutter project. ''', ), ).called(1); @@ -253,12 +262,8 @@ Please make sure you are running "shorebird init" from the root of your Flutter }); test('throws software error when unable to detect schemes', () async { - final tempDir = Directory.systemTemp.createTempSync(); - Directory(p.join(tempDir.path, 'ios')).createSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + Directory(p.join(projectRoot.path, 'ios')).createSync(recursive: true); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( () => logger.err( @@ -269,11 +274,7 @@ Please make sure you are running "shorebird init" from the root of your Flutter }); test('creates shorebird for an android-only app', () async { - final tempDir = Directory.systemTemp.createTempSync(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdYamlFile.writeAsStringSync( @@ -284,13 +285,12 @@ Please make sure you are running "shorebird init" from the root of your Flutter }); test('creates shorebird for an app without flavors', () async { - final tempDir = Directory.systemTemp.createTempSync(); when( () => gradlew.productFlavors(any()), - ).thenThrow(MissingAndroidProjectException(tempDir.path)); + ).thenThrow(MissingAndroidProjectException(projectRoot.path)); File( p.join( - tempDir.path, + projectRoot.path, 'ios', 'Runner.xcodeproj', 'xcshareddata', @@ -298,10 +298,7 @@ Please make sure you are running "shorebird init" from the root of your Flutter 'Runner.xcscheme', ), ).createSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( () => shorebirdYamlFile.writeAsStringSync( @@ -322,12 +319,11 @@ Please make sure you are running "shorebird init" from the root of your Flutter final appName = invocation.namedArguments[#appName] as String?; return App(id: appIds[index++], displayName: appName ?? '-'); }); - final tempDir = Directory.systemTemp.createTempSync(); when( () => gradlew.productFlavors(any()), - ).thenThrow(MissingAndroidProjectException(tempDir.path)); + ).thenThrow(MissingAndroidProjectException(projectRoot.path)); final schemesPath = p.join( - tempDir.path, + projectRoot.path, 'ios', 'Runner.xcodeproj', 'xcshareddata', @@ -342,10 +338,7 @@ Please make sure you are running "shorebird init" from the root of your Flutter File( p.join(schemesPath, 'stable.xcscheme'), ).createSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify(() => progress.complete('2 product flavors detected:')) .called(1); diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_aar_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_aar_command_test.dart index dae1dea9..8047e630 100644 --- a/packages/shorebird_cli/test/src/commands/patch/patch_aar_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/patch/patch_aar_command_test.dart @@ -85,6 +85,7 @@ void main() { late Auth auth; late CodePushClientWrapper codePushClientWrapper; late Directory shorebirdRoot; + late Directory projectRoot; late Directory flutterDirectory; late OperatingSystemInterface operatingSystemInterface; late PatchDiffChecker patchDiffChecker; @@ -122,11 +123,9 @@ void main() { ); } - Directory setUpTempDir() => Directory.systemTemp.createTempSync(); - - void setUpTempArtifacts(Directory dir) { + void setUpProjectRootArtifacts() { final aarDir = p.join( - dir.path, + projectRoot.path, 'build', 'host', 'outputs', @@ -170,6 +169,7 @@ void main() { auth = MockAuth(); codePushClientWrapper = MockCodePushClientWrapper(); shorebirdRoot = Directory.systemTemp.createTempSync(); + projectRoot = Directory.systemTemp.createTempSync(); flutterDirectory = Directory( p.join(shorebirdRoot.path, 'bin', 'cache', 'flutter'), ); @@ -191,6 +191,9 @@ void main() { .thenReturn('/path/to/flutter'); when(() => platform.environment).thenReturn({}); when(() => shorebirdEnv.shorebirdRoot).thenReturn(shorebirdRoot); + when( + () => shorebirdEnv.getShorebirdProjectRoot(), + ).thenReturn(projectRoot); when(() => shorebirdEnv.flutterDirectory).thenReturn(flutterDirectory); when( () => shorebirdEnv.androidPackageName, @@ -458,12 +461,8 @@ ${release.version}'''), ), ], ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify( () => logger.err(''' @@ -490,12 +489,8 @@ Please re-run the release command for this version or create a new release.'''), ), ], ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); }); @@ -509,12 +504,8 @@ Please re-run the release command for this version or create a new release.'''), outputPath: any(named: 'outputPath'), ), ).thenThrow(exception); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify(() => progress.fail('$exception')).called(1); expect(exitCode, ExitCode.software.code); }); @@ -524,13 +515,9 @@ Please re-run the release command for this version or create a new release.'''), 'when release flutter revision differs', () async { const otherRevision = 'other-revision'; when(() => shorebirdEnv.flutterRevision).thenReturn(otherRevision); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( () => logger.progress( @@ -564,20 +551,16 @@ Please re-run the release command for this version or create a new release.'''), environment: any(named: 'environment'), ), ).thenAnswer((_) async => flutterBuildProcessResult); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - await IOOverrides.runZoned( - () => runWithOverrides( - () => runScoped( - () => command.run(), - values: { - processRef.overrideWith( - () => ShorebirdProcess(processWrapper: processWrapper), - ), - }, - ), + setUpProjectRootArtifacts(); + await runWithOverrides( + () => runScoped( + () => command.run(), + values: { + processRef.overrideWith( + () => ShorebirdProcess(processWrapper: processWrapper), + ), + }, ), - getCurrentDirectory: () => tempDir, ); verify( () => processWrapper.run( @@ -609,13 +592,9 @@ Please re-run the release command for this version or create a new release.'''), revision: any(named: 'revision'), ), ).thenThrow(exception); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( () => logger.progress( @@ -649,13 +628,9 @@ Please re-run the release command for this version or create a new release.'''), force: any(named: 'force'), ), ).thenThrow(UserCancelledException()); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( @@ -690,13 +665,9 @@ Please re-run the release command for this version or create a new release.'''), ), ).thenThrow(UnpatchableChangeException()); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -727,24 +698,16 @@ Please re-run the release command for this version or create a new release.'''), patchArtifactPath: any(named: 'patchArtifactPath'), ), ).thenThrow(error); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify(() => progress.fail('$error')).called(1); expect(exitCode, ExitCode.software.code); }); test('does not create patch on --dry-run', () async { when(() => argResults['dry-run']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever( () => codePushClientWrapper.publishPatch( @@ -760,25 +723,17 @@ Please re-run the release command for this version or create a new release.'''), test('aborts when user opts out', () async { when(() => logger.confirm(any())).thenReturn(false); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.info('Aborting.')).called(1); }); test('does not prompt on --force', () async { when(() => argResults['force']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); @@ -794,13 +749,9 @@ Please re-run the release command for this version or create a new release.'''), }); test('succeeds when patch is successful', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify( @@ -846,13 +797,9 @@ Please re-run the release command for this version or create a new release.'''), test('runs flutter pub get with system flutter after successful build', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRootArtifacts(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -866,13 +813,9 @@ Please re-run the release command for this version or create a new release.'''), test('does not prompt if running on CI', () async { when(() => shorebirdEnv.isRunningOnCI).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart index ee3d9040..00e51ebf 100644 --- a/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart @@ -97,6 +97,7 @@ flutter: late CodePushClientWrapper codePushClientWrapper; late Directory flutterDirectory; late Directory shorebirdRoot; + late Directory projectRoot; late Doctor doctor; late Java java; late OperatingSystemInterface operatingSystemInterface; @@ -139,22 +140,20 @@ flutter: ); } - Directory setUpTempDir() { - final tempDir = Directory.systemTemp.createTempSync(); + void setUpProjectRoot() { File( - p.join(tempDir.path, 'pubspec.yaml'), + p.join(projectRoot.path, 'pubspec.yaml'), ).writeAsStringSync(pubspecYamlContent); File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync('app_id: $appId'); - return tempDir; } - void setUpTempArtifacts(Directory dir, {String? flavor}) { + void setUpProjectRootArtifacts({String? flavor}) { for (final archMetadata in ShorebirdBuildMixin.allAndroidArchitectures.values) { final artifactPath = p.join( - dir.path, + projectRoot.path, 'build', 'app', 'intermediates', @@ -190,6 +189,7 @@ flutter: doctor = MockDoctor(); java = MockJava(); shorebirdRoot = Directory.systemTemp.createTempSync(); + projectRoot = Directory.systemTemp.createTempSync(); flutterDirectory = Directory( p.join(shorebirdRoot.path, 'bin', 'cache', 'flutter'), ); @@ -216,6 +216,9 @@ flutter: when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml); when(() => shorebirdEnv.shorebirdRoot).thenReturn(shorebirdRoot); + when( + () => shorebirdEnv.getShorebirdProjectRoot(), + ).thenReturn(projectRoot); when(() => shorebirdEnv.flutterDirectory).thenReturn(flutterDirectory); when(() => shorebirdEnv.flutterRevision).thenReturn(flutterRevision); when(() => shorebirdFlutter.useRevision(revision: any(named: 'revision'))) @@ -395,11 +398,8 @@ flutter: 'both --dry-run and --force are specified', () async { when(() => argResults['dry-run']).thenReturn(true); when(() => argResults['force']).thenReturn(true); - final tempDir = setUpTempDir(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.usage.code)); }); @@ -407,11 +407,8 @@ flutter: when(() => flutterBuildProcessResult.exitCode).thenReturn(1); when(() => flutterBuildProcessResult.stderr).thenReturn('oops'); - final tempDir = setUpTempDir(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); }); @@ -436,12 +433,9 @@ flutter: updatedAt: DateTime(2023), ), ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify( () => logger.err(''' @@ -470,12 +464,9 @@ Please re-run the release command for this version or create a new release.'''), ), ], ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); }); @@ -484,13 +475,10 @@ Please re-run the release command for this version or create a new release.'''), () async { const otherRevision = 'other-revision'; when(() => shorebirdEnv.flutterRevision).thenReturn(otherRevision); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); // Verify that we switch back to the original revision once we're done. @@ -523,13 +511,10 @@ Please re-run the release command for this version or create a new release.'''), when(() => flutterBuildProcessResult.exitCode).thenReturn(1); when(() => flutterBuildProcessResult.stderr).thenReturn('oops'); }); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); }, @@ -541,12 +526,9 @@ Please re-run the release command for this version or create a new release.'''), }); test('does not extract release version from app bundle', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + await runWithOverrides(command.run); verifyNever(() => bundletool.getVersionName(any())); verifyNever(() => bundletool.getVersionCode(any())); verifyNever(() => logger.progress('Detecting release version')); @@ -555,12 +537,9 @@ Please re-run the release command for this version or create a new release.'''), group('when release-version option is not provided', () { test('extracts release version from app bundle', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + await runWithOverrides(command.run); verify(() => bundletool.getVersionName(any())).called(1); verify(() => bundletool.getVersionCode(any())).called(1); verify(() => logger.progress('Detecting release version')).called(1); @@ -572,12 +551,9 @@ Please re-run the release command for this version or create a new release.'''), 'Failed to extract version name from app bundle: oops', ); when(() => bundletool.getVersionName(any())).thenThrow(exception); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify(() => progress.fail('$exception')).called(1); }); @@ -587,23 +563,17 @@ Please re-run the release command for this version or create a new release.'''), 'Failed to extract version code from app bundle: oops', ); when(() => bundletool.getVersionCode(any())).thenThrow(exception); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify(() => progress.fail('$exception')).called(1); }); test('prints release version when detected', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( @@ -613,12 +583,9 @@ Please re-run the release command for this version or create a new release.'''), test('aborts when user opts out', () async { when(() => logger.confirm(any())).thenReturn(false); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.info('Aborting.')).called(1); }); @@ -633,12 +600,9 @@ Please re-run the release command for this version or create a new release.'''), outputPath: any(named: 'outputPath'), ), ).thenThrow(exception); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify(() => progress.fail('$exception')).called(1); expect(exitCode, ExitCode.software.code); }); @@ -648,12 +612,9 @@ Please re-run the release command for this version or create a new release.'''), 'Failed to extract version name from app bundle: oops', ); when(() => bundletool.getVersionName(any())).thenThrow(exception); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify(() => progress.fail('$exception')).called(1); }); @@ -663,23 +624,17 @@ Please re-run the release command for this version or create a new release.'''), 'Failed to extract version code from app bundle: oops', ); when(() => bundletool.getVersionCode(any())).thenThrow(exception); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify(() => progress.fail('$exception')).called(1); }); test('prints release version when detected', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( @@ -699,13 +654,10 @@ Please re-run the release command for this version or create a new release.'''), force: any(named: 'force'), ), ).thenThrow(UserCancelledException()); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( @@ -740,13 +692,10 @@ Please re-run the release command for this version or create a new release.'''), ), ).thenThrow(UnpatchableChangeException()); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -777,24 +726,18 @@ Please re-run the release command for this version or create a new release.'''), patchArtifactPath: any(named: 'patchArtifactPath'), ), ).thenThrow(error); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify(() => progress.fail('$error')).called(1); expect(exitCode, ExitCode.software.code); }); test('does not create patch on --dry-run', () async { when(() => argResults['dry-run']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever( () => codePushClientWrapper.publishPatch( @@ -812,13 +755,10 @@ Please re-run the release command for this version or create a new release.'''), when(() => argResults['force']).thenReturn(true); when(() => archiveDiffer.containsPotentiallyBreakingAssetDiffs(any())) .thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); @@ -834,12 +774,9 @@ Please re-run the release command for this version or create a new release.'''), }); test('succeeds when patch is successful (production)', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify( () => logger.info( any( @@ -865,12 +802,9 @@ Please re-run the release command for this version or create a new release.'''), test('succeeds when patch is successful (staging)', () async { when(() => argResults['staging']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify( () => logger.info( any( @@ -896,12 +830,9 @@ Please re-run the release command for this version or create a new release.'''), test('runs flutter pub get with system flutter after successful build', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -920,18 +851,15 @@ Please re-run the release command for this version or create a new release.'''), const target = './lib/main_development.dart'; when(() => argResults['flavor']).thenReturn(flavor); when(() => argResults['target']).thenReturn(target); - final tempDir = setUpTempDir(); + setUpProjectRoot(); File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync(''' app_id: productionAppId flavors: development: $appId'''); - setUpTempArtifacts(tempDir, flavor: flavor); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(flavor: flavor); + final exitCode = await runWithOverrides(command.run); verify( () => codePushClientWrapper.publishPatch( appId: appId, @@ -946,13 +874,10 @@ flavors: test('does not prompt if running on CI', () async { when(() => shorebirdEnv.isRunningOnCI).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart index 9f41e9be..93b73ed7 100644 --- a/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart @@ -126,6 +126,7 @@ flutter: late CodePushClientWrapper codePushClientWrapper; late Directory flutterDirectory; late Directory shorebirdRoot; + late Directory projectRoot; late File genSnapshotFile; late Doctor doctor; late IosArchiveDiffer archiveDiffer; @@ -164,17 +165,16 @@ flutter: ); } - Directory setUpTempDir() { - final tempDir = Directory.systemTemp.createTempSync(); + void setUpProjectRoot() { File( - p.join(tempDir.path, 'pubspec.yaml'), + p.join(projectRoot.path, 'pubspec.yaml'), ).writeAsStringSync(pubspecYamlContent); File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync('app_id: $appId'); File( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -184,15 +184,14 @@ flutter: ) ..createSync(recursive: true) ..writeAsStringSync(infoPlistContent); - File(p.join(tempDir.path, ipaPath)).createSync(recursive: true); - return tempDir; + File(p.join(projectRoot.path, ipaPath)).createSync(recursive: true); } - void setUpTempArtifacts(Directory dir) { + void setUpProjectRootArtifacts() { // Create a second app.dill for coverage of newestAppDill file. File( p.join( - dir.path, + projectRoot.path, '.dart_tool', 'flutter_build', 'subdir', @@ -200,11 +199,11 @@ flutter: ), ).createSync(recursive: true); File( - p.join(dir.path, '.dart_tool', 'flutter_build', 'app.dill'), + p.join(projectRoot.path, '.dart_tool', 'flutter_build', 'app.dill'), + ).createSync(recursive: true); + File( + p.join(projectRoot.path, 'build', elfAotSnapshotFileName), ).createSync(recursive: true); - File(p.join(dir.path, 'build', elfAotSnapshotFileName)).createSync( - recursive: true, - ); } setUpAll(() { @@ -224,6 +223,7 @@ flutter: codePushClientWrapper = MockCodePushClientWrapper(); doctor = MockDoctor(); shorebirdRoot = Directory.systemTemp.createTempSync(); + projectRoot = Directory.systemTemp.createTempSync(); flutterDirectory = Directory( p.join(shorebirdRoot.path, 'bin', 'cache', 'flutter'), ); @@ -299,6 +299,9 @@ flutter: when(() => platform.script).thenReturn(shorebirdRoot.uri); when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml); when(() => shorebirdEnv.shorebirdRoot).thenReturn(shorebirdRoot); + when( + () => shorebirdEnv.getShorebirdProjectRoot(), + ).thenReturn(projectRoot); when(() => shorebirdEnv.flutterDirectory).thenReturn(flutterDirectory); when(() => shorebirdEnv.genSnapshotFile).thenReturn(genSnapshotFile); when(() => shorebirdEnv.flutterRevision).thenReturn(flutterRevision); @@ -390,11 +393,8 @@ flutter: 'both --dry-run and --force are specified', () async { when(() => argResults['dry-run']).thenReturn(true); when(() => argResults['force']).thenReturn(true); - final tempDir = setUpTempDir(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.usage.code)); }); @@ -402,11 +402,8 @@ flutter: when(() => flutterBuildProcessResult.exitCode).thenReturn(1); when(() => flutterBuildProcessResult.stderr).thenReturn('oops'); - final tempDir = setUpTempDir(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); }); @@ -430,11 +427,8 @@ error: exportArchive: Communication with Apple failed error: exportArchive: No signing certificate "iOS Distribution" found '''); - final tempDir = setUpTempDir(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -451,28 +445,28 @@ error: exportArchive: No signing certificate "iOS Distribution" found group('when build directory has non-default structure', () { test('exits with code 70 if xcarchive is not found', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - Directory(p.join(tempDir.path, 'build')).deleteSync(recursive: true); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + Directory( + p.join(projectRoot.path, 'build'), + ).deleteSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( - () => logger - .err(any(that: contains('Unable to find .xcarchive directory'))), + () => logger.err( + any(that: contains('Unable to find .xcarchive directory')), + ), ).called(1); }); test('prints error and exits with code 70 if Info.plist does not exist', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); final plistPath = p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -481,22 +475,20 @@ error: exportArchive: No signing certificate "iOS Distribution" found ); File(plistPath).deleteSync(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); - verify(() => logger.err('No Info.plist file found at $plistPath.')) - .called(1); + verify( + () => logger.err('No Info.plist file found at $plistPath.'), + ).called(1); }); test('finds xcarchive that has been renamed from Runner', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); Directory( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -504,7 +496,7 @@ error: exportArchive: No signing certificate "iOS Distribution" found ), ).renameSync( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -512,10 +504,7 @@ error: exportArchive: No signing certificate "iOS Distribution" found ), ); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); }); @@ -541,12 +530,9 @@ error: exportArchive: No signing certificate "iOS Distribution" found updatedAt: DateTime(2023), ), ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify(() => logger.err('No iOS release found for 1.2.3+1.')).called(1); }); @@ -571,12 +557,9 @@ error: exportArchive: No signing certificate "iOS Distribution" found updatedAt: DateTime(2023), ), ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify( () => logger.err(''' @@ -607,12 +590,9 @@ Please re-run the release command for this version or create a new release.'''), updatedAt: DateTime(2023), ), ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); }); @@ -621,13 +601,10 @@ Please re-run the release command for this version or create a new release.'''), () async { const otherRevision = 'other-revision'; when(() => shorebirdEnv.flutterRevision).thenReturn(otherRevision); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); // Verify that we switch back to the original revision once we're done. @@ -661,13 +638,10 @@ Please re-run the release command for this version or create a new release.'''), when(() => flutterBuildProcessResult.exitCode).thenReturn(1); when(() => flutterBuildProcessResult.stderr).thenReturn('oops'); }); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); }, @@ -677,17 +651,15 @@ Please re-run the release command for this version or create a new release.'''), const customReleaseVersion = 'custom-release-version'; setUp(() { - when(() => argResults['release-version']) - .thenReturn(customReleaseVersion); + when( + () => argResults['release-version'], + ).thenReturn(customReleaseVersion); }); test('does not extract release version from archive', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + await runWithOverrides(command.run); verify( () => codePushClientWrapper.getRelease( @@ -700,12 +672,9 @@ Please re-run the release command for this version or create a new release.'''), group('when release-version option is not provided', () { test('extracts release version from app bundle', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + await runWithOverrides(command.run); verify( () => codePushClientWrapper.getRelease( @@ -718,11 +687,11 @@ Please re-run the release command for this version or create a new release.'''), test('exits with code 70 when release version cannot be determiend', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); final file = File( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -733,10 +702,7 @@ Please re-run the release command for this version or create a new release.'''), ..createSync(recursive: true) ..writeAsStringSync(emptyPlistContent); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -748,13 +714,10 @@ Please re-run the release command for this version or create a new release.'''), }); test('prints release version when detected', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify(() => logger.info('Detected release version 1.2.3+1')).called(1); @@ -762,12 +725,9 @@ Please re-run the release command for this version or create a new release.'''), test('aborts when user opts out', () async { when(() => logger.confirm(any())).thenReturn(false); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.info('Aborting.')).called(1); }); @@ -776,12 +736,9 @@ Please re-run the release command for this version or create a new release.'''), const error = 'oops something went wrong'; when(() => aotBuildProcessResult.exitCode).thenReturn(1); when(() => aotBuildProcessResult.stderr).thenReturn(error); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify( () => progress.fail('Exception: Failed to create snapshot: $error'), ).called(1); @@ -800,13 +757,10 @@ Please re-run the release command for this version or create a new release.'''), force: any(named: 'force'), ), ).thenThrow(UserCancelledException()); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( @@ -840,13 +794,10 @@ Please re-run the release command for this version or create a new release.'''), force: any(named: 'force'), ), ).thenThrow(UnpatchableChangeException()); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -870,12 +821,9 @@ Please re-run the release command for this version or create a new release.'''), test('does not create patch on --dry-run', () async { when(() => argResults['dry-run']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever( () => codePushClientWrapper.createPatch( @@ -888,12 +836,9 @@ Please re-run the release command for this version or create a new release.'''), test('does not prompt on --force', () async { when(() => argResults['force']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); verify( @@ -908,12 +853,9 @@ Please re-run the release command for this version or create a new release.'''), }); test('succeeds when patch is successful (production)', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify( () => logger.info( any( @@ -939,12 +881,9 @@ Please re-run the release command for this version or create a new release.'''), test('succeeds when patch is successful (staging)', () async { when(() => argResults['staging']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify( () => logger.info( any( @@ -970,13 +909,10 @@ Please re-run the release command for this version or create a new release.'''), test('runs flutter pub get with system flutter after successful build', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -990,12 +926,9 @@ Please re-run the release command for this version or create a new release.'''), test('forwards codesign to flutter build', () async { when(() => argResults['codesign']).thenReturn(false); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -1017,13 +950,10 @@ Please re-run the release command for this version or create a new release.'''), test('does not provide export options when codesign is false', () async { when(() => argResults['codesign']).thenReturn(false); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); final capturedArgs = verify( () => shorebirdProcess.run( @@ -1047,18 +977,15 @@ Please re-run the release command for this version or create a new release.'''), const target = './lib/main_development.dart'; when(() => argResults['flavor']).thenReturn(flavor); when(() => argResults['target']).thenReturn(target); - final tempDir = setUpTempDir(); + setUpProjectRoot(); File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync(''' app_id: productionAppId flavors: development: $appId'''); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify( () => codePushClientWrapper.publishPatch( @@ -1072,31 +999,25 @@ flavors: }); test('succeeds when patch is successful using custom base_url', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); const baseUrl = 'https://example.com'; File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync( ''' app_id: $appId base_url: $baseUrl''', ); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); }); test('does not prompt if running on CI', () async { when(() => shorebirdEnv.isRunningOnCI).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_ios_framework_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_ios_framework_command_test.dart index 1eebee85..e48404c2 100644 --- a/packages/shorebird_cli/test/src/commands/patch/patch_ios_framework_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/patch/patch_ios_framework_command_test.dart @@ -77,6 +77,7 @@ flutter: late ArgResults argResults; late CodePushClientWrapper codePushClientWrapper; late Directory shorebirdRoot; + late Directory projectRoot; late Directory flutterDirectory; late File genSnapshotFile; late Doctor doctor; @@ -116,11 +117,11 @@ flutter: ); } - void setUpTempArtifacts(Directory dir) { + void setUpProjectRootArtifacts() { // Create a second app.dill for coverage of newestAppDill file. File( p.join( - dir.path, + projectRoot.path, '.dart_tool', 'flutter_build', 'subdir', @@ -128,14 +129,15 @@ flutter: ), ).createSync(recursive: true); File( - p.join(dir.path, '.dart_tool', 'flutter_build', 'app.dill'), + p.join(projectRoot.path, '.dart_tool', 'flutter_build', 'app.dill'), ).createSync(recursive: true); - File(p.join(dir.path, 'build', elfAotSnapshotFileName)).createSync( + File(p.join(projectRoot.path, 'build', elfAotSnapshotFileName)) + .createSync( recursive: true, ); Directory( p.join( - dir.path, + projectRoot.path, 'build', 'ios', 'framework', @@ -147,15 +149,13 @@ flutter: ); } - Directory setUpTempDir() { - final tempDir = Directory.systemTemp.createTempSync(); + void setUpProjectRoot() { File( - p.join(tempDir.path, 'pubspec.yaml'), + p.join(projectRoot.path, 'pubspec.yaml'), ).writeAsStringSync(pubspecYamlContent); File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync('app_id: $appId'); - return tempDir; } setUpAll(() { @@ -174,6 +174,7 @@ flutter: patchDiffChecker = MockPatchDiffChecker(); platform = MockPlatform(); shorebirdRoot = Directory.systemTemp.createTempSync(); + projectRoot = Directory.systemTemp.createTempSync(); flutterDirectory = Directory( p.join(shorebirdRoot.path, 'bin', 'cache', 'flutter'), ); @@ -232,11 +233,15 @@ flutter: when(() => logger.level).thenReturn(Level.info); when(() => logger.progress(any())).thenReturn(progress); when(() => logger.confirm(any())).thenReturn(true); - when(() => operatingSystemInterface.which('flutter')) - .thenReturn('/path/to/flutter'); + when( + () => operatingSystemInterface.which('flutter'), + ).thenReturn('/path/to/flutter'); when(() => platform.operatingSystem).thenReturn(Platform.macOS); when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml); when(() => shorebirdEnv.shorebirdRoot).thenReturn(shorebirdRoot); + when( + () => shorebirdEnv.getShorebirdProjectRoot(), + ).thenReturn(projectRoot); when(() => shorebirdEnv.flutterDirectory).thenReturn(flutterDirectory); when(() => shorebirdEnv.genSnapshotFile).thenReturn(genSnapshotFile); when(() => shorebirdEnv.flutterRevision).thenReturn(flutterRevision); @@ -425,12 +430,9 @@ ${release.version}'''), ), ], ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify( () => logger.err(''' @@ -457,12 +459,9 @@ Please re-run the release command for this version or create a new release.'''), ), ], ); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); }); @@ -471,13 +470,10 @@ Please re-run the release command for this version or create a new release.'''), 'when release flutter revision differs', () async { const otherRevision = 'other-revision'; when(() => shorebirdEnv.flutterRevision).thenReturn(otherRevision); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( () => logger.progress( @@ -511,20 +507,17 @@ Please re-run the release command for this version or create a new release.'''), environment: any(named: 'environment'), ), ).thenAnswer((_) async => flutterBuildProcessResult); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - await IOOverrides.runZoned( - () => runWithOverrides( - () => runScoped( - () => command.run(), - values: { - processRef.overrideWith( - () => ShorebirdProcess(processWrapper: processWrapper), - ), - }, - ), + setUpProjectRoot(); + setUpProjectRootArtifacts(); + await runWithOverrides( + () => runScoped( + () => command.run(), + values: { + processRef.overrideWith( + () => ShorebirdProcess(processWrapper: processWrapper), + ), + }, ), - getCurrentDirectory: () => tempDir, ); verify( () => processWrapper.run( @@ -556,13 +549,10 @@ Please re-run the release command for this version or create a new release.'''), revision: any(named: 'revision'), ), ).thenThrow(exception); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( () => logger.progress( @@ -579,12 +569,9 @@ Please re-run the release command for this version or create a new release.'''), test('aborts when user opts out', () async { when(() => logger.confirm(any())).thenReturn(false); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.info('Aborting.')).called(1); }); @@ -593,12 +580,9 @@ Please re-run the release command for this version or create a new release.'''), when(() => flutterBuildProcessResult.exitCode).thenReturn(1); when(() => flutterBuildProcessResult.stderr).thenReturn('oh no'); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.software.code); verify(() => progress.fail('Failed to build: oh no')).called(1); }); @@ -607,12 +591,9 @@ Please re-run the release command for this version or create a new release.'''), const error = 'oops something went wrong'; when(() => aotBuildProcessResult.exitCode).thenReturn(1); when(() => aotBuildProcessResult.stderr).thenReturn(error); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify( () => progress.fail('Exception: Failed to create snapshot: $error'), ).called(1); @@ -631,13 +612,10 @@ Please re-run the release command for this version or create a new release.'''), force: any(named: 'force'), ), ).thenThrow(UserCancelledException()); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verify( @@ -671,13 +649,10 @@ Please re-run the release command for this version or create a new release.'''), force: any(named: 'force'), ), ).thenThrow(UnpatchableChangeException()); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -701,12 +676,9 @@ Please re-run the release command for this version or create a new release.'''), test('does not create patch on --dry-run', () async { when(() => argResults['dry-run']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever( () => codePushClientWrapper.createPatch( @@ -719,12 +691,9 @@ Please re-run the release command for this version or create a new release.'''), test('does not prompt on --force', () async { when(() => argResults['force']).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); verify( @@ -739,12 +708,9 @@ Please re-run the release command for this version or create a new release.'''), }); test('succeeds when patch is successful', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); verify( () => logger.info( any( @@ -770,13 +736,10 @@ Please re-run the release command for this version or create a new release.'''), test('runs flutter pub get with system flutter after successful build', () async { - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -790,13 +753,10 @@ Please re-run the release command for this version or create a new release.'''), test('does not prompt if running on CI', () async { when(() => shorebirdEnv.isRunningOnCI).thenReturn(true); - final tempDir = setUpTempDir(); - setUpTempArtifacts(tempDir); + setUpProjectRoot(); + setUpProjectRootArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); diff --git a/packages/shorebird_cli/test/src/commands/release/release_aar_command_test.dart b/packages/shorebird_cli/test/src/commands/release/release_aar_command_test.dart index 86cce051..8adb8575 100644 --- a/packages/shorebird_cli/test/src/commands/release/release_aar_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/release/release_aar_command_test.dart @@ -59,6 +59,7 @@ void main() { late Auth auth; late CodePushClientWrapper codePushClientWrapper; late Directory shorebirdRoot; + late Directory projectRoot; late Java java; late OperatingSystemInterface operatingSystemInterface; late Platform platform; @@ -89,10 +90,9 @@ void main() { ); } - Directory setUpTempArtifacts() { - final dir = Directory.systemTemp.createTempSync(); + void setUpProjectRootArtifacts() { final aarDir = p.join( - dir.path, + projectRoot.path, 'build', 'host', 'outputs', @@ -116,7 +116,6 @@ void main() { File(artifactPath).createSync(recursive: true); } File(aarPath).createSync(recursive: true); - return dir; } setUpAll(() { @@ -140,6 +139,7 @@ void main() { flutterPubGetProcessResult = MockProcessResult(); shorebirdProcess = MockShorebirdProcess(); shorebirdRoot = Directory.systemTemp.createTempSync(); + projectRoot = Directory.systemTemp.createTempSync(); shorebirdEnv = MockShorebirdEnv(); shorebirdValidator = MockShorebirdValidator(); @@ -155,6 +155,9 @@ void main() { when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml); when(() => shorebirdEnv.shorebirdRoot).thenReturn(shorebirdRoot); + when( + () => shorebirdEnv.getShorebirdProjectRoot(), + ).thenReturn(projectRoot); when( () => shorebirdEnv.androidPackageName, ).thenReturn(androidPackageName); @@ -302,22 +305,16 @@ void main() { defaultValue: any(named: 'defaultValue'), ), ).thenAnswer((_) => '1.0.0'); - final tempDir = setUpTempArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.info('Aborting.')).called(1); }); test('does not prompt for confirmation when --force is used', () async { when(() => argResults['force']).thenReturn(true); - final tempDir = setUpTempArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.success('\n✅ Published Release!')).called(1); verifyNever( @@ -326,11 +323,8 @@ void main() { }); test('succeeds when release is successful', () async { - final tempDir = setUpTempArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.success('\n✅ Published Release!')).called(1); verify( @@ -386,23 +380,20 @@ void main() { }); test('copies aar library to a releases folder', () async { - final tempDir = setUpTempArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); - expect(Directory(p.join(tempDir.path, 'release')).existsSync(), isTrue); + expect( + Directory(p.join(projectRoot.path, 'release')).existsSync(), + isTrue, + ); }); test('runs flutter pub get with system flutter after successful build', () async { - final tempDir = setUpTempArtifacts(); + setUpProjectRootArtifacts(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -422,11 +413,8 @@ void main() { releaseVersion: any(named: 'releaseVersion'), ), ).thenAnswer((_) async => release); - final tempDir = setUpTempArtifacts(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verifyNever( () => codePushClientWrapper.createRelease( diff --git a/packages/shorebird_cli/test/src/commands/release/release_android_command_test.dart b/packages/shorebird_cli/test/src/commands/release/release_android_command_test.dart index f809569f..de4c5abe 100644 --- a/packages/shorebird_cli/test/src/commands/release/release_android_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/release/release_android_command_test.dart @@ -62,6 +62,7 @@ void main() { late http.Client httpClient; late CodePushClientWrapper codePushClientWrapper; late Directory shorebirdRoot; + late Directory projectRoot; late Doctor doctor; late Platform platform; late Auth auth; @@ -115,6 +116,7 @@ void main() { operatingSystemInterface = MockOperatingSystemInterface(); platform = MockPlatform(); shorebirdRoot = Directory.systemTemp.createTempSync(); + projectRoot = Directory.systemTemp.createTempSync(); auth = MockAuth(); cache = MockCache(); java = MockJava(); @@ -129,6 +131,9 @@ void main() { when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml); when(() => shorebirdEnv.shorebirdRoot).thenReturn(shorebirdRoot); + when( + () => shorebirdEnv.getShorebirdProjectRoot(), + ).thenReturn(projectRoot); when(() => shorebirdEnv.flutterRevision).thenReturn(flutterRevision); when(() => shorebirdEnv.isRunningOnCI).thenReturn(false); @@ -195,6 +200,7 @@ void main() { () => codePushClientWrapper.createAndroidReleaseArtifacts( appId: any(named: 'appId'), releaseId: any(named: 'releaseId'), + projectRoot: any(named: 'projectRoot'), aabPath: any(named: 'aabPath'), platform: any(named: 'platform'), architectures: any(named: 'architectures'), @@ -335,6 +341,7 @@ void main() { final exitCode = await runWithOverrides(command.run); verify(() => logger.success('\n✅ Published Release!')).called(1); final aabPath = p.join( + projectRoot.path, 'build', 'app', 'outputs', @@ -358,6 +365,7 @@ ${link(uri: Uri.parse('https://support.google.com/googleplay/android-developer/a appId: appId, releaseId: release.id, platform: releasePlatform, + projectRoot: any(named: 'projectRoot'), aabPath: any(named: 'aabPath'), architectures: any(named: 'architectures'), ), @@ -379,6 +387,7 @@ ${link(uri: Uri.parse('https://support.google.com/googleplay/android-developer/a verify(() => logger.success('\n✅ Published Release!')).called(1); // Verify info message does include apk instructions. final aabPath = p.join( + projectRoot.path, 'build', 'app', 'outputs', @@ -387,6 +396,7 @@ ${link(uri: Uri.parse('https://support.google.com/googleplay/android-developer/a 'app-release.aab', ); final apkPath = p.join( + projectRoot.path, 'build', 'app', 'outputs', @@ -412,6 +422,7 @@ ${link(uri: Uri.parse('https://support.google.com/googleplay/android-developer/a appId: appId, releaseId: release.id, platform: releasePlatform, + projectRoot: any(named: 'projectRoot'), aabPath: any(named: 'aabPath'), architectures: any(named: 'architectures'), ), @@ -568,6 +579,7 @@ Either run `flutter pub get` manually, or follow the steps in ${link(uri: Uri.pa appId: appId, releaseId: release.id, platform: releasePlatform, + projectRoot: any(named: 'projectRoot'), aabPath: any(named: 'aabPath'), architectures: any(named: 'architectures'), flavor: flavor, diff --git a/packages/shorebird_cli/test/src/commands/release/release_ios_command_test.dart b/packages/shorebird_cli/test/src/commands/release/release_ios_command_test.dart index e439b2d5..a435f3f5 100644 --- a/packages/shorebird_cli/test/src/commands/release/release_ios_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/release/release_ios_command_test.dart @@ -107,6 +107,7 @@ flutter: late ArgResults argResults; late CodePushClientWrapper codePushClientWrapper; late Directory shorebirdRoot; + late Directory projectRoot; late Doctor doctor; late Platform platform; late Auth auth; @@ -138,17 +139,16 @@ flutter: ); } - Directory setUpTempDir() { - final tempDir = Directory.systemTemp.createTempSync(); + void setUpProjectRoot() { File( - p.join(tempDir.path, 'pubspec.yaml'), + p.join(projectRoot.path, 'pubspec.yaml'), ).writeAsStringSync(pubspecYamlContent); File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync('app_id: $appId'); File( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -160,7 +160,7 @@ flutter: ..writeAsStringSync(infoPlistContent); Directory( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -170,8 +170,7 @@ flutter: 'Runner.app', ), ).createSync(recursive: true); - File(p.join(tempDir.path, ipaPath)).createSync(recursive: true); - return tempDir; + File(p.join(projectRoot.path, ipaPath)).createSync(recursive: true); } setUpAll(() { @@ -187,6 +186,7 @@ flutter: doctor = MockDoctor(); platform = MockPlatform(); shorebirdRoot = Directory.systemTemp.createTempSync(); + projectRoot = Directory.systemTemp.createTempSync(); auth = MockAuth(); operatingSystemInterface = MockOperatingSystemInterface(); progress = MockProgress(); @@ -200,6 +200,9 @@ flutter: when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml); when(() => shorebirdEnv.shorebirdRoot).thenReturn(shorebirdRoot); + when( + () => shorebirdEnv.getShorebirdProjectRoot(), + ).thenReturn(projectRoot); when(() => shorebirdEnv.flutterRevision).thenReturn(flutterRevision); when(() => shorebirdEnv.isRunningOnCI).thenReturn(false); when( @@ -233,14 +236,16 @@ flutter: when( () => logger.prompt(any(), defaultValue: any(named: 'defaultValue')), ).thenReturn(version); - when(() => operatingSystemInterface.which('flutter')) - .thenReturn('/path/to/flutter'); + when( + () => operatingSystemInterface.which('flutter'), + ).thenReturn('/path/to/flutter'); when(() => platform.operatingSystem).thenReturn(Platform.macOS); when( () => flutterBuildProcessResult.exitCode, ).thenReturn(ExitCode.success.code); - when(() => flutterPubGetProcessResult.exitCode) - .thenReturn(ExitCode.success.code); + when( + () => flutterPubGetProcessResult.exitCode, + ).thenReturn(ExitCode.success.code); when( () => codePushClientWrapper.getApp(appId: any(named: 'appId')), ).thenAnswer((_) async => appMetadata); @@ -330,11 +335,8 @@ flutter: }); test('prints instructions to manually codesign', () async { - final tempDir = setUpTempDir(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + await runWithOverrides(command.run); verify( () => logger.info( @@ -344,11 +346,8 @@ flutter: }); test('builds without codesigning', () async { - final tempDir = setUpTempDir(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -371,10 +370,10 @@ flutter: group('when build directory has non-default structure', () { test('prints error and exits with code 70 if xcarchive does not exist', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); Directory( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -382,23 +381,21 @@ flutter: ), ).deleteSync(recursive: true); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.software.code)); - verify(() => logger.err('Unable to find .xcarchive directory')) - .called(1); + expect(exitCode, equals(ExitCode.software.code)); + verify( + () => logger.err('Unable to find .xcarchive directory'), + ).called(1); }); test( '''prints error and exits with code 70 if .app directory does not exist''', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); Directory( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -408,21 +405,18 @@ flutter: ), ).deleteSync(recursive: true); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.software.code)); + expect(exitCode, equals(ExitCode.software.code)); verify(() => logger.err('Unable to find .app directory')).called(1); }); test( '''finds .xcarchive and .app when they do not have the default "Runner" name''', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); final archivePath = p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -446,24 +440,19 @@ flutter: ), ); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); }); }); test('prints archive upload instructions on success', () async { - final tempDir = setUpTempDir(); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); final archivePath = p.join( + projectRoot.path, 'build', 'ios', 'archive', @@ -475,10 +464,10 @@ flutter: that: stringContainsInOrder( [ 'Your next step is to submit the archive', - archivePath, + p.relative(archivePath), 'to the App Store using Xcode.', 'You can open the archive in Xcode by running', - 'open $archivePath', + 'open ${p.relative(archivePath)}', '''Make sure to uncheck "Manage Version and Build Number", or else shorebird will not work.''', ], ), @@ -488,20 +477,19 @@ flutter: }); test('creates unsigned release artifacts', () async { - final tempDir = setUpTempDir(); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.success.code)); + expect(exitCode, equals(ExitCode.success.code)); verify( () => codePushClientWrapper.createIosReleaseArtifacts( appId: appId, releaseId: release.id, - xcarchivePath: - any(named: 'xcarchivePath', that: endsWith('.xcarchive')), + xcarchivePath: any( + named: 'xcarchivePath', + that: endsWith('.xcarchive'), + ), runnerPath: any(named: 'runnerPath', that: endsWith('Runner.app')), isCodesigned: false, ), @@ -512,18 +500,16 @@ flutter: group('when both export-method and export-options-plist are provided', () { setUp(() { when(() => argResults.wasParsed(exportMethodArgName)).thenReturn(true); - when(() => argResults[exportOptionsPlistArgName]) - .thenReturn('/path/to/export.plist'); + when( + () => argResults[exportOptionsPlistArgName], + ).thenReturn('/path/to/export.plist'); }); test('logs error and exits with usage code', () async { - final tempDir = setUpTempDir(); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.usage.code)); + expect(exitCode, equals(ExitCode.usage.code)); verify( () => logger.err( 'Cannot specify both --export-method and --export-options-plist.', @@ -542,11 +528,8 @@ flutter: test('generates an export options plist with that export method', () async { - final tempDir = setUpTempDir(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + await runWithOverrides(command.run); final capturedArgs = verify( () => shorebirdProcess.run( @@ -578,13 +561,10 @@ flutter: }); test('exits with usage code', () async { - final tempDir = setUpTempDir(); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.usage.code)); + expect(exitCode, equals(ExitCode.usage.code)); verify( () => logger.err( 'Exception: Export options plist file /does/not/exist does not exist', @@ -604,18 +584,16 @@ flutter: '''; test('exits with usage code', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); final exportPlistFile = File( - p.join(tempDir.path, 'export.plist'), + p.join(projectRoot.path, 'export.plist'), )..writeAsStringSync(exportPlistContent); - when(() => argResults[exportOptionsPlistArgName]) - .thenReturn(exportPlistFile.path); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + when( + () => argResults[exportOptionsPlistArgName], + ).thenReturn(exportPlistFile.path); + final exitCode = await runWithOverrides(command.run); - expect(result, equals(ExitCode.usage.code)); + expect(exitCode, equals(ExitCode.usage.code)); verify( () => logger.err( '''Exception: Export options plist ${exportPlistFile.path} does not set manageAppVersionAndBuildNumber to false. This is required for shorebird to work.''', @@ -634,11 +612,8 @@ flutter: test('generates an export options plist with app-store export method', () async { - final tempDir = setUpTempDir(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + await runWithOverrides(command.run); final capturedArgs = verify( () => shorebirdProcess.run( @@ -667,11 +642,8 @@ flutter: when(() => flutterBuildProcessResult.exitCode).thenReturn(1); when(() => flutterBuildProcessResult.stderr).thenReturn('oops'); - final tempDir = setUpTempDir(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -697,11 +669,8 @@ error: exportArchive: Communication with Apple failed error: exportArchive: No signing certificate "iOS Distribution" found '''); - final tempDir = setUpTempDir(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -718,10 +687,10 @@ error: exportArchive: No signing certificate "iOS Distribution" found test('exits with code 70 when release version cannot be determined', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); final file = File( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -731,10 +700,7 @@ error: exportArchive: No signing certificate "iOS Distribution" found ) ..createSync(recursive: true) ..writeAsStringSync(emptyPlistContent); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -747,12 +713,9 @@ error: exportArchive: No signing certificate "iOS Distribution" found test('aborts when user opts out', () async { when(() => logger.confirm(any())).thenReturn(false); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.info('Aborting.')).called(1); @@ -769,10 +732,10 @@ error: exportArchive: No signing certificate "iOS Distribution" found }); test('exits with code 70 if Info.plist does not exist', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); final infoPlistFile = File( p.join( - tempDir.path, + projectRoot.path, 'build', 'ios', 'archive', @@ -781,10 +744,7 @@ error: exportArchive: No signing certificate "iOS Distribution" found ), )..deleteSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -793,28 +753,22 @@ error: exportArchive: No signing certificate "iOS Distribution" found }); test('exits with code 70 if build directory does not exist', () async { - final tempDir = setUpTempDir(); - Directory(p.join(tempDir.path, 'build')).deleteSync(recursive: true); + setUpProjectRoot(); + Directory(p.join(projectRoot.path, 'build')).deleteSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify(() => logger.err('Unable to find .xcarchive directory')).called(1); }); test('exits with code 70 if ipa build directory does not exist', () async { - final tempDir = setUpTempDir(); - final ipaDirectory = - Directory(p.join(tempDir.path, 'build', 'ios', 'ipa')) - ..deleteSync(recursive: true); + setUpProjectRoot(); + final ipaDirectory = Directory( + p.join(projectRoot.path, 'build', 'ios', 'ipa'), + )..deleteSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -832,13 +786,10 @@ error: exportArchive: No signing certificate "iOS Distribution" found }); test('exits with code 70 if ipa file does not exist', () async { - final tempDir = setUpTempDir(); - File(p.join(tempDir.path, ipaPath)).deleteSync(recursive: true); + setUpProjectRoot(); + File(p.join(projectRoot.path, ipaPath)).deleteSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -855,14 +806,12 @@ error: exportArchive: No signing certificate "iOS Distribution" found }); test('exits with code 70 if more than one ipa file is found', () async { - final tempDir = setUpTempDir(); - File(p.join(tempDir.path, 'build/ios/ipa/Runner2.ipa')) - .createSync(recursive: true); + setUpProjectRoot(); + File( + p.join(projectRoot.path, 'build/ios/ipa/Runner2.ipa'), + ).createSync(recursive: true); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -883,12 +832,9 @@ error: exportArchive: No signing certificate "iOS Distribution" found 'when --release-version and --force are used', () async { when(() => argResults['force']).thenReturn(true); when(() => argResults['release-version']).thenReturn(version); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); verify(() => logger.success('\n✅ Published Release!')).called(1); expect(exitCode, ExitCode.success.code); @@ -906,12 +852,9 @@ error: exportArchive: No signing certificate "iOS Distribution" found }); test('succeeds when release is successful', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); verify(() => logger.success('\n✅ Published Release!')).called(1); verify( @@ -949,12 +892,9 @@ error: exportArchive: No signing certificate "iOS Distribution" found test('runs flutter pub get with system flutter after successful build', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( @@ -973,18 +913,15 @@ error: exportArchive: No signing certificate "iOS Distribution" found final target = p.join('lib', 'main_development.dart'); when(() => argResults['flavor']).thenReturn(flavor); when(() => argResults['target']).thenReturn(target); - final tempDir = setUpTempDir(); + setUpProjectRoot(); File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync(''' app_id: productionAppId flavors: development: $appId'''); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); verify(() => logger.success('\n✅ Published Release!')).called(1); verify( @@ -1020,12 +957,9 @@ flavors: releaseVersion: any(named: 'releaseVersion'), ), ).thenAnswer((_) async => release); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verifyNever( @@ -1058,12 +992,9 @@ flavors: test('provides appropriate ExportOptions.plist to build ipa command', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); final capturedArgs = verify( @@ -1093,12 +1024,9 @@ flavors: test('does not provide export options when codesign is false', () async { when(() => argResults['codesign']).thenReturn(false); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); final capturedArgs = verify( () => shorebirdProcess.run( @@ -1117,12 +1045,9 @@ flavors: test('does not prompt if running on CI', () async { when(() => shorebirdEnv.isRunningOnCI).thenReturn(true); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.success.code)); verifyNever(() => logger.confirm(any())); diff --git a/packages/shorebird_cli/test/src/commands/release/release_ios_framework_command_test.dart b/packages/shorebird_cli/test/src/commands/release/release_ios_framework_command_test.dart index e39f0aaf..bb159054 100644 --- a/packages/shorebird_cli/test/src/commands/release/release_ios_framework_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/release/release_ios_framework_command_test.dart @@ -63,6 +63,7 @@ flutter: late ArgResults argResults; late CodePushClientWrapper codePushClientWrapper; late Directory shorebirdRoot; + late Directory projectRoot; late Doctor doctor; late Platform platform; late Auth auth; @@ -94,15 +95,13 @@ flutter: ); } - Directory setUpTempDir() { - final tempDir = Directory.systemTemp.createTempSync(); + void setUpProjectRoot() { File( - p.join(tempDir.path, 'pubspec.yaml'), + p.join(projectRoot.path, 'pubspec.yaml'), ).writeAsStringSync(pubspecYamlContent); File( - p.join(tempDir.path, 'shorebird.yaml'), + p.join(projectRoot.path, 'shorebird.yaml'), ).writeAsStringSync('app_id: $appId'); - return tempDir; } setUpAll(() { @@ -119,6 +118,7 @@ flutter: doctor = MockDoctor(); platform = MockPlatform(); shorebirdRoot = Directory.systemTemp.createTempSync(); + projectRoot = Directory.systemTemp.createTempSync(); auth = MockAuth(); progress = MockProgress(); logger = MockLogger(); @@ -132,6 +132,9 @@ flutter: when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml); when(() => shorebirdEnv.shorebirdRoot).thenReturn(shorebirdRoot); + when( + () => shorebirdEnv.getShorebirdProjectRoot(), + ).thenReturn(projectRoot); when(() => shorebirdEnv.flutterRevision).thenReturn(flutterRevision); when( () => shorebirdProcess.run( @@ -247,11 +250,8 @@ flutter: when(() => flutterBuildProcessResult.exitCode).thenReturn(1); when(() => flutterBuildProcessResult.stderr).thenReturn('oops'); - final tempDir = setUpTempDir(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + setUpProjectRoot(); + final exitCode = await runWithOverrides(command.run); expect(exitCode, equals(ExitCode.software.code)); verify( @@ -266,12 +266,9 @@ flutter: releaseVersion: any(named: 'releaseVersion'), ), ).thenAnswer((_) async => release); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => codePushClientWrapper.ensureReleaseIsNotActive( @@ -283,12 +280,9 @@ flutter: test('aborts when user opts out', () async { when(() => logger.confirm(any())).thenReturn(false); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); expect(exitCode, ExitCode.success.code); verify(() => logger.info('Aborting.')).called(1); @@ -296,8 +290,10 @@ flutter: () => codePushClientWrapper.createIosReleaseArtifacts( appId: appId, releaseId: release.id, - xcarchivePath: - any(named: 'xcarchivePath', that: endsWith('.xcarchive')), + xcarchivePath: any( + named: 'xcarchivePath', + that: endsWith('.xcarchive'), + ), runnerPath: any(named: 'runnerPath', that: endsWith('Runner.app')), isCodesigned: any(named: 'isCodesigned'), ), @@ -309,12 +305,9 @@ flutter: 'when --release-version and --force are used', () async { when(() => argResults['force']).thenReturn(true); when(() => argResults['release-version']).thenReturn(version); - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); verify(() => logger.success('\n✅ Published Release!')).called(1); expect(exitCode, ExitCode.success.code); @@ -332,12 +325,9 @@ flutter: }); test('succeeds when release is successful', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); - final exitCode = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); verify(() => logger.success('\n✅ Published Release!')).called(1); verify( @@ -378,12 +368,9 @@ flutter: test('runs flutter pub get with system flutter after successful build', () async { - final tempDir = setUpTempDir(); + setUpProjectRoot(); - await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + await runWithOverrides(command.run); verify( () => shorebirdProcess.run( 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 52c90620..2989c0ea 100644 --- a/packages/shorebird_cli/test/src/commands/run_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/run_command_test.dart @@ -114,13 +114,11 @@ Please use "shorebird preview" instead.'''), }); test('exits with code when running the app fails', () async { - final tempDir = Directory.systemTemp.createTempSync(); - final progress = MockProgress(); when(() => logger.progress(any())).thenReturn(progress); const error = 'oops something went wrong'; - const exitCode = 1; + const expectedExitCode = 1; when( () => process.stdout, ).thenAnswer((_) => const Stream.empty()); @@ -128,20 +126,15 @@ Please use "shorebird preview" instead.'''), when(() => process.stderr).thenAnswer( (_) => Stream.value(utf8.encode(error)), ); - when(() => process.exitCode).thenAnswer((_) async => exitCode); + when(() => process.exitCode).thenAnswer((_) async => expectedExitCode); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - await expectLater(result, equals(exitCode)); + await expectLater(exitCode, equals(expectedExitCode)); verify(() => logger.err(error)).called(1); }); test('exits with code 0 when running the app succeeds', () async { - final tempDir = Directory.systemTemp.createTempSync(); - final progress = MockProgress(); when(() => logger.progress(any())).thenReturn(progress); @@ -155,19 +148,14 @@ Please use "shorebird preview" instead.'''), () => process.exitCode, ).thenAnswer((_) async => ExitCode.success.code); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); - await expectLater(result, equals(ExitCode.success.code)); + await expectLater(exitCode, equals(ExitCode.success.code)); verify(() => logger.info(output)).called(1); verify(() => ioSink.addStream(any())).called(1); }); test('passes additional args when specified', () async { - final tempDir = Directory.systemTemp.createTempSync(); - final progress = MockProgress(); when(() => logger.progress(any())).thenReturn(progress); @@ -187,10 +175,7 @@ Please use "shorebird preview" instead.'''), () => process.exitCode, ).thenAnswer((_) async => ExitCode.success.code); - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); + final exitCode = await runWithOverrides(command.run); final args = verify( () => shorebirdProcess.start( @@ -212,7 +197,7 @@ Please use "shorebird preview" instead.'''), ]), ); - await expectLater(result, equals(ExitCode.success.code)); + await expectLater(exitCode, equals(ExitCode.success.code)); }); }); } diff --git a/packages/shorebird_cli/test/src/mocks.dart b/packages/shorebird_cli/test/src/mocks.dart index 7ecf5589..cd0264d1 100644 --- a/packages/shorebird_cli/test/src/mocks.dart +++ b/packages/shorebird_cli/test/src/mocks.dart @@ -60,6 +60,8 @@ class MockCodePushClientWrapper extends Mock implements CodePushClientWrapper {} class MockDevicectl extends Mock implements Devicectl {} +class MockDirectory extends Mock implements Directory {} + class MockDoctor extends Mock implements Doctor {} class MockFile extends Mock implements File {} diff --git a/packages/shorebird_cli/test/src/shorebird_env_test.dart b/packages/shorebird_cli/test/src/shorebird_env_test.dart index 32c920f3..4b662bb9 100644 --- a/packages/shorebird_cli/test/src/shorebird_env_test.dart +++ b/packages/shorebird_cli/test/src/shorebird_env_test.dart @@ -45,6 +45,103 @@ void main() { when(() => platform.script).thenReturn(platformScript); }); + group('getShorebirdYamlFile', () { + test('returns correct file', () { + final tempDir = Directory.systemTemp.createTempSync(); + expect( + runWithOverrides( + () => shorebirdEnv.getShorebirdYamlFile(cwd: tempDir).path, + ), + equals(p.join(tempDir.path, 'shorebird.yaml')), + ); + }); + }); + + group('getFlutterProjectRoot', () { + test('returns null when no Flutter project exists', () { + final tempDir = Directory.systemTemp.createTempSync(); + expect( + IOOverrides.runZoned( + () => runWithOverrides(() => shorebirdEnv.getFlutterProjectRoot()), + getCurrentDirectory: () => tempDir, + ), + isNull, + ); + }); + + test('returns correct directory when Flutter project exists (root)', () { + final tempDir = Directory.systemTemp.createTempSync(); + File(p.join(tempDir.path, 'pubspec.yaml')).createSync(recursive: true); + final projectRoot = IOOverrides.runZoned( + () => runWithOverrides( + () => shorebirdEnv.getFlutterProjectRoot(), + ), + getCurrentDirectory: () => tempDir, + ); + expect(projectRoot!.path, equals(tempDir.path)); + }); + + test('returns correct directory when Flutter project exists (nested)', + () { + final tempDir = Directory.systemTemp.createTempSync(); + final nestedDir = Directory(p.join(tempDir.path, 'nested')); + File(p.join(tempDir.path, 'pubspec.yaml')).createSync(recursive: true); + final projectRoot = IOOverrides.runZoned( + () => runWithOverrides( + () => shorebirdEnv.getFlutterProjectRoot(), + ), + getCurrentDirectory: () => nestedDir, + ); + expect(projectRoot!.path, equals(tempDir.path)); + }); + }); + + group('getShorebirdProjectRoot', () { + test('returns null when no Shorebird project exists', () { + final tempDir = Directory.systemTemp.createTempSync(); + expect( + IOOverrides.runZoned( + () => runWithOverrides( + () => shorebirdEnv.getShorebirdProjectRoot(), + ), + getCurrentDirectory: () => tempDir, + ), + isNull, + ); + }); + + test('returns correct directory when Shorebird project exists (root)', + () { + final tempDir = Directory.systemTemp.createTempSync(); + File( + p.join(tempDir.path, 'shorebird.yaml'), + ).createSync(recursive: true); + final projectRoot = IOOverrides.runZoned( + () => runWithOverrides( + () => shorebirdEnv.getShorebirdProjectRoot(), + ), + getCurrentDirectory: () => tempDir, + ); + expect(projectRoot!.path, equals(tempDir.path)); + }); + + test('returns correct directory when Flutter project exists (nested)', + () { + final tempDir = Directory.systemTemp.createTempSync(); + final nestedDir = Directory(p.join(tempDir.path, 'nested')); + File( + p.join(tempDir.path, 'shorebird.yaml'), + ).createSync(recursive: true); + final projectRoot = IOOverrides.runZoned( + () => runWithOverrides( + () => shorebirdEnv.getShorebirdProjectRoot(), + ), + getCurrentDirectory: () => nestedDir, + ); + expect(projectRoot!.path, equals(tempDir.path)); + }); + }); + group('flutterBinaryFile', () { test('returns correct path', () { expect( @@ -89,15 +186,10 @@ void main() { group('getPubspecYamlFile', () { test('returns correct file', () { - final tempDir = Directory('temp'); + final tempDir = Directory.systemTemp.createTempSync(); expect( - IOOverrides.runZoned( - () { - return runWithOverrides( - () => shorebirdEnv.getPubspecYamlFile().path, - ); - }, - getCurrentDirectory: () => tempDir, + runWithOverrides( + () => shorebirdEnv.getPubspecYamlFile(cwd: tempDir).path, ), equals(p.join(tempDir.path, 'pubspec.yaml')), ); @@ -106,7 +198,7 @@ void main() { group('getPubspecYaml', () { test('returns null when pubspec.yaml does not exist', () { - final tempDir = Directory('temp'); + final tempDir = Directory.systemTemp.createTempSync(); expect( IOOverrides.runZoned( () => runWithOverrides(() => shorebirdEnv.getPubspecYaml()), @@ -133,7 +225,7 @@ void main() { group('hasPubspecYaml', () { test('returns false when pubspec.yaml does not exist', () { - final tempDir = Directory('temp'); + final tempDir = Directory.systemTemp.createTempSync(); expect( IOOverrides.runZoned( () => runWithOverrides(() => shorebirdEnv.hasPubspecYaml), diff --git a/packages/shorebird_cli/test/src/validators/android_internet_permission_validator_test.dart b/packages/shorebird_cli/test/src/validators/android_internet_permission_validator_test.dart index 92c6c94f..14359a06 100644 --- a/packages/shorebird_cli/test/src/validators/android_internet_permission_validator_test.dart +++ b/packages/shorebird_cli/test/src/validators/android_internet_permission_validator_test.dart @@ -1,9 +1,14 @@ import 'dart:io'; +import 'package:mocktail/mocktail.dart'; import 'package:path/path.dart' as p; +import 'package:scoped/scoped.dart'; +import 'package:shorebird_cli/src/shorebird_env.dart'; import 'package:shorebird_cli/src/validators/validators.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { const manifestWithInternetPermission = ''' Directory.systemTemp.createTempSync(); + late Directory projectRoot; + late ShorebirdEnv shorebirdEnv; void writeManifestToPath(String manifestContents, String path) { Directory(path).createSync(recursive: true); - File(p.join(path, 'AndroidManifest.xml')) - .writeAsStringSync(manifestContents); + File( + p.join(path, 'AndroidManifest.xml'), + ).writeAsStringSync(manifestContents); } + R runWithOverrides(R Function() body) { + return runScoped( + body, + values: { + shorebirdEnvRef.overrideWith(() => shorebirdEnv), + }, + ); + } + + setUp(() { + projectRoot = Directory.systemTemp.createTempSync(); + shorebirdEnv = MockShorebirdEnv(); + + when(() => shorebirdEnv.getFlutterProjectRoot()).thenReturn(projectRoot); + }); + test('has a non-empty description', () { expect(AndroidInternetPermissionValidator().description, isNotEmpty); }); group('canRunInContext', () { test('returns false if no android src directory exists', () { - final tempDirectory = createTempDir(); - - final result = IOOverrides.runZoned( + final result = runWithOverrides( () => AndroidInternetPermissionValidator().canRunInCurrentContext(), - getCurrentDirectory: () => tempDirectory, ); expect(result, isFalse); }); test('returns true if an android src directory exists', () { - final tempDirectory = createTempDir(); writeManifestToPath( manifestWithInternetPermission, - p.join(tempDirectory.path, 'android', 'app', 'src', 'main'), + p.join(projectRoot.path, 'android', 'app', 'src', 'main'), ); - final result = IOOverrides.runZoned( + final result = runWithOverrides( () => AndroidInternetPermissionValidator().canRunInCurrentContext(), - getCurrentDirectory: () => tempDirectory, ); expect(result, isTrue); @@ -76,15 +94,13 @@ void main() { test( '''returns successful result if the main AndroidManifest.xml file has the INTERNET permission''', () async { - final tempDirectory = createTempDir(); writeManifestToPath( manifestWithInternetPermission, - p.join(tempDirectory.path, 'android', 'app', 'src', 'main'), + p.join(projectRoot.path, 'android', 'app', 'src', 'main'), ); - final results = await IOOverrides.runZoned( + final results = await runWithOverrides( AndroidInternetPermissionValidator().validate, - getCurrentDirectory: () => tempDirectory, ); expect(results.map((res) => res.severity), isEmpty); @@ -93,13 +109,12 @@ void main() { test('returns an error if AndroidManifest.xml file does not exist', () async { - final tempDirectory = createTempDir(); - Directory(p.join(tempDirectory.path, 'android', 'app', 'src', 'main')) - .createSync(recursive: true); + Directory( + p.join(projectRoot.path, 'android', 'app', 'src', 'main'), + ).createSync(recursive: true); - final results = await IOOverrides.runZoned( + final results = await runWithOverrides( AndroidInternetPermissionValidator().validate, - getCurrentDirectory: () => tempDirectory, ); expect(results, hasLength(1)); @@ -113,18 +128,21 @@ void main() { group('when the INTERNET permission is commented out', () { test('returns error', () async { - final tempDirectory = createTempDir(); - final manifestPath = - p.join(tempDirectory.path, 'android', 'app', 'src', 'main'); + final manifestPath = p.join( + projectRoot.path, + 'android', + 'app', + 'src', + 'main', + ); writeManifestToPath( manifestWithCommentedOutInternetPermission, manifestPath, ); - final results = await IOOverrides.runZoned( + final results = await runWithOverrides( AndroidInternetPermissionValidator().validate, - getCurrentDirectory: () => tempDirectory, ); expect(results, hasLength(1)); @@ -143,15 +161,18 @@ void main() { group('when the INTERNET permission is missing', () { test('returns error', () async { - final tempDirectory = createTempDir(); - final manifestPath = - p.join(tempDirectory.path, 'android', 'app', 'src', 'main'); + final manifestPath = p.join( + projectRoot.path, + 'android', + 'app', + 'src', + 'main', + ); writeManifestToPath(manifestWithNoPermissions, manifestPath); - final results = await IOOverrides.runZoned( + final results = await runWithOverrides( AndroidInternetPermissionValidator().validate, - getCurrentDirectory: () => tempDirectory, ); expect(results, hasLength(1)); @@ -170,18 +191,21 @@ void main() { group('when manifest has non-INTERNET permissions', () { test('returns error', () async { - final tempDirectory = createTempDir(); - final manifestPath = - p.join(tempDirectory.path, 'android', 'app', 'src', 'main'); + final manifestPath = p.join( + projectRoot.path, + 'android', + 'app', + 'src', + 'main', + ); writeManifestToPath( manifestWithNonInternetPermissions, manifestPath, ); - final results = await IOOverrides.runZoned( + final results = await runWithOverrides( AndroidInternetPermissionValidator().validate, - getCurrentDirectory: () => tempDirectory, ); expect(results, hasLength(1)); @@ -200,27 +224,21 @@ void main() { group('fix', () { test('adds permission to manifest file', () async { - final tempDirectory = createTempDir(); writeManifestToPath( manifestWithNonInternetPermissions, - p.join(tempDirectory.path, 'android', 'app', 'src', 'main'), + p.join(projectRoot.path, 'android', 'app', 'src', 'main'), ); - var results = await IOOverrides.runZoned( + var results = await runWithOverrides( AndroidInternetPermissionValidator().validate, - getCurrentDirectory: () => tempDirectory, ); expect(results, hasLength(1)); expect(results.first.fix, isNotNull); - await IOOverrides.runZoned( - () => results.first.fix!(), - getCurrentDirectory: () => tempDirectory, - ); + await runWithOverrides(() => results.first.fix!()); - results = await IOOverrides.runZoned( + results = await runWithOverrides( AndroidInternetPermissionValidator().validate, - getCurrentDirectory: () => tempDirectory, ); expect(results, isEmpty); });