Migrate dev/bots to null safety (#86522)
This commit is contained in:
parent
2f3bf078c5
commit
045ba2b661
@ -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 =
|
|||||||
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 =
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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>{
|
|||||||
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})
|
|||||||
.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
|
|||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
// 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 {
|
|||||||
'--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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
.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
|
|||||||
}
|
}
|
||||||
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';
|
|||||||
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';
|
|||||||
/// 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 {
|
|||||||
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 {
|
|||||||
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 @@
|
|||||||
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 {
|
|||||||
///
|
///
|
||||||
/// 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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
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 {
|
|||||||
/// 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 {
|
|||||||
|
|
||||||
/// 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';
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
/// 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 {
|
|||||||
|
|
||||||
/// 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 {
|
|||||||
/// 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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// [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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
/// 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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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
|
|||||||
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';
|
|||||||
/// 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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
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 {
|
|||||||
/// `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, {
|
|||||||
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, {
|
|||||||
/// 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 @@
|
|||||||
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 {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
/// 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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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({
|
|||||||
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({
|
|||||||
(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({
|
|||||||
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({
|
|||||||
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({
|
|||||||
|
|
||||||
expect(reportedVersion, '2');
|
expect(reportedVersion, '2');
|
||||||
reportedVersion = null;
|
reportedVersion = null;
|
||||||
await server.stop();
|
await server!.stop();
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
@ -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({
|
|||||||
// 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;
|
|||||||
|
|
||||||
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();
|
|||||||
///
|
///
|
||||||
/// 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';
|
|||||||
///
|
///
|
||||||
/// 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 {
|
|||||||
}
|
}
|
||||||
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 {
|
|||||||
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 {
|
|||||||
// 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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|||||||
}
|
}
|
||||||
|
|
||||||
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, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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(
|
|||||||
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(
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
/// 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(
|
|||||||
}
|
}
|
||||||
|
|
||||||
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({
|
|||||||
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 {
|
|||||||
/// 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 {
|
|||||||
//
|
//
|
||||||
// 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 {
|
|||||||
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 })
|
|||||||
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, {
|
|||||||
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, {
|
|||||||
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
|
|||||||
// 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
|
|||||||
// 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, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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, {
|
|||||||
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, {
|
|||||||
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, {
|
|||||||
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, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
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(
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
///
|
///
|
||||||
/// 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 {
|
|||||||
/// 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
|
|||||||
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(
|
|||||||
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
|
|||||||
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() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
'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() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
''';
|
''';
|
||||||
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() {
|
|||||||
''';
|
''';
|
||||||
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() {
|
|||||||
''';
|
''';
|
||||||
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() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
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() {
|
|||||||
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) {
|
|||||||
|
|
||||||
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() {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
|
|
||||||
/// 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 {
|
|||||||
/// 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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
// 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 {
|
|||||||
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(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user