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