Add tag support for executing reduced test sets (#86821)
diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart
index 2876b8c..8cfaeec 100644
--- a/dev/bots/analyze.dart
+++ b/dev/bots/analyze.dart
@@ -23,6 +23,7 @@
final String flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script))));
final String flutter = path.join(flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter');
+final String flutterPackages = path.join(flutterRoot, 'packages');
final String dart = path.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', Platform.isWindows ? 'dart.exe' : 'dart');
final String pub = path.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', Platform.isWindows ? 'pub.bat' : 'pub');
final String pubCache = path.join(flutterRoot, '.pub-cache');
@@ -65,6 +66,9 @@
print('$clock Deprecations...');
await verifyDeprecations(flutterRoot);
+ print('$clock Goldens...');
+ await verifyGoldenTags(flutterPackages);
+
print('$clock Skip test comments...');
await verifySkipTestComments(flutterRoot);
@@ -146,6 +150,72 @@
// TESTS
+final RegExp _findGoldenTestPattern = RegExp(r'matchesGoldenFile\(');
+final RegExp _findGoldenDefinitionPattern = RegExp(r'matchesGoldenFile\(Object');
+final RegExp _leadingComment = RegExp(r'\/\/');
+final RegExp _goldenTagPattern1 = RegExp(r'@Tags\(');
+final RegExp _goldenTagPattern2 = RegExp(r"'reduced-test-set'");
+
+/// Only golden file tests in the flutter package are subject to reduced testing,
+/// for example, invocations in flutter_test to validate comparator
+/// functionality do not require tagging.
+const String _ignoreGoldenTag = '// flutter_ignore: golden_tag (see analyze.dart)';
+const String _ignoreGoldenTagForFile = '// flutter_ignore_for_file: golden_tag (see analyze.dart)';
+
+Future<void> verifyGoldenTags(String workingDirectory, { int minimumMatches = 2000 }) async {
+ final List<String> errors = <String>[];
+ await for (final File file in _allFiles(workingDirectory, 'dart', minimumMatches: minimumMatches)) {
+ bool needsTag = false;
+ bool hasTagNotation = false;
+ bool hasReducedTag = false;
+ bool ignoreForFile = false;
+ final List<String> lines = file.readAsLinesSync();
+ for (final String line in lines) {
+ if (line.contains(_goldenTagPattern1)) {
+ hasTagNotation = true;
+ }
+ if (line.contains(_goldenTagPattern2)) {
+ hasReducedTag = true;
+ }
+ if (line.contains(_findGoldenTestPattern)
+ && !line.contains(_findGoldenDefinitionPattern)
+ && !line.contains(_leadingComment)
+ && !line.contains(_ignoreGoldenTag)) {
+ needsTag = true;
+ }
+ if (line.contains(_ignoreGoldenTagForFile)) {
+ ignoreForFile = true;
+ }
+ // If the file is being ignored or a reduced test tag is already accounted
+ // for, skip parsing the rest of the lines for golden file tests.
+ if (ignoreForFile || (hasTagNotation && hasReducedTag)) {
+ break;
+ }
+ }
+ // If a reduced test tag is already accounted for, move on to the next file.
+ if (ignoreForFile || (hasTagNotation && hasReducedTag)) {
+ continue;
+ }
+ // If there are golden file tests, ensure they are tagged for all reduced
+ // test environments.
+ if (needsTag) {
+ if (!hasTagNotation) {
+ errors.add('${file.path}: Files containing golden tests must be tagged using '
+ '`@Tags(...)` at the top of the file before import statements.');
+ } else if (!hasReducedTag) {
+ errors.add('${file.path}: Files containing golden tests must be tagged with '
+ "'reduced-test-set'.");
+ }
+ }
+ }
+ if (errors.isNotEmpty) {
+ exitWithError(<String>[
+ ...errors,
+ '${bold}See: https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter$reset',
+ ]);
+ }
+}
+
final RegExp _findDeprecationPattern = RegExp(r'@[Dd]eprecated');
final RegExp _deprecationPattern1 = RegExp(r'^( *)@Deprecated\($'); // flutter_ignore: deprecation_syntax (see analyze.dart)
final RegExp _deprecationPattern2 = RegExp(r"^ *'(.+) '$");