Unverified Commit 77ea848c authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Inject Usage dependency into FallbackDiscovery and BuildEvent (#53443)

* Usage dependency injection

* Review edits
parent c3ec1caa
...@@ -242,9 +242,9 @@ Future<void> buildGradleApp({ ...@@ -242,9 +242,9 @@ Future<void> buildGradleApp({
final bool usesAndroidX = isAppUsingAndroidX(project.android.hostAppGradleRoot); final bool usesAndroidX = isAppUsingAndroidX(project.android.hostAppGradleRoot);
if (usesAndroidX) { if (usesAndroidX) {
BuildEvent('app-using-android-x').send(); BuildEvent('app-using-android-x', flutterUsage: globals.flutterUsage).send();
} else if (!usesAndroidX) { } else if (!usesAndroidX) {
BuildEvent('app-not-using-android-x').send(); BuildEvent('app-not-using-android-x', flutterUsage: globals.flutterUsage).send();
globals.printStatus("$warningMark Your app isn't using AndroidX.", emphasis: true); globals.printStatus("$warningMark Your app isn't using AndroidX.", emphasis: true);
globals.printStatus( globals.printStatus(
'To avoid potential build failures, you can quickly migrate your app ' 'To avoid potential build failures, you can quickly migrate your app '
...@@ -404,7 +404,7 @@ Future<void> buildGradleApp({ ...@@ -404,7 +404,7 @@ Future<void> buildGradleApp({
if (exitCode != 0) { if (exitCode != 0) {
if (detectedGradleError == null) { if (detectedGradleError == null) {
BuildEvent('gradle-unkown-failure').send(); BuildEvent('gradle-unkown-failure', flutterUsage: globals.flutterUsage).send();
throwToolExit( throwToolExit(
'Gradle task $assembleTask failed with exit code $exitCode', 'Gradle task $assembleTask failed with exit code $exitCode',
exitCode: exitCode, exitCode: exitCode,
...@@ -430,7 +430,7 @@ Future<void> buildGradleApp({ ...@@ -430,7 +430,7 @@ Future<void> buildGradleApp({
shouldBuildPluginAsAar: shouldBuildPluginAsAar, shouldBuildPluginAsAar: shouldBuildPluginAsAar,
retries: retries - 1, retries: retries - 1,
); );
BuildEvent(successEventLabel).send(); BuildEvent(successEventLabel, flutterUsage: globals.flutterUsage).send();
return; return;
case GradleBuildStatus.retryWithAarPlugins: case GradleBuildStatus.retryWithAarPlugins:
await buildGradleApp( await buildGradleApp(
...@@ -442,13 +442,13 @@ Future<void> buildGradleApp({ ...@@ -442,13 +442,13 @@ Future<void> buildGradleApp({
shouldBuildPluginAsAar: true, shouldBuildPluginAsAar: true,
retries: retries - 1, retries: retries - 1,
); );
BuildEvent(successEventLabel).send(); BuildEvent(successEventLabel, flutterUsage: globals.flutterUsage).send();
return; return;
case GradleBuildStatus.exit: case GradleBuildStatus.exit:
// noop. // noop.
} }
} }
BuildEvent('gradle-${detectedGradleError.eventLabel}-failure').send(); BuildEvent('gradle-${detectedGradleError.eventLabel}-failure', flutterUsage: globals.flutterUsage).send();
throwToolExit( throwToolExit(
'Gradle task $assembleTask failed with exit code $exitCode', 'Gradle task $assembleTask failed with exit code $exitCode',
exitCode: exitCode, exitCode: exitCode,
...@@ -697,7 +697,7 @@ String _calculateSha(File file) { ...@@ -697,7 +697,7 @@ String _calculateSha(File file) {
} }
void _exitWithUnsupportedProjectMessage() { void _exitWithUnsupportedProjectMessage() {
BuildEvent('unsupported-project', eventError: 'gradle-plugin').send(); BuildEvent('unsupported-project', eventError: 'gradle-plugin', flutterUsage: globals.flutterUsage).send();
throwToolExit( throwToolExit(
'$warningMark Your app is using an unsupported Gradle project. ' '$warningMark Your app is using an unsupported Gradle project. '
'To fix this problem, create a new project by running `flutter create -t app <app-directory>` ' 'To fix this problem, create a new project by running `flutter create -t app <app-directory>` '
...@@ -706,7 +706,7 @@ void _exitWithUnsupportedProjectMessage() { ...@@ -706,7 +706,7 @@ void _exitWithUnsupportedProjectMessage() {
} }
void _exitWithProjectNotUsingGradleMessage() { void _exitWithProjectNotUsingGradleMessage() {
BuildEvent('unsupported-project', eventError: 'app-not-using-gradle').send(); BuildEvent('unsupported-project', eventError: 'app-not-using-gradle', flutterUsage: globals.flutterUsage).send();
throwToolExit( throwToolExit(
'$warningMark The build process for Android has changed, and the ' '$warningMark The build process for Android has changed, and the '
'current project configuration is no longer valid. Please consult\n\n' 'current project configuration is no longer valid. Please consult\n\n'
...@@ -770,7 +770,7 @@ Future<void> buildPluginsAsAar( ...@@ -770,7 +770,7 @@ Future<void> buildPluginsAsAar(
} on ToolExit { } on ToolExit {
// Log the entire plugin entry in `.flutter-plugins` since it // Log the entire plugin entry in `.flutter-plugins` since it
// includes the plugin name and the version. // includes the plugin name and the version.
BuildEvent('gradle-plugin-aar-failure', eventError: plugin).send(); BuildEvent('gradle-plugin-aar-failure', eventError: plugin, flutterUsage: globals.flutterUsage).send();
throwToolExit('The plugin $pluginName could not be built due to the issue above.'); throwToolExit('The plugin $pluginName could not be built due to the issue above.');
} }
} }
...@@ -866,12 +866,13 @@ void _exitWithExpectedFileNotFound({ ...@@ -866,12 +866,13 @@ void _exitWithExpectedFileNotFound({
assert(fileExtension != null); assert(fileExtension != null);
final String androidGradlePluginVersion = final String androidGradlePluginVersion =
getGradleVersionForAndroidPlugin(project.android.hostAppGradleRoot); getGradleVersionForAndroidPlugin(project.android.hostAppGradleRoot);
BuildEvent('gradle-expected-file-not-found', BuildEvent('gradle-expected-file-not-found',
settings: settings:
'androidGradlePluginVersion: $androidGradlePluginVersion, ' 'androidGradlePluginVersion: $androidGradlePluginVersion, '
'fileExtension: $fileExtension' 'fileExtension: $fileExtension',
).send(); flutterUsage: globals.flutterUsage,
).send();
throwToolExit( throwToolExit(
'Gradle build failed to produce an $fileExtension file. ' 'Gradle build failed to produce an $fileExtension file. '
"It's likely that this file was generated under ${project.android.buildDirectory.path}, " "It's likely that this file was generated under ${project.android.buildDirectory.path}, "
......
...@@ -183,6 +183,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError( ...@@ -183,6 +183,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError(
BuildEvent( BuildEvent(
'gradle-android-x-failure', 'gradle-android-x-failure',
eventError: 'app-not-using-plugins', eventError: 'app-not-using-plugins',
flutterUsage: globals.flutterUsage,
).send(); ).send();
} }
if (hasPlugins && !usesAndroidX) { if (hasPlugins && !usesAndroidX) {
...@@ -195,6 +196,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError( ...@@ -195,6 +196,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError(
BuildEvent( BuildEvent(
'gradle-android-x-failure', 'gradle-android-x-failure',
eventError: 'app-not-using-androidx', eventError: 'app-not-using-androidx',
flutterUsage: globals.flutterUsage,
).send(); ).send();
} }
if (hasPlugins && usesAndroidX && shouldBuildPluginAsAar) { if (hasPlugins && usesAndroidX && shouldBuildPluginAsAar) {
...@@ -204,6 +206,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError( ...@@ -204,6 +206,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError(
BuildEvent( BuildEvent(
'gradle-android-x-failure', 'gradle-android-x-failure',
eventError: 'using-jetifier', eventError: 'using-jetifier',
flutterUsage: globals.flutterUsage,
).send(); ).send();
} }
if (hasPlugins && usesAndroidX && !shouldBuildPluginAsAar) { if (hasPlugins && usesAndroidX && !shouldBuildPluginAsAar) {
...@@ -214,6 +217,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError( ...@@ -214,6 +217,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError(
BuildEvent( BuildEvent(
'gradle-android-x-failure', 'gradle-android-x-failure',
eventError: 'not-using-jetifier', eventError: 'not-using-jetifier',
flutterUsage: globals.flutterUsage,
).send(); ).send();
return GradleBuildStatus.retryWithAarPlugins; return GradleBuildStatus.retryWithAarPlugins;
} }
......
...@@ -301,7 +301,7 @@ void writeLocalProperties(File properties) { ...@@ -301,7 +301,7 @@ void writeLocalProperties(File properties) {
} }
void exitWithNoSdkMessage() { void exitWithNoSdkMessage() {
BuildEvent('unsupported-project', eventError: 'android-sdk-not-found').send(); BuildEvent('unsupported-project', eventError: 'android-sdk-not-found', flutterUsage: globals.flutterUsage).send();
throwToolExit( throwToolExit(
'$warningMark No Android SDK found. ' '$warningMark No Android SDK found. '
'Try setting the ANDROID_HOME environment variable.' 'Try setting the ANDROID_HOME environment variable.'
......
...@@ -89,7 +89,7 @@ class BuildIOSCommand extends BuildSubCommand { ...@@ -89,7 +89,7 @@ class BuildIOSCommand extends BuildSubCommand {
); );
if (!result.success) { if (!result.success) {
await diagnoseXcodeBuildFailure(result); await diagnoseXcodeBuildFailure(result, globals.flutterUsage, globals.logger);
throwToolExit('Encountered error while building for $logTarget.'); throwToolExit('Encountered error while building for $logTarget.');
} }
......
...@@ -220,6 +220,7 @@ Future<T> runInContext<T>( ...@@ -220,6 +220,7 @@ Future<T> runInContext<T>(
platform: globals.platform, platform: globals.platform,
fileSystem: globals.fs, fileSystem: globals.fs,
terminal: globals.terminal, terminal: globals.terminal,
usage: globals.flutterUsage,
), ),
}, },
); );
......
...@@ -242,7 +242,7 @@ class IOSDevice extends Device { ...@@ -242,7 +242,7 @@ class IOSDevice extends Device {
); );
if (!buildResult.success) { if (!buildResult.success) {
_logger.printError('Could not build the precompiled application for the device.'); _logger.printError('Could not build the precompiled application for the device.');
await diagnoseXcodeBuildFailure(buildResult); await diagnoseXcodeBuildFailure(buildResult, globals.flutterUsage, _logger);
_logger.printError(''); _logger.printError('');
return LaunchResult.failed(); return LaunchResult.failed();
} }
...@@ -338,6 +338,7 @@ class IOSDevice extends Device { ...@@ -338,6 +338,7 @@ class IOSDevice extends Device {
mDnsObservatoryDiscovery: MDnsObservatoryDiscovery.instance, mDnsObservatoryDiscovery: MDnsObservatoryDiscovery.instance,
portForwarder: portForwarder, portForwarder: portForwarder,
protocolDiscovery: observatoryDiscovery, protocolDiscovery: observatoryDiscovery,
flutterUsage: globals.flutterUsage,
); );
final Uri localUri = await fallbackDiscovery.discover( final Uri localUri = await fallbackDiscovery.discover(
assumedDevicePort: assumedObservatoryPort, assumedDevicePort: assumedObservatoryPort,
......
...@@ -9,7 +9,6 @@ import 'package:vm_service/vm_service_io.dart' as vm_service_io; ...@@ -9,7 +9,6 @@ import 'package:vm_service/vm_service_io.dart' as vm_service_io;
import '../base/io.dart'; import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart' as globals;
import '../mdns_discovery.dart'; import '../mdns_discovery.dart';
import '../protocol_discovery.dart'; import '../protocol_discovery.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
...@@ -42,12 +41,14 @@ class FallbackDiscovery { ...@@ -42,12 +41,14 @@ class FallbackDiscovery {
@required MDnsObservatoryDiscovery mDnsObservatoryDiscovery, @required MDnsObservatoryDiscovery mDnsObservatoryDiscovery,
@required Logger logger, @required Logger logger,
@required ProtocolDiscovery protocolDiscovery, @required ProtocolDiscovery protocolDiscovery,
@required Usage flutterUsage,
Future<VmService> Function(String wsUri, {Log log}) vmServiceConnectUri = Future<VmService> Function(String wsUri, {Log log}) vmServiceConnectUri =
vm_service_io.vmServiceConnectUri, vm_service_io.vmServiceConnectUri,
}) : _logger = logger, }) : _logger = logger,
_mDnsObservatoryDiscovery = mDnsObservatoryDiscovery, _mDnsObservatoryDiscovery = mDnsObservatoryDiscovery,
_portForwarder = portForwarder, _portForwarder = portForwarder,
_protocolDiscovery = protocolDiscovery, _protocolDiscovery = protocolDiscovery,
_flutterUsage = flutterUsage,
_vmServiceConnectUri = vmServiceConnectUri; _vmServiceConnectUri = vmServiceConnectUri;
static const String _kEventName = 'ios-handshake'; static const String _kEventName = 'ios-handshake';
...@@ -56,6 +57,7 @@ class FallbackDiscovery { ...@@ -56,6 +57,7 @@ class FallbackDiscovery {
final MDnsObservatoryDiscovery _mDnsObservatoryDiscovery; final MDnsObservatoryDiscovery _mDnsObservatoryDiscovery;
final Logger _logger; final Logger _logger;
final ProtocolDiscovery _protocolDiscovery; final ProtocolDiscovery _protocolDiscovery;
final Usage _flutterUsage;
final Future<VmService> Function(String wsUri, {Log log}) _vmServiceConnectUri; final Future<VmService> Function(String wsUri, {Log log}) _vmServiceConnectUri;
/// Attempt to discover the observatory port. /// Attempt to discover the observatory port.
...@@ -87,7 +89,7 @@ class FallbackDiscovery { ...@@ -87,7 +89,7 @@ class FallbackDiscovery {
UsageEvent( UsageEvent(
_kEventName, _kEventName,
'mdns-success', 'mdns-success',
flutterUsage: globals.flutterUsage, flutterUsage: _flutterUsage,
).send(); ).send();
return result; return result;
} }
...@@ -98,7 +100,7 @@ class FallbackDiscovery { ...@@ -98,7 +100,7 @@ class FallbackDiscovery {
UsageEvent( UsageEvent(
_kEventName, _kEventName,
'mdns-failure', 'mdns-failure',
flutterUsage: globals.flutterUsage, flutterUsage: _flutterUsage,
).send(); ).send();
try { try {
...@@ -107,7 +109,7 @@ class FallbackDiscovery { ...@@ -107,7 +109,7 @@ class FallbackDiscovery {
UsageEvent( UsageEvent(
_kEventName, _kEventName,
'fallback-success', 'fallback-success',
flutterUsage: globals.flutterUsage, flutterUsage: _flutterUsage,
).send(); ).send();
return result; return result;
} }
...@@ -121,7 +123,7 @@ class FallbackDiscovery { ...@@ -121,7 +123,7 @@ class FallbackDiscovery {
UsageEvent( UsageEvent(
_kEventName, _kEventName,
'fallback-failure', 'fallback-failure',
flutterUsage: globals.flutterUsage, flutterUsage: _flutterUsage,
).send(); ).send();
return null; return null;
} }
...@@ -167,7 +169,7 @@ class FallbackDiscovery { ...@@ -167,7 +169,7 @@ class FallbackDiscovery {
UsageEvent( UsageEvent(
_kEventName, _kEventName,
'success', 'success',
flutterUsage: globals.flutterUsage, flutterUsage: _flutterUsage,
).send(); ).send();
return Uri.parse('http://localhost:$hostPort'); return Uri.parse('http://localhost:$hostPort');
} }
...@@ -207,7 +209,7 @@ class FallbackDiscovery { ...@@ -207,7 +209,7 @@ class FallbackDiscovery {
_kEventName, _kEventName,
eventAction, eventAction,
label: eventLabel, label: eventLabel,
flutterUsage: globals.flutterUsage, flutterUsage: _flutterUsage,
).send(); ).send();
} }
} }
...@@ -342,6 +342,7 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -342,6 +342,7 @@ Future<XcodeBuildResult> buildXcodeProject({
if (e.toString().contains('timed out')) { if (e.toString().contains('timed out')) {
BuildEvent('xcode-show-build-settings-timeout', BuildEvent('xcode-show-build-settings-timeout',
command: showBuildSettingsCommand.join(' '), command: showBuildSettingsCommand.join(' '),
flutterUsage: globals.flutterUsage,
).send(); ).send();
} }
rethrow; rethrow;
...@@ -447,13 +448,14 @@ return result.exitCode != 0 && ...@@ -447,13 +448,14 @@ return result.exitCode != 0 &&
result.stdout.contains('there are two concurrent builds running'); result.stdout.contains('there are two concurrent builds running');
} }
Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async { Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result, Usage flutterUsage, Logger logger) async {
if (result.xcodeBuildExecution != null && if (result.xcodeBuildExecution != null &&
result.xcodeBuildExecution.buildForPhysicalDevice && result.xcodeBuildExecution.buildForPhysicalDevice &&
result.stdout?.toUpperCase()?.contains('BITCODE') == true) { result.stdout?.toUpperCase()?.contains('BITCODE') == true) {
BuildEvent('xcode-bitcode-failure', BuildEvent('xcode-bitcode-failure',
command: result.xcodeBuildExecution.buildCommands.toString(), command: result.xcodeBuildExecution.buildCommands.toString(),
settings: result.xcodeBuildExecution.buildSettings.toString(), settings: result.xcodeBuildExecution.buildSettings.toString(),
flutterUsage: flutterUsage,
).send(); ).send();
} }
...@@ -463,11 +465,11 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async { ...@@ -463,11 +465,11 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
if (result.stdout?.contains('Building for iOS') == true if (result.stdout?.contains('Building for iOS') == true
&& result.stdout?.contains('but the linked and embedded framework') == true && result.stdout?.contains('but the linked and embedded framework') == true
&& result.stdout?.contains('was built for iOS') == true) { && result.stdout?.contains('was built for iOS') == true) {
globals.printError(''); logger.printError('');
globals.printError('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.'); logger.printError('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
globals.printError(''); logger.printError('');
globals.printError('You can temporarily work around this issue by running:'); logger.printError('You can temporarily work around this issue by running:');
globals.printError(' rm -rf ios/Flutter/App.framework'); logger.printError(' rm -rf ios/Flutter/App.framework');
return; return;
} }
...@@ -476,7 +478,7 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async { ...@@ -476,7 +478,7 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
result.stdout?.contains('BCEROR') == true && result.stdout?.contains('BCEROR') == true &&
// May need updating if Xcode changes its outputs. // May need updating if Xcode changes its outputs.
result.stdout?.contains("Xcode couldn't find a provisioning profile matching") == true) { result.stdout?.contains("Xcode couldn't find a provisioning profile matching") == true) {
globals.printError(noProvisioningProfileInstruction, emphasis: true); logger.printError(noProvisioningProfileInstruction, emphasis: true);
return; return;
} }
// Make sure the user has specified one of: // Make sure the user has specified one of:
...@@ -486,26 +488,26 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async { ...@@ -486,26 +488,26 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
result.xcodeBuildExecution.buildForPhysicalDevice && result.xcodeBuildExecution.buildForPhysicalDevice &&
!<String>['DEVELOPMENT_TEAM', 'PROVISIONING_PROFILE'].any( !<String>['DEVELOPMENT_TEAM', 'PROVISIONING_PROFILE'].any(
result.xcodeBuildExecution.buildSettings.containsKey)) { result.xcodeBuildExecution.buildSettings.containsKey)) {
globals.printError(noDevelopmentTeamInstruction, emphasis: true); logger.printError(noDevelopmentTeamInstruction, emphasis: true);
return; return;
} }
if (result.xcodeBuildExecution != null && if (result.xcodeBuildExecution != null &&
result.xcodeBuildExecution.buildForPhysicalDevice && result.xcodeBuildExecution.buildForPhysicalDevice &&
result.xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER']?.contains('com.example') == true) { result.xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER']?.contains('com.example') == true) {
globals.printError(''); logger.printError('');
globals.printError('It appears that your application still contains the default signing identifier.'); logger.printError('It appears that your application still contains the default signing identifier.');
globals.printError("Try replacing 'com.example' with your signing id in Xcode:"); logger.printError("Try replacing 'com.example' with your signing id in Xcode:");
globals.printError(' open ios/Runner.xcworkspace'); logger.printError(' open ios/Runner.xcworkspace');
return; return;
} }
if (result.stdout?.contains('Code Sign error') == true) { if (result.stdout?.contains('Code Sign error') == true) {
globals.printError(''); logger.printError('');
globals.printError('It appears that there was a problem signing your application prior to installation on the device.'); logger.printError('It appears that there was a problem signing your application prior to installation on the device.');
globals.printError(''); logger.printError('');
globals.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode'); logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode');
globals.printError(' open ios/Runner.xcworkspace'); logger.printError(' open ios/Runner.xcworkspace');
globals.printError(''); logger.printError('');
globals.printError("Also try selecting 'Product > Build' to fix the problem:"); logger.printError("Also try selecting 'Product > Build' to fix the problem:");
return; return;
} }
} }
......
...@@ -254,17 +254,20 @@ class XcodeProjectInterpreter { ...@@ -254,17 +254,20 @@ class XcodeProjectInterpreter {
@required Logger logger, @required Logger logger,
@required FileSystem fileSystem, @required FileSystem fileSystem,
@required Terminal terminal, @required Terminal terminal,
@required Usage usage,
}) : _platform = platform, }) : _platform = platform,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_terminal = terminal, _terminal = terminal,
_logger = logger, _logger = logger,
_processUtils = ProcessUtils(logger: logger, processManager: processManager); _processUtils = ProcessUtils(logger: logger, processManager: processManager),
_usage = usage;
final Platform _platform; final Platform _platform;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final ProcessUtils _processUtils; final ProcessUtils _processUtils;
final Terminal _terminal; final Terminal _terminal;
final Logger _logger; final Logger _logger;
final Usage _usage;
static const String _executable = '/usr/bin/xcodebuild'; static const String _executable = '/usr/bin/xcodebuild';
static final RegExp _versionRegex = RegExp(r'Xcode ([0-9.]+)'); static final RegExp _versionRegex = RegExp(r'Xcode ([0-9.]+)');
...@@ -359,6 +362,7 @@ class XcodeProjectInterpreter { ...@@ -359,6 +362,7 @@ class XcodeProjectInterpreter {
if (error is ProcessException && error.toString().contains('timed out')) { if (error is ProcessException && error.toString().contains('timed out')) {
BuildEvent('xcode-show-build-settings-timeout', BuildEvent('xcode-show-build-settings-timeout',
command: showBuildSettingsCommand.join(' '), command: showBuildSettingsCommand.join(' '),
flutterUsage: _usage,
).send(); ).send();
} }
_logger.printTrace('Unexpected failure to get the build settings: $error.'); _logger.printTrace('Unexpected failure to get the build settings: $error.');
......
...@@ -135,10 +135,14 @@ class PubResultEvent extends UsageEvent { ...@@ -135,10 +135,14 @@ class PubResultEvent extends UsageEvent {
/// An event that reports something about a build. /// An event that reports something about a build.
class BuildEvent extends UsageEvent { class BuildEvent extends UsageEvent {
BuildEvent(String label, { BuildEvent(String label, {
this.command, String command,
this.settings, String settings,
this.eventError, String eventError,
}) : super( @required Usage flutterUsage,
}) : _command = command,
_settings = settings,
_eventError = eventError,
super(
// category // category
'build', 'build',
// parameter // parameter
...@@ -146,22 +150,22 @@ class BuildEvent extends UsageEvent { ...@@ -146,22 +150,22 @@ class BuildEvent extends UsageEvent {
? 'unspecified' ? 'unspecified'
: FlutterCommand.current.name, : FlutterCommand.current.name,
label: label, label: label,
flutterUsage: globals.flutterUsage, flutterUsage: flutterUsage,
); );
final String command; final String _command;
final String settings; final String _settings;
final String eventError; final String _eventError;
@override @override
void send() { void send() {
final Map<String, String> parameters = _useCdKeys(<CustomDimensions, String>{ final Map<String, String> parameters = _useCdKeys(<CustomDimensions, String>{
if (command != null) if (_command != null)
CustomDimensions.buildEventCommand: command, CustomDimensions.buildEventCommand: _command,
if (settings != null) if (_settings != null)
CustomDimensions.buildEventSettings: settings, CustomDimensions.buildEventSettings: _settings,
if (eventError != null) if (_eventError != null)
CustomDimensions.buildEventError: eventError, CustomDimensions.buildEventError: _eventError,
}); });
flutterUsage.sendEvent( flutterUsage.sendEvent(
category, category,
......
...@@ -83,6 +83,8 @@ abstract class Usage { ...@@ -83,6 +83,8 @@ abstract class Usage {
analyticsIOFactory: analyticsIOFactory, analyticsIOFactory: analyticsIOFactory,
runningOnBot: runningOnBot); runningOnBot: runningOnBot);
factory Usage.test() => _DefaultUsage.test();
/// Uses the global [Usage] instance to send a 'command' to analytics. /// Uses the global [Usage] instance to send a 'command' to analytics.
static void command(String command, { static void command(String command, {
Map<CustomDimensions, String> parameters, Map<CustomDimensions, String> parameters,
...@@ -265,6 +267,10 @@ class _DefaultUsage implements Usage { ...@@ -265,6 +267,10 @@ class _DefaultUsage implements Usage {
_analytics.analyticsOpt = AnalyticsOpt.optOut; _analytics.analyticsOpt = AnalyticsOpt.optOut;
} }
_DefaultUsage.test() :
_suppressAnalytics = true,
_analytics = AnalyticsMock();
Analytics _analytics; Analytics _analytics;
bool _printedWelcome = false; bool _printedWelcome = false;
......
...@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/build_info.dart'; ...@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/base/build.dart'; import 'package:flutter_tools/src/base/build.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
...@@ -189,6 +190,7 @@ void main() { ...@@ -189,6 +190,7 @@ void main() {
logger: logger, logger: logger,
fileSystem: fileSystem, fileSystem: fileSystem,
terminal: Terminal.test(), terminal: Terminal.test(),
usage: Usage.test(),
), ),
), ),
artifacts: mockArtifacts, artifacts: mockArtifacts,
......
...@@ -8,15 +8,14 @@ import 'package:flutter_tools/src/device.dart'; ...@@ -8,15 +8,14 @@ import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/ios/fallback_discovery.dart'; import 'package:flutter_tools/src/ios/fallback_discovery.dart';
import 'package:flutter_tools/src/mdns_discovery.dart'; import 'package:flutter_tools/src/mdns_discovery.dart';
import 'package:flutter_tools/src/protocol_discovery.dart'; import 'package:flutter_tools/src/protocol_discovery.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart'; import '../../src/mocks.dart';
// This test still uses `testUsingContext` due to analytics usage.
void main() { void main() {
BufferLogger logger; BufferLogger logger;
FallbackDiscovery fallbackDiscovery; FallbackDiscovery fallbackDiscovery;
...@@ -39,6 +38,7 @@ void main() { ...@@ -39,6 +38,7 @@ void main() {
mDnsObservatoryDiscovery: mockMDnsObservatoryDiscovery, mDnsObservatoryDiscovery: mockMDnsObservatoryDiscovery,
portForwarder: mockPortForwarder, portForwarder: mockPortForwarder,
protocolDiscovery: mockPrototcolDiscovery, protocolDiscovery: mockPrototcolDiscovery,
flutterUsage: Usage.test(),
vmServiceConnectUri: (String uri, {Log log}) async { vmServiceConnectUri: (String uri, {Log log}) async {
return mockVmService; return mockVmService;
}, },
...@@ -47,7 +47,7 @@ void main() { ...@@ -47,7 +47,7 @@ void main() {
.thenAnswer((Invocation invocation) async => 1); .thenAnswer((Invocation invocation) async => 1);
}); });
testUsingContext('Selects assumed port if VM service connection is successful', () async { testWithoutContext('Selects assumed port if VM service connection is successful', () async {
when(mockVmService.getVM()).thenAnswer((Invocation invocation) async { when(mockVmService.getVM()).thenAnswer((Invocation invocation) async {
return VM.parse(<String, Object>{})..isolates = <IsolateRef>[ return VM.parse(<String, Object>{})..isolates = <IsolateRef>[
IsolateRef.parse(<String, Object>{}), IsolateRef.parse(<String, Object>{}),
...@@ -68,7 +68,7 @@ void main() { ...@@ -68,7 +68,7 @@ void main() {
), Uri.parse('http://localhost:1')); ), Uri.parse('http://localhost:1'));
}); });
testUsingContext('Selects assumed port when another isolate has no root library', () async { testWithoutContext('Selects assumed port when another isolate has no root library', () async {
when(mockVmService.getVM()).thenAnswer((Invocation invocation) async { when(mockVmService.getVM()).thenAnswer((Invocation invocation) async {
return VM.parse(<String, Object>{})..isolates = <IsolateRef>[ return VM.parse(<String, Object>{})..isolates = <IsolateRef>[
IsolateRef.parse(<String, Object>{})..id = '1', IsolateRef.parse(<String, Object>{})..id = '1',
...@@ -93,7 +93,7 @@ void main() { ...@@ -93,7 +93,7 @@ void main() {
), Uri.parse('http://localhost:1')); ), Uri.parse('http://localhost:1'));
}); });
testUsingContext('Selects mdns discovery if VM service connecton fails due to Sentinel', () async { testWithoutContext('Selects mdns discovery if VM service connecton fails due to Sentinel', () async {
when(mockVmService.getVM()).thenAnswer((Invocation invocation) async { when(mockVmService.getVM()).thenAnswer((Invocation invocation) async {
return VM.parse(<String, Object>{})..isolates = <IsolateRef>[ return VM.parse(<String, Object>{})..isolates = <IsolateRef>[
IsolateRef( IsolateRef(
...@@ -124,7 +124,7 @@ void main() { ...@@ -124,7 +124,7 @@ void main() {
), Uri.parse('http://localhost:1234')); ), Uri.parse('http://localhost:1234'));
}); });
testUsingContext('Selects mdns discovery if VM service connecton fails', () async { testWithoutContext('Selects mdns discovery if VM service connecton fails', () async {
when(mockVmService.getVM()).thenThrow(Exception()); when(mockVmService.getVM()).thenThrow(Exception());
when(mockMDnsObservatoryDiscovery.getObservatoryUri( when(mockMDnsObservatoryDiscovery.getObservatoryUri(
...@@ -146,7 +146,7 @@ void main() { ...@@ -146,7 +146,7 @@ void main() {
), Uri.parse('http://localhost:1234')); ), Uri.parse('http://localhost:1234'));
}); });
testUsingContext('Selects log scanning if both VM Service and mDNS fails', () async { testWithoutContext('Selects log scanning if both VM Service and mDNS fails', () async {
when(mockVmService.getVM()).thenThrow(Exception()); when(mockVmService.getVM()).thenThrow(Exception());
when(mockMDnsObservatoryDiscovery.getObservatoryUri( when(mockMDnsObservatoryDiscovery.getObservatoryUri(
'hello', 'hello',
......
...@@ -132,7 +132,7 @@ void main() { ...@@ -132,7 +132,7 @@ void main() {
), ),
); );
await diagnoseXcodeBuildFailure(buildResult); await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
verify(mockUsage.sendEvent('build', verify(mockUsage.sendEvent('build',
any, any,
label: 'xcode-bitcode-failure', label: 'xcode-bitcode-failure',
...@@ -140,8 +140,6 @@ void main() { ...@@ -140,8 +140,6 @@ void main() {
cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(), cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(),
cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(), cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(),
})).called(1); })).called(1);
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
}); });
testUsingContext('No provisioning profile shows message', () async { testUsingContext('No provisioning profile shows message', () async {
...@@ -210,9 +208,9 @@ Error launching application on iPhone.''', ...@@ -210,9 +208,9 @@ Error launching application on iPhone.''',
), ),
); );
await diagnoseXcodeBuildFailure(buildResult); await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
expect( expect(
testLogger.errorText, logger.errorText,
contains("No Provisioning Profile was found for your project's Bundle Identifier or your \ndevice."), contains("No Provisioning Profile was found for your project's Bundle Identifier or your \ndevice."),
); );
}, overrides: noColorTerminalOverride); }, overrides: noColorTerminalOverride);
...@@ -291,9 +289,9 @@ Could not build the precompiled application for the device.''', ...@@ -291,9 +289,9 @@ Could not build the precompiled application for the device.''',
), ),
); );
await diagnoseXcodeBuildFailure(buildResult); await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
expect( expect(
testLogger.errorText, logger.errorText,
contains('Building a deployable iOS app requires a selected Development Team with a \nProvisioning Profile.'), contains('Building a deployable iOS app requires a selected Development Team with a \nProvisioning Profile.'),
); );
}, overrides: noColorTerminalOverride); }, overrides: noColorTerminalOverride);
...@@ -328,9 +326,9 @@ Exited (sigterm)''', ...@@ -328,9 +326,9 @@ Exited (sigterm)''',
), ),
); );
await diagnoseXcodeBuildFailure(buildResult); await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
expect( expect(
testLogger.errorText, logger.errorText,
contains('Your Xcode project requires migration.'), contains('Your Xcode project requires migration.'),
); );
}, overrides: noColorTerminalOverride); }, overrides: noColorTerminalOverride);
...@@ -365,9 +363,9 @@ Exited (sigterm)''', ...@@ -365,9 +363,9 @@ Exited (sigterm)''',
), ),
); );
await diagnoseXcodeBuildFailure(buildResult); await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
expect( expect(
testLogger.errorText, logger.errorText,
contains('Your Xcode project requires migration.'), contains('Your Xcode project requires migration.'),
); );
}, overrides: noColorTerminalOverride); }, overrides: noColorTerminalOverride);
......
...@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/base/terminal.dart'; ...@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
...@@ -48,6 +49,7 @@ void main() { ...@@ -48,6 +49,7 @@ void main() {
platform: platform, platform: platform,
processManager: processManager, processManager: processManager,
terminal: terminal, terminal: terminal,
usage: null,
); );
}); });
...@@ -130,6 +132,7 @@ void main() { ...@@ -130,6 +132,7 @@ void main() {
platform: platform, platform: platform,
processManager: processManager, processManager: processManager,
terminal: terminal, terminal: terminal,
usage: Usage.test(),
); );
fileSystem.file(xcodebuild).deleteSync(); fileSystem.file(xcodebuild).deleteSync();
...@@ -261,6 +264,7 @@ void main() { ...@@ -261,6 +264,7 @@ void main() {
platform: platform, platform: platform,
processManager: processManager, processManager: processManager,
terminal: terminal, terminal: terminal,
usage: Usage.test(),
); );
expect(await xcodeProjectInterpreter.getInfo(workingDirectory), isNotNull); expect(await xcodeProjectInterpreter.getInfo(workingDirectory), isNotNull);
...@@ -282,6 +286,7 @@ void main() { ...@@ -282,6 +286,7 @@ void main() {
platform: platform, platform: platform,
processManager: processManager, processManager: processManager,
terminal: terminal, terminal: terminal,
usage: Usage.test(),
); );
expect( expect(
......
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