Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .ci/targets/ios_platform_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ tasks:
script: .ci/scripts/tool_runner.sh
args: ["fetch-deps", "--ios", "--supporting-target-platforms-only"]
infra_step: true
- name: build examples
- name: build examples with CocoaPods integration

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to build-all twice; there's already some redundancy in the build-all app vs individual example builds. We use that redundancy to get x64/arm64 coverage already, and I would vote for doing the same thing here.

To do that we would remove this step, and only build-all with SPM. That gives us SPM build coverage of all plugin in this step, and CocoaPods coverage in all the example app builds. Then when the flag is removed or reversed, we switch build-all to force SPM off and reverse the coverage roles.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if I understand correctly, you're suggesting we update build-all (https://github.com/flutter/packages/blob/main/.ci/targets/ios_build_all_packages.yaml / https://github.com/flutter/packages/blob/main/.ci/scripts/build_all_packages_app.sh) to have SPM enabled so it builds all with SPM.

And then in platform tests (this file), only build with CocoaPods?

Just a reminder, native tests will need to be run with SPM enabled because CocoaPod testing dependencies will have been removed (see "Updating unit tests in plugin example app"), which will make native tests not be able to be run without SPM. But we can still do what you're suggesting and just add a new step to the yaml that enables SPM

- name: native test
script: .ci/scripts/tool_runner.sh
# Simulator name and version must match name and version in create_simulator.sh
args: ["native-test", "--ios", "--ios-destination", "platform=iOS Simulator,name=Flutter-iPhone,OS=17.0"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then in platform tests (this file), only build with CocoaPods?

Whoops, I was skimming and thought this was the build-all step. But yes, thanks for figuring out what I meant despite the confusing description.

Just a reminder, native tests will need to be run with SPM enabled because CocoaPod testing dependencies will have been removed

Right, I forgot about that.

I guess we could flip it around from the start, and do the SPM testing in-package, and the CocoaPod testing only in build-all (and, until the flag reaches stable, in stable post-submit). The reason I was thinking we should start the other way is that we could potentially break the example app for people who don't have the flag enabled without noticing if we only tested SPM in-package, but the impact of that if it happens is extremely small, so probably not worth worrying about unless it actually starts happening in practice.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I was thinking we should start the other way is that we could potentially break the example app for people who don't have the flag enabled without noticing if we only tested SPM in-package

So the way I currently have set up, it builds the example app with the flag disabled, then it builds with the flag enabled, then it runs tests (still with the flag enabled).

So the example app builds with both the flag disabled (aka CocoaPods only) and enabled. I'm inclined to keep it this way so we can be sure the example app works both ways.

As for build-all, we could also do it twice - once with it disabled and once with it enabled?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the example app builds with both the flag disabled (aka CocoaPods only) and enabled. I'm inclined to keep it this way so we can be sure the example app works both ways.

The problem is that adds about 5 minutes to each shard (a roughly 25-33% increase). If the only thing we get from that is coverage of an example app that almost nobody but us runs most of the time, and doesn't affect production clients, I don't think that's a good tradeoff of CI resources.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, then yeah I think we keep build-all using CocoaPods and do platform tests with SPM (because the example app has to be built with SPM so native tests use SPM).

script: .ci/scripts/tool_runner.sh
args: ["build-examples", "--ios"]
- name: build examples with Swift Package Manager integration
script: .ci/scripts/tool_runner.sh
args: ["build-examples", "--ios", "--swift-package-manager"]
- name: xcode analyze
script: .ci/scripts/tool_runner.sh
args: ["xcode-analyze", "--ios"]
Expand Down
5 changes: 4 additions & 1 deletion .ci/targets/macos_platform_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ tasks:
script: .ci/scripts/tool_runner.sh
args: ["fetch-deps", "--macos", "--supporting-target-platforms-only"]
infra_step: true
- name: build examples
- name: build examples with CocoaPods integration
script: .ci/scripts/tool_runner.sh
args: ["build-examples", "--macos"]
- name: build examples with Swift Package Manager integration
script: .ci/scripts/tool_runner.sh
args: ["build-examples", "--macos", "--swift-package-manager"]
- name: xcode analyze
script: .ci/scripts/tool_runner.sh
args: ["xcode-analyze", "--macos"]
Expand Down
40 changes: 40 additions & 0 deletions script/tool/lib/src/build_examples_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ const String _flutterBuildTypeWindows = 'windows';

const String _flutterBuildTypeAndroidAlias = 'android';

/// Key for Swift Package Manager.
const String _swiftPackageManagerFlag = 'swift-package-manager';

/// A command to build the example applications for packages.
class BuildExamplesCommand extends PackageLoopingCommand {
/// Creates an instance of the build command.
Expand All @@ -58,6 +61,7 @@ class BuildExamplesCommand extends PackageLoopingCommand {
defaultsTo: '',
help: 'Enables the given Dart SDK experiments.',
);
argParser.addFlag(_swiftPackageManagerFlag);
}

// Maps the switch this command uses to identify a platform to information
Expand Down Expand Up @@ -111,6 +115,15 @@ class BuildExamplesCommand extends PackageLoopingCommand {
'single key "$_pluginToolsConfigGlobalKey" containing a list of build '
'arguments.';

/// Returns true if `--swift-package-manager` flag was passed along with
/// either `--ios` or `--macos`.
bool get usingSwiftPackageManager {
final List<String> platformFlags = _platforms.keys.toList();
return getBoolArg(_swiftPackageManagerFlag) &&
(platformFlags.contains(platformIOS) ||
platformFlags.contains(platformMacOS));
}

@override
Future<void> initializeRun() async {
final List<String> platformFlags = _platforms.keys.toList();
Expand All @@ -121,6 +134,14 @@ class BuildExamplesCommand extends PackageLoopingCommand {
'were specified. At least one platform must be provided.');
throw ToolExit(_exitNoPlatformFlags);
}

if (usingSwiftPackageManager) {
await processRunner.runAndStream(
flutterCommand,
<String>['config', '--enable-swift-package-manager'],
exitOnError: true,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will explode on our stable tests (which you aren't seeing in presubmit because we only run native stable tests on post-submit to reduce CI utilization). You'll need to gate either the whole call, or just exiting on failure, on a Platform.environment['CHANNEL'] != 'stable' check for now, with a TODO to enable it for stable once the flag is available there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

);
}
}

@override
Expand Down Expand Up @@ -269,6 +290,12 @@ class BuildExamplesCommand extends PackageLoopingCommand {
}) async {
final String enableExperiment = getStringArg(kEnableExperiment);

// Clean app before building when using Swift Package Manager since this
// is the second time it's being built.
if (usingSwiftPackageManager) {
await _cleanExample(example);
}

final int exitCode = await processRunner.runAndStream(
flutterCommand,
<String>[
Expand All @@ -283,6 +310,19 @@ class BuildExamplesCommand extends PackageLoopingCommand {
);
return exitCode == 0;
}

Future<bool> _cleanExample(
RepositoryPackage example,
) async {
final int exitCode = await processRunner.runAndStream(
flutterCommand,
<String>[
'clean',
],
workingDir: example.directory,
);
return exitCode == 0;
}
}

/// A collection of information related to a specific platform.
Expand Down
94 changes: 94 additions & 0 deletions script/tool/test/build_examples_command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,56 @@ void main() {
]));
});

