Unverified Commit 045ba2b6 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Migrate dev/bots to null safety (#86522)

parent 2f3bf078
...@@ -167,17 +167,17 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches = ...@@ -167,17 +167,17 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
} }
for (int lineNumber in linesWithDeprecations) { for (int lineNumber in linesWithDeprecations) {
try { try {
final Match match1 = _deprecationPattern1.firstMatch(lines[lineNumber]); final Match? match1 = _deprecationPattern1.firstMatch(lines[lineNumber]);
if (match1 == null) if (match1 == null)
throw 'Deprecation notice does not match required pattern.'; throw 'Deprecation notice does not match required pattern.';
final String indent = match1[1]; final String indent = match1[1]!;
lineNumber += 1; lineNumber += 1;
if (lineNumber >= lines.length) if (lineNumber >= lines.length)
throw 'Incomplete deprecation notice.'; throw 'Incomplete deprecation notice.';
Match match3; Match? match3;
String message; String? message;
do { do {
final Match match2 = _deprecationPattern2.firstMatch(lines[lineNumber]); final Match? match2 = _deprecationPattern2.firstMatch(lines[lineNumber]);
if (match2 == null) { if (match2 == null) {
String possibleReason = ''; String possibleReason = '';
if (lines[lineNumber].trimLeft().startsWith('"')) { if (lines[lineNumber].trimLeft().startsWith('"')) {
...@@ -188,7 +188,7 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches = ...@@ -188,7 +188,7 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
if (!lines[lineNumber].startsWith("$indent '")) if (!lines[lineNumber].startsWith("$indent '"))
throw 'Unexpected deprecation notice indent.'; throw 'Unexpected deprecation notice indent.';
if (message == null) { if (message == null) {
final String firstChar = String.fromCharCode(match2[1].runes.first); final String firstChar = String.fromCharCode(match2[1]!.runes.first);
if (firstChar.toUpperCase() != firstChar) if (firstChar.toUpperCase() != firstChar)
throw 'Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo'; throw 'Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo';
} }
...@@ -198,14 +198,14 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches = ...@@ -198,14 +198,14 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
throw 'Incomplete deprecation notice.'; throw 'Incomplete deprecation notice.';
match3 = _deprecationPattern3.firstMatch(lines[lineNumber]); match3 = _deprecationPattern3.firstMatch(lines[lineNumber]);
} while (match3 == null); } while (match3 == null);
final int v1 = int.parse(match3[1]); final int v1 = int.parse(match3[1]!);
final int v2 = int.parse(match3[2]); final int v2 = int.parse(match3[2]!);
final bool hasV4 = match3[4] != null; final bool hasV4 = match3[4] != null;
if (v1 > 1 || (v1 == 1 && v2 >= 20)) { if (v1 > 1 || (v1 == 1 && v2 >= 20)) {
if (!hasV4) if (!hasV4)
throw 'Deprecation notice does not accurately indicate a dev branch version number; please see https://flutter.dev/docs/development/tools/sdk/releases to find the latest dev build version number.'; throw 'Deprecation notice does not accurately indicate a dev branch version number; please see https://flutter.dev/docs/development/tools/sdk/releases to find the latest dev build version number.';
} }
if (!message.endsWith('.') && !message.endsWith('!') && !message.endsWith('?')) if (!message!.endsWith('.') && !message.endsWith('!') && !message.endsWith('?'))
throw 'Deprecation notice should be a grammatically correct sentence and end with a period.'; throw 'Deprecation notice should be a grammatically correct sentence and end with a period.';
if (!lines[lineNumber].startsWith("$indent '")) if (!lines[lineNumber].startsWith("$indent '"))
throw 'Unexpected deprecation notice indent.'; throw 'Unexpected deprecation notice indent.';
...@@ -238,7 +238,7 @@ String _generateLicense(String prefix) { ...@@ -238,7 +238,7 @@ String _generateLicense(String prefix) {
} }
Future<void> verifyNoMissingLicense(String workingDirectory, { bool checkMinimums = true }) async { Future<void> verifyNoMissingLicense(String workingDirectory, { bool checkMinimums = true }) async {
final int overrideMinimumMatches = checkMinimums ? null : 0; final int? overrideMinimumMatches = checkMinimums ? null : 0;
await _verifyNoMissingLicenseForExtension(workingDirectory, 'dart', overrideMinimumMatches ?? 2000, _generateLicense('// ')); await _verifyNoMissingLicenseForExtension(workingDirectory, 'dart', overrideMinimumMatches ?? 2000, _generateLicense('// '));
await _verifyNoMissingLicenseForExtension(workingDirectory, 'java', overrideMinimumMatches ?? 39, _generateLicense('// ')); await _verifyNoMissingLicenseForExtension(workingDirectory, 'java', overrideMinimumMatches ?? 39, _generateLicense('// '));
await _verifyNoMissingLicenseForExtension(workingDirectory, 'h', overrideMinimumMatches ?? 30, _generateLicense('// ')); await _verifyNoMissingLicenseForExtension(workingDirectory, 'h', overrideMinimumMatches ?? 30, _generateLicense('// '));
...@@ -291,7 +291,7 @@ Future<void> verifyNoTestImports(String workingDirectory) async { ...@@ -291,7 +291,7 @@ Future<void> verifyNoTestImports(String workingDirectory) async {
final List<File> dartFiles = await _allFiles(path.join(workingDirectory, 'packages'), 'dart', minimumMatches: 1500).toList(); final List<File> dartFiles = await _allFiles(path.join(workingDirectory, 'packages'), 'dart', minimumMatches: 1500).toList();
for (final File file in dartFiles) { for (final File file in dartFiles) {
for (final String line in file.readAsLinesSync()) { for (final String line in file.readAsLinesSync()) {
final Match match = _testImportPattern.firstMatch(line); final Match? match = _testImportPattern.firstMatch(line);
if (match != null && !_exemptTestImports.contains(match.group(2))) if (match != null && !_exemptTestImports.contains(match.group(2)))
errors.add(file.path); errors.add(file.path);
} }
...@@ -333,11 +333,11 @@ Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async { ...@@ -333,11 +333,11 @@ Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async {
for (final String directory in directories) { for (final String directory in directories) {
dependencyMap[directory] = await _findFlutterDependencies(path.join(srcPath, directory), errors, checkForMeta: directory != 'foundation'); dependencyMap[directory] = await _findFlutterDependencies(path.join(srcPath, directory), errors, checkForMeta: directory != 'foundation');
} }
assert(dependencyMap['material'].contains('widgets') && assert(dependencyMap['material']!.contains('widgets') &&
dependencyMap['widgets'].contains('rendering') && dependencyMap['widgets']!.contains('rendering') &&
dependencyMap['rendering'].contains('painting')); // to make sure we're convinced _findFlutterDependencies is finding some dependencyMap['rendering']!.contains('painting')); // to make sure we're convinced _findFlutterDependencies is finding some
for (final String package in dependencyMap.keys) { for (final String package in dependencyMap.keys) {
if (dependencyMap[package].contains(package)) { if (dependencyMap[package]!.contains(package)) {
errors.add( errors.add(
'One of the files in the $yellow$package$reset package imports that package recursively.' 'One of the files in the $yellow$package$reset package imports that package recursively.'
); );
...@@ -345,7 +345,7 @@ Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async { ...@@ -345,7 +345,7 @@ Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async {
} }
for (final String key in dependencyMap.keys) { for (final String key in dependencyMap.keys) {
for (final String dependency in dependencyMap[key]) { for (final String dependency in dependencyMap[key]!) {
if (dependencyMap[dependency] != null) if (dependencyMap[dependency] != null)
continue; continue;
// Sanity check before performing _deepSearch, to ensure there's no rogue // Sanity check before performing _deepSearch, to ensure there's no rogue
...@@ -360,7 +360,7 @@ Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async { ...@@ -360,7 +360,7 @@ Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async {
} }
for (final String package in dependencyMap.keys) { for (final String package in dependencyMap.keys) {
final List<String> loop = _deepSearch<String>(dependencyMap, package); final List<String>? loop = _deepSearch<String>(dependencyMap, package);
if (loop != null) { if (loop != null) {
errors.add('${yellow}Dependency loop:$reset ${loop.join(' depends on ')}'); errors.add('${yellow}Dependency loop:$reset ${loop.join(' depends on ')}');
} }
...@@ -973,7 +973,7 @@ final Set<Hash256> _legacyBinaries = <Hash256>{ ...@@ -973,7 +973,7 @@ final Set<Hash256> _legacyBinaries = <Hash256>{
const Hash256(0x63D2ABD0041C3E3B, 0x4B52AD8D382353B5, 0x3C51C6785E76CE56, 0xED9DACAD2D2E31C4), const Hash256(0x63D2ABD0041C3E3B, 0x4B52AD8D382353B5, 0x3C51C6785E76CE56, 0xED9DACAD2D2E31C4),
}; };
Future<void> verifyNoBinaries(String workingDirectory, { Set<Hash256> legacyBinaries }) async { Future<void> verifyNoBinaries(String workingDirectory, { Set<Hash256>? legacyBinaries }) async {
// Please do not add anything to the _legacyBinaries set above. // Please do not add anything to the _legacyBinaries set above.
// We have a policy of not checking in binaries into this repository. // We have a policy of not checking in binaries into this repository.
// If you are adding/changing template images, use the flutter_template_images // If you are adding/changing template images, use the flutter_template_images
...@@ -1051,7 +1051,7 @@ Future<List<File>> _gitFiles(String workingDirectory, {bool runSilently = true}) ...@@ -1051,7 +1051,7 @@ Future<List<File>> _gitFiles(String workingDirectory, {bool runSilently = true})
.toList(); .toList();
} }
Stream<File> _allFiles(String workingDirectory, String extension, { @required int minimumMatches }) async* { Stream<File> _allFiles(String workingDirectory, String? extension, { required int minimumMatches }) async* {
final Set<String> gitFileNamesSet = <String>{}; final Set<String> gitFileNamesSet = <String>{};
gitFileNamesSet.addAll((await _gitFiles(workingDirectory)).map((File f) => path.canonicalize(f.absolute.path))); gitFileNamesSet.addAll((await _gitFiles(workingDirectory)).map((File f) => path.canonicalize(f.absolute.path)));
...@@ -1101,8 +1101,8 @@ Stream<File> _allFiles(String workingDirectory, String extension, { @required in ...@@ -1101,8 +1101,8 @@ Stream<File> _allFiles(String workingDirectory, String extension, { @required in
class EvalResult { class EvalResult {
EvalResult({ EvalResult({
this.stdout, required this.stdout,
this.stderr, required this.stderr,
this.exitCode = 0, this.exitCode = 0,
}); });
...@@ -1113,18 +1113,13 @@ class EvalResult { ...@@ -1113,18 +1113,13 @@ class EvalResult {
// TODO(ianh): Refactor this to reuse the code in run_command.dart // TODO(ianh): Refactor this to reuse the code in run_command.dart
Future<EvalResult> _evalCommand(String executable, List<String> arguments, { Future<EvalResult> _evalCommand(String executable, List<String> arguments, {
@required String workingDirectory, required String workingDirectory,
Map<String, String> environment, Map<String, String>? environment,
bool skip = false,
bool allowNonZeroExit = false, bool allowNonZeroExit = false,
bool runSilently = false, bool runSilently = false,
}) async { }) async {
final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}'; final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}';
final String relativeWorkingDir = path.relative(workingDirectory); final String relativeWorkingDir = path.relative(workingDirectory);
if (skip) {
printProgress('SKIPPING', relativeWorkingDir, commandDescription);
return null;
}
if (!runSilently) { if (!runSilently) {
printProgress('RUNNING', relativeWorkingDir, commandDescription); printProgress('RUNNING', relativeWorkingDir, commandDescription);
...@@ -1168,8 +1163,8 @@ Future<void> _checkConsumerDependencies() async { ...@@ -1168,8 +1163,8 @@ Future<void> _checkConsumerDependencies() async {
'--consumer-only', '--consumer-only',
]); ]);
if (result.exitCode != 0) { if (result.exitCode != 0) {
print(result.stdout); print(result.stdout as Object);
print(result.stderr); print(result.stderr as Object);
exit(result.exitCode); exit(result.exitCode);
} }
final Set<String> dependencySet = <String>{}; final Set<String> dependencySet = <String>{};
...@@ -1217,7 +1212,7 @@ Future<void> _checkConsumerDependencies() async { ...@@ -1217,7 +1212,7 @@ Future<void> _checkConsumerDependencies() async {
} }
} }
Future<void> _runFlutterAnalyze(String workingDirectory, { Future<CommandResult> _runFlutterAnalyze(String workingDirectory, {
List<String> options = const <String>[], List<String> options = const <String>[],
}) async { }) async {
return runCommand( return runCommand(
...@@ -1235,9 +1230,9 @@ Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors ...@@ -1235,9 +1230,9 @@ Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors
.map<Set<String>>((File file) { .map<Set<String>>((File file) {
final Set<String> result = <String>{}; final Set<String> result = <String>{};
for (final String line in file.readAsLinesSync()) { for (final String line in file.readAsLinesSync()) {
Match match = _importPattern.firstMatch(line); Match? match = _importPattern.firstMatch(line);
if (match != null) if (match != null)
result.add(match.group(2)); result.add(match.group(2)!);
if (checkForMeta) { if (checkForMeta) {
match = _importMetaPattern.firstMatch(line); match = _importMetaPattern.firstMatch(line);
if (match != null) { if (match != null) {
...@@ -1250,23 +1245,23 @@ Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors ...@@ -1250,23 +1245,23 @@ Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors
} }
return result; return result;
}) })
.reduce((Set<String> value, Set<String> element) { .reduce((Set<String>? value, Set<String> element) {
value ??= <String>{}; value ??= <String>{};
value.addAll(element); value.addAll(element);
return value; return value;
}); });
} }
List<T> _deepSearch<T>(Map<T, Set<T>> map, T start, [ Set<T> seen ]) { List<T>? _deepSearch<T>(Map<T, Set<T>> map, T start, [ Set<T>? seen ]) {
if (map[start] == null) if (map[start] == null)
return null; // We catch these separately. return null; // We catch these separately.
for (final T key in map[start]) { for (final T key in map[start]!) {
if (key == start) if (key == start)
continue; // we catch these separately continue; // we catch these separately
if (seen != null && seen.contains(key)) if (seen != null && seen.contains(key))
return <T>[start, key]; return <T>[start, key];
final List<T> result = _deepSearch<T>( final List<T>? result = _deepSearch<T>(
map, map,
key, key,
<T>{ <T>{
......
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ import 'dart:async';
import 'dart:io' as io; import 'dart:io' as io;
import 'package:flutter_devicelab/framework/browser.dart'; import 'package:flutter_devicelab/framework/browser.dart';
import 'package:meta/meta.dart';
import 'package:shelf/shelf.dart'; import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io; import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_static/shelf_static.dart'; import 'package:shelf_static/shelf_static.dart';
...@@ -21,13 +20,13 @@ import 'package:shelf_static/shelf_static.dart'; ...@@ -21,13 +20,13 @@ import 'package:shelf_static/shelf_static.dart';
/// request to "/test-result" containing result data as plain text body of the /// request to "/test-result" containing result data as plain text body of the
/// request. This function has no opinion about what that string contains. /// request. This function has no opinion about what that string contains.
Future<String> evalTestAppInChrome({ Future<String> evalTestAppInChrome({
@required String appUrl, required String appUrl,
@required String appDirectory, required String appDirectory,
int serverPort = 8080, int serverPort = 8080,
int browserDebugPort = 8081, int browserDebugPort = 8081,
}) async { }) async {
io.HttpServer server; io.HttpServer? server;
Chrome chrome; Chrome? chrome;
try { try {
final Completer<String> resultCompleter = Completer<String>(); final Completer<String> resultCompleter = Completer<String>();
server = await io.HttpServer.bind('localhost', serverPort); server = await io.HttpServer.bind('localhost', serverPort);
...@@ -63,13 +62,13 @@ class AppServer { ...@@ -63,13 +62,13 @@ class AppServer {
AppServer._(this._server, this.chrome, this.onChromeError); AppServer._(this._server, this.chrome, this.onChromeError);
static Future<AppServer> start({ static Future<AppServer> start({
@required String appUrl, required String appUrl,
@required String appDirectory, required String appDirectory,
@required String cacheControl, required String cacheControl,
int serverPort = 8080, int serverPort = 8080,
int browserDebugPort = 8081, int browserDebugPort = 8081,
bool headless = true, bool headless = true,
List<Handler> additionalRequestHandlers, List<Handler>? additionalRequestHandlers,
}) async { }) async {
io.HttpServer server; io.HttpServer server;
Chrome chrome; Chrome chrome;
...@@ -106,7 +105,7 @@ class AppServer { ...@@ -106,7 +105,7 @@ class AppServer {
final Chrome chrome; final Chrome chrome;
Future<void> stop() async { Future<void> stop() async {
chrome?.stop(); chrome.stop();
await _server?.close(); await _server.close();
} }
} }
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:meta/meta.dart';
final Stopwatch _stopwatch = Stopwatch(); final Stopwatch _stopwatch = Stopwatch();
/// A wrapper around package:test's JSON reporter. /// A wrapper around package:test's JSON reporter.
...@@ -75,7 +73,7 @@ class FlutterCompactFormatter { ...@@ -75,7 +73,7 @@ class FlutterCompactFormatter {
/// ///
/// Callers are responsible for splitting multiple lines before calling this /// Callers are responsible for splitting multiple lines before calling this
/// method. /// method.
TestResult processRawOutput(String raw) { TestResult? processRawOutput(String raw) {
assert(raw != null); assert(raw != null);
// We might be getting messages from Flutter Tool about updating/building. // We might be getting messages from Flutter Tool about updating/building.
if (!raw.startsWith('{')) { if (!raw.startsWith('{')) {
...@@ -83,7 +81,7 @@ class FlutterCompactFormatter { ...@@ -83,7 +81,7 @@ class FlutterCompactFormatter {
return null; return null;
} }
final Map<String, dynamic> decoded = json.decode(raw) as Map<String, dynamic>; final Map<String, dynamic> decoded = json.decode(raw) as Map<String, dynamic>;
final TestResult originalResult = _tests[decoded['testID']]; final TestResult? originalResult = _tests[decoded['testID']];
switch (decoded['type'] as String) { switch (decoded['type'] as String) {
case 'done': case 'done':
stdout.write(_clearLine); stdout.write(_clearLine);
...@@ -104,9 +102,9 @@ class FlutterCompactFormatter { ...@@ -104,9 +102,9 @@ class FlutterCompactFormatter {
_tests[testData['id'] as int] = TestResult( _tests[testData['id'] as int] = TestResult(
id: testData['id'] as int, id: testData['id'] as int,
name: testData['name'] as String, name: testData['name'] as String,
line: testData['root_line'] as int ?? testData['line'] as int, line: testData['root_line'] as int? ?? testData['line'] as int,
column: testData['root_column'] as int ?? testData['column'] as int, column: testData['root_column'] as int? ?? testData['column'] as int,
path: testData['root_url'] as String ?? testData['url'] as String, path: testData['root_url'] as String? ?? testData['url'] as String,
startTime: decoded['time'] as int, startTime: decoded['time'] as int,
); );
break; break;
...@@ -173,9 +171,9 @@ class FlutterCompactFormatter { ...@@ -173,9 +171,9 @@ class FlutterCompactFormatter {
case TestStatus.failed: case TestStatus.failed:
failed.addAll(<String>[ failed.addAll(<String>[
'$_bold${_red}Failed ${result.name} (${result.pathLineColumn}):', '$_bold${_red}Failed ${result.name} (${result.pathLineColumn}):',
result.errorMessage, result.errorMessage!,
_noColor + _red, _noColor + _red,
result.stackTrace, result.stackTrace!,
]); ]);
failed.addAll(result.messages); failed.addAll(result.messages);
failed.add(_noColor); failed.add(_noColor);
...@@ -209,12 +207,12 @@ enum TestStatus { ...@@ -209,12 +207,12 @@ enum TestStatus {
/// The detailed status of a test run. /// The detailed status of a test run.
class TestResult { class TestResult {
TestResult({ TestResult({
@required this.id, required this.id,
@required this.name, required this.name,
@required this.line, required this.line,
@required this.column, required this.column,
@required this.path, required this.path,
@required this.startTime, required this.startTime,
this.status = TestStatus.started, this.status = TestStatus.started,
}) : assert(id != null), }) : assert(id != null),
assert(name != null), assert(name != null),
...@@ -254,13 +252,13 @@ class TestResult { ...@@ -254,13 +252,13 @@ class TestResult {
/// The error message from the test, from an `expect`, an [Exception] or /// The error message from the test, from an `expect`, an [Exception] or
/// [Error]. /// [Error].
String errorMessage; String? errorMessage;
/// The stacktrace from a test failure. /// The stacktrace from a test failure.
String stackTrace; String? stackTrace;
/// The time, in milliseconds relative to suite startup, that the test ended. /// The time, in milliseconds relative to suite startup, that the test ended.
int endTime; int? endTime;
/// The total time, in milliseconds, that the test took. /// The total time, in milliseconds, that the test took.
int get totalTime => (endTime ?? _stopwatch.elapsedMilliseconds) - startTime; int get totalTime => (endTime ?? _stopwatch.elapsedMilliseconds) - startTime;
......
...@@ -11,7 +11,6 @@ import 'package:args/args.dart'; ...@@ -11,7 +11,6 @@ import 'package:args/args.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:crypto/src/digest_sink.dart'; import 'package:crypto/src/digest_sink.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:meta/meta.dart' show required;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:platform/platform.dart' show Platform, LocalPlatform; import 'package:platform/platform.dart' show Platform, LocalPlatform;
import 'package:process/process.dart'; import 'package:process/process.dart';
...@@ -32,7 +31,7 @@ class PreparePackageException implements Exception { ...@@ -32,7 +31,7 @@ class PreparePackageException implements Exception {
PreparePackageException(this.message, [this.result]); PreparePackageException(this.message, [this.result]);
final String message; final String message;
final ProcessResult result; final ProcessResult? result;
int get exitCode => result?.exitCode ?? -1; int get exitCode => result?.exitCode ?? -1;
@override @override
...@@ -41,7 +40,7 @@ class PreparePackageException implements Exception { ...@@ -41,7 +40,7 @@ class PreparePackageException implements Exception {
if (message != null) { if (message != null) {
output += ': $message'; output += ': $message';
} }
final String stderr = result?.stderr as String ?? ''; final String stderr = result?.stderr as String? ?? '';
if (stderr.isNotEmpty) { if (stderr.isNotEmpty) {
output += ':\n$stderr'; output += ':\n$stderr';
} }
...@@ -60,7 +59,6 @@ String getBranchName(Branch branch) { ...@@ -60,7 +59,6 @@ String getBranchName(Branch branch) {
case Branch.stable: case Branch.stable:
return 'stable'; return 'stable';
} }
return null;
} }
Branch fromBranchName(String name) { Branch fromBranchName(String name) {
...@@ -81,7 +79,7 @@ Branch fromBranchName(String name) { ...@@ -81,7 +79,7 @@ Branch fromBranchName(String name) {
/// properly without dropping any. /// properly without dropping any.
class ProcessRunner { class ProcessRunner {
ProcessRunner({ ProcessRunner({
ProcessManager processManager, ProcessManager? processManager,
this.subprocessOutput = true, this.subprocessOutput = true,
this.defaultWorkingDirectory, this.defaultWorkingDirectory,
this.platform = const LocalPlatform(), this.platform = const LocalPlatform(),
...@@ -102,10 +100,10 @@ class ProcessRunner { ...@@ -102,10 +100,10 @@ class ProcessRunner {
/// Sets the default directory used when `workingDirectory` is not specified /// Sets the default directory used when `workingDirectory` is not specified
/// to [runProcess]. /// to [runProcess].
final Directory defaultWorkingDirectory; final Directory? defaultWorkingDirectory;
/// The environment to run processes with. /// The environment to run processes with.
Map<String, String> environment; late Map<String, String> environment;
/// Run the command and arguments in `commandLine` as a sub-process from /// Run the command and arguments in `commandLine` as a sub-process from
/// `workingDirectory` if set, or the [defaultWorkingDirectory] if not. Uses /// `workingDirectory` if set, or the [defaultWorkingDirectory] if not. Uses
...@@ -115,7 +113,7 @@ class ProcessRunner { ...@@ -115,7 +113,7 @@ class ProcessRunner {
/// command completes with a non-zero exit code. /// command completes with a non-zero exit code.
Future<String> runProcess( Future<String> runProcess(
List<String> commandLine, { List<String> commandLine, {
Directory workingDirectory, Directory? workingDirectory,
bool failOk = false, bool failOk = false,
}) async { }) async {
workingDirectory ??= defaultWorkingDirectory ?? Directory.current; workingDirectory ??= defaultWorkingDirectory ?? Directory.current;
...@@ -125,7 +123,7 @@ class ProcessRunner { ...@@ -125,7 +123,7 @@ class ProcessRunner {
final List<int> output = <int>[]; final List<int> output = <int>[];
final Completer<void> stdoutComplete = Completer<void>(); final Completer<void> stdoutComplete = Completer<void>();
final Completer<void> stderrComplete = Completer<void>(); final Completer<void> stderrComplete = Completer<void>();
Process process; late Process process;
Future<int> allComplete() async { Future<int> allComplete() async {
await stderrComplete.future; await stderrComplete.future;
await stdoutComplete.future; await stdoutComplete.future;
...@@ -197,10 +195,10 @@ class ArchiveCreator { ...@@ -197,10 +195,10 @@ class ArchiveCreator {
this.revision, this.revision,
this.branch, { this.branch, {
this.strict = true, this.strict = true,
ProcessManager processManager, ProcessManager? processManager,
bool subprocessOutput = true, bool subprocessOutput = true,
this.platform = const LocalPlatform(), this.platform = const LocalPlatform(),
HttpReader httpReader, HttpReader? httpReader,
}) : assert(revision.length == 40), }) : assert(revision.length == 40),
flutterRoot = Directory(path.join(tempDir.path, 'flutter')), flutterRoot = Directory(path.join(tempDir.path, 'flutter')),
httpReader = httpReader ?? http.readBytes, httpReader = httpReader ?? http.readBytes,
...@@ -252,9 +250,9 @@ class ArchiveCreator { ...@@ -252,9 +250,9 @@ class ArchiveCreator {
/// [http.readBytes]. /// [http.readBytes].
final HttpReader httpReader; final HttpReader httpReader;
File _outputFile; late File _outputFile;
String _version; late String _version;
String _flutter; late String _flutter;
/// Get the name of the channel as a string. /// Get the name of the channel as a string.
String get branchName => getBranchName(branch); String get branchName => getBranchName(branch);
...@@ -446,14 +444,14 @@ class ArchiveCreator { ...@@ -446,14 +444,14 @@ class ArchiveCreator {
} }
} }
Future<String> _runFlutter(List<String> args, {Directory workingDirectory}) { Future<String> _runFlutter(List<String> args, {Directory? workingDirectory}) {
return _processRunner.runProcess( return _processRunner.runProcess(
<String>[_flutter, ...args], <String>[_flutter, ...args],
workingDirectory: workingDirectory ?? flutterRoot, workingDirectory: workingDirectory ?? flutterRoot,
); );
} }
Future<String> _runGit(List<String> args, {Directory workingDirectory}) { Future<String> _runGit(List<String> args, {Directory? workingDirectory}) {
return _processRunner.runProcess( return _processRunner.runProcess(
<String>['git', ...args], <String>['git', ...args],
workingDirectory: workingDirectory ?? flutterRoot, workingDirectory: workingDirectory ?? flutterRoot,
...@@ -462,7 +460,7 @@ class ArchiveCreator { ...@@ -462,7 +460,7 @@ class ArchiveCreator {
/// Unpacks the given zip file into the currentDirectory (if set), or the /// Unpacks the given zip file into the currentDirectory (if set), or the
/// same directory as the archive. /// same directory as the archive.
Future<String> _unzipArchive(File archive, {Directory workingDirectory}) { Future<String> _unzipArchive(File archive, {Directory? workingDirectory}) {
workingDirectory ??= Directory(path.dirname(archive.absolute.path)); workingDirectory ??= Directory(path.dirname(archive.absolute.path));
List<String> commandLine; List<String> commandLine;
if (platform.isWindows) { if (platform.isWindows) {
...@@ -532,7 +530,7 @@ class ArchivePublisher { ...@@ -532,7 +530,7 @@ class ArchivePublisher {
this.version, this.version,
this.outputFile, this.outputFile,
this.dryRun, { this.dryRun, {
ProcessManager processManager, ProcessManager? processManager,
bool subprocessOutput = true, bool subprocessOutput = true,
this.platform = const LocalPlatform(), this.platform = const LocalPlatform(),
}) : assert(revision.length == 40), }) : assert(revision.length == 40),
...@@ -662,7 +660,7 @@ class ArchivePublisher { ...@@ -662,7 +660,7 @@ class ArchivePublisher {
Future<String> _runGsUtil( Future<String> _runGsUtil(
List<String> args, { List<String> args, {
Directory workingDirectory, Directory? workingDirectory,
bool failOk = false, bool failOk = false,
}) async { }) async {
if (dryRun) { if (dryRun) {
...@@ -671,7 +669,7 @@ class ArchivePublisher { ...@@ -671,7 +669,7 @@ class ArchivePublisher {
} }
if (platform.isWindows) { if (platform.isWindows) {
return _processRunner.runProcess( return _processRunner.runProcess(
<String>['python', path.join(platform.environment['DEPOT_TOOLS'], 'gsutil.py'), '--', ...args], <String>['python', path.join(platform.environment['DEPOT_TOOLS']!, 'gsutil.py'), '--', ...args],
workingDirectory: workingDirectory, workingDirectory: workingDirectory,
failOk: failOk, failOk: failOk,
); );
...@@ -699,14 +697,14 @@ class ArchivePublisher { ...@@ -699,14 +697,14 @@ class ArchivePublisher {
} }
Future<String> _cloudCopy({ Future<String> _cloudCopy({
@required String src, required String src,
@required String dest, required String dest,
int cacheSeconds, int? cacheSeconds,
}) async { }) async {
// We often don't have permission to overwrite, but // We often don't have permission to overwrite, but
// we have permission to remove, so that's what we do. // we have permission to remove, so that's what we do.
await _runGsUtil(<String>['rm', dest], failOk: true); await _runGsUtil(<String>['rm', dest], failOk: true);
String mimeType; String? mimeType;
if (dest.endsWith('.tar.xz')) { if (dest.endsWith('.tar.xz')) {
mimeType = 'application/x-gtar'; mimeType = 'application/x-gtar';
} }
...@@ -841,7 +839,7 @@ Future<void> main(List<String> rawArguments) async { ...@@ -841,7 +839,7 @@ Future<void> main(List<String> rawArguments) async {
final Branch branch = fromBranchName(parsedArguments['branch'] as String); final Branch branch = fromBranchName(parsedArguments['branch'] as String);
final ArchiveCreator creator = ArchiveCreator(tempDir, outputDir, revision, branch, strict: parsedArguments['publish'] as bool); final ArchiveCreator creator = ArchiveCreator(tempDir, outputDir, revision, branch, strict: parsedArguments['publish'] as bool);
int exitCode = 0; int exitCode = 0;
String message; late String message;
try { try {
final String version = await creator.initializeRepo(); final String version = await creator.initializeRepo();
final File outputFile = await creator.createArchive(); final File outputFile = await creator.createArchive();
......
...@@ -2,7 +2,7 @@ name: tests_on_bots ...@@ -2,7 +2,7 @@ name: tests_on_bots
description: Scripts which run on bots. description: Scripts which run on bots.
environment: environment:
sdk: ">=2.2.2 <3.0.0" sdk: ">=2.12.0 <3.0.0"
dependencies: dependencies:
args: 2.1.1 args: 2.1.1
......
...@@ -19,12 +19,12 @@ import 'utils.dart'; ...@@ -19,12 +19,12 @@ import 'utils.dart';
/// code fails the test immediately by exiting the test process with exit code /// code fails the test immediately by exiting the test process with exit code
/// 1. /// 1.
Stream<String> runAndGetStdout(String executable, List<String> arguments, { Stream<String> runAndGetStdout(String executable, List<String> arguments, {
String workingDirectory, String? workingDirectory,
Map<String, String> environment, Map<String, String>? environment,
bool expectNonZeroExit = false, bool expectNonZeroExit = false,
}) async* { }) async* {
final StreamController<String> output = StreamController<String>(); final StreamController<String> output = StreamController<String>();
final Future<CommandResult> command = runCommand( final Future<CommandResult?> command = runCommand(
executable, executable,
arguments, arguments,
workingDirectory: workingDirectory, workingDirectory: workingDirectory,
...@@ -52,8 +52,8 @@ class Command { ...@@ -52,8 +52,8 @@ class Command {
final io.Process process; final io.Process process;
final Stopwatch _time; final Stopwatch _time;
final Future<List<List<int>>> _savedStdout; final Future<List<List<int>>>? _savedStdout;
final Future<List<List<int>>> _savedStderr; final Future<List<List<int>>>? _savedStderr;
/// Evaluates when the [process] exits. /// Evaluates when the [process] exits.
/// ///
...@@ -63,8 +63,8 @@ class Command { ...@@ -63,8 +63,8 @@ class Command {
_time.stop(); _time.stop();
// Saved output is null when OutputMode.print is used. // Saved output is null when OutputMode.print is used.
final String flattenedStdout = _savedStdout != null ? _flattenToString(await _savedStdout) : null; final String? flattenedStdout = _savedStdout != null ? _flattenToString((await _savedStdout)!) : null;
final String flattenedStderr = _savedStderr != null ? _flattenToString(await _savedStderr) : null; final String? flattenedStderr = _savedStderr != null ? _flattenToString((await _savedStderr)!) : null;
return CommandResult._(exitCode, _time.elapsed, flattenedStdout, flattenedStderr); return CommandResult._(exitCode, _time.elapsed, flattenedStdout, flattenedStderr);
} }
} }
...@@ -80,10 +80,10 @@ class CommandResult { ...@@ -80,10 +80,10 @@ class CommandResult {
final Duration elapsedTime; final Duration elapsedTime;
/// Standard output decoded as a string using UTF8 decoder. /// Standard output decoded as a string using UTF8 decoder.
final String flattenedStdout; final String? flattenedStdout;
/// Standard error output decoded as a string using UTF8 decoder. /// Standard error output decoded as a string using UTF8 decoder.
final String flattenedStderr; final String? flattenedStderr;
} }
/// Starts the `executable` and returns a command object representing the /// Starts the `executable` and returns a command object representing the
...@@ -97,11 +97,11 @@ class CommandResult { ...@@ -97,11 +97,11 @@ class CommandResult {
/// `outputMode` controls where the standard output from the command process /// `outputMode` controls where the standard output from the command process
/// goes. See [OutputMode]. /// goes. See [OutputMode].
Future<Command> startCommand(String executable, List<String> arguments, { Future<Command> startCommand(String executable, List<String> arguments, {
String workingDirectory, String? workingDirectory,
Map<String, String> environment, Map<String, String>? environment,
OutputMode outputMode = OutputMode.print, OutputMode outputMode = OutputMode.print,
bool Function(String) removeLine, bool Function(String)? removeLine,
void Function(String, io.Process) outputListener, void Function(String, io.Process)? outputListener,
}) async { }) async {
final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}'; final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}';
final String relativeWorkingDir = path.relative(workingDirectory ?? io.Directory.current.path); final String relativeWorkingDir = path.relative(workingDirectory ?? io.Directory.current.path);
...@@ -113,7 +113,7 @@ Future<Command> startCommand(String executable, List<String> arguments, { ...@@ -113,7 +113,7 @@ Future<Command> startCommand(String executable, List<String> arguments, {
environment: environment, environment: environment,
); );
Future<List<List<int>>> savedStdout, savedStderr; Future<List<List<int>>>? savedStdout, savedStderr;
final Stream<List<int>> stdoutSource = process.stdout final Stream<List<int>> stdoutSource = process.stdout
.transform<String>(const Utf8Decoder()) .transform<String>(const Utf8Decoder())
.transform(const LineSplitter()) .transform(const LineSplitter())
...@@ -150,27 +150,22 @@ Future<Command> startCommand(String executable, List<String> arguments, { ...@@ -150,27 +150,22 @@ Future<Command> startCommand(String executable, List<String> arguments, {
/// an indefinitely running process, for example, by waiting until the process /// an indefinitely running process, for example, by waiting until the process
/// emits certain output. /// emits certain output.
/// ///
/// Returns the result of the finished process, or null if `skip` is true. /// Returns the result of the finished process.
/// ///
/// `outputMode` controls where the standard output from the command process /// `outputMode` controls where the standard output from the command process
/// goes. See [OutputMode]. /// goes. See [OutputMode].
Future<CommandResult> runCommand(String executable, List<String> arguments, { Future<CommandResult> runCommand(String executable, List<String> arguments, {
String workingDirectory, String? workingDirectory,
Map<String, String> environment, Map<String, String>? environment,
bool expectNonZeroExit = false, bool expectNonZeroExit = false,
int expectedExitCode, int? expectedExitCode,
String failureMessage, String? failureMessage,
OutputMode outputMode = OutputMode.print, OutputMode outputMode = OutputMode.print,
bool skip = false, bool Function(String)? removeLine,
bool Function(String) removeLine, void Function(String, io.Process)? outputListener,
void Function(String, io.Process) outputListener,
}) async { }) async {
final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}'; final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}';
final String relativeWorkingDir = path.relative(workingDirectory ?? io.Directory.current.path); final String relativeWorkingDir = path.relative(workingDirectory ?? io.Directory.current.path);
if (skip) {
printProgress('SKIPPING', relativeWorkingDir, commandDescription);
return null;
}
final Command command = await startCommand(executable, arguments, final Command command = await startCommand(executable, arguments,
workingDirectory: workingDirectory, workingDirectory: workingDirectory,
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:shelf/shelf.dart'; import 'package:shelf/shelf.dart';
...@@ -37,7 +36,7 @@ Future<void> _setAppVersion(int version) async { ...@@ -37,7 +36,7 @@ Future<void> _setAppVersion(int version) async {
); );
} }
Future<void> _rebuildApp({ @required int version }) async { Future<void> _rebuildApp({ required int version }) async {
await _setAppVersion(version); await _setAppVersion(version);
await runCommand( await runCommand(
_flutter, _flutter,
...@@ -56,7 +55,7 @@ Future<void> _rebuildApp({ @required int version }) async { ...@@ -56,7 +55,7 @@ Future<void> _rebuildApp({ @required int version }) async {
/// A drop-in replacement for `package:test` expect that can run outside the /// A drop-in replacement for `package:test` expect that can run outside the
/// test zone. /// test zone.
void expect(Object actual, Object expected) { void expect(Object? actual, Object? expected) {
final Matcher matcher = wrapMatcher(expected); final Matcher matcher = wrapMatcher(expected);
final Map<Object, Object> matchState = <Object, Object>{}; final Map<Object, Object> matchState = <Object, Object>{};
if (matcher.matches(actual, matchState)) { if (matcher.matches(actual, matchState)) {
...@@ -68,7 +67,7 @@ void expect(Object actual, Object expected) { ...@@ -68,7 +67,7 @@ void expect(Object actual, Object expected) {
} }
Future<void> runWebServiceWorkerTest({ Future<void> runWebServiceWorkerTest({
@required bool headless, required bool headless,
}) async { }) async {
await _rebuildApp(version: 1); await _rebuildApp(version: 1);
...@@ -78,25 +77,25 @@ Future<void> runWebServiceWorkerTest({ ...@@ -78,25 +77,25 @@ Future<void> runWebServiceWorkerTest({
requestedPathCounts.clear(); requestedPathCounts.clear();
} }
AppServer server; AppServer? server;
Future<void> waitForAppToLoad(Map<String, int> waitForCounts) async { Future<void> waitForAppToLoad(Map<String, int> waitForCounts) async {
print('Waiting for app to load $waitForCounts'); print('Waiting for app to load $waitForCounts');
await Future.any(<Future<void>>[ await Future.any(<Future<Object?>>[
() async { () async {
while (!waitForCounts.entries.every((MapEntry<String, int> entry) => (requestedPathCounts[entry.key] ?? 0) >= entry.value)) { while (!waitForCounts.entries.every((MapEntry<String, int> entry) => (requestedPathCounts[entry.key] ?? 0) >= entry.value)) {
await Future<void>.delayed(const Duration(milliseconds: 100)); await Future<void>.delayed(const Duration(milliseconds: 100));
} }
}(), }(),
server.onChromeError.then((String error) { server!.onChromeError.then((String error) {
throw Exception('Chrome error: $error'); throw Exception('Chrome error: $error');
}), }),
]); ]);
} }
String reportedVersion; String? reportedVersion;
Future<void> startAppServer({ Future<void> startAppServer({
@required String cacheControl, required String cacheControl,
}) async { }) async {
final int serverPort = await findAvailablePort(); final int serverPort = await findAvailablePort();
final int browserDebugPort = await findAvailablePort(); final int browserDebugPort = await findAvailablePort();
...@@ -113,7 +112,7 @@ Future<void> runWebServiceWorkerTest({ ...@@ -113,7 +112,7 @@ Future<void> runWebServiceWorkerTest({
(Request request) { (Request request) {
final String requestedPath = request.url.path; final String requestedPath = request.url.path;
requestedPathCounts.putIfAbsent(requestedPath, () => 0); requestedPathCounts.putIfAbsent(requestedPath, () => 0);
requestedPathCounts[requestedPath] += 1; requestedPathCounts[requestedPath] = requestedPathCounts[requestedPath]! + 1;
if (requestedPath == 'CLOSE') { if (requestedPath == 'CLOSE') {
reportedVersion = request.url.queryParameters['version']; reportedVersion = request.url.queryParameters['version'];
return Response.ok('OK'); return Response.ok('OK');
...@@ -158,7 +157,7 @@ Future<void> runWebServiceWorkerTest({ ...@@ -158,7 +157,7 @@ Future<void> runWebServiceWorkerTest({
reportedVersion = null; reportedVersion = null;
print('With cache: test page reload'); print('With cache: test page reload');
await server.chrome.reloadPage(); await server!.chrome.reloadPage();
await waitForAppToLoad(<String, int>{ await waitForAppToLoad(<String, int>{
'CLOSE': 1, 'CLOSE': 1,
'flutter_service_worker.js': 1, 'flutter_service_worker.js': 1,
...@@ -175,7 +174,7 @@ Future<void> runWebServiceWorkerTest({ ...@@ -175,7 +174,7 @@ Future<void> runWebServiceWorkerTest({
await _rebuildApp(version: 2); await _rebuildApp(version: 2);
// Since we're caching, we need to ignore cache when reloading the page. // Since we're caching, we need to ignore cache when reloading the page.
await server.chrome.reloadPage(ignoreCache: true); await server!.chrome.reloadPage(ignoreCache: true);
await waitForAppToLoad(<String, int>{ await waitForAppToLoad(<String, int>{
'CLOSE': 1, 'CLOSE': 1,
'flutter_service_worker.js': 2, 'flutter_service_worker.js': 2,
...@@ -195,7 +194,7 @@ Future<void> runWebServiceWorkerTest({ ...@@ -195,7 +194,7 @@ Future<void> runWebServiceWorkerTest({
expect(reportedVersion, '2'); expect(reportedVersion, '2');
reportedVersion = null; reportedVersion = null;
await server.stop(); await server!.stop();
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
...@@ -231,7 +230,7 @@ Future<void> runWebServiceWorkerTest({ ...@@ -231,7 +230,7 @@ Future<void> runWebServiceWorkerTest({
reportedVersion = null; reportedVersion = null;
print('No cache: test page reload'); print('No cache: test page reload');
await server.chrome.reloadPage(); await server!.chrome.reloadPage();
await waitForAppToLoad(<String, int>{ await waitForAppToLoad(<String, int>{
'CLOSE': 1, 'CLOSE': 1,
'flutter_service_worker.js': 1, 'flutter_service_worker.js': 1,
...@@ -254,7 +253,7 @@ Future<void> runWebServiceWorkerTest({ ...@@ -254,7 +253,7 @@ Future<void> runWebServiceWorkerTest({
// refresh when running Chrome manually as normal. At the time of writing // refresh when running Chrome manually as normal. At the time of writing
// this test I wasn't able to figure out what's wrong with the way we run // this test I wasn't able to figure out what's wrong with the way we run
// Chrome from tests. // Chrome from tests.
await server.chrome.reloadPage(ignoreCache: true); await server!.chrome.reloadPage(ignoreCache: true);
await waitForAppToLoad(<String, int>{ await waitForAppToLoad(<String, int>{
'CLOSE': 1, 'CLOSE': 1,
'flutter_service_worker.js': 1, 'flutter_service_worker.js': 1,
......
...@@ -9,7 +9,6 @@ import 'dart:math' as math; ...@@ -9,7 +9,6 @@ import 'dart:math' as math;
import 'package:file/file.dart' as fs; import 'package:file/file.dart' as fs;
import 'package:file/local.dart'; import 'package:file/local.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'browser.dart'; import 'browser.dart';
...@@ -26,7 +25,7 @@ typedef ShardRunner = Future<void> Function(); ...@@ -26,7 +25,7 @@ typedef ShardRunner = Future<void> Function();
/// ///
/// If the output does not match expectations, the function shall return an /// If the output does not match expectations, the function shall return an
/// appropriate error message. /// appropriate error message.
typedef OutputChecker = String Function(CommandResult); typedef OutputChecker = String? Function(CommandResult);
final String exe = Platform.isWindows ? '.exe' : ''; final String exe = Platform.isWindows ? '.exe' : '';
final String bat = Platform.isWindows ? '.bat' : ''; final String bat = Platform.isWindows ? '.bat' : '';
...@@ -73,7 +72,7 @@ const String kSubshardKey = 'SUBSHARD'; ...@@ -73,7 +72,7 @@ const String kSubshardKey = 'SUBSHARD';
/// ///
/// The last shard also runs the Web plugin tests. /// The last shard also runs the Web plugin tests.
int get webShardCount => Platform.environment.containsKey('WEB_SHARD_COUNT') int get webShardCount => Platform.environment.containsKey('WEB_SHARD_COUNT')
? int.parse(Platform.environment['WEB_SHARD_COUNT']) ? int.parse(Platform.environment['WEB_SHARD_COUNT']!)
: 8; : 8;
/// Tests that we don't run on Web for compilation reasons. /// Tests that we don't run on Web for compilation reasons.
// //
...@@ -148,7 +147,7 @@ Future<void> _validateEngineHash() async { ...@@ -148,7 +147,7 @@ Future<void> _validateEngineHash() async {
} }
final String expectedVersion = File(engineVersionFile).readAsStringSync().trim(); final String expectedVersion = File(engineVersionFile).readAsStringSync().trim();
final CommandResult result = await runCommand(flutterTester, <String>['--help'], outputMode: OutputMode.capture); final CommandResult result = await runCommand(flutterTester, <String>['--help'], outputMode: OutputMode.capture);
final String actualVersion = result.flattenedStderr.split('\n').firstWhere((final String line) { final String actualVersion = result.flattenedStderr!.split('\n').firstWhere((final String line) {
return line.startsWith('Flutter Engine Version:'); return line.startsWith('Flutter Engine Version:');
}); });
if (!actualVersion.contains(expectedVersion)) { if (!actualVersion.contains(expectedVersion)) {
...@@ -199,7 +198,7 @@ Future<void> _runSmokeTests() async { ...@@ -199,7 +198,7 @@ Future<void> _runSmokeTests() async {
path.join('test_smoke_test', 'pending_timer_fail_test.dart'), path.join('test_smoke_test', 'pending_timer_fail_test.dart'),
expectFailure: true, expectFailure: true,
printOutput: false, outputChecker: (CommandResult result) { printOutput: false, outputChecker: (CommandResult result) {
return result.flattenedStdout.contains('failingPendingTimerTest') return result.flattenedStdout!.contains('failingPendingTimerTest')
? null ? null
: 'Failed to find the stack trace for the pending Timer.'; : 'Failed to find the stack trace for the pending Timer.';
}), }),
...@@ -250,7 +249,7 @@ Future<void> _runSmokeTests() async { ...@@ -250,7 +249,7 @@ Future<void> _runSmokeTests() async {
// Smoke tests are special and run first for all test shards. // Smoke tests are special and run first for all test shards.
// Run all smoke tests for other shards. // Run all smoke tests for other shards.
// Only shard smoke tests when explicitly specified. // Only shard smoke tests when explicitly specified.
final String shardName = Platform.environment[kShardKey]; final String? shardName = Platform.environment[kShardKey];
if (shardName == kSmokeTestShardName) { if (shardName == kSmokeTestShardName) {
testsToRun = _selectIndexOfTotalSubshard<ShardRunner>(tests); testsToRun = _selectIndexOfTotalSubshard<ShardRunner>(tests);
} else { } else {
...@@ -261,7 +260,7 @@ Future<void> _runSmokeTests() async { ...@@ -261,7 +260,7 @@ Future<void> _runSmokeTests() async {
} }
// Verify that we correctly generated the version file. // Verify that we correctly generated the version file.
final String versionError = await verifyVersion(File(path.join(flutterRoot, 'version'))); final String? versionError = await verifyVersion(File(path.join(flutterRoot, 'version')));
if (versionError != null) if (versionError != null)
exitWithError(<String>[versionError]); exitWithError(<String>[versionError]);
} }
...@@ -479,7 +478,7 @@ Future<void> _runExampleProjectBuildTests(FileSystemEntity exampleDirectory) asy ...@@ -479,7 +478,7 @@ Future<void> _runExampleProjectBuildTests(FileSystemEntity exampleDirectory) asy
} }
Future<void> _flutterBuildApk(String relativePathToApplication, { Future<void> _flutterBuildApk(String relativePathToApplication, {
@required bool release, required bool release,
bool verifyCaching = false, bool verifyCaching = false,
List<String> additionalArgs = const <String>[], List<String> additionalArgs = const <String>[],
}) async { }) async {
...@@ -492,7 +491,7 @@ Future<void> _flutterBuildApk(String relativePathToApplication, { ...@@ -492,7 +491,7 @@ Future<void> _flutterBuildApk(String relativePathToApplication, {
} }
Future<void> _flutterBuildIpa(String relativePathToApplication, { Future<void> _flutterBuildIpa(String relativePathToApplication, {
@required bool release, required bool release,
List<String> additionalArgs = const <String>[], List<String> additionalArgs = const <String>[],
bool verifyCaching = false, bool verifyCaching = false,
}) async { }) async {
...@@ -506,7 +505,7 @@ Future<void> _flutterBuildIpa(String relativePathToApplication, { ...@@ -506,7 +505,7 @@ Future<void> _flutterBuildIpa(String relativePathToApplication, {
} }
Future<void> _flutterBuildLinux(String relativePathToApplication, { Future<void> _flutterBuildLinux(String relativePathToApplication, {
@required bool release, required bool release,
bool verifyCaching = false, bool verifyCaching = false,
List<String> additionalArgs = const <String>[], List<String> additionalArgs = const <String>[],
}) async { }) async {
...@@ -521,7 +520,7 @@ Future<void> _flutterBuildLinux(String relativePathToApplication, { ...@@ -521,7 +520,7 @@ Future<void> _flutterBuildLinux(String relativePathToApplication, {
} }
Future<void> _flutterBuildMacOS(String relativePathToApplication, { Future<void> _flutterBuildMacOS(String relativePathToApplication, {
@required bool release, required bool release,
bool verifyCaching = false, bool verifyCaching = false,
List<String> additionalArgs = const <String>[], List<String> additionalArgs = const <String>[],
}) async { }) async {
...@@ -536,7 +535,7 @@ Future<void> _flutterBuildMacOS(String relativePathToApplication, { ...@@ -536,7 +535,7 @@ Future<void> _flutterBuildMacOS(String relativePathToApplication, {
} }
Future<void> _flutterBuildWin32(String relativePathToApplication, { Future<void> _flutterBuildWin32(String relativePathToApplication, {
@required bool release, required bool release,
bool verifyCaching = false, bool verifyCaching = false,
List<String> additionalArgs = const <String>[], List<String> additionalArgs = const <String>[],
}) async { }) async {
...@@ -554,7 +553,7 @@ Future<void> _flutterBuild( ...@@ -554,7 +553,7 @@ Future<void> _flutterBuild(
String relativePathToApplication, String relativePathToApplication,
String platformLabel, String platformLabel,
String platformBuildName, { String platformBuildName, {
@required bool release, required bool release,
bool verifyCaching = false, bool verifyCaching = false,
List<String> additionalArgs = const <String>[], List<String> additionalArgs = const <String>[],
}) async { }) async {
...@@ -598,11 +597,11 @@ Future<void> _flutterBuild( ...@@ -598,11 +597,11 @@ Future<void> _flutterBuild(
} }
bool _allTargetsCached(File performanceFile) { bool _allTargetsCached(File performanceFile) {
final Map<String, Object> data = json.decode(performanceFile.readAsStringSync()) final Map<String, Object?> data = json.decode(performanceFile.readAsStringSync())
as Map<String, Object>; as Map<String, Object?>;
final List<Map<String, Object>> targets = (data['targets'] as List<Object>) final List<Map<String, Object?>> targets = (data['targets']! as List<Object?>)
.cast<Map<String, Object>>(); .cast<Map<String, Object?>>();
return targets.every((Map<String, Object> element) => element['skipped'] == true); return targets.every((Map<String, Object?> element) => element['skipped'] == true);
} }
Future<void> _flutterBuildDart2js(String relativePathToApplication, String target, { bool expectNonZeroExit = false }) async { Future<void> _flutterBuildDart2js(String relativePathToApplication, String target, { bool expectNonZeroExit = false }) async {
...@@ -760,7 +759,7 @@ Future<void> _runFrameworkTests() async { ...@@ -760,7 +759,7 @@ Future<void> _runFrameworkTests() async {
expectFailure: true, expectFailure: true,
printOutput: false, printOutput: false,
outputChecker: (CommandResult result) { outputChecker: (CommandResult result) {
final Iterable<Match> matches = httpClientWarning.allMatches(result.flattenedStdout); final Iterable<Match> matches = httpClientWarning.allMatches(result.flattenedStdout!);
if (matches == null || matches.isEmpty || matches.length > 1) { if (matches == null || matches.isEmpty || matches.length > 1) {
return 'Failed to print warning about HttpClientUsage, or printed it too many times.\n' return 'Failed to print warning about HttpClientUsage, or printed it too many times.\n'
'stdout:\n${result.flattenedStdout}'; 'stdout:\n${result.flattenedStdout}';
...@@ -959,8 +958,8 @@ Future<void> _runWebLongRunningTests() async { ...@@ -959,8 +958,8 @@ Future<void> _runWebLongRunningTests() async {
/// Runs one of the `dev/integration_tests/web_e2e_tests` tests. /// Runs one of the `dev/integration_tests/web_e2e_tests` tests.
Future<void> _runWebE2eTest( Future<void> _runWebE2eTest(
String name, { String name, {
@required String buildMode, required String buildMode,
@required String renderer, required String renderer,
}) async { }) async {
await _runFlutterDriverWebTest( await _runFlutterDriverWebTest(
target: path.join('test_driver', '$name.dart'), target: path.join('test_driver', '$name.dart'),
...@@ -971,10 +970,10 @@ Future<void> _runWebE2eTest( ...@@ -971,10 +970,10 @@ Future<void> _runWebE2eTest(
} }
Future<void> _runFlutterDriverWebTest({ Future<void> _runFlutterDriverWebTest({
@required String target, required String target,
@required String buildMode, required String buildMode,
@required String renderer, required String renderer,
@required String testAppDirectory, required String testAppDirectory,
bool expectFailure = false, bool expectFailure = false,
bool silenceBrowserOutput = false, bool silenceBrowserOutput = false,
}) async { }) async {
...@@ -987,7 +986,7 @@ Future<void> _runFlutterDriverWebTest({ ...@@ -987,7 +986,7 @@ Future<void> _runFlutterDriverWebTest({
await runCommand( await runCommand(
flutter, flutter,
<String>[ <String>[
...?flutterTestArgs, ...flutterTestArgs,
'drive', 'drive',
'--target=$target', '--target=$target',
'--browser-name=chrome', '--browser-name=chrome',
...@@ -1083,7 +1082,7 @@ Future<void> _runWebTreeshakeTest() async { ...@@ -1083,7 +1082,7 @@ Future<void> _runWebTreeshakeTest() async {
/// plugins version file, when null [flutterPluginsVersionFile] is used. /// plugins version file, when null [flutterPluginsVersionFile] is used.
Future<String> getFlutterPluginsVersion({ Future<String> getFlutterPluginsVersion({
fs.FileSystem fileSystem = const LocalFileSystem(), fs.FileSystem fileSystem = const LocalFileSystem(),
String pluginsVersionFile, String? pluginsVersionFile,
}) async { }) async {
final File versionFile = fileSystem.file(pluginsVersionFile ?? flutterPluginsVersionFile); final File versionFile = fileSystem.file(pluginsVersionFile ?? flutterPluginsVersionFile);
final String versionFileContents = await versionFile.readAsString(); final String versionFileContents = await versionFile.readAsString();
...@@ -1163,7 +1162,7 @@ Future<void> _runSkpGeneratorTests() async { ...@@ -1163,7 +1162,7 @@ Future<void> _runSkpGeneratorTests() async {
// //
// If an existing chromedriver is already available on port 4444, the existing // If an existing chromedriver is already available on port 4444, the existing
// process is reused and this variable remains null. // process is reused and this variable remains null.
Command _chromeDriver; Command? _chromeDriver;
Future<bool> _isChromeDriverRunning() async { Future<bool> _isChromeDriverRunning() async {
try { try {
...@@ -1208,7 +1207,7 @@ Future<void> _stopChromeDriver() async { ...@@ -1208,7 +1207,7 @@ Future<void> _stopChromeDriver() async {
return; return;
} }
print('Stopping chromedriver'); print('Stopping chromedriver');
_chromeDriver.process.kill(); _chromeDriver!.process.kill();
} }
/// Exercises the old gallery in a browser for a long period of time, looking /// Exercises the old gallery in a browser for a long period of time, looking
...@@ -1231,7 +1230,7 @@ Future<void> _runGalleryE2eWebTest(String buildMode, { bool canvasKit = false }) ...@@ -1231,7 +1230,7 @@ Future<void> _runGalleryE2eWebTest(String buildMode, { bool canvasKit = false })
await runCommand( await runCommand(
flutter, flutter,
<String>[ <String>[
...?flutterTestArgs, ...flutterTestArgs,
'drive', 'drive',
if (canvasKit) if (canvasKit)
'--dart-define=FLUTTER_WEB_USE_SKIA=true', '--dart-define=FLUTTER_WEB_USE_SKIA=true',
...@@ -1315,7 +1314,7 @@ Future<void> _runWebReleaseTest(String target, { ...@@ -1315,7 +1314,7 @@ Future<void> _runWebReleaseTest(String target, {
await runCommand( await runCommand(
flutter, flutter,
<String>[ <String>[
...?flutterTestArgs, ...flutterTestArgs,
'build', 'build',
'web', 'web',
'--release', '--release',
...@@ -1394,8 +1393,8 @@ Future<void> _runWebDebugTest(String target, { ...@@ -1394,8 +1393,8 @@ Future<void> _runWebDebugTest(String target, {
if (success) { if (success) {
print('${green}Web stack trace integration test passed.$reset'); print('${green}Web stack trace integration test passed.$reset');
} else { } else {
print(result.flattenedStdout); print(result.flattenedStdout!);
print(result.flattenedStderr); print(result.flattenedStderr!);
print('${red}Web stack trace integration test failed.$reset'); print('${red}Web stack trace integration test failed.$reset');
exit(1); exit(1);
} }
...@@ -1413,7 +1412,7 @@ Future<void> _runFlutterWebTest(String workingDirectory, List<String> tests) asy ...@@ -1413,7 +1412,7 @@ Future<void> _runFlutterWebTest(String workingDirectory, List<String> tests) asy
// TODO(ferhatb): Run web tests with both rendering backends. // TODO(ferhatb): Run web tests with both rendering backends.
'--web-renderer=html', // use html backend for web tests. '--web-renderer=html', // use html backend for web tests.
'--sound-null-safety', // web tests do not autodetect yet. '--sound-null-safety', // web tests do not autodetect yet.
...?flutterTestArgs, ...flutterTestArgs,
...tests, ...tests,
], ],
workingDirectory: workingDirectory, workingDirectory: workingDirectory,
...@@ -1429,17 +1428,17 @@ Future<void> _runFlutterWebTest(String workingDirectory, List<String> tests) asy ...@@ -1429,17 +1428,17 @@ Future<void> _runFlutterWebTest(String workingDirectory, List<String> tests) asy
// dependent targets are only built on some engines). // dependent targets are only built on some engines).
// See https://github.com/flutter/flutter/issues/72368 // See https://github.com/flutter/flutter/issues/72368
Future<void> _pubRunTest(String workingDirectory, { Future<void> _pubRunTest(String workingDirectory, {
List<String> testPaths, List<String>? testPaths,
bool enableFlutterToolAsserts = true, bool enableFlutterToolAsserts = true,
bool useBuildRunner = false, bool useBuildRunner = false,
String coverage, String? coverage,
bool forceSingleCore = false, bool forceSingleCore = false,
Duration perTestTimeout, Duration? perTestTimeout,
bool includeLocalEngineEnv = false, bool includeLocalEngineEnv = false,
bool ensurePrecompiledTool = true, bool ensurePrecompiledTool = true,
}) async { }) async {
int cpus; int? cpus;
final String cpuVariable = Platform.environment['CPU']; // CPU is set in cirrus.yml final String? cpuVariable = Platform.environment['CPU']; // CPU is set in cirrus.yml
if (cpuVariable != null) { if (cpuVariable != null) {
cpus = int.tryParse(cpuVariable, radix: 10); cpus = int.tryParse(cpuVariable, radix: 10);
if (cpus == null) { if (cpus == null) {
...@@ -1525,13 +1524,12 @@ Future<void> _pubRunTest(String workingDirectory, { ...@@ -1525,13 +1524,12 @@ Future<void> _pubRunTest(String workingDirectory, {
} }
Future<void> _runFlutterTest(String workingDirectory, { Future<void> _runFlutterTest(String workingDirectory, {
String script, String? script,
bool expectFailure = false, bool expectFailure = false,
bool printOutput = true, bool printOutput = true,
OutputChecker outputChecker, OutputChecker? outputChecker,
List<String> options = const <String>[], List<String> options = const <String>[],
bool skip = false, Map<String, String>? environment,
Map<String, String> environment,
List<String> tests = const <String>[], List<String> tests = const <String>[],
}) async { }) async {
assert(!printOutput || outputChecker == null, 'Output either can be printed or checked but not both'); assert(!printOutput || outputChecker == null, 'Output either can be printed or checked but not both');
...@@ -1539,7 +1537,7 @@ Future<void> _runFlutterTest(String workingDirectory, { ...@@ -1539,7 +1537,7 @@ Future<void> _runFlutterTest(String workingDirectory, {
final List<String> args = <String>[ final List<String> args = <String>[
'test', 'test',
...options, ...options,
...?flutterTestArgs, ...flutterTestArgs,
]; ];
final bool shouldProcessOutput = useFlutterTestFormatter && !expectFailure && !options.contains('--coverage'); final bool shouldProcessOutput = useFlutterTestFormatter && !expectFailure && !options.contains('--coverage');
...@@ -1554,8 +1552,6 @@ Future<void> _runFlutterTest(String workingDirectory, { ...@@ -1554,8 +1552,6 @@ Future<void> _runFlutterTest(String workingDirectory, {
print('Script: $green$script$reset'); print('Script: $green$script$reset');
if (!printOutput) if (!printOutput)
print('This is one of the tests that does not normally print output.'); print('This is one of the tests that does not normally print output.');
if (skip)
print('This is one of the tests that is normally skipped in this configuration.');
exit(1); exit(1);
} }
args.add(script); args.add(script);
...@@ -1574,12 +1570,11 @@ Future<void> _runFlutterTest(String workingDirectory, { ...@@ -1574,12 +1570,11 @@ Future<void> _runFlutterTest(String workingDirectory, {
workingDirectory: workingDirectory, workingDirectory: workingDirectory,
expectNonZeroExit: expectFailure, expectNonZeroExit: expectFailure,
outputMode: outputMode, outputMode: outputMode,
skip: skip,
environment: environment, environment: environment,
); );
if (outputChecker != null) { if (outputChecker != null) {
final String message = outputChecker(result); final String? message = outputChecker(result);
if (message != null) if (message != null)
exitWithError(<String>[message]); exitWithError(<String>[message]);
} }
...@@ -1612,7 +1607,7 @@ Future<void> _runFlutterTest(String workingDirectory, { ...@@ -1612,7 +1607,7 @@ Future<void> _runFlutterTest(String workingDirectory, {
} }
Map<String, String> _initGradleEnvironment() { Map<String, String> _initGradleEnvironment() {
final String androidSdkRoot = (Platform.environment['ANDROID_HOME']?.isEmpty ?? true) final String? androidSdkRoot = (Platform.environment['ANDROID_HOME']?.isEmpty ?? true)
? Platform.environment['ANDROID_SDK_ROOT'] ? Platform.environment['ANDROID_SDK_ROOT']
: Platform.environment['ANDROID_HOME']; : Platform.environment['ANDROID_HOME'];
if (androidSdkRoot == null || androidSdkRoot.isEmpty) { if (androidSdkRoot == null || androidSdkRoot.isEmpty) {
...@@ -1620,7 +1615,7 @@ Map<String, String> _initGradleEnvironment() { ...@@ -1620,7 +1615,7 @@ Map<String, String> _initGradleEnvironment() {
exit(1); exit(1);
} }
return <String, String>{ return <String, String>{
'ANDROID_HOME': androidSdkRoot, 'ANDROID_HOME': androidSdkRoot!,
'ANDROID_SDK_ROOT': androidSdkRoot, 'ANDROID_SDK_ROOT': androidSdkRoot,
}; };
} }
...@@ -1654,7 +1649,7 @@ Future<void> _processTestOutput( ...@@ -1654,7 +1649,7 @@ Future<void> _processTestOutput(
formatter.finish(); formatter.finish();
} }
CiProviders get ciProvider { CiProviders? get ciProvider {
if (Platform.environment['CIRRUS_CI'] == 'true') { if (Platform.environment['CIRRUS_CI'] == 'true') {
return CiProviders.cirrus; return CiProviders.cirrus;
} }
...@@ -1668,11 +1663,12 @@ CiProviders get ciProvider { ...@@ -1668,11 +1663,12 @@ CiProviders get ciProvider {
String get branchName { String get branchName {
switch(ciProvider) { switch(ciProvider) {
case CiProviders.cirrus: case CiProviders.cirrus:
return Platform.environment['CIRRUS_BRANCH']; return Platform.environment['CIRRUS_BRANCH']!;
case CiProviders.luci: case CiProviders.luci:
return Platform.environment['LUCI_BRANCH']; return Platform.environment['LUCI_BRANCH']!;
} case null:
return ''; return '';
}
} }
/// Checks the given file's contents to determine if they match the allowed /// Checks the given file's contents to determine if they match the allowed
...@@ -1680,7 +1676,7 @@ String get branchName { ...@@ -1680,7 +1676,7 @@ String get branchName {
/// ///
/// Returns null if the contents are good. Returns a string if they are bad. /// Returns null if the contents are good. Returns a string if they are bad.
/// The string is an error message. /// The string is an error message.
Future<String> verifyVersion(File file) async { Future<String?> verifyVersion(File file) async {
final RegExp pattern = RegExp( final RegExp pattern = RegExp(
r'^(\d+)\.(\d+)\.(\d+)((-\d+\.\d+)?\.pre(\.\d+)?)?$'); r'^(\d+)\.(\d+)\.(\d+)((-\d+\.\d+)?\.pre(\.\d+)?)?$');
final String version = await file.readAsString(); final String version = await file.readAsString();
...@@ -1705,7 +1701,7 @@ Future<String> verifyVersion(File file) async { ...@@ -1705,7 +1701,7 @@ Future<String> verifyVersion(File file) async {
/// 3_3 /// 3_3
List<T> _selectIndexOfTotalSubshard<T>(List<T> tests, {String subshardKey = kSubshardKey}) { List<T> _selectIndexOfTotalSubshard<T>(List<T> tests, {String subshardKey = kSubshardKey}) {
// Example: "1_3" means the first (one-indexed) shard of three total shards. // Example: "1_3" means the first (one-indexed) shard of three total shards.
final String subshardName = Platform.environment[subshardKey]; final String? subshardName = Platform.environment[subshardKey];
if (subshardName == null) { if (subshardName == null) {
print('$kSubshardKey environment variable is missing, skipping sharding'); print('$kSubshardKey environment variable is missing, skipping sharding');
return tests; return tests;
...@@ -1713,14 +1709,14 @@ List<T> _selectIndexOfTotalSubshard<T>(List<T> tests, {String subshardKey = kSub ...@@ -1713,14 +1709,14 @@ List<T> _selectIndexOfTotalSubshard<T>(List<T> tests, {String subshardKey = kSub
print('$bold$subshardKey=$subshardName$reset'); print('$bold$subshardKey=$subshardName$reset');
final RegExp pattern = RegExp(r'^(\d+)_(\d+)$'); final RegExp pattern = RegExp(r'^(\d+)_(\d+)$');
final Match match = pattern.firstMatch(subshardName); final Match? match = pattern.firstMatch(subshardName);
if (match == null || match.groupCount != 2) { if (match == null || match.groupCount != 2) {
print('${red}Invalid subshard name "$subshardName". Expected format "[int]_[int]" ex. "1_3"'); print('${red}Invalid subshard name "$subshardName". Expected format "[int]_[int]" ex. "1_3"');
exit(1); exit(1);
} }
// One-indexed. // One-indexed.
final int index = int.parse(match.group(1)); final int index = int.parse(match!.group(1)!);
final int total = int.parse(match.group(2)); final int total = int.parse(match.group(2)!);
if (index > total) { if (index > total) {
print('${red}Invalid subshard name "$subshardName". Index number must be greater or equal to total.'); print('${red}Invalid subshard name "$subshardName". Index number must be greater or equal to total.');
exit(1); exit(1);
...@@ -1760,16 +1756,16 @@ Future<void> selectSubshard(Map<String, ShardRunner> subshards) => _runFromList( ...@@ -1760,16 +1756,16 @@ Future<void> selectSubshard(Map<String, ShardRunner> subshards) => _runFromList(
const String CIRRUS_TASK_NAME = 'CIRRUS_TASK_NAME'; const String CIRRUS_TASK_NAME = 'CIRRUS_TASK_NAME';
Future<void> _runFromList(Map<String, ShardRunner> items, String key, String name, int positionInTaskName) async { Future<void> _runFromList(Map<String, ShardRunner> items, String key, String name, int positionInTaskName) async {
String item = Platform.environment[key]; String? item = Platform.environment[key];
if (item == null && Platform.environment.containsKey(CIRRUS_TASK_NAME)) { if (item == null && Platform.environment.containsKey(CIRRUS_TASK_NAME)) {
final List<String> parts = Platform.environment[CIRRUS_TASK_NAME].split('-'); final List<String> parts = Platform.environment[CIRRUS_TASK_NAME]!.split('-');
assert(positionInTaskName < parts.length); assert(positionInTaskName < parts.length);
item = parts[positionInTaskName]; item = parts[positionInTaskName];
} }
if (item == null) { if (item == null) {
for (final String currentItem in items.keys) { for (final String currentItem in items.keys) {
print('$bold$key=$currentItem$reset'); print('$bold$key=$currentItem$reset');
await items[currentItem](); await items[currentItem]!();
print(''); print('');
} }
} else { } else {
...@@ -1779,6 +1775,6 @@ Future<void> _runFromList(Map<String, ShardRunner> items, String key, String nam ...@@ -1779,6 +1775,6 @@ Future<void> _runFromList(Map<String, ShardRunner> items, String key, String nam
exit(1); exit(1);
} }
print('$bold$key=$item$reset'); print('$bold$key=$item$reset');
await items[item](); await items[item]!();
} }
} }
...@@ -74,16 +74,16 @@ void main() { ...@@ -74,16 +74,16 @@ void main() {
}); });
}); });
group('ArchiveCreator for $platformName', () { group('ArchiveCreator for $platformName', () {
ArchiveCreator creator; late ArchiveCreator creator;
Directory tempDir; late Directory tempDir;
Directory flutterDir; Directory flutterDir;
Directory cacheDir; Directory cacheDir;
FakeProcessManager processManager; late FakeProcessManager processManager;
final List<List<String>> args = <List<String>>[]; final List<List<String>> args = <List<String>>[];
final List<Map<Symbol, dynamic>> namedArgs = <Map<Symbol, dynamic>>[]; final List<Map<Symbol, dynamic>> namedArgs = <Map<Symbol, dynamic>>[];
String flutter; late String flutter;
Future<Uint8List> fakeHttpReader(Uri url, {Map<String, String> headers}) { Future<Uint8List> fakeHttpReader(Uri url, {Map<String, String>? headers}) {
return Future<Uint8List>.value(Uint8List(0)); return Future<Uint8List>.value(Uint8List(0));
} }
...@@ -118,7 +118,7 @@ void main() { ...@@ -118,7 +118,7 @@ void main() {
final String archiveName = path.join(tempDir.absolute.path, final String archiveName = path.join(tempDir.absolute.path,
'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}'); 'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}');
processManager.addCommands(convertResults(<String, List<ProcessResult>>{ processManager.addCommands(convertResults(<String, List<ProcessResult>?>{
'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter': null, 'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter': null,
'git reset --hard $testRef': null, 'git reset --hard $testRef': null,
'git remote set-url origin https://github.com/flutter/flutter.git': null, 'git remote set-url origin https://github.com/flutter/flutter.git': null,
...@@ -147,7 +147,7 @@ void main() { ...@@ -147,7 +147,7 @@ void main() {
final String createBase = path.join(tempDir.absolute.path, 'create_'); final String createBase = path.join(tempDir.absolute.path, 'create_');
final String archiveName = path.join(tempDir.absolute.path, final String archiveName = path.join(tempDir.absolute.path,
'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}'); 'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}');
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{ final Map<String, List<ProcessResult>?> calls = <String, List<ProcessResult>?>{
'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter': null, 'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter': null,
'git reset --hard $testRef': null, 'git reset --hard $testRef': null,
'git remote set-url origin https://github.com/flutter/flutter.git': null, 'git remote set-url origin https://github.com/flutter/flutter.git': null,
...@@ -197,7 +197,7 @@ void main() { ...@@ -197,7 +197,7 @@ void main() {
final String createBase = path.join(tempDir.absolute.path, 'create_'); final String createBase = path.join(tempDir.absolute.path, 'create_');
final String archiveName = path.join(tempDir.absolute.path, final String archiveName = path.join(tempDir.absolute.path,
'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}'); 'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}');
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{ final Map<String, List<ProcessResult>?> calls = <String, List<ProcessResult>?>{
'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter': null, 'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter': null,
'git reset --hard $testRef': null, 'git reset --hard $testRef': null,
'git remote set-url origin https://github.com/flutter/flutter.git': null, 'git remote set-url origin https://github.com/flutter/flutter.git': null,
...@@ -239,7 +239,7 @@ void main() { ...@@ -239,7 +239,7 @@ void main() {
'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}'); 'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}');
final ProcessResult codesignFailure = ProcessResult(1, 1, '', 'code object is not signed at all'); final ProcessResult codesignFailure = ProcessResult(1, 1, '', 'code object is not signed at all');
final String binPath = path.join(tempDir.path, 'flutter', 'bin', 'cache', 'dart-sdk', 'bin', 'dart'); final String binPath = path.join(tempDir.path, 'flutter', 'bin', 'cache', 'dart-sdk', 'bin', 'dart');
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{ final Map<String, List<ProcessResult>?> calls = <String, List<ProcessResult>?>{
'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter': null, 'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter': null,
'git reset --hard $testRef': null, 'git reset --hard $testRef': null,
'git remote set-url origin https://github.com/flutter/flutter.git': null, 'git remote set-url origin https://github.com/flutter/flutter.git': null,
...@@ -286,8 +286,8 @@ void main() { ...@@ -286,8 +286,8 @@ void main() {
}); });
group('ArchivePublisher for $platformName', () { group('ArchivePublisher for $platformName', () {
FakeProcessManager processManager; late FakeProcessManager processManager;
Directory tempDir; late Directory tempDir;
final String gsutilCall = platform.isWindows final String gsutilCall = platform.isWindows
? 'python ${path.join("D:", "depot_tools", "gsutil.py")}' ? 'python ${path.join("D:", "depot_tools", "gsutil.py")}'
: 'gsutil.py'; : 'gsutil.py';
...@@ -346,7 +346,7 @@ void main() { ...@@ -346,7 +346,7 @@ void main() {
'''; ''';
File(jsonPath).writeAsStringSync(releasesJson); File(jsonPath).writeAsStringSync(releasesJson);
File(archivePath).writeAsStringSync('archive contents'); File(archivePath).writeAsStringSync('archive contents');
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{ final Map<String, List<ProcessResult>?> calls = <String, List<ProcessResult>?>{
// This process fails because the file does NOT already exist // This process fails because the file does NOT already exist
'$gsutilCall -- stat $gsArchivePath': <ProcessResult>[ProcessResult(0, 1, '', '')], '$gsutilCall -- stat $gsArchivePath': <ProcessResult>[ProcessResult(0, 1, '', '')],
'$gsutilCall -- rm $gsArchivePath': null, '$gsutilCall -- rm $gsArchivePath': null,
...@@ -442,7 +442,7 @@ void main() { ...@@ -442,7 +442,7 @@ void main() {
'''; ''';
File(jsonPath).writeAsStringSync(releasesJson); File(jsonPath).writeAsStringSync(releasesJson);
File(archivePath).writeAsStringSync('archive contents'); File(archivePath).writeAsStringSync('archive contents');
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{ final Map<String, List<ProcessResult>?> calls = <String, List<ProcessResult>?>{
// This process fails because the file does NOT already exist // This process fails because the file does NOT already exist
'$gsutilCall -- stat $gsArchivePath': <ProcessResult>[ProcessResult(0, 1, '', '')], '$gsutilCall -- stat $gsArchivePath': <ProcessResult>[ProcessResult(0, 1, '', '')],
'$gsutilCall -- rm $gsArchivePath': null, '$gsutilCall -- rm $gsArchivePath': null,
...@@ -552,7 +552,7 @@ void main() { ...@@ -552,7 +552,7 @@ void main() {
'''; ''';
File(jsonPath).writeAsStringSync(releasesJson); File(jsonPath).writeAsStringSync(releasesJson);
File(archivePath).writeAsStringSync('archive contents'); File(archivePath).writeAsStringSync('archive contents');
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{ final Map<String, List<ProcessResult>?> calls = <String, List<ProcessResult>?>{
'$gsutilCall -- rm $gsArchivePath': null, '$gsutilCall -- rm $gsArchivePath': null,
'$gsutilCall -- -h Content-Type:$archiveMime cp $archivePath $gsArchivePath': null, '$gsutilCall -- -h Content-Type:$archiveMime cp $archivePath $gsArchivePath': null,
'$gsutilCall -- cp $gsJsonPath $jsonPath': null, '$gsutilCall -- cp $gsJsonPath $jsonPath': null,
...@@ -567,10 +567,10 @@ void main() { ...@@ -567,10 +567,10 @@ void main() {
} }
} }
List<FakeCommand> convertResults(Map<String, List<ProcessResult>> results) { List<FakeCommand> convertResults(Map<String, List<ProcessResult>?> results) {
final List<FakeCommand> commands = <FakeCommand>[]; final List<FakeCommand> commands = <FakeCommand>[];
for (final String key in results.keys) { for (final String key in results.keys) {
final List<ProcessResult> candidates = results[key]; final List<ProcessResult>? candidates = results[key];
final List<String> args = key.split(' '); final List<String> args = key.split(' ');
if (candidates == null) { if (candidates == null) {
commands.add(FakeCommand( commands.add(FakeCommand(
...@@ -581,8 +581,8 @@ List<FakeCommand> convertResults(Map<String, List<ProcessResult>> results) { ...@@ -581,8 +581,8 @@ List<FakeCommand> convertResults(Map<String, List<ProcessResult>> results) {
commands.add(FakeCommand( commands.add(FakeCommand(
command: args, command: args,
exitCode: result.exitCode, exitCode: result.exitCode,
stderr: result.stderr?.toString(), stderr: result.stderr.toString(),
stdout: result.stdout?.toString(), stdout: result.stdout.toString(),
)); ));
} }
} }
......
...@@ -12,10 +12,10 @@ void main() { ...@@ -12,10 +12,10 @@ void main() {
test('We are in a directory with a space in it', () async { test('We are in a directory with a space in it', () async {
// The Flutter SDK should be in a directory with a space in it, to make sure // The Flutter SDK should be in a directory with a space in it, to make sure
// our tools support that. // our tools support that.
final String expectedName = Platform.environment['FLUTTER_SDK_PATH_WITH_SPACE']; final String? expectedName = Platform.environment['FLUTTER_SDK_PATH_WITH_SPACE'];
expect(expectedName, 'flutter sdk'); expect(expectedName, 'flutter sdk');
expect(expectedName, contains(' ')); expect(expectedName, contains(' '));
final List<String> parts = path.split(Directory.current.absolute.path); final List<String> parts = path.split(Directory.current.absolute.path);
expect(parts.reversed.take(3), <String>['bots', 'dev', expectedName]); expect(parts.reversed.take(3), <String?>['bots', 'dev', expectedName]);
}, skip: true); // https://github.com/flutter/flutter/issues/62919 }, skip: true); // https://github.com/flutter/flutter/issues/62919
} }
...@@ -23,7 +23,7 @@ void expectExitCode(ProcessResult result, int expectedExitCode) { ...@@ -23,7 +23,7 @@ void expectExitCode(ProcessResult result, int expectedExitCode) {
void main() { void main() {
group('verifyVersion()', () { group('verifyVersion()', () {
MemoryFileSystem fileSystem; late MemoryFileSystem fileSystem;
setUp(() { setUp(() {
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
...@@ -97,7 +97,7 @@ void main() { ...@@ -97,7 +97,7 @@ void main() {
const ProcessManager processManager = LocalProcessManager(); const ProcessManager processManager = LocalProcessManager();
Future<ProcessResult> runScript( Future<ProcessResult> runScript(
[Map<String, String> environment, List<String> otherArgs = const <String>[]]) async { [Map<String, String>? environment, List<String> otherArgs = const <String>[]]) async {
final String dart = path.absolute( final String dart = path.absolute(
path.join('..', '..', 'bin', 'cache', 'dart-sdk', 'bin', 'dart')); path.join('..', '..', 'bin', 'cache', 'dart-sdk', 'bin', 'dart'));
final ProcessResult scriptProcess = processManager.runSync(<String>[ final ProcessResult scriptProcess = processManager.runSync(<String>[
......
...@@ -32,7 +32,7 @@ class UnpublishException implements Exception { ...@@ -32,7 +32,7 @@ class UnpublishException implements Exception {
UnpublishException(this.message, [this.result]); UnpublishException(this.message, [this.result]);
final String message; final String message;
final ProcessResult result; final ProcessResult? result;
int get exitCode => result?.exitCode ?? -1; int get exitCode => result?.exitCode ?? -1;
@override @override
...@@ -41,7 +41,7 @@ class UnpublishException implements Exception { ...@@ -41,7 +41,7 @@ class UnpublishException implements Exception {
if (message != null) { if (message != null) {
output += ': $message'; output += ': $message';
} }
final String stderr = result?.stderr as String ?? ''; final String stderr = result?.stderr as String? ?? '';
if (stderr.isNotEmpty) { if (stderr.isNotEmpty) {
output += ':\n$stderr'; output += ':\n$stderr';
} }
...@@ -60,10 +60,9 @@ String getChannelName(Channel channel) { ...@@ -60,10 +60,9 @@ String getChannelName(Channel channel) {
case Channel.stable: case Channel.stable:
return 'stable'; return 'stable';
} }
return null;
} }
Channel fromChannelName(String name) { Channel fromChannelName(String? name) {
switch (name) { switch (name) {
case 'beta': case 'beta':
return Channel.beta; return Channel.beta;
...@@ -87,7 +86,6 @@ String getPublishedPlatform(PublishedPlatform platform) { ...@@ -87,7 +86,6 @@ String getPublishedPlatform(PublishedPlatform platform) {
case PublishedPlatform.windows: case PublishedPlatform.windows:
return 'windows'; return 'windows';
} }
return null;
} }
PublishedPlatform fromPublishedPlatform(String name) { PublishedPlatform fromPublishedPlatform(String name) {
...@@ -135,10 +133,10 @@ class ProcessRunner { ...@@ -135,10 +133,10 @@ class ProcessRunner {
/// Sets the default directory used when `workingDirectory` is not specified /// Sets the default directory used when `workingDirectory` is not specified
/// to [runProcess]. /// to [runProcess].
final Directory defaultWorkingDirectory; final Directory? defaultWorkingDirectory;
/// The environment to run processes with. /// The environment to run processes with.
Map<String, String> environment; late Map<String, String> environment;
/// Run the command and arguments in `commandLine` as a sub-process from /// Run the command and arguments in `commandLine` as a sub-process from
/// `workingDirectory` if set, or the [defaultWorkingDirectory] if not. Uses /// `workingDirectory` if set, or the [defaultWorkingDirectory] if not. Uses
...@@ -148,7 +146,7 @@ class ProcessRunner { ...@@ -148,7 +146,7 @@ class ProcessRunner {
/// command completes with a non-zero exit code. /// command completes with a non-zero exit code.
Future<String> runProcess( Future<String> runProcess(
List<String> commandLine, { List<String> commandLine, {
Directory workingDirectory, Directory? workingDirectory,
bool failOk = false, bool failOk = false,
}) async { }) async {
workingDirectory ??= defaultWorkingDirectory ?? Directory.current; workingDirectory ??= defaultWorkingDirectory ?? Directory.current;
...@@ -158,7 +156,7 @@ class ProcessRunner { ...@@ -158,7 +156,7 @@ class ProcessRunner {
final List<int> output = <int>[]; final List<int> output = <int>[];
final Completer<void> stdoutComplete = Completer<void>(); final Completer<void> stdoutComplete = Completer<void>();
final Completer<void> stderrComplete = Completer<void>(); final Completer<void> stderrComplete = Completer<void>();
Process process; late Process process;
Future<int> allComplete() async { Future<int> allComplete() async {
await stderrComplete.future; await stderrComplete.future;
await stdoutComplete.future; await stdoutComplete.future;
...@@ -221,12 +219,12 @@ class ArchiveUnpublisher { ...@@ -221,12 +219,12 @@ class ArchiveUnpublisher {
this.channels, this.channels,
this.platform, { this.platform, {
this.confirmed = false, this.confirmed = false,
ProcessManager processManager, ProcessManager? processManager,
bool subprocessOutput = true, bool subprocessOutput = true,
}) : assert(revisionsBeingRemoved.length == 40), }) : assert(revisionsBeingRemoved.length == 40),
metadataGsPath = '$gsReleaseFolder/${getMetadataFilename(platform)}', metadataGsPath = '$gsReleaseFolder/${getMetadataFilename(platform)}',
_processRunner = ProcessRunner( _processRunner = ProcessRunner(
processManager: processManager, processManager: processManager ?? const LocalProcessManager(),
subprocessOutput: subprocessOutput, subprocessOutput: subprocessOutput,
); );
...@@ -249,8 +247,8 @@ class ArchiveUnpublisher { ...@@ -249,8 +247,8 @@ class ArchiveUnpublisher {
final Map<Channel, Map<String, String>> paths = await _getArchivePaths(releases); final Map<Channel, Map<String, String>> paths = await _getArchivePaths(releases);
releases.removeWhere((Map<String, String> value) => revisionsBeingRemoved.contains(value['hash']) && channels.contains(fromChannelName(value['channel']))); releases.removeWhere((Map<String, String> value) => revisionsBeingRemoved.contains(value['hash']) && channels.contains(fromChannelName(value['channel'])));
releases.sort((Map<String, String> a, Map<String, String> b) { releases.sort((Map<String, String> a, Map<String, String> b) {
final DateTime aDate = DateTime.parse(a['release_date']); final DateTime aDate = DateTime.parse(a['release_date']!);
final DateTime bDate = DateTime.parse(b['release_date']); final DateTime bDate = DateTime.parse(b['release_date']!);
return bDate.compareTo(aDate); return bDate.compareTo(aDate);
}); });
jsonData['releases'] = releases; jsonData['releases'] = releases;
...@@ -277,12 +275,12 @@ class ArchiveUnpublisher { ...@@ -277,12 +275,12 @@ class ArchiveUnpublisher {
final Set<String> hashes = <String>{}; final Set<String> hashes = <String>{};
final Map<Channel, Map<String, String>> paths = <Channel, Map<String, String>>{}; final Map<Channel, Map<String, String>> paths = <Channel, Map<String, String>>{};
for (final Map<String, String> revision in releases) { for (final Map<String, String> revision in releases) {
final String hash = revision['hash']; final String hash = revision['hash']!;
final Channel channel = fromChannelName(revision['channel']); final Channel channel = fromChannelName(revision['channel']);
hashes.add(hash); hashes.add(hash);
if (revisionsBeingRemoved.contains(hash) && channels.contains(channel)) { if (revisionsBeingRemoved.contains(hash) && channels.contains(channel)) {
paths[channel] ??= <String, String>{}; paths[channel] ??= <String, String>{};
paths[channel][hash] = revision['archive']; paths[channel]![hash] = revision['archive']!;
} }
} }
final Set<String> missingRevisions = revisionsBeingRemoved.difference(hashes.intersection(revisionsBeingRemoved)); final Set<String> missingRevisions = revisionsBeingRemoved.difference(hashes.intersection(revisionsBeingRemoved));
...@@ -330,7 +328,7 @@ class ArchiveUnpublisher { ...@@ -330,7 +328,7 @@ class ArchiveUnpublisher {
Future<String> _runGsUtil( Future<String> _runGsUtil(
List<String> args, { List<String> args, {
Directory workingDirectory, Directory? workingDirectory,
bool failOk = false, bool failOk = false,
bool confirm = false, bool confirm = false,
}) async { }) async {
...@@ -351,7 +349,7 @@ class ArchiveUnpublisher { ...@@ -351,7 +349,7 @@ class ArchiveUnpublisher {
final List<String> files = <String>[]; final List<String> files = <String>[];
print('${confirmed ? 'Removing' : 'Would remove'} the following release archives:'); print('${confirmed ? 'Removing' : 'Would remove'} the following release archives:');
for (final Channel channel in paths.keys) { for (final Channel channel in paths.keys) {
final Map<String, String> hashes = paths[channel]; final Map<String, String> hashes = paths[channel]!;
for (final String hash in hashes.keys) { for (final String hash in hashes.keys) {
final String file = '$gsReleaseFolder/${hashes[hash]}'; final String file = '$gsReleaseFolder/${hashes[hash]}';
files.add(file); files.add(file);
...@@ -367,7 +365,7 @@ class ArchiveUnpublisher { ...@@ -367,7 +365,7 @@ class ArchiveUnpublisher {
// We often don't have permission to overwrite, but // We often don't have permission to overwrite, but
// we have permission to remove, so that's what we do first. // we have permission to remove, so that's what we do first.
await _runGsUtil(<String>['rm', dest], failOk: true, confirm: confirmed); await _runGsUtil(<String>['rm', dest], failOk: true, confirm: confirmed);
String mimeType; String? mimeType;
if (dest.endsWith('.tar.xz')) { if (dest.endsWith('.tar.xz')) {
mimeType = 'application/x-gtar'; mimeType = 'application/x-gtar';
} }
...@@ -497,8 +495,8 @@ Future<void> main(List<String> rawArguments) async { ...@@ -497,8 +495,8 @@ Future<void> main(List<String> rawArguments) async {
final List<String> platformOptions = platformArg.isNotEmpty ? platformArg : allowedPlatformNames; final List<String> platformOptions = platformArg.isNotEmpty ? platformArg : allowedPlatformNames;
final List<PublishedPlatform> platforms = platformOptions.map<PublishedPlatform>((String value) => fromPublishedPlatform(value)).toList(); final List<PublishedPlatform> platforms = platformOptions.map<PublishedPlatform>((String value) => fromPublishedPlatform(value)).toList();
int exitCode = 0; int exitCode = 0;
String message; late String message;
String stack; late String stack;
try { try {
for (final PublishedPlatform platform in platforms) { for (final PublishedPlatform platform in platforms) {
final ArchiveUnpublisher publisher = ArchiveUnpublisher( final ArchiveUnpublisher publisher = ArchiveUnpublisher(
......
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