Unverified Commit 7020f59a authored by Alex Wallen's avatar Alex Wallen Committed by GitHub

[tool] Support `--flavor` option for `flutter install`. (#114048)

* Alphabetize setup calls

* Add --flavor as an option for install

* Add verbose logging in install command

* Test that flavors build succeeds with proper flavor and fails with bogus one.

* Remove unused import

* The import was used...

* SQUASH

* Add flavor install test

* Rename test

* Add flavors install integration tests

* correct error message

* remove unused imports

* Delete copy test

* update test target

* Refactor mechanism to read buildInfo

* Remove unused import

* Set affected test targets to bringup: true
Co-authored-by: 's avatara-wallen <stephenwallen@google.com>
parent 1725a26e
...@@ -1687,6 +1687,7 @@ targets: ...@@ -1687,6 +1687,7 @@ targets:
task_name: fast_scroll_large_images__memory task_name: fast_scroll_large_images__memory
- name: Linux_android flavors_test - name: Linux_android flavors_test
bringup: true
recipe: devicelab/devicelab_drone recipe: devicelab/devicelab_drone
presubmit: false presubmit: false
timeout: 60 timeout: 60
...@@ -3371,6 +3372,7 @@ targets: ...@@ -3371,6 +3372,7 @@ targets:
task_name: route_test_ios task_name: route_test_ios
- name: Mac_ios flavors_test_ios - name: Mac_ios flavors_test_ios
bringup: true
recipe: devicelab/devicelab_drone recipe: devicelab/devicelab_drone
presubmit: false presubmit: false
timeout: 60 timeout: 60
...@@ -4537,7 +4539,7 @@ targets: ...@@ -4537,7 +4539,7 @@ targets:
properties: properties:
tags: > tags: >
["devicelab", "android", "windows"] ["devicelab", "android", "windows"]
task_name: flavors_test_win task_name: flavors_test
- name: Windows_android flutter_gallery_win__compile - name: Windows_android flutter_gallery_win__compile
recipe: devicelab/devicelab_drone recipe: devicelab/devicelab_drone
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter_devicelab/framework/devices.dart'; import 'package:flutter_devicelab/framework/devices.dart';
import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/task_result.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:flutter_devicelab/tasks/integration_tests.dart'; import 'package:flutter_devicelab/tasks/integration_tests.dart';
Future<void> main() async { Future<void> main() async {
...@@ -12,6 +13,30 @@ Future<void> main() async { ...@@ -12,6 +13,30 @@ Future<void> main() async {
await task(() async { await task(() async {
await createFlavorsTest().call(); await createFlavorsTest().call();
await createIntegrationTestFlavorsTest().call(); await createIntegrationTestFlavorsTest().call();
// test install and uninstall of flavors app
await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async {
await flutter(
'install',
options: <String>['--flavor', 'paid'],
);
await flutter(
'install',
options: <String>['--flavor', 'paid', '--uninstall-only'],
);
final StringBuffer stderr = StringBuffer();
await evalFlutter(
'install',
canFail: true,
stderr: stderr,
options: <String>['--flavor', 'bogus'],
);
final String stderrString = stderr.toString();
if (!stderrString.contains('The Xcode project defines schemes: free, paid')) {
print(stderrString);
return TaskResult.failure('Should not succeed with bogus flavor');
}
});
return TaskResult.success(null); return TaskResult.success(null);
}); });
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter_devicelab/framework/devices.dart'; import 'package:flutter_devicelab/framework/devices.dart';
import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/task_result.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:flutter_devicelab/tasks/integration_tests.dart'; import 'package:flutter_devicelab/tasks/integration_tests.dart';
Future<void> main() async { Future<void> main() async {
...@@ -12,6 +13,30 @@ Future<void> main() async { ...@@ -12,6 +13,30 @@ Future<void> main() async {
await task(() async { await task(() async {
await createFlavorsTest().call(); await createFlavorsTest().call();
await createIntegrationTestFlavorsTest().call(); await createIntegrationTestFlavorsTest().call();
// test install and uninstall of flavors app
await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async {
await flutter(
'install',
options: <String>['--flavor', 'paid'],
);
await flutter(
'install',
options: <String>['--flavor', 'paid', '--uninstall-only'],
);
final StringBuffer stderr = StringBuffer();
await evalFlutter(
'install',
canFail: true,
stderr: stderr,
options: <String>['--flavor', 'bogus'],
);
final String stderrString = stderr.toString();
if (!stderrString.contains('install failed, bogus flavor not found')) {
print(stderrString);
return TaskResult.failure('Should not succeed with bogus flavor');
}
});
return TaskResult.success(null); return TaskResult.success(null);
}); });
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_devicelab/framework/devices.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/task_result.dart';
import 'package:flutter_devicelab/tasks/integration_tests.dart';
Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.android;
await task(() async {
await createFlavorsTest().call();
await createIntegrationTestFlavorsTest().call();
return TaskResult.success(null);
});
}
...@@ -200,7 +200,9 @@ List<FlutterCommand> generateCommands({ ...@@ -200,7 +200,9 @@ List<FlutterCommand> generateCommands({
artifacts: globals.artifacts!, artifacts: globals.artifacts!,
processManager: globals.processManager, processManager: globals.processManager,
), ),
InstallCommand(), InstallCommand(
verboseHelp: verboseHelp,
),
LogsCommand(), LogsCommand(),
MakeHostAppEditableCommand(), MakeHostAppEditableCommand(),
PackagesCommand(), PackagesCommand(),
......
...@@ -12,11 +12,15 @@ import '../globals.dart' as globals; ...@@ -12,11 +12,15 @@ import '../globals.dart' as globals;
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
InstallCommand() { InstallCommand({
required bool verboseHelp,
}) {
addBuildModeFlags(verboseHelp: verboseHelp);
requiresPubspecYaml(); requiresPubspecYaml();
usesDeviceUserOption();
usesDeviceTimeoutOption();
usesApplicationBinaryOption(); usesApplicationBinaryOption();
usesDeviceTimeoutOption();
usesDeviceUserOption();
usesFlavorOption();
argParser.addFlag('uninstall-only', argParser.addFlag('uninstall-only',
help: 'Uninstall the app if already on the device. Skip install.', help: 'Uninstall the app if already on the device. Skip install.',
); );
...@@ -60,6 +64,7 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts ...@@ -60,6 +64,7 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
final ApplicationPackage? package = await applicationPackages?.getPackageForPlatform( final ApplicationPackage? package = await applicationPackages?.getPackageForPlatform(
await targetDevice.targetPlatform, await targetDevice.targetPlatform,
applicationBinary: _applicationBinary, applicationBinary: _applicationBinary,
buildInfo: await getBuildInfo(),
); );
if (package == null) { if (package == null) {
throwToolExit('Could not find or build package'); throwToolExit('Could not find or build package');
......
...@@ -32,7 +32,7 @@ void main() { ...@@ -32,7 +32,7 @@ void main() {
}); });
testUsingContext('returns 0 when Android is connected and ready for an install', () async { testUsingContext('returns 0 when Android is connected and ready for an install', () async {
final InstallCommand command = InstallCommand(); final InstallCommand command = InstallCommand(verboseHelp: false);
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk()); command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
final FakeAndroidDevice device = FakeAndroidDevice(); final FakeAndroidDevice device = FakeAndroidDevice();
...@@ -46,7 +46,7 @@ void main() { ...@@ -46,7 +46,7 @@ void main() {
}); });
testUsingContext('returns 1 when targeted device is not Android with --device-user', () async { testUsingContext('returns 1 when targeted device is not Android with --device-user', () async {
final InstallCommand command = InstallCommand(); final InstallCommand command = InstallCommand(verboseHelp: false);
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk()); command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
final FakeIOSDevice device = FakeIOSDevice(); final FakeIOSDevice device = FakeIOSDevice();
...@@ -61,7 +61,7 @@ void main() { ...@@ -61,7 +61,7 @@ void main() {
}); });
testUsingContext('returns 0 when iOS is connected and ready for an install', () async { testUsingContext('returns 0 when iOS is connected and ready for an install', () async {
final InstallCommand command = InstallCommand(); final InstallCommand command = InstallCommand(verboseHelp: false);
command.applicationPackages = FakeApplicationPackageFactory(FakeIOSApp()); command.applicationPackages = FakeApplicationPackageFactory(FakeIOSApp());
final FakeIOSDevice device = FakeIOSDevice(); final FakeIOSDevice device = FakeIOSDevice();
...@@ -75,7 +75,7 @@ void main() { ...@@ -75,7 +75,7 @@ void main() {
}); });
testUsingContext('fails when prebuilt binary not found', () async { testUsingContext('fails when prebuilt binary not found', () async {
final InstallCommand command = InstallCommand(); final InstallCommand command = InstallCommand(verboseHelp: false);
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk()); command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
final FakeAndroidDevice device = FakeAndroidDevice(); final FakeAndroidDevice device = FakeAndroidDevice();
...@@ -90,7 +90,7 @@ void main() { ...@@ -90,7 +90,7 @@ void main() {
}); });
testUsingContext('succeeds using prebuilt binary', () async { testUsingContext('succeeds using prebuilt binary', () async {
final InstallCommand command = InstallCommand(); final InstallCommand command = InstallCommand(verboseHelp: false);
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk()); command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
final FakeAndroidDevice device = FakeAndroidDevice(); final FakeAndroidDevice device = FakeAndroidDevice();
...@@ -103,6 +103,24 @@ void main() { ...@@ -103,6 +103,24 @@ void main() {
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testUsingContext('Passes flavor to application package.', () async {
const String flavor = 'free';
final InstallCommand command = InstallCommand(verboseHelp: false);
final FakeApplicationPackageFactory fakeAppFactory = FakeApplicationPackageFactory(FakeIOSApp());
command.applicationPackages = fakeAppFactory;
final FakeIOSDevice device = FakeIOSDevice();
testDeviceManager.addDevice(device);
await createTestCommandRunner(command).run(<String>['install', '--flavor', flavor]);
expect(fakeAppFactory.buildInfo, isNotNull);
expect(fakeAppFactory.buildInfo!.flavor, flavor);
}, overrides: <Type, Generator>{
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
}); });
} }
...@@ -110,9 +128,11 @@ class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFa ...@@ -110,9 +128,11 @@ class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFa
FakeApplicationPackageFactory(this.app); FakeApplicationPackageFactory(this.app);
final ApplicationPackage app; final ApplicationPackage app;
BuildInfo? buildInfo;
@override @override
Future<ApplicationPackage> getPackageForPlatform(TargetPlatform platform, {BuildInfo? buildInfo, File? applicationBinary}) async { Future<ApplicationPackage> getPackageForPlatform(TargetPlatform platform, {BuildInfo? buildInfo, File? applicationBinary}) async {
this.buildInfo = buildInfo;
return app; return app;
} }
} }
......
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