test('building for iOS with Swift Package Manager', () async {
mockPlatform.isMacOS = true;
final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir,
platformSupport: <String, PlatformDetails>{
platformIOS: const PlatformDetails(PlatformSupport.inline),
});

final Directory pluginExampleDirectory = getExampleDir(plugin);

final List<String> output = await runCapturingPrint(runner, <String>[
'build-examples',
'--ios',
'--enable-experiment=exp1',
'--swift-package-manager',
]);

expect(
output,
containsAllInOrder(<String>[
'\nBUILDING plugin/example for iOS',
]),
);

expect(
processRunner.recordedCalls,
orderedEquals(<ProcessCall>[
ProcessCall(
getFlutterCommand(mockPlatform),
const <String>['config', '--enable-swift-package-manager'],
null,
),
ProcessCall(
getFlutterCommand(mockPlatform),
const <String>['clean'],
pluginExampleDirectory.path,
),
ProcessCall(
getFlutterCommand(mockPlatform),
const <String>[
'build',
'ios',
'--no-codesign',
'--enable-experiment=exp1'
],
pluginExampleDirectory.path,
),
]),
);
});

test(
'building for Linux when plugin is not set up for Linux results in no-op',
() async {
Expand Down Expand Up @@ -261,6 +311,50 @@ void main() {
]));
});

test('building for macOS with Swift Package Manager', () async {
mockPlatform.isMacOS = true;
final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir,
platformSupport: <String, PlatformDetails>{
platformMacOS: const PlatformDetails(PlatformSupport.inline),
});

final Directory pluginExampleDirectory = getExampleDir(plugin);

final List<String> output = await runCapturingPrint(runner,
<String>['build-examples', '--macos', '--swift-package-manager']);

expect(
output,
containsAllInOrder(<String>[
'\nBUILDING plugin/example for macOS',
]),
);

expect(
processRunner.recordedCalls,
orderedEquals(<ProcessCall>[
ProcessCall(
getFlutterCommand(mockPlatform),
const <String>['config', '--enable-swift-package-manager'],
null,
),
ProcessCall(
getFlutterCommand(mockPlatform),
const <String>['clean'],
pluginExampleDirectory.path,
),
ProcessCall(
getFlutterCommand(mockPlatform),
const <String>[
'build',
'macos',
],
pluginExampleDirectory.path,
),
]),
);
});

test('building for web with no implementation results in no-op', () async {
createFakePlugin('plugin', packagesDir);

Expand Down