Skip to content

Commit 7d668f2

Browse files
matanlureymboetger
authored andcommitted
Report feature flags enabled if the flutter tool crashes on a bot. (flutter#171304)
Towards flutter#38901. Next PR will also add feature flags to `flutter doctor`.
1 parent f45457b commit 7d668f2

2 files changed

Lines changed: 74 additions & 3 deletions

File tree

packages/flutter_tools/lib/runner.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Future<int> run(
119119
reportCrashes!,
120120
getVersion,
121121
shutdownHooks,
122+
featureFlags: featureFlags,
122123
);
123124
}
124125
},
@@ -136,6 +137,7 @@ Future<int> run(
136137
reportCrashes!,
137138
getVersion,
138139
shutdownHooks,
140+
featureFlags: featureFlags,
139141
);
140142
},
141143
)!;
@@ -149,8 +151,9 @@ Future<int> _handleToolError(
149151
List<String> args,
150152
bool reportCrashes,
151153
String Function() getFlutterVersion,
152-
ShutdownHooks shutdownHooks,
153-
) async {
154+
ShutdownHooks shutdownHooks, {
155+
required FeatureFlags featureFlags,
156+
}) async {
154157
if (error is UsageException) {
155158
globals.printError('${error.message}\n');
156159
globals.printError(
@@ -187,11 +190,16 @@ Future<int> _handleToolError(
187190
} else {
188191
// We've crashed; emit a log report.
189192
globals.stdio.stderrWrite('\n');
190-
191193
if (!reportCrashes) {
192194
// Print the stack trace on the bots - don't write a crash report.
193195
globals.stdio.stderrWrite('$error\n');
194196
globals.stdio.stderrWrite('$stackTrace\n');
197+
198+
final String featureFlagsEnabled = allConfigurableFeatures
199+
.where(featureFlags.isEnabled)
200+
.map((Feature f) => f.configSetting)
201+
.join(', ');
202+
globals.stdio.stderrWrite('Feature flags enabled: $featureFlagsEnabled\n');
195203
return exitWithHooks(1, shutdownHooks: shutdownHooks);
196204
}
197205

packages/flutter_tools/test/general.shard/runner/runner_test.dart

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ void main() {
3434
int? firstExitCode;
3535
late MemoryFileSystem fileSystem;
3636
late FakeAnalytics fakeAnalytics;
37+
late FakeStdio fakeStdio;
3738

3839
setUp(() {
3940
// Instead of exiting with dart:io exit(), this causes an exception to
@@ -58,6 +59,7 @@ void main() {
5859
fs: fileSystem,
5960
fakeFlutterVersion: FakeFlutterVersion(),
6061
);
62+
fakeStdio = FakeStdio();
6163
});
6264

6365
tearDown(() {
@@ -120,6 +122,66 @@ void main() {
120122
},
121123
);
122124

125+
testUsingContext(
126+
'error handling crash report (bot)',
127+
() async {
128+
final Completer<void> completer = Completer<void>();
129+
// runner.run() asynchronously calls the exit function set above, so we
130+
// catch it in a zone.
131+
unawaited(
132+
runZonedGuarded<Future<void>?>(
133+
() {
134+
unawaited(
135+
runner.run(
136+
<String>['crash'],
137+
() => <FlutterCommand>[CrashingFlutterCommand()],
138+
// This flutterVersion disables crash reporting.
139+
flutterVersion: '[user-branch]/',
140+
shutdownHooks: ShutdownHooks(),
141+
),
142+
);
143+
return null;
144+
},
145+
(Object error, StackTrace stack) {
146+
expect(firstExitCode, isNotNull);
147+
expect(firstExitCode, isNot(0));
148+
expect(error.toString(), 'Exception: test exit');
149+
completer.complete();
150+
},
151+
),
152+
);
153+
await completer.future;
154+
155+
expect(
156+
fakeAnalytics.sentEvents,
157+
isNot(contains(Event.exception(exception: '_Exception'))),
158+
reason: 'Does not send a report on a bot',
159+
);
160+
161+
expect(
162+
fakeStdio.writtenToStderr,
163+
contains(contains('Feature flags enabled:')),
164+
reason: 'Should emit feature flags (ignore specifics for test stability)',
165+
);
166+
},
167+
overrides: <Type, Generator>{
168+
Platform:
169+
() => FakePlatform(
170+
environment: <String, String>{
171+
'FLUTTER_ANALYTICS_LOG_FILE': 'test',
172+
'FLUTTER_ROOT': '/',
173+
},
174+
),
175+
FileSystem: () => fileSystem,
176+
ProcessManager: () => FakeProcessManager.any(),
177+
Artifacts: () => Artifacts.test(),
178+
HttpClientFactory: () => () => FakeHttpClient.any(),
179+
Analytics: () => fakeAnalytics,
180+
BotDetector: () => const FakeBotDetector(true),
181+
io.Stdio: () => fakeStdio,
182+
},
183+
);
184+
123185
// This Completer completes when CrashingFlutterCommand.runCommand
124186
// completes, but ideally we'd want it to complete when execution resumes
125187
// runner.run. Currently the distinction does not matter, but if it ever
@@ -282,6 +344,7 @@ void main() {
282344
fileSystem.currentDirectory = currentDirectory;
283345
inTestSetup = false;
284346
});
347+
285348
testUsingContext(
286349
'create local report in temporary directory',
287350
() async {

0 commit comments

Comments
 (0)