Unverified Commit bc38ac07 authored by flutteractionsbot's avatar flutteractionsbot Committed by GitHub

[CP-beta] Increase the recommended Xcode version to Xcode 15 (#146440)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

Part of https://github.com/flutter/flutter/issues/144582#issuecomment-2040653877

### Changelog Description:
Increase the `flutter doctor` recommended Xcode version to Xcode 15.

### Impact Description:

Update the `flutter doctor` validator to suggest Xcode 15 if installed version is lower.

This is to encourage upgrades, as Apple will soon be enforcing this during iOS App Store submissions.
> Please note that as of April 2024 all iOS and iPadOS apps submitted to the App Store must be built with a minimum of Xcode 15 and the iOS 17 SDK.

https://developer.apple.com/ios/submit/

It's also to encourage updates before Swift Package Manager requires this version in https://github.com/flutter/flutter/pull/146256.

### Workaround:
N/A

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
Install and `xcode-select` Xcode 14.x or lower.  Run `flutter doctor`.  See 
```
[!] Xcode - develop for iOS and macOS (Xcode 15.3)
    ✗ Flutter requires Xcode 14 or higher.
      Download the latest version or update via the Mac App Store.
```
parent fa0a4c04
...@@ -24,7 +24,7 @@ Version get xcodeRequiredVersion => Version(14, null, null); ...@@ -24,7 +24,7 @@ Version get xcodeRequiredVersion => Version(14, null, null);
/// Diverging this number from the minimum required version will provide a doctor /// Diverging this number from the minimum required version will provide a doctor
/// warning, not error, that users should upgrade Xcode. /// warning, not error, that users should upgrade Xcode.
Version get xcodeRecommendedVersion => xcodeRequiredVersion; Version get xcodeRecommendedVersion => Version(15, null, null);
/// SDK name passed to `xcrun --sdk`. Corresponds to undocumented Xcode /// SDK name passed to `xcrun --sdk`. Corresponds to undocumented Xcode
/// SUPPORTED_PLATFORMS values. /// SUPPORTED_PLATFORMS values.
......
...@@ -312,12 +312,12 @@ void main() { ...@@ -312,12 +312,12 @@ void main() {
expect(xcode.isRecommendedVersionSatisfactory, isFalse); expect(xcode.isRecommendedVersionSatisfactory, isFalse);
}); });
testWithoutContext('version checks pass when version meets minimum', () { testWithoutContext('version checks pass when version meets minimum but not recommended', () {
xcodeProjectInterpreter.isInstalled = true; xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(14, null, null); xcodeProjectInterpreter.version = Version(14, null, null);
expect(xcode.isRequiredVersionSatisfactory, isTrue); expect(xcode.isRequiredVersionSatisfactory, isTrue);
expect(xcode.isRecommendedVersionSatisfactory, isTrue); expect(xcode.isRecommendedVersionSatisfactory, isFalse);
}); });
testWithoutContext('version checks pass when major version exceeds minimum', () { testWithoutContext('version checks pass when major version exceeds minimum', () {
...@@ -325,7 +325,6 @@ void main() { ...@@ -325,7 +325,6 @@ void main() {
xcodeProjectInterpreter.version = Version(15, 0, 0); xcodeProjectInterpreter.version = Version(15, 0, 0);
expect(xcode.isRequiredVersionSatisfactory, isTrue); expect(xcode.isRequiredVersionSatisfactory, isTrue);
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
}); });
testWithoutContext('version checks pass when minor version exceeds minimum', () { testWithoutContext('version checks pass when minor version exceeds minimum', () {
...@@ -333,13 +332,35 @@ void main() { ...@@ -333,13 +332,35 @@ void main() {
xcodeProjectInterpreter.version = Version(14, 3, 0); xcodeProjectInterpreter.version = Version(14, 3, 0);
expect(xcode.isRequiredVersionSatisfactory, isTrue); expect(xcode.isRequiredVersionSatisfactory, isTrue);
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
}); });
testWithoutContext('version checks pass when patch version exceeds minimum', () { testWithoutContext('version checks pass when patch version exceeds minimum', () {
xcodeProjectInterpreter.isInstalled = true; xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(14, 0, 2); xcodeProjectInterpreter.version = Version(14, 0, 2);
expect(xcode.isRequiredVersionSatisfactory, isTrue);
});
testWithoutContext('version checks pass when major version exceeds recommendation', () {
xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(16, 0, 0);
expect(xcode.isRequiredVersionSatisfactory, isTrue);
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
});
testWithoutContext('version checks pass when minor version exceeds recommendation', () {
xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(15, 3, 0);
expect(xcode.isRequiredVersionSatisfactory, isTrue);
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
});
testWithoutContext('version checks pass when patch version exceeds recommendation', () {
xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(15, 0, 2);
expect(xcode.isRequiredVersionSatisfactory, isTrue); expect(xcode.isRequiredVersionSatisfactory, isTrue);
expect(xcode.isRecommendedVersionSatisfactory, isTrue); expect(xcode.isRecommendedVersionSatisfactory, isTrue);
}); });
......
...@@ -77,7 +77,7 @@ void main() { ...@@ -77,7 +77,7 @@ void main() {
final ProcessManager processManager = FakeProcessManager.any(); final ProcessManager processManager = FakeProcessManager.any();
final Xcode xcode = Xcode.test( final Xcode xcode = Xcode.test(
processManager: processManager, processManager: processManager,
xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: Version(12, 4, null)), xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: Version(14, 4, null)),
); );
final XcodeValidator validator = XcodeValidator( final XcodeValidator validator = XcodeValidator(
xcode: xcode, xcode: xcode,
...@@ -87,8 +87,8 @@ void main() { ...@@ -87,8 +87,8 @@ void main() {
final ValidationResult result = await validator.validate(); final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.partial); expect(result.type, ValidationType.partial);
expect(result.messages.last.type, ValidationMessageType.hint); expect(result.messages.last.type, ValidationMessageType.hint);
expect(result.messages.last.message, contains('Flutter recommends a minimum Xcode version of 13')); expect(result.messages.last.message, contains('Flutter recommends a minimum Xcode version of 15'));
}, skip: true); // [intended] Unskip and update when minimum and required check versions diverge. }, skip: false); // [intended] Skip this test when minimum and required check versions converge.
testWithoutContext('Emits partial status when Xcode EULA not signed', () async { testWithoutContext('Emits partial status when Xcode EULA not signed', () async {
final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment