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"^ *'(.+) '$");