Unverified Commit 48187028 authored by Elias Yishak's avatar Elias Yishak Committed by GitHub

Add `commandHasTerminal` parameter + apple usage event + `sendException`...

Add `commandHasTerminal` parameter + apple usage event + `sendException` events for `package:unified_analytics` (#138806)

Relates to tracker issue:
- https://github.com/flutter/flutter/issues/128251

This PR includes 3 major updates:
- Adding the `commandHasTerminal` parameter for `Event.flutterCommandResult`
  - In `packages/flutter_tools/lib/src/runner/flutter_command.dart`
- Adding the new event for `sendException` from package:usage to be `Event.exception` (this event can be used by all dash tools)
  - In `packages/flutter_tools/lib/runner.dart`
- Migrating the generic `UsageEvent` which was only used for Apple related workflows for iOS and macOS. I did an initial analysis in this [sheet](https://docs.google.com/spreadsheets/d/11KJLkHXFpECMX7tw-trNkYSr5MHDG15XNGv6TgLjfQs/edit?resourcekey=0-j4qdvsOEEg3wQW79YlY1-g#gid=0) to identify all the call sites
  - Found in several files, highlighted in the sheet above
parent 67a602d7
...@@ -7,6 +7,7 @@ import 'dart:async'; ...@@ -7,6 +7,7 @@ import 'dart:async';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:intl/intl.dart' as intl; import 'package:intl/intl.dart' as intl;
import 'package:intl/intl_standalone.dart' as intl_standalone; import 'package:intl/intl_standalone.dart' as intl_standalone;
import 'package:unified_analytics/unified_analytics.dart';
import 'src/base/async_guard.dart'; import 'src/base/async_guard.dart';
import 'src/base/common.dart'; import 'src/base/common.dart';
...@@ -186,6 +187,7 @@ Future<int> _handleToolError( ...@@ -186,6 +187,7 @@ Future<int> _handleToolError(
// Report to both [Usage] and [CrashReportSender]. // Report to both [Usage] and [CrashReportSender].
globals.flutterUsage.sendException(error); globals.flutterUsage.sendException(error);
globals.analytics.send(Event.exception(exception: error.runtimeType.toString()));
await asyncGuard(() async { await asyncGuard(() async {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
usage: globals.flutterUsage, usage: globals.flutterUsage,
......
...@@ -8,6 +8,7 @@ import 'package:crypto/crypto.dart'; ...@@ -8,6 +8,7 @@ import 'package:crypto/crypto.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:pool/pool.dart'; import 'package:pool/pool.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/error_handling_io.dart'; import '../base/error_handling_io.dart';
...@@ -335,6 +336,7 @@ class Environment { ...@@ -335,6 +336,7 @@ class Environment {
required ProcessManager processManager, required ProcessManager processManager,
required Platform platform, required Platform platform,
required Usage usage, required Usage usage,
required Analytics analytics,
String? engineVersion, String? engineVersion,
required bool generateDartPluginRegistry, required bool generateDartPluginRegistry,
Directory? buildDir, Directory? buildDir,
...@@ -376,6 +378,7 @@ class Environment { ...@@ -376,6 +378,7 @@ class Environment {
processManager: processManager, processManager: processManager,
platform: platform, platform: platform,
usage: usage, usage: usage,
analytics: analytics,
engineVersion: engineVersion, engineVersion: engineVersion,
inputs: inputs, inputs: inputs,
generateDartPluginRegistry: generateDartPluginRegistry, generateDartPluginRegistry: generateDartPluginRegistry,
...@@ -397,6 +400,7 @@ class Environment { ...@@ -397,6 +400,7 @@ class Environment {
String? engineVersion, String? engineVersion,
Platform? platform, Platform? platform,
Usage? usage, Usage? usage,
Analytics? analytics,
bool generateDartPluginRegistry = false, bool generateDartPluginRegistry = false,
required FileSystem fileSystem, required FileSystem fileSystem,
required Logger logger, required Logger logger,
...@@ -417,6 +421,7 @@ class Environment { ...@@ -417,6 +421,7 @@ class Environment {
processManager: processManager, processManager: processManager,
platform: platform ?? FakePlatform(), platform: platform ?? FakePlatform(),
usage: usage ?? TestUsage(), usage: usage ?? TestUsage(),
analytics: analytics ?? NoOpAnalytics(),
engineVersion: engineVersion, engineVersion: engineVersion,
generateDartPluginRegistry: generateDartPluginRegistry, generateDartPluginRegistry: generateDartPluginRegistry,
); );
...@@ -436,6 +441,7 @@ class Environment { ...@@ -436,6 +441,7 @@ class Environment {
required this.fileSystem, required this.fileSystem,
required this.artifacts, required this.artifacts,
required this.usage, required this.usage,
required this.analytics,
this.engineVersion, this.engineVersion,
required this.inputs, required this.inputs,
required this.generateDartPluginRegistry, required this.generateDartPluginRegistry,
...@@ -518,6 +524,8 @@ class Environment { ...@@ -518,6 +524,8 @@ class Environment {
final Usage usage; final Usage usage;
final Analytics analytics;
/// The version of the current engine, or `null` if built with a local engine. /// The version of the current engine, or `null` if built with a local engine.
final String? engineVersion; final String? engineVersion;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../../artifacts.dart'; import '../../artifacts.dart';
import '../../base/build.dart'; import '../../base/build.dart';
...@@ -640,6 +641,11 @@ class ReleaseIosApplicationBundle extends _IosAssetBundleWithDSYM { ...@@ -640,6 +641,11 @@ class ReleaseIosApplicationBundle extends _IosAssetBundleWithDSYM {
label: buildSuccess ? 'success' : 'fail', label: buildSuccess ? 'success' : 'fail',
flutterUsage: environment.usage, flutterUsage: environment.usage,
).send(); ).send();
environment.analytics.send(Event.appleUsageEvent(
workflow: 'assemble',
parameter: 'ios-archive',
result: buildSuccess ? 'success' : 'fail',
));
} }
} }
} }
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:unified_analytics/unified_analytics.dart';
import '../../artifacts.dart'; import '../../artifacts.dart';
import '../../base/build.dart'; import '../../base/build.dart';
import '../../base/file_system.dart'; import '../../base/file_system.dart';
...@@ -628,6 +630,11 @@ class ReleaseMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { ...@@ -628,6 +630,11 @@ class ReleaseMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets {
label: buildSuccess ? 'success' : 'fail', label: buildSuccess ? 'success' : 'fail',
flutterUsage: environment.usage, flutterUsage: environment.usage,
).send(); ).send();
environment.analytics.send(Event.appleUsageEvent(
workflow: 'assemble',
parameter: 'macos-archive',
result: buildSuccess ? 'success' : 'fail',
));
} }
} }
} }
......
...@@ -72,6 +72,7 @@ class BundleBuilder { ...@@ -72,6 +72,7 @@ class BundleBuilder {
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
platform: globals.platform, platform: globals.platform,
generateDartPluginRegistry: true, generateDartPluginRegistry: true,
); );
......
...@@ -233,6 +233,7 @@ class AssembleCommand extends FlutterCommand { ...@@ -233,6 +233,7 @@ class AssembleCommand extends FlutterCommand {
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
platform: globals.platform, platform: globals.platform,
engineVersion: artifacts.isLocalEngine engineVersion: artifacts.isLocalEngine
? null ? null
......
...@@ -461,6 +461,7 @@ end ...@@ -461,6 +461,7 @@ end
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
engineVersion: globals.artifacts!.isLocalEngine engineVersion: globals.artifacts!.isLocalEngine
? null ? null
: globals.flutterVersion.engineRevision, : globals.flutterVersion.engineRevision,
......
...@@ -226,6 +226,7 @@ end ...@@ -226,6 +226,7 @@ end
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
engineVersion: globals.artifacts!.isLocalEngine ? null : globals.flutterVersion.engineRevision, engineVersion: globals.artifacts!.isLocalEngine ? null : globals.flutterVersion.engineRevision,
generateDartPluginRegistry: true, generateDartPluginRegistry: true,
); );
......
...@@ -534,6 +534,7 @@ abstract class CreateBase extends FlutterCommand { ...@@ -534,6 +534,7 @@ abstract class CreateBase extends FlutterCommand {
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
projectDir: project.directory, projectDir: project.directory,
generateDartPluginRegistry: true, generateDartPluginRegistry: true,
); );
......
...@@ -298,6 +298,7 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -298,6 +298,7 @@ class PackagesGetCommand extends FlutterCommand {
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
projectDir: rootProject.directory, projectDir: rootProject.directory,
generateDartPluginRegistry: true, generateDartPluginRegistry: true,
); );
...@@ -318,6 +319,7 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -318,6 +319,7 @@ class PackagesGetCommand extends FlutterCommand {
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
projectDir: rootProject.directory, projectDir: rootProject.directory,
generateDartPluginRegistry: true, generateDartPluginRegistry: true,
); );
......
...@@ -168,6 +168,7 @@ Future<T> runInContext<T>( ...@@ -168,6 +168,7 @@ Future<T> runInContext<T>(
platform: globals.platform, platform: globals.platform,
xcodeProjectInterpreter: globals.xcodeProjectInterpreter!, xcodeProjectInterpreter: globals.xcodeProjectInterpreter!,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
), ),
CocoaPodsValidator: () => CocoaPodsValidator( CocoaPodsValidator: () => CocoaPodsValidator(
globals.cocoaPods!, globals.cocoaPods!,
...@@ -300,6 +301,7 @@ Future<T> runInContext<T>( ...@@ -300,6 +301,7 @@ Future<T> runInContext<T>(
MDnsVmServiceDiscovery: () => MDnsVmServiceDiscovery( MDnsVmServiceDiscovery: () => MDnsVmServiceDiscovery(
logger: globals.logger, logger: globals.logger,
flutterUsage: globals.flutterUsage, flutterUsage: globals.flutterUsage,
analytics: globals.analytics,
), ),
OperatingSystemUtils: () => OperatingSystemUtils( OperatingSystemUtils: () => OperatingSystemUtils(
fileSystem: globals.fs, fileSystem: globals.fs,
...@@ -382,6 +384,7 @@ Future<T> runInContext<T>( ...@@ -382,6 +384,7 @@ Future<T> runInContext<T>(
dyLdLibEntry: globals.cache.dyLdLibEntry, dyLdLibEntry: globals.cache.dyLdLibEntry,
), ),
fileSystem: globals.fs, fileSystem: globals.fs,
analytics: globals.analytics,
), ),
XcodeProjectInterpreter: () => XcodeProjectInterpreter( XcodeProjectInterpreter: () => XcodeProjectInterpreter(
logger: globals.logger, logger: globals.logger,
......
...@@ -143,7 +143,7 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -143,7 +143,7 @@ Future<XcodeBuildResult> buildXcodeProject({
} }
final List<ProjectMigrator> migrators = <ProjectMigrator>[ final List<ProjectMigrator> migrators = <ProjectMigrator>[
RemoveFrameworkLinkAndEmbeddingMigration(app.project, globals.logger, globals.flutterUsage), RemoveFrameworkLinkAndEmbeddingMigration(app.project, globals.logger, globals.flutterUsage, globals.analytics),
XcodeBuildSystemMigration(app.project, globals.logger), XcodeBuildSystemMigration(app.project, globals.logger),
ProjectBaseConfigurationMigration(app.project, globals.logger), ProjectBaseConfigurationMigration(app.project, globals.logger),
ProjectBuildLocationMigration(app.project, globals.logger), ProjectBuildLocationMigration(app.project, globals.logger),
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:unified_analytics/unified_analytics.dart';
import '../../base/common.dart'; import '../../base/common.dart';
import '../../base/file_system.dart'; import '../../base/file_system.dart';
import '../../base/project_migrator.dart'; import '../../base/project_migrator.dart';
...@@ -16,11 +18,14 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends ProjectMigrator { ...@@ -16,11 +18,14 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends ProjectMigrator {
IosProject project, IosProject project,
super.logger, super.logger,
Usage usage, Usage usage,
Analytics analytics,
) : _xcodeProjectInfoFile = project.xcodeProjectInfoFile, ) : _xcodeProjectInfoFile = project.xcodeProjectInfoFile,
_usage = usage; _usage = usage,
_analytics = analytics;
final File _xcodeProjectInfoFile; final File _xcodeProjectInfoFile;
final Usage _usage; final Usage _usage;
final Analytics _analytics;
@override @override
void migrate() { void migrate() {
...@@ -91,6 +96,11 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends ProjectMigrator { ...@@ -91,6 +96,11 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends ProjectMigrator {
if (line.contains('/* App.framework ') || line.contains('/* Flutter.framework ')) { if (line.contains('/* App.framework ') || line.contains('/* Flutter.framework ')) {
// Print scary message. // Print scary message.
UsageEvent('ios-migration', 'remove-frameworks', label: 'failure', flutterUsage: _usage).send(); UsageEvent('ios-migration', 'remove-frameworks', label: 'failure', flutterUsage: _usage).send();
_analytics.send(Event.appleUsageEvent(
workflow: 'ios-migration',
parameter: 'remove-frameworks',
result: 'failure',
));
throwToolExit('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.'); throwToolExit('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
} }
......
...@@ -71,6 +71,7 @@ Future<void> buildMacOS({ ...@@ -71,6 +71,7 @@ Future<void> buildMacOS({
flutterProject.macos, flutterProject.macos,
globals.logger, globals.logger,
globals.flutterUsage, globals.flutterUsage,
globals.analytics,
), ),
MacOSDeploymentTargetMigration(flutterProject.macos, globals.logger), MacOSDeploymentTargetMigration(flutterProject.macos, globals.logger),
XcodeProjectObjectVersionMigration(flutterProject.macos, globals.logger), XcodeProjectObjectVersionMigration(flutterProject.macos, globals.logger),
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/error_handling_io.dart'; import '../base/error_handling_io.dart';
...@@ -93,11 +94,13 @@ class CocoaPods { ...@@ -93,11 +94,13 @@ class CocoaPods {
required Logger logger, required Logger logger,
required Platform platform, required Platform platform,
required Usage usage, required Usage usage,
required Analytics analytics,
}) : _fileSystem = fileSystem, }) : _fileSystem = fileSystem,
_processManager = processManager, _processManager = processManager,
_xcodeProjectInterpreter = xcodeProjectInterpreter, _xcodeProjectInterpreter = xcodeProjectInterpreter,
_logger = logger, _logger = logger,
_usage = usage, _usage = usage,
_analytics = analytics,
_processUtils = ProcessUtils(processManager: processManager, logger: logger), _processUtils = ProcessUtils(processManager: processManager, logger: logger),
_operatingSystemUtils = OperatingSystemUtils( _operatingSystemUtils = OperatingSystemUtils(
fileSystem: fileSystem, fileSystem: fileSystem,
...@@ -113,6 +116,7 @@ class CocoaPods { ...@@ -113,6 +116,7 @@ class CocoaPods {
final XcodeProjectInterpreter _xcodeProjectInterpreter; final XcodeProjectInterpreter _xcodeProjectInterpreter;
final Logger _logger; final Logger _logger;
final Usage _usage; final Usage _usage;
final Analytics _analytics;
Future<String?>? _versionText; Future<String?>? _versionText;
...@@ -384,6 +388,10 @@ class CocoaPods { ...@@ -384,6 +388,10 @@ class CocoaPods {
'arm-ffi', 'arm-ffi',
flutterUsage: _usage, flutterUsage: _usage,
).send(); ).send();
_analytics.send(Event.appleUsageEvent(
workflow: 'pod-install-failure',
parameter: 'arm-ffi',
));
_logger.printError( _logger.printError(
'Error: To set up CocoaPods for ARM macOS, run:\n' 'Error: To set up CocoaPods for ARM macOS, run:\n'
' sudo gem uninstall ffi && sudo gem install ffi -- --enable-libffi-alloc\n', ' sudo gem uninstall ffi && sudo gem install ffi -- --enable-libffi-alloc\n',
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:unified_analytics/unified_analytics.dart';
import '../../base/common.dart'; import '../../base/common.dart';
import '../../base/file_system.dart'; import '../../base/file_system.dart';
import '../../base/project_migrator.dart'; import '../../base/project_migrator.dart';
...@@ -14,11 +16,14 @@ class RemoveMacOSFrameworkLinkAndEmbeddingMigration extends ProjectMigrator { ...@@ -14,11 +16,14 @@ class RemoveMacOSFrameworkLinkAndEmbeddingMigration extends ProjectMigrator {
MacOSProject project, MacOSProject project,
super.logger, super.logger,
Usage usage, Usage usage,
Analytics analytics,
) : _xcodeProjectInfoFile = project.xcodeProjectInfoFile, ) : _xcodeProjectInfoFile = project.xcodeProjectInfoFile,
_usage = usage; _usage = usage,
_analytics = analytics;
final File _xcodeProjectInfoFile; final File _xcodeProjectInfoFile;
final Usage _usage; final Usage _usage;
final Analytics _analytics;
@override @override
void migrate() { void migrate() {
...@@ -89,6 +94,11 @@ class RemoveMacOSFrameworkLinkAndEmbeddingMigration extends ProjectMigrator { ...@@ -89,6 +94,11 @@ class RemoveMacOSFrameworkLinkAndEmbeddingMigration extends ProjectMigrator {
UsageEvent('macos-migration', 'remove-frameworks', UsageEvent('macos-migration', 'remove-frameworks',
label: 'failure', flutterUsage: _usage) label: 'failure', flutterUsage: _usage)
.send(); .send();
_analytics.send(Event.appleUsageEvent(
workflow: 'macos-migration',
parameter: 'remove-frameworks',
result: 'failure',
));
throwToolExit( throwToolExit(
'Your Xcode project requires migration.'); 'Your Xcode project requires migration.');
} }
......
...@@ -6,6 +6,7 @@ import 'dart:async'; ...@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
...@@ -69,6 +70,7 @@ class XCDevice { ...@@ -69,6 +70,7 @@ class XCDevice {
required Platform platform, required Platform platform,
required IProxy iproxy, required IProxy iproxy,
required FileSystem fileSystem, required FileSystem fileSystem,
required Analytics analytics,
@visibleForTesting @visibleForTesting
IOSCoreDeviceControl? coreDeviceControl, IOSCoreDeviceControl? coreDeviceControl,
XcodeDebug? xcodeDebug, XcodeDebug? xcodeDebug,
...@@ -100,7 +102,8 @@ class XCDevice { ...@@ -100,7 +102,8 @@ class XCDevice {
fileSystem: fileSystem, fileSystem: fileSystem,
), ),
_iProxy = iproxy, _iProxy = iproxy,
_xcode = xcode { _xcode = xcode,
_analytics = analytics {
_setupDeviceIdentifierByEventStream(); _setupDeviceIdentifierByEventStream();
} }
...@@ -120,6 +123,7 @@ class XCDevice { ...@@ -120,6 +123,7 @@ class XCDevice {
final IProxy _iProxy; final IProxy _iProxy;
final IOSCoreDeviceControl _coreDeviceControl; final IOSCoreDeviceControl _coreDeviceControl;
final XcodeDebug _xcodeDebug; final XcodeDebug _xcodeDebug;
final Analytics _analytics;
List<Object>? _cachedListResults; List<Object>? _cachedListResults;
...@@ -546,6 +550,8 @@ class XCDevice { ...@@ -546,6 +550,8 @@ class XCDevice {
if (errorMessage != null) { if (errorMessage != null) {
if (errorMessage.contains('not paired')) { if (errorMessage.contains('not paired')) {
UsageEvent('device', 'ios-trust-failure', flutterUsage: globals.flutterUsage).send(); UsageEvent('device', 'ios-trust-failure', flutterUsage: globals.flutterUsage).send();
_analytics.send(Event.appleUsageEvent(workflow: 'device', parameter: 'ios-trust-failure'));
} }
_logger.printTrace(errorMessage); _logger.printTrace(errorMessage);
} }
......
...@@ -6,6 +6,7 @@ import 'dart:async'; ...@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:multicast_dns/multicast_dns.dart'; import 'package:multicast_dns/multicast_dns.dart';
import 'package:unified_analytics/unified_analytics.dart';
import 'base/common.dart'; import 'base/common.dart';
import 'base/context.dart'; import 'base/context.dart';
...@@ -26,10 +27,12 @@ class MDnsVmServiceDiscovery { ...@@ -26,10 +27,12 @@ class MDnsVmServiceDiscovery {
MDnsClient? preliminaryMDnsClient, MDnsClient? preliminaryMDnsClient,
required Logger logger, required Logger logger,
required Usage flutterUsage, required Usage flutterUsage,
required Analytics analytics,
}) : _client = mdnsClient ?? MDnsClient(), }) : _client = mdnsClient ?? MDnsClient(),
_preliminaryClient = preliminaryMDnsClient, _preliminaryClient = preliminaryMDnsClient,
_logger = logger, _logger = logger,
_flutterUsage = flutterUsage; _flutterUsage = flutterUsage,
_analytics = analytics;
final MDnsClient _client; final MDnsClient _client;
...@@ -39,6 +42,7 @@ class MDnsVmServiceDiscovery { ...@@ -39,6 +42,7 @@ class MDnsVmServiceDiscovery {
final Logger _logger; final Logger _logger;
final Usage _flutterUsage; final Usage _flutterUsage;
final Analytics _analytics;
@visibleForTesting @visibleForTesting
static const String dartVmServiceName = '_dartVmService._tcp.local'; static const String dartVmServiceName = '_dartVmService._tcp.local';
...@@ -504,6 +508,7 @@ class MDnsVmServiceDiscovery { ...@@ -504,6 +508,7 @@ class MDnsVmServiceDiscovery {
switch (targetPlatform) { switch (targetPlatform) {
case TargetPlatform.ios: case TargetPlatform.ios:
UsageEvent('ios-mdns', 'no-ipv4-link-local', flutterUsage: _flutterUsage).send(); UsageEvent('ios-mdns', 'no-ipv4-link-local', flutterUsage: _flutterUsage).send();
_analytics.send(Event.appleUsageEvent(workflow: 'ios-mdns', parameter: 'no-ipv4-link-local'));
_logger.printError( _logger.printError(
'The mDNS query for an attached iOS device failed. It may ' 'The mDNS query for an attached iOS device failed. It may '
'be necessary to disable the "Personal Hotspot" on the device, and ' 'be necessary to disable the "Personal Hotspot" on the device, and '
......
...@@ -1254,6 +1254,7 @@ abstract class ResidentRunner extends ResidentHandlers { ...@@ -1254,6 +1254,7 @@ abstract class ResidentRunner extends ResidentHandlers {
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
projectDir: globals.fs.currentDirectory, projectDir: globals.fs.currentDirectory,
generateDartPluginRegistry: generateDartPluginRegistry, generateDartPluginRegistry: generateDartPluginRegistry,
defines: <String, String>{ defines: <String, String>{
......
...@@ -1621,6 +1621,7 @@ abstract class FlutterCommand extends Command<void> { ...@@ -1621,6 +1621,7 @@ abstract class FlutterCommand extends Command<void> {
commandPath: commandPath, commandPath: commandPath,
result: commandResult.toString(), result: commandResult.toString(),
maxRss: maxRss, maxRss: maxRss,
commandHasTerminal: globals.stdio.hasTerminal,
)); ));
// Send timing. // Send timing.
...@@ -1706,6 +1707,7 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and ...@@ -1706,6 +1707,7 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
analytics: globals.analytics,
projectDir: project.directory, projectDir: project.directory,
generateDartPluginRegistry: true, generateDartPluginRegistry: true,
); );
......
...@@ -110,6 +110,7 @@ class WebBuilder { ...@@ -110,6 +110,7 @@ class WebBuilder {
processManager: _processManager, processManager: _processManager,
platform: globals.platform, platform: globals.platform,
usage: _flutterUsage, usage: _flutterUsage,
analytics: _analytics,
cacheDir: globals.cache.getRoot(), cacheDir: globals.cache.getRoot(),
engineVersion: globals.artifacts!.isLocalEngine ? null : _flutterVersion.engineRevision, engineVersion: globals.artifacts!.isLocalEngine ? null : _flutterVersion.engineRevision,
flutterRootDir: _fileSystem.directory(Cache.flutterRoot), flutterRootDir: _fileSystem.directory(Cache.flutterRoot),
......
...@@ -21,7 +21,7 @@ dependencies: ...@@ -21,7 +21,7 @@ dependencies:
http: 0.13.6 http: 0.13.6
intl: 0.18.1 intl: 0.18.1
meta: 1.11.0 meta: 1.11.0
multicast_dns: 0.3.2+4 multicast_dns: 0.3.2+5
mustache_template: 2.0.0 mustache_template: 2.0.0
package_config: 2.1.0 package_config: 2.1.0
process: 5.0.1 process: 5.0.1
...@@ -48,7 +48,7 @@ dependencies: ...@@ -48,7 +48,7 @@ dependencies:
http_multi_server: 3.2.1 http_multi_server: 3.2.1
convert: 3.1.1 convert: 3.1.1
async: 2.11.0 async: 2.11.0
unified_analytics: 5.4.0 unified_analytics: 5.5.0
cli_config: 0.1.2 cli_config: 0.1.2
graphs: 2.3.1 graphs: 2.3.1
...@@ -91,13 +91,14 @@ dependencies: ...@@ -91,13 +91,14 @@ dependencies:
source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sse: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sse: 4.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_interface: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service_interface: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web: 0.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml_edit: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml_edit: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies: dev_dependencies:
...@@ -114,4 +115,4 @@ dartdoc: ...@@ -114,4 +115,4 @@ dartdoc:
# Exclude this package from the hosted API docs. # Exclude this package from the hosted API docs.
nodoc: true nodoc: true
# PUBSPEC CHECKSUM: 5011 # PUBSPEC CHECKSUM: e59e
...@@ -162,6 +162,7 @@ void main() { ...@@ -162,6 +162,7 @@ void main() {
preliminaryMDnsClient: FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}), preliminaryMDnsClient: FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}),
logger: logger, logger: logger,
flutterUsage: TestUsage(), flutterUsage: TestUsage(),
analytics: NoOpAnalytics(),
), ),
}); });
...@@ -225,6 +226,7 @@ void main() { ...@@ -225,6 +226,7 @@ void main() {
preliminaryMDnsClient: FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}), preliminaryMDnsClient: FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}),
logger: logger, logger: logger,
flutterUsage: TestUsage(), flutterUsage: TestUsage(),
analytics: NoOpAnalytics(),
), ),
Signals: () => FakeSignals(), Signals: () => FakeSignals(),
}); });
...@@ -294,6 +296,7 @@ void main() { ...@@ -294,6 +296,7 @@ void main() {
preliminaryMDnsClient: FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}), preliminaryMDnsClient: FakeMDnsClient(<PtrResourceRecord>[], <String, List<SrvResourceRecord>>{}),
logger: logger, logger: logger,
flutterUsage: TestUsage(), flutterUsage: TestUsage(),
analytics: NoOpAnalytics(),
), ),
ProcessManager: () => FakeProcessManager.empty(), ProcessManager: () => FakeProcessManager.empty(),
}); });
...@@ -363,6 +366,7 @@ void main() { ...@@ -363,6 +366,7 @@ void main() {
), ),
logger: logger, logger: logger,
flutterUsage: TestUsage(), flutterUsage: TestUsage(),
analytics: NoOpAnalytics(),
), ),
}); });
...@@ -433,6 +437,7 @@ void main() { ...@@ -433,6 +437,7 @@ void main() {
), ),
logger: logger, logger: logger,
flutterUsage: TestUsage(), flutterUsage: TestUsage(),
analytics: NoOpAnalytics(),
), ),
}); });
...@@ -507,6 +512,7 @@ void main() { ...@@ -507,6 +512,7 @@ void main() {
), ),
logger: logger, logger: logger,
flutterUsage: TestUsage(), flutterUsage: TestUsage(),
analytics: NoOpAnalytics(),
), ),
}); });
...@@ -581,6 +587,7 @@ void main() { ...@@ -581,6 +587,7 @@ void main() {
), ),
logger: logger, logger: logger,
flutterUsage: TestUsage(), flutterUsage: TestUsage(),
analytics: NoOpAnalytics(),
), ),
}); });
......
...@@ -13,10 +13,12 @@ import 'package:flutter_tools/src/build_system/build_system.dart'; ...@@ -13,10 +13,12 @@ import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/targets/ios.dart'; import 'package:flutter_tools/src/build_system/targets/ios.dart';
import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../../../src/common.dart'; import '../../../src/common.dart';
import '../../../src/context.dart'; import '../../../src/context.dart';
import '../../../src/fake_process_manager.dart'; import '../../../src/fake_process_manager.dart';
import '../../../src/fakes.dart';
final Platform macPlatform = FakePlatform(operatingSystem: 'macos', environment: <String, String>{}); final Platform macPlatform = FakePlatform(operatingSystem: 'macos', environment: <String, String>{});
...@@ -45,6 +47,7 @@ void main() { ...@@ -45,6 +47,7 @@ void main() {
late Artifacts artifacts; late Artifacts artifacts;
late BufferLogger logger; late BufferLogger logger;
late TestUsage usage; late TestUsage usage;
late FakeAnalytics fakeAnalytics;
setUp(() { setUp(() {
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
...@@ -52,6 +55,10 @@ void main() { ...@@ -52,6 +55,10 @@ void main() {
logger = BufferLogger.test(); logger = BufferLogger.test();
artifacts = Artifacts.test(); artifacts = Artifacts.test();
usage = TestUsage(); usage = TestUsage();
fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: fileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
environment = Environment.test( environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
defines: <String, String>{ defines: <String, String>{
...@@ -64,6 +71,7 @@ void main() { ...@@ -64,6 +71,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
engineVersion: '2', engineVersion: '2',
usage: usage, usage: usage,
analytics: fakeAnalytics,
); );
}); });
...@@ -386,6 +394,7 @@ void main() { ...@@ -386,6 +394,7 @@ void main() {
expect(assetDirectory.childFile('vm_snapshot_data'), isNot(exists)); expect(assetDirectory.childFile('vm_snapshot_data'), isNot(exists));
expect(assetDirectory.childFile('isolate_snapshot_data'), isNot(exists)); expect(assetDirectory.childFile('isolate_snapshot_data'), isNot(exists));
expect(usage.events, isEmpty); expect(usage.events, isEmpty);
expect(fakeAnalytics.sentEvents, isEmpty);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => processManager, ProcessManager: () => processManager,
...@@ -425,6 +434,11 @@ void main() { ...@@ -425,6 +434,11 @@ void main() {
await const ReleaseIosApplicationBundle().build(environment); await const ReleaseIosApplicationBundle().build(environment);
expect(usage.events, contains(const TestUsageEvent('assemble', 'ios-archive', label: 'success'))); expect(usage.events, contains(const TestUsageEvent('assemble', 'ios-archive', label: 'success')));
expect(fakeAnalytics.sentEvents, contains(Event.appleUsageEvent(
workflow: 'assemble',
parameter: 'ios-archive',
result: 'success',
)));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => processManager, ProcessManager: () => processManager,
...@@ -439,6 +453,11 @@ void main() { ...@@ -439,6 +453,11 @@ void main() {
await expectLater(() => const ReleaseIosApplicationBundle().build(environment), await expectLater(() => const ReleaseIosApplicationBundle().build(environment),
throwsA(const TypeMatcher<FileSystemException>())); throwsA(const TypeMatcher<FileSystemException>()));
expect(usage.events, contains(const TestUsageEvent('assemble', 'ios-archive', label: 'fail'))); expect(usage.events, contains(const TestUsageEvent('assemble', 'ios-archive', label: 'fail')));
expect(fakeAnalytics.sentEvents, contains(Event.appleUsageEvent(
workflow: 'assemble',
parameter: 'ios-archive',
result: 'fail',
)));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => processManager, ProcessManager: () => processManager,
......
...@@ -12,10 +12,12 @@ import 'package:flutter_tools/src/build_system/build_system.dart'; ...@@ -12,10 +12,12 @@ import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/targets/macos.dart'; import 'package:flutter_tools/src/build_system/targets/macos.dart';
import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../../../src/common.dart'; import '../../../src/common.dart';
import '../../../src/context.dart'; import '../../../src/context.dart';
import '../../../src/fake_process_manager.dart'; import '../../../src/fake_process_manager.dart';
import '../../../src/fakes.dart';
void main() { void main() {
late Environment environment; late Environment environment;
...@@ -29,6 +31,7 @@ void main() { ...@@ -29,6 +31,7 @@ void main() {
late FakeCommand lipoInfoFatCommand; late FakeCommand lipoInfoFatCommand;
late FakeCommand lipoVerifyX86_64Command; late FakeCommand lipoVerifyX86_64Command;
late TestUsage usage; late TestUsage usage;
late FakeAnalytics fakeAnalytics;
setUp(() { setUp(() {
processManager = FakeProcessManager.empty(); processManager = FakeProcessManager.empty();
...@@ -36,6 +39,10 @@ void main() { ...@@ -36,6 +39,10 @@ void main() {
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
logger = BufferLogger.test(); logger = BufferLogger.test();
usage = TestUsage(); usage = TestUsage();
fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: fileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
environment = Environment.test( environment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
defines: <String, String>{ defines: <String, String>{
...@@ -50,6 +57,7 @@ void main() { ...@@ -50,6 +57,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
engineVersion: '2', engineVersion: '2',
usage: usage, usage: usage,
analytics: fakeAnalytics,
); );
binary = environment.outputDir binary = environment.outputDir
...@@ -398,6 +406,13 @@ void main() { ...@@ -398,6 +406,13 @@ void main() {
await const ReleaseMacOSBundleFlutterAssets().build(environment); await const ReleaseMacOSBundleFlutterAssets().build(environment);
expect(usage.events, contains(const TestUsageEvent('assemble', 'macos-archive', label: 'success'))); expect(usage.events, contains(const TestUsageEvent('assemble', 'macos-archive', label: 'success')));
expect(fakeAnalytics.sentEvents, contains(
Event.appleUsageEvent(
workflow: 'assemble',
parameter: 'macos-archive',
result: 'success',
),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => processManager, ProcessManager: () => processManager,
...@@ -411,6 +426,13 @@ void main() { ...@@ -411,6 +426,13 @@ void main() {
await expectLater(() => const ReleaseMacOSBundleFlutterAssets().build(environment), await expectLater(() => const ReleaseMacOSBundleFlutterAssets().build(environment),
throwsA(const TypeMatcher<FileSystemException>())); throwsA(const TypeMatcher<FileSystemException>()));
expect(usage.events, contains(const TestUsageEvent('assemble', 'macos-archive', label: 'fail'))); expect(usage.events, contains(const TestUsageEvent('assemble', 'macos-archive', label: 'fail')));
expect(fakeAnalytics.sentEvents, contains(
Event.appleUsageEvent(
workflow: 'assemble',
parameter: 'macos-archive',
result: 'fail',
),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => processManager, ProcessManager: () => processManager,
......
...@@ -23,16 +23,25 @@ import 'package:flutter_tools/src/migrations/xcode_thin_binary_build_phase_input ...@@ -23,16 +23,25 @@ import 'package:flutter_tools/src/migrations/xcode_thin_binary_build_phase_input
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/xcode_project.dart'; import 'package:flutter_tools/src/xcode_project.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/fake_process_manager.dart'; import '../../src/fake_process_manager.dart';
import '../../src/fakes.dart';
void main () { void main () {
group('iOS migration', () { group('iOS migration', () {
late TestUsage testUsage; late TestUsage testUsage;
late FakeAnalytics fakeAnalytics;
setUp(() { setUp(() {
testUsage = TestUsage(); testUsage = TestUsage();
final MemoryFileSystem fs = MemoryFileSystem.test();
fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: fs,
fakeFlutterVersion: FakeFlutterVersion(),
);
}); });
testWithoutContext('migrators succeed', () { testWithoutContext('migrators succeed', () {
...@@ -59,10 +68,12 @@ void main () { ...@@ -59,10 +68,12 @@ void main () {
final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration( final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration(
project, project,
testLogger, testLogger,
testUsage testUsage,
fakeAnalytics,
); );
iosProjectMigration.migrate(); iosProjectMigration.migrate();
expect(testUsage.events, isEmpty); expect(testUsage.events, isEmpty);
expect(fakeAnalytics.sentEvents, isEmpty);
expect(xcodeProjectInfoFile.existsSync(), isFalse); expect(xcodeProjectInfoFile.existsSync(), isFalse);
...@@ -79,9 +90,11 @@ void main () { ...@@ -79,9 +90,11 @@ void main () {
project, project,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
iosProjectMigration.migrate(); iosProjectMigration.migrate();
expect(testUsage.events, isEmpty); expect(testUsage.events, isEmpty);
expect(fakeAnalytics.sentEvents, isEmpty);
expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified); expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified);
expect(xcodeProjectInfoFile.readAsStringSync(), contents); expect(xcodeProjectInfoFile.readAsStringSync(), contents);
...@@ -99,6 +112,7 @@ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend. ...@@ -99,6 +112,7 @@ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.
project, project,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
iosProjectMigration.migrate(); iosProjectMigration.migrate();
expect(xcodeProjectInfoFile.readAsStringSync(), contents); expect(xcodeProjectInfoFile.readAsStringSync(), contents);
...@@ -126,9 +140,11 @@ keep this 2 ...@@ -126,9 +140,11 @@ keep this 2
project, project,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
iosProjectMigration.migrate(); iosProjectMigration.migrate();
expect(testUsage.events, isEmpty); expect(testUsage.events, isEmpty);
expect(fakeAnalytics.sentEvents, isEmpty);
expect(xcodeProjectInfoFile.readAsStringSync(), r''' expect(xcodeProjectInfoFile.readAsStringSync(), r'''
keep this 1 keep this 1
...@@ -147,12 +163,20 @@ keep this 2 ...@@ -147,12 +163,20 @@ keep this 2
project, project,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration')); expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
expect(testUsage.events, contains( expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'), const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
)); ));
expect(fakeAnalytics.sentEvents, contains(
Event.appleUsageEvent(
workflow: 'ios-migration',
parameter: 'remove-frameworks',
result: 'failure',
)
));
}); });
testWithoutContext('migration fails with leftover Flutter.framework reference', () { testWithoutContext('migration fails with leftover Flutter.framework reference', () {
...@@ -164,11 +188,19 @@ keep this 2 ...@@ -164,11 +188,19 @@ keep this 2
project, project,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration')); expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
expect(testUsage.events, contains( expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'), const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
)); ));
expect(fakeAnalytics.sentEvents, contains(
Event.appleUsageEvent(
workflow: 'ios-migration',
parameter: 'remove-frameworks',
result: 'failure',
)
));
}); });
testWithoutContext('migration fails without Xcode installed', () { testWithoutContext('migration fails without Xcode installed', () {
...@@ -180,11 +212,19 @@ keep this 2 ...@@ -180,11 +212,19 @@ keep this 2
project, project,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration')); expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
expect(testUsage.events, contains( expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'), const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
)); ));
expect(fakeAnalytics.sentEvents, contains(
Event.appleUsageEvent(
workflow: 'ios-migration',
parameter: 'remove-frameworks',
result: 'failure',
)
));
}); });
}); });
......
...@@ -15,10 +15,12 @@ import 'package:flutter_tools/src/macos/cocoapods.dart'; ...@@ -15,10 +15,12 @@ import 'package:flutter_tools/src/macos/cocoapods.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:flutter_tools/src/reporting/reporting.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/fake_process_manager.dart'; import '../../src/fake_process_manager.dart';
import '../../src/fakes.dart';
enum _StdioStream { enum _StdioStream {
stdout, stdout,
...@@ -31,6 +33,7 @@ void main() { ...@@ -31,6 +33,7 @@ void main() {
late CocoaPods cocoaPodsUnderTest; late CocoaPods cocoaPodsUnderTest;
late BufferLogger logger; late BufferLogger logger;
late TestUsage usage; late TestUsage usage;
late FakeAnalytics fakeAnalytics;
void pretendPodVersionFails() { void pretendPodVersionFails() {
fakeProcessManager.addCommand( fakeProcessManager.addCommand(
...@@ -72,6 +75,10 @@ void main() { ...@@ -72,6 +75,10 @@ void main() {
fakeProcessManager = FakeProcessManager.empty(); fakeProcessManager = FakeProcessManager.empty();
logger = BufferLogger.test(); logger = BufferLogger.test();
usage = TestUsage(); usage = TestUsage();
fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: fileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
cocoaPodsUnderTest = CocoaPods( cocoaPodsUnderTest = CocoaPods(
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: fakeProcessManager, processManager: fakeProcessManager,
...@@ -79,6 +86,7 @@ void main() { ...@@ -79,6 +86,7 @@ void main() {
platform: FakePlatform(operatingSystem: 'macos'), platform: FakePlatform(operatingSystem: 'macos'),
xcodeProjectInterpreter: FakeXcodeProjectInterpreter(), xcodeProjectInterpreter: FakeXcodeProjectInterpreter(),
usage: usage, usage: usage,
analytics: fakeAnalytics,
); );
fileSystem.file(fileSystem.path.join( fileSystem.file(fileSystem.path.join(
Cache.flutterRoot!, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-ios-objc', Cache.flutterRoot!, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-ios-objc',
...@@ -197,6 +205,7 @@ void main() { ...@@ -197,6 +205,7 @@ void main() {
platform: FakePlatform(operatingSystem: 'macos'), platform: FakePlatform(operatingSystem: 'macos'),
xcodeProjectInterpreter: fakeXcodeProjectInterpreter, xcodeProjectInterpreter: fakeXcodeProjectInterpreter,
usage: usage, usage: usage,
analytics: fakeAnalytics,
); );
final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project')); final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
...@@ -232,6 +241,7 @@ void main() { ...@@ -232,6 +241,7 @@ void main() {
platform: FakePlatform(operatingSystem: 'macos'), platform: FakePlatform(operatingSystem: 'macos'),
xcodeProjectInterpreter: FakeXcodeProjectInterpreter(isInstalled: false), xcodeProjectInterpreter: FakeXcodeProjectInterpreter(isInstalled: false),
usage: usage, usage: usage,
analytics: fakeAnalytics,
); );
final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project')); final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
...@@ -545,6 +555,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ...@@ -545,6 +555,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
contains('enable-libffi-alloc'), contains('enable-libffi-alloc'),
); );
expect(usage.events, contains(const TestUsageEvent('pod-install-failure', 'arm-ffi'))); expect(usage.events, contains(const TestUsageEvent('pod-install-failure', 'arm-ffi')));
expect(fakeAnalytics.sentEvents, contains(Event.appleUsageEvent(workflow: 'pod-install-failure', parameter: 'arm-ffi')));
}); });
} }
testToolExitsWithCocoapodsMessage(_StdioStream.stdout); testToolExitsWithCocoapodsMessage(_StdioStream.stdout);
...@@ -779,6 +790,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ...@@ -779,6 +790,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
platform: FakePlatform(operatingSystem: 'macos'), platform: FakePlatform(operatingSystem: 'macos'),
xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: fakeProcessManager, version: Version(14, 3, 0)), xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: fakeProcessManager, version: Version(14, 3, 0)),
usage: usage, usage: usage,
analytics: fakeAnalytics,
); );
final bool didInstall = await cocoaPodsUnderTestXcode143.processPods( final bool didInstall = await cocoaPodsUnderTestXcode143.processPods(
......
...@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/macos/migrations/remove_macos_framework_link_a ...@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/macos/migrations/remove_macos_framework_link_a
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
...@@ -20,6 +21,7 @@ import '../../src/fakes.dart'; ...@@ -20,6 +21,7 @@ import '../../src/fakes.dart';
void main() { void main() {
group('remove link and embed migration', () { group('remove link and embed migration', () {
late TestUsage testUsage; late TestUsage testUsage;
late FakeAnalytics fakeAnalytics;
late MemoryFileSystem memoryFileSystem; late MemoryFileSystem memoryFileSystem;
late BufferLogger testLogger; late BufferLogger testLogger;
late FakeMacOSProject macOSProject; late FakeMacOSProject macOSProject;
...@@ -28,6 +30,10 @@ void main() { ...@@ -28,6 +30,10 @@ void main() {
setUp(() { setUp(() {
testUsage = TestUsage(); testUsage = TestUsage();
memoryFileSystem = MemoryFileSystem.test(); memoryFileSystem = MemoryFileSystem.test();
fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: memoryFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
xcodeProjectInfoFile = memoryFileSystem.file('project.pbxproj'); xcodeProjectInfoFile = memoryFileSystem.file('project.pbxproj');
testLogger = BufferLogger.test(); testLogger = BufferLogger.test();
macOSProject = FakeMacOSProject(); macOSProject = FakeMacOSProject();
...@@ -40,9 +46,11 @@ void main() { ...@@ -40,9 +46,11 @@ void main() {
macOSProject, macOSProject,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
macosProjectMigration.migrate(); macosProjectMigration.migrate();
expect(testUsage.events, isEmpty); expect(testUsage.events, isEmpty);
expect(fakeAnalytics.sentEvents, isEmpty);
expect(xcodeProjectInfoFile.existsSync(), isFalse); expect(xcodeProjectInfoFile.existsSync(), isFalse);
...@@ -64,9 +72,11 @@ void main() { ...@@ -64,9 +72,11 @@ void main() {
macOSProject, macOSProject,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
macosProjectMigration.migrate(); macosProjectMigration.migrate();
expect(testUsage.events, isEmpty); expect(testUsage.events, isEmpty);
expect(fakeAnalytics.sentEvents, isEmpty);
expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified); expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified);
expect(xcodeProjectInfoFile.readAsStringSync(), contents); expect(xcodeProjectInfoFile.readAsStringSync(), contents);
...@@ -85,6 +95,7 @@ shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/. ...@@ -85,6 +95,7 @@ shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.
macOSProject, macOSProject,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
macosProjectMigration.migrate(); macosProjectMigration.migrate();
expect(xcodeProjectInfoFile.readAsStringSync(), contents); expect(xcodeProjectInfoFile.readAsStringSync(), contents);
...@@ -108,9 +119,11 @@ keep this 2 ...@@ -108,9 +119,11 @@ keep this 2
macOSProject, macOSProject,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
macosProjectMigration.migrate(); macosProjectMigration.migrate();
expect(testUsage.events, isEmpty); expect(testUsage.events, isEmpty);
expect(fakeAnalytics.sentEvents, isEmpty);
expect(xcodeProjectInfoFile.readAsStringSync(), r''' expect(xcodeProjectInfoFile.readAsStringSync(), r'''
keep this 1 keep this 1
...@@ -130,6 +143,7 @@ keep this 2 ...@@ -130,6 +143,7 @@ keep this 2
macOSProject, macOSProject,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
expect(macosProjectMigration.migrate, expect(macosProjectMigration.migrate,
...@@ -137,6 +151,13 @@ keep this 2 ...@@ -137,6 +151,13 @@ keep this 2
expect(testUsage.events, contains( expect(testUsage.events, contains(
const TestUsageEvent('macos-migration', 'remove-frameworks', label: 'failure'), const TestUsageEvent('macos-migration', 'remove-frameworks', label: 'failure'),
)); ));
expect(fakeAnalytics.sentEvents, contains(
Event.appleUsageEvent(
workflow: 'macos-migration',
parameter: 'remove-frameworks',
result: 'failure',
)
));
}); });
testWithoutContext( testWithoutContext(
...@@ -150,12 +171,20 @@ keep this 2 ...@@ -150,12 +171,20 @@ keep this 2
macOSProject, macOSProject,
testLogger, testLogger,
testUsage, testUsage,
fakeAnalytics,
); );
expect(macosProjectMigration.migrate, expect(macosProjectMigration.migrate,
throwsToolExit(message: 'Your Xcode project requires migration')); throwsToolExit(message: 'Your Xcode project requires migration'));
expect(testUsage.events, contains( expect(testUsage.events, contains(
const TestUsageEvent('macos-migration', 'remove-frameworks', label: 'failure'), const TestUsageEvent('macos-migration', 'remove-frameworks', label: 'failure'),
)); ));
expect(fakeAnalytics.sentEvents, contains(
Event.appleUsageEvent(
workflow: 'macos-migration',
parameter: 'remove-frameworks',
result: 'failure',
)
));
}); });
}); });
......
...@@ -22,10 +22,12 @@ import 'package:flutter_tools/src/ios/xcodeproj.dart'; ...@@ -22,10 +22,12 @@ import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/xcdevice.dart'; import 'package:flutter_tools/src/macos/xcdevice.dart';
import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/fake_process_manager.dart'; import '../../src/fake_process_manager.dart';
import '../../src/fakes.dart';
void main() { void main() {
late BufferLogger logger; late BufferLogger logger;
...@@ -515,6 +517,7 @@ void main() { ...@@ -515,6 +517,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
coreDeviceControl: FakeIOSCoreDeviceControl(), coreDeviceControl: FakeIOSCoreDeviceControl(),
xcodeDebug: FakeXcodeDebug(), xcodeDebug: FakeXcodeDebug(),
analytics: NoOpAnalytics(),
); );
}); });
...@@ -533,12 +536,17 @@ void main() { ...@@ -533,12 +536,17 @@ void main() {
late XCDevice xcdevice; late XCDevice xcdevice;
late Xcode xcode; late Xcode xcode;
late MemoryFileSystem fileSystem; late MemoryFileSystem fileSystem;
late FakeAnalytics fakeAnalytics;
late FakeIOSCoreDeviceControl coreDeviceControl; late FakeIOSCoreDeviceControl coreDeviceControl;
setUp(() { setUp(() {
xcode = Xcode.test(processManager: FakeProcessManager.any()); xcode = Xcode.test(processManager: FakeProcessManager.any());
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
coreDeviceControl = FakeIOSCoreDeviceControl(); coreDeviceControl = FakeIOSCoreDeviceControl();
fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: fileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
xcdevice = XCDevice( xcdevice = XCDevice(
processManager: fakeProcessManager, processManager: fakeProcessManager,
logger: logger, logger: logger,
...@@ -550,6 +558,7 @@ void main() { ...@@ -550,6 +558,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
coreDeviceControl: coreDeviceControl, coreDeviceControl: coreDeviceControl,
xcodeDebug: FakeXcodeDebug(), xcodeDebug: FakeXcodeDebug(),
analytics: fakeAnalytics,
); );
}); });
...@@ -1447,6 +1456,13 @@ void main() { ...@@ -1447,6 +1456,13 @@ void main() {
expect(devices[4].devModeEnabled, true); expect(devices[4].devModeEnabled, true);
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
expect(fakeAnalytics.sentEvents, contains(
Event.appleUsageEvent(
workflow: 'device',
parameter: 'ios-trust-failure',
)
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => macPlatform, Platform: () => macPlatform,
Artifacts: () => Artifacts.test(), Artifacts: () => Artifacts.test(),
......
...@@ -233,7 +233,8 @@ void main() { ...@@ -233,7 +233,8 @@ void main() {
Event.flutterCommandResult( Event.flutterCommandResult(
commandPath: 'dummy', commandPath: 'dummy',
result: 'success', result: 'success',
maxRss: 10 maxRss: 10,
commandHasTerminal: false,
), ),
]); ]);
}); });
...@@ -266,7 +267,8 @@ void main() { ...@@ -266,7 +267,8 @@ void main() {
Event.flutterCommandResult( Event.flutterCommandResult(
commandPath: 'dummy', commandPath: 'dummy',
result: 'warning', result: 'warning',
maxRss: 10 maxRss: 10,
commandHasTerminal: false,
), ),
]); ]);
}); });
...@@ -301,7 +303,8 @@ void main() { ...@@ -301,7 +303,8 @@ void main() {
Event.flutterCommandResult( Event.flutterCommandResult(
commandPath: 'dummy', commandPath: 'dummy',
result: 'fail', result: 'fail',
maxRss: 10 maxRss: 10,
commandHasTerminal: false,
), ),
]); ]);
}); });
...@@ -414,7 +417,8 @@ void main() { ...@@ -414,7 +417,8 @@ void main() {
Event.flutterCommandResult( Event.flutterCommandResult(
commandPath: 'dummy', commandPath: 'dummy',
result: 'killed', result: 'killed',
maxRss: 10 maxRss: 10,
commandHasTerminal: false,
), ),
]); ]);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
......
...@@ -32,6 +32,8 @@ void main() { ...@@ -32,6 +32,8 @@ void main() {
late MemoryFileSystem fileSystem; late MemoryFileSystem fileSystem;
group('runner', () { group('runner', () {
late FakeAnalytics fakeAnalytics;
setUp(() { setUp(() {
// Instead of exiting with dart:io exit(), this causes an exception to // Instead of exiting with dart:io exit(), this causes an exception to
// be thrown, which we catch with the onError callback in the zone below. // be thrown, which we catch with the onError callback in the zone below.
...@@ -50,6 +52,11 @@ void main() { ...@@ -50,6 +52,11 @@ void main() {
Cache.disableLocking(); Cache.disableLocking();
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: fileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
}); });
tearDown(() { tearDown(() {
...@@ -92,6 +99,7 @@ void main() { ...@@ -92,6 +99,7 @@ void main() {
// attempt. // attempt.
final CrashingUsage crashingUsage = globals.flutterUsage as CrashingUsage; final CrashingUsage crashingUsage = globals.flutterUsage as CrashingUsage;
expect(crashingUsage.sentException.toString(), 'Exception: an exception % --'); expect(crashingUsage.sentException.toString(), 'Exception: an exception % --');
expect(fakeAnalytics.sentEvents, contains(Event.exception(exception: '_Exception')));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(environment: <String, String>{ Platform: () => FakePlatform(environment: <String, String>{
'FLUTTER_ANALYTICS_LOG_FILE': 'test', 'FLUTTER_ANALYTICS_LOG_FILE': 'test',
...@@ -102,6 +110,7 @@ void main() { ...@@ -102,6 +110,7 @@ void main() {
Usage: () => CrashingUsage(), Usage: () => CrashingUsage(),
Artifacts: () => Artifacts.test(), Artifacts: () => Artifacts.test(),
HttpClientFactory: () => () => FakeHttpClient.any(), HttpClientFactory: () => () => FakeHttpClient.any(),
Analytics: () => fakeAnalytics,
}); });
// This Completer completes when CrashingFlutterCommand.runCommand // This Completer completes when CrashingFlutterCommand.runCommand
......
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