Unverified Commit 03220cac authored by xster's avatar xster Committed by GitHub

Make sure add-to-app build bundle from outer xcodebuild/gradlew sends analytics (#36122)

parent 07735578
...@@ -154,13 +154,18 @@ Future<void> main() async { ...@@ -154,13 +154,18 @@ Future<void> main() async {
Directory(path.join(hostApp.path, 'gradle', 'wrapper')), Directory(path.join(hostApp.path, 'gradle', 'wrapper')),
); );
final File analyticsOutputFile = File(path.join(tempDir.path, 'analytics.log'));
await inDirectory(hostApp, () async { await inDirectory(hostApp, () async {
if (!Platform.isWindows) { if (!Platform.isWindows) {
await exec('chmod', <String>['+x', 'gradlew']); await exec('chmod', <String>['+x', 'gradlew']);
} }
await exec(gradlewExecutable, await exec(gradlewExecutable,
<String>['app:assembleDebug'], <String>['app:assembleDebug'],
environment: <String, String>{ 'JAVA_HOME': javaHome }, environment: <String, String>{
'JAVA_HOME': javaHome,
'FLUTTER_ANALYTICS_LOG_FILE': analyticsOutputFile.path,
},
); );
}); });
...@@ -173,10 +178,21 @@ Future<void> main() async { ...@@ -173,10 +178,21 @@ Future<void> main() async {
'debug', 'debug',
'app-debug.apk', 'app-debug.apk',
))); )));
if (!existingAppBuilt) { if (!existingAppBuilt) {
return TaskResult.failure('Failed to build existing app .apk'); return TaskResult.failure('Failed to build existing app .apk');
} }
final String analyticsOutput = analyticsOutputFile.readAsStringSync();
if (!analyticsOutput.contains('cd24: android-arm64')
|| !analyticsOutput.contains('cd25: true')
|| !analyticsOutput.contains('viewName: build/bundle')) {
return TaskResult.failure(
'Building outer app produced the following analytics: "$analyticsOutput"'
'but not the expected strings: "cd24: android-arm64", "cd25: true" and '
'"viewName: build/bundle"'
);
}
return TaskResult.success(null); return TaskResult.success(null);
} catch (e) { } catch (e) {
return TaskResult.failure(e.toString()); return TaskResult.failure(e.toString());
......
...@@ -219,6 +219,8 @@ Future<void> main() async { ...@@ -219,6 +219,8 @@ Future<void> main() async {
hostApp, hostApp,
); );
final File analyticsOutputFile = File(path.join(tempDir.path, 'analytics.log'));
await inDirectory(hostApp, () async { await inDirectory(hostApp, () async {
await exec('pod', <String>['install']); await exec('pod', <String>['install']);
await exec( await exec(
...@@ -236,6 +238,9 @@ Future<void> main() async { ...@@ -236,6 +238,9 @@ Future<void> main() async {
'EXPANDED_CODE_SIGN_IDENTITY=-', 'EXPANDED_CODE_SIGN_IDENTITY=-',
'CONFIGURATION_BUILD_DIR=${tempDir.path}', 'CONFIGURATION_BUILD_DIR=${tempDir.path}',
], ],
environment: <String, String> {
'FLUTTER_ANALYTICS_LOG_FILE': analyticsOutputFile.path,
}
); );
}); });
...@@ -244,11 +249,20 @@ Future<void> main() async { ...@@ -244,11 +249,20 @@ Future<void> main() async {
'Host.app', 'Host.app',
'Host', 'Host',
))); )));
if (!existingAppBuilt) { if (!existingAppBuilt) {
return TaskResult.failure('Failed to build existing app .app'); return TaskResult.failure('Failed to build existing app .app');
} }
final String analyticsOutput = analyticsOutputFile.readAsStringSync();
if (!analyticsOutput.contains('cd24: ios')
|| !analyticsOutput.contains('cd25: true')
|| !analyticsOutput.contains('viewName: build/bundle')) {
return TaskResult.failure(
'Building outer app produced the following analytics: "$analyticsOutput"'
'but not the expected strings: "cd24: ios", "cd25: true", "viewName: build/bundle"'
);
}
return TaskResult.success(null); return TaskResult.success(null);
} catch (e) { } catch (e) {
return TaskResult.failure(e.toString()); return TaskResult.failure(e.toString());
......
...@@ -249,7 +249,7 @@ BuildApp() { ...@@ -249,7 +249,7 @@ BuildApp() {
fi fi
StreamOutput " ├─Assembling Flutter resources..." StreamOutput " ├─Assembling Flutter resources..."
RunCommand "${FLUTTER_ROOT}/bin/flutter" \ RunCommand "${FLUTTER_ROOT}/bin/flutter" \
${verbose_flag} \ ${verbose_flag} \
build bundle \ build bundle \
--target-platform=ios \ --target-platform=ios \
......
...@@ -223,7 +223,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -223,7 +223,7 @@ class FlutterPlugin implements Plugin<Project> {
initWith debug initWith debug
} }
} }
pluginProject.android.buildTypes.each { pluginProject.android.buildTypes.each {
def buildMode = buildModeFor(it) def buildMode = buildModeFor(it)
addFlutterJarCompileOnlyDependency(pluginProject, it.name, project.files( flutterJar ?: baseJar[buildMode] )) addFlutterJarCompileOnlyDependency(pluginProject, it.name, project.files( flutterJar ?: baseJar[buildMode] ))
...@@ -652,6 +652,7 @@ abstract class BaseFlutterTask extends DefaultTask { ...@@ -652,6 +652,7 @@ abstract class BaseFlutterTask extends DefaultTask {
project.exec { project.exec {
executable flutterExecutable.absolutePath executable flutterExecutable.absolutePath
workingDir sourceDir workingDir sourceDir
if (localEngine != null) { if (localEngine != null) {
args "--local-engine", localEngine args "--local-engine", localEngine
args "--local-engine-src-path", localEngineSrcPath args "--local-engine-src-path", localEngineSrcPath
......
...@@ -27,6 +27,8 @@ class BotDetector { ...@@ -27,6 +27,8 @@ class BotDetector {
// Set by the IDEs to the IDE name, so a strong signal that this is not a bot. // Set by the IDEs to the IDE name, so a strong signal that this is not a bot.
|| platform.environment.containsKey('FLUTTER_HOST') || platform.environment.containsKey('FLUTTER_HOST')
// When set, GA logs to a local file (normally for tests) so we don't need to filter.
|| platform.environment.containsKey('FLUTTER_ANALYTICS_LOG_FILE')
) { ) {
return false; return false;
} }
......
...@@ -69,8 +69,18 @@ class Usage { ...@@ -69,8 +69,18 @@ class Usage {
Usage({ String settingsName = 'flutter', String versionOverride, String configDirOverride}) { Usage({ String settingsName = 'flutter', String versionOverride, String configDirOverride}) {
final FlutterVersion flutterVersion = FlutterVersion.instance; final FlutterVersion flutterVersion = FlutterVersion.instance;
final String version = versionOverride ?? flutterVersion.getVersionString(redactUnknownBranches: true); final String version = versionOverride ?? flutterVersion.getVersionString(redactUnknownBranches: true);
_analytics = AnalyticsIO(_kFlutterUA, settingsName, version,
documentDirectory: configDirOverride != null ? fs.directory(configDirOverride) : null); final String logFilePath = platform.environment['FLUTTER_ANALYTICS_LOG_FILE'];
_analytics = logFilePath == null || logFilePath.isEmpty ?
AnalyticsIO(
_kFlutterUA,
settingsName,
version,
documentDirectory: configDirOverride != null ? fs.directory(configDirOverride) : null,
) :
// Used for testing.
LogToFileAnalytics(logFilePath);
// Report a more detailed OS version string than package:usage does by default. // Report a more detailed OS version string than package:usage does by default.
_analytics.setSessionValue(kSessionHostOsDetails, os.name); _analytics.setSessionValue(kSessionHostOsDetails, os.name);
...@@ -94,6 +104,7 @@ class Usage { ...@@ -94,6 +104,7 @@ class Usage {
_analytics.analyticsOpt = AnalyticsOpt.optOut; _analytics.analyticsOpt = AnalyticsOpt.optOut;
final bool suppressEnvFlag = platform.environment['FLUTTER_SUPPRESS_ANALYTICS'] == 'true'; final bool suppressEnvFlag = platform.environment['FLUTTER_SUPPRESS_ANALYTICS'] == 'true';
_analytics.sendScreenView('version is $version, is bot $isRunningOnBot, suppressed $suppressEnvFlag');
// Many CI systems don't do a full git checkout. // Many CI systems don't do a full git checkout.
if (version.endsWith('/unknown') || isRunningOnBot || suppressEnvFlag) { if (version.endsWith('/unknown') || isRunningOnBot || suppressEnvFlag) {
// If we think we're running on a CI system, suppress sending analytics. // If we think we're running on a CI system, suppress sending analytics.
...@@ -213,3 +224,22 @@ class Usage { ...@@ -213,3 +224,22 @@ class Usage {
''', emphasis: true); ''', emphasis: true);
} }
} }
// An Analytics mock that logs to file. Unimplemented methods goes to stdout.
// But stdout can't be used for testing since wrapper scripts like
// xcode_backend.sh etc manipulates them.
class LogToFileAnalytics extends AnalyticsMock {
LogToFileAnalytics(String logFilePath) :
logFile = fs.file(logFilePath)..createSync(recursive: true),
super(true);
final File logFile;
@override
Future<void> sendScreenView(String viewName, {Map<String, String> parameters}) {
parameters ??= <String, String>{};
parameters['viewName'] = viewName;
logFile.writeAsStringSync('screenView $parameters\n');
return Future<void>.value(null);
}
}
...@@ -51,6 +51,15 @@ void main() { ...@@ -51,6 +51,15 @@ void main() {
Stdio: () => mockStdio, Stdio: () => mockStdio,
Platform: () => fakePlatform, Platform: () => fakePlatform,
}); });
testUsingContext('can test analytics outputs on bots when outputting to a file', () async {
fakePlatform.environment['TRAVIS'] = 'true';
fakePlatform.environment['FLUTTER_ANALYTICS_LOG_FILE'] = '/some/file';
expect(botDetector.isRunningOnBot, isFalse);
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Platform: () => fakePlatform,
});
}); });
}); });
} }
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