From cbbe2ceda91cbf9c356276dcc037a842ef27064b Mon Sep 17 00:00:00 2001 From: Bryan Oltman Date: Thu, 4 Apr 2024 14:45:30 -0400 Subject: [PATCH] chore(shorebird_cli): don't allow iOS releases to be created with Flutter < 3.19.5 (#1864) --- .../commands/release/release_ios_command.dart | 16 ++- .../release_ios_framework_command.dart | 15 ++- .../shorebird_cli/lib/src/platform/ios.dart | 4 + ...lutter_version_supports_ios_validator.dart | 67 ---------- .../lib/src/validators/validators.dart | 1 - .../release/release_ios_command_test.dart | 18 ++- .../release_ios_framework_command_test.dart | 18 ++- ...r_version_supports_ios_validator_test.dart | 122 ------------------ 8 files changed, 58 insertions(+), 203 deletions(-) delete mode 100644 packages/shorebird_cli/lib/src/validators/shorebird_flutter_version_supports_ios_validator.dart delete mode 100644 packages/shorebird_cli/test/src/validators/shorebird_flutter_version_supports_ios_validator_test.dart diff --git a/packages/shorebird_cli/lib/src/commands/release/release_ios_command.dart b/packages/shorebird_cli/lib/src/commands/release/release_ios_command.dart index 93a7e07a..ce632b36 100644 --- a/packages/shorebird_cli/lib/src/commands/release/release_ios_command.dart +++ b/packages/shorebird_cli/lib/src/commands/release/release_ios_command.dart @@ -3,6 +3,7 @@ import 'dart:io' hide Platform; import 'package:mason_logger/mason_logger.dart'; import 'package:path/path.dart' as p; import 'package:platform/platform.dart'; +import 'package:pub_semver/pub_semver.dart'; import 'package:scoped/scoped.dart'; import 'package:shorebird_cli/src/archive_analysis/archive_analysis.dart'; import 'package:shorebird_cli/src/code_push_client_wrapper.dart'; @@ -20,7 +21,6 @@ import 'package:shorebird_cli/src/shorebird_build_mixin.dart'; import 'package:shorebird_cli/src/shorebird_env.dart'; import 'package:shorebird_cli/src/shorebird_flutter.dart'; import 'package:shorebird_cli/src/shorebird_validator.dart'; -import 'package:shorebird_cli/src/validators/validators.dart'; import 'package:shorebird_cli/src/version.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; @@ -59,7 +59,7 @@ class ReleaseIosCommand extends ShorebirdCommand ) ..addOption( 'flutter-version', - help: 'The Flutter version to use when building the app (e.g: 3.16.3).', + help: 'The Flutter version to use when building the app (e.g: 3.19.5).', ) ..addFlag( 'codesign', @@ -93,10 +93,7 @@ make smaller updates to your app. await shorebirdValidator.validatePreconditions( checkUserIsAuthenticated: true, checkShorebirdInitialized: true, - validators: [ - ...doctor.iosCommandValidators, - ShorebirdFlutterVersionSupportsIOSValidator(), - ], + validators: doctor.iosCommandValidators, supportedOperatingSystems: {Platform.macOS}, ); } on PreconditionFailedException catch (e) { @@ -154,6 +151,13 @@ make smaller updates to your app. var flutterRevisionForRelease = shorebirdEnv.flutterRevision; if (flutterVersion != null) { + if (Version.parse(flutterVersion) < minimumSupportedIosFlutterVersion) { + logger.err( + '''iOS releases are not supported with Flutter versions older than $minimumSupportedIosFlutterVersion.''', + ); + return ExitCode.usage.code; + } + final String? revision; try { revision = await shorebirdFlutter.getRevisionForVersion( diff --git a/packages/shorebird_cli/lib/src/commands/release/release_ios_framework_command.dart b/packages/shorebird_cli/lib/src/commands/release/release_ios_framework_command.dart index 5c116c19..c3c872a7 100644 --- a/packages/shorebird_cli/lib/src/commands/release/release_ios_framework_command.dart +++ b/packages/shorebird_cli/lib/src/commands/release/release_ios_framework_command.dart @@ -4,6 +4,7 @@ import 'package:io/io.dart' show copyPath; import 'package:mason_logger/mason_logger.dart'; import 'package:path/path.dart' as p; import 'package:platform/platform.dart'; +import 'package:pub_semver/pub_semver.dart'; import 'package:scoped/scoped.dart'; import 'package:shorebird_cli/src/code_push_client_wrapper.dart'; import 'package:shorebird_cli/src/command.dart'; @@ -13,12 +14,12 @@ import 'package:shorebird_cli/src/doctor.dart'; import 'package:shorebird_cli/src/executables/xcodebuild.dart'; import 'package:shorebird_cli/src/logger.dart'; import 'package:shorebird_cli/src/platform.dart'; +import 'package:shorebird_cli/src/platform/ios.dart'; import 'package:shorebird_cli/src/shorebird_artifact_mixin.dart'; import 'package:shorebird_cli/src/shorebird_build_mixin.dart'; import 'package:shorebird_cli/src/shorebird_env.dart'; import 'package:shorebird_cli/src/shorebird_flutter.dart'; import 'package:shorebird_cli/src/shorebird_validator.dart'; -import 'package:shorebird_cli/src/validators/validators.dart'; import 'package:shorebird_cli/src/version.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; @@ -62,10 +63,7 @@ of the iOS app that is using this module.''', checkUserIsAuthenticated: true, checkShorebirdInitialized: true, supportedOperatingSystems: {Platform.macOS}, - validators: [ - ...doctor.iosCommandValidators, - ShorebirdFlutterVersionSupportsIOSValidator(), - ], + validators: doctor.iosCommandValidators, ); } on PreconditionFailedException catch (e) { return e.exitCode.code; @@ -99,6 +97,13 @@ of the iOS app that is using this module.''', var flutterRevisionForRelease = shorebirdEnv.flutterRevision; if (flutterVersion != null) { + if (Version.parse(flutterVersion) < minimumSupportedIosFlutterVersion) { + logger.err( + '''iOS releases are not supported with Flutter versions older than $minimumSupportedIosFlutterVersion.''', + ); + return ExitCode.usage.code; + } + final String? revision; try { revision = await shorebirdFlutter.getRevisionForVersion( diff --git a/packages/shorebird_cli/lib/src/platform/ios.dart b/packages/shorebird_cli/lib/src/platform/ios.dart index e9cf280d..bb97bc4f 100644 --- a/packages/shorebird_cli/lib/src/platform/ios.dart +++ b/packages/shorebird_cli/lib/src/platform/ios.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:args/args.dart'; import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import 'package:scoped/scoped.dart'; import 'package:shorebird_cli/src/archive_analysis/archive_analysis.dart'; @@ -48,6 +49,9 @@ class InvalidExportOptionsPlistException implements Exception { final String message; } +/// The minimum allowed Flutter version for creating iOS releases. +final minimumSupportedIosFlutterVersion = Version(3, 19, 5); + /// A reference to a [Ios] instance. final iosRef = create(Ios.new); diff --git a/packages/shorebird_cli/lib/src/validators/shorebird_flutter_version_supports_ios_validator.dart b/packages/shorebird_cli/lib/src/validators/shorebird_flutter_version_supports_ios_validator.dart deleted file mode 100644 index a6651d34..00000000 --- a/packages/shorebird_cli/lib/src/validators/shorebird_flutter_version_supports_ios_validator.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:mason_logger/mason_logger.dart'; -import 'package:pub_semver/pub_semver.dart'; -import 'package:shorebird_cli/src/shorebird_flutter.dart'; -import 'package:shorebird_cli/src/validators/validators.dart'; - -class ShorebirdFlutterVersionSupportsIOSValidator extends Validator { - ShorebirdFlutterVersionSupportsIOSValidator(); - - @override - String get description => 'Shorebird Flutter version supports iOS'; - - @override - Future> validate() async { - final issues = []; - - // TODO(eseidel): Share "parse version" logic with the - // ShorebirdFlutterValidator. - final flutterVersion = await shorebirdFlutter.getVersion(); - if (flutterVersion == null) { - issues.add( - const ValidationIssue( - severity: ValidationIssueSeverity.warning, - message: 'Unable to determine Shorebird Flutter version', - ), - ); - return issues; - } - - // Our new mixed-mode engine had crashes in our last release of 3.16.4 - // through several releases of 3.16.7. There are OK release of 3.16.7 - // but it's easier to just warn away from all of 3.16.7. - // We did not release 3.16.8 so we're recommending 3.16.9. - final firstBadFlutter = Version(3, 16, 4); - final lastBadFlutter = Version(3, 16, 7); - final recommendedFlutter = Version(3, 16, 9); - final useFlutterVersionCommand = lightCyan.wrap( - 'shorebird flutter versions use $recommendedFlutter', - ); - // This is a warning to encourage those patching older versions of Flutter - // to upgrade. - if (flutterVersion < firstBadFlutter) { - issues.add( - ValidationIssue( - severity: ValidationIssueSeverity.warning, - message: ''' -Shorebird iOS recommends Flutter $recommendedFlutter or later. -Run $useFlutterVersionCommand to upgrade. -''', - ), - ); - } - // This is an error to disallow known-bad versions of Flutter for iOS. - if (flutterVersion >= firstBadFlutter && flutterVersion <= lastBadFlutter) { - issues.add( - ValidationIssue( - severity: ValidationIssueSeverity.error, - message: ''' -Shorebird iOS does not support Flutter $flutterVersion. -Run $useFlutterVersionCommand to upgrade. -''', - ), - ); - } - - return issues; - } -} diff --git a/packages/shorebird_cli/lib/src/validators/validators.dart b/packages/shorebird_cli/lib/src/validators/validators.dart index 8c61220c..a9b101fb 100644 --- a/packages/shorebird_cli/lib/src/validators/validators.dart +++ b/packages/shorebird_cli/lib/src/validators/validators.dart @@ -6,7 +6,6 @@ import 'package:shorebird_cli/src/shorebird_process.dart'; export 'android_internet_permission_validator.dart'; export 'shorebird_flutter_validator.dart'; -export 'shorebird_flutter_version_supports_ios_validator.dart'; export 'shorebird_version_validator.dart'; export 'storage_access_validator.dart'; 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 74906f08..c4d44abd 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 @@ -583,7 +583,7 @@ flutter: }); group('when flutter-version is provided', () { - const flutterVersion = '3.16.3'; + const flutterVersion = '3.19.5'; setUp(() { when(() => argResults['flutter-version']).thenReturn(flutterVersion); }); @@ -609,6 +609,22 @@ $exception''', }); }); + group('when flutter version is too old', () { + setUp(() { + when(() => argResults['flutter-version']).thenReturn('3.16.3'); + }); + + test('prints error log and exits with code 64 (usage)', () async { + final exitCode = await runWithOverrides(command.run); + expect(exitCode, equals(ExitCode.usage.code)); + verify( + () => logger.err( + '''iOS releases are not supported with Flutter versions older than 3.19.5.''', + ), + ).called(1); + }); + }); + group('when flutter version is not supported', () { setUp(() { when( 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 2fe17a1a..d89aeb73 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 @@ -313,7 +313,7 @@ flutter: }); group('when flutter-version is provided', () { - const flutterVersion = '3.16.3'; + const flutterVersion = '3.19.5'; setUp(() { when(() => argResults['flutter-version']).thenReturn(flutterVersion); }); @@ -339,6 +339,22 @@ $exception''', }); }); + group('when flutter version is too old', () { + setUp(() { + when(() => argResults['flutter-version']).thenReturn('3.16.3'); + }); + + test('prints error log and exits with code 64 (usage)', () async { + final exitCode = await runWithOverrides(command.run); + expect(exitCode, equals(ExitCode.usage.code)); + verify( + () => logger.err( + '''iOS releases are not supported with Flutter versions older than 3.19.5.''', + ), + ).called(1); + }); + }); + group('when flutter version is not supported', () { setUp(() { when( diff --git a/packages/shorebird_cli/test/src/validators/shorebird_flutter_version_supports_ios_validator_test.dart b/packages/shorebird_cli/test/src/validators/shorebird_flutter_version_supports_ios_validator_test.dart deleted file mode 100644 index fd5bf0be..00000000 --- a/packages/shorebird_cli/test/src/validators/shorebird_flutter_version_supports_ios_validator_test.dart +++ /dev/null @@ -1,122 +0,0 @@ -import 'package:mason_logger/mason_logger.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:pub_semver/pub_semver.dart'; -import 'package:scoped/scoped.dart'; -import 'package:shorebird_cli/src/shorebird_flutter.dart'; -import 'package:shorebird_cli/src/validators/validators.dart'; -import 'package:test/test.dart'; - -import '../mocks.dart'; - -void main() { - group(ShorebirdFlutterVersionSupportsIOSValidator, () { - late ShorebirdFlutter shorebirdFlutter; - late ShorebirdFlutterVersionSupportsIOSValidator validator; - - R runWithOverrides(R Function() body) { - return runScoped( - () => body(), - values: { - shorebirdFlutterRef.overrideWith(() => shorebirdFlutter), - }, - ); - } - - setUp(() { - shorebirdFlutter = MockShorebirdFlutter(); - validator = ShorebirdFlutterVersionSupportsIOSValidator(); - }); - - test('has a non-empty description', () { - expect(validator.description, isNotEmpty); - }); - - group('when flutter version lookup fails', () { - setUp(() { - when(() => shorebirdFlutter.getVersion()).thenAnswer((_) async => null); - }); - - test('returns validation warning', () async { - final results = await runWithOverrides(validator.validate); - - expect( - results, - equals([ - const ValidationIssue( - severity: ValidationIssueSeverity.warning, - message: 'Unable to determine Shorebird Flutter version', - ), - ]), - ); - }); - }); - - group('when flutter version is before the first bad version', () { - setUp(() { - when( - () => shorebirdFlutter.getVersion(), - ).thenAnswer((_) async => Version(3, 16, 3)); - }); - - test('returns validation warning', () async { - final results = await runWithOverrides(validator.validate); - - expect( - results, - equals( - [ - ValidationIssue( - severity: ValidationIssueSeverity.warning, - message: ''' -Shorebird iOS recommends Flutter 3.16.9 or later. -Run ${lightCyan.wrap('shorebird flutter versions use 3.16.9')} to upgrade. -''', - ), - ], - ), - ); - }); - - group('when flutter version is in known bad range', () { - setUp(() { - when( - () => shorebirdFlutter.getVersion(), - ).thenAnswer((_) async => Version(3, 16, 7)); - }); - - test('returns validation warning', () async { - final results = await runWithOverrides(validator.validate); - - expect( - results, - equals( - [ - ValidationIssue( - severity: ValidationIssueSeverity.error, - message: ''' -Shorebird iOS does not support Flutter 3.16.7. -Run ${lightCyan.wrap('shorebird flutter versions use 3.16.9')} to upgrade. -''', - ), - ], - ), - ); - }); - }); - - group('when flutter version is above the last bad flutter version', () { - setUp(() { - when( - () => shorebirdFlutter.getVersion(), - ).thenAnswer((_) async => Version(3, 16, 10)); - }); - - test('returns no validation issues', () async { - final results = await runWithOverrides(validator.validate); - - expect(results, isEmpty); - }); - }); - }); - }); -}