chore(shorebird_cli): don't allow iOS releases to be created with Flutter < 3.19.5 (#1864)

This commit is contained in:
Bryan Oltman
2024-04-04 14:45:30 -04:00
committed by GitHub
parent a1137c2b44
commit cbbe2ceda9
8 changed files with 58 additions and 203 deletions
@@ -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(
@@ -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(
@@ -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);
@@ -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<List<ValidationIssue>> validate() async {
final issues = <ValidationIssue>[];
// 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;
}
}
@@ -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';
@@ -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(
@@ -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(
@@ -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>(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);
});
});
});
});
}