Add the platform to test names in the github reporter when applicable (#1715)

Fixes https://github.com/dart-lang/test/issues/1714

Uses the same logic as the expanded reporter, outputting names when more than one platform is being ran.
diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md
index b3e606d..b409dc0 100644
--- a/pkgs/test/CHANGELOG.md
+++ b/pkgs/test/CHANGELOG.md
@@ -1,6 +1,8 @@
 ## 1.21.2-dev
 
 * Add `Target` to restrict `TestOn` annotation to library level.
+* Update the github reporter to output the platform in the test names when
+  multiple platforms are used.
 * Fix `spawnHybridUri` support for `package:` uris.
 
 ## 1.21.1
diff --git a/pkgs/test/test/runner/github_reporter_test.dart b/pkgs/test/test/runner/github_reporter_test.dart
index 4943dab..28bacaf 100644
--- a/pkgs/test/test/runner/github_reporter_test.dart
+++ b/pkgs/test/test/runner/github_reporter_test.dart
@@ -36,6 +36,20 @@
         🎉 3 tests passed.''');
   });
 
+  test('includes the platform name when multiple platforms are ran', () {
+    return _expectReportLines('''
+        test('success 1', () {});''', [
+      '::group::✅ [VM] success 1',
+      '::endgroup::',
+      '::group::✅ [Chrome] success 1',
+      '::endgroup::',
+      '🎉 2 tests passed.',
+    ], args: [
+      '-p',
+      'vm,chrome'
+    ]);
+  });
+
   test('runs several failing tests and reports when each fails', () {
     return _expectReport('''
         test('failure 1', () => throw TestFailure('oh no'));
@@ -306,12 +320,36 @@
   });
 }
 
+/// Expects exactly [expected] to appear in the test output.
+///
+/// If [useContains] is passed, then the output only must contain [expected].
 Future<void> _expectReport(
   String tests,
   String expected, {
   List<String> args = const [],
   bool useContains = false,
 }) async {
+  expected = expected.split('\n').map(_unindent).join('\n');
+
+  var actual = (await _reportLines(tests, args)).join('\n');
+
+  expect(actual, useContains ? contains(expected) : equals(expected));
+}
+
+/// Expects all of [expected] lines to appear in the test output, but additional
+/// output is allowed.
+Future<void> _expectReportLines(
+  String tests,
+  List<String> expected, {
+  List<String> args = const [],
+}) async {
+  expected = [for (var line in expected) _unindent(line)];
+  var actual = await _reportLines(tests, args);
+  expect(actual, containsAllInOrder(expected));
+}
+
+/// All the output lines from running [tests].
+Future<List<String>> _reportLines(String tests, List<String> args) async {
   await d.file('test.dart', '''
     import 'dart:async';
 
@@ -329,17 +367,11 @@
   await test.shouldExit();
 
   var stdoutLines = await test.stdoutStream().toList();
-  var actual = stdoutLines
+  return stdoutLines
       .map((line) => line.trim())
       .where((line) => line.isNotEmpty)
-      .join('\n');
-
-  // Un-indent the expected string.
-  var indentation = expected.indexOf(RegExp('[^ ]'));
-  expected = expected.split('\n').map((line) {
-    if (line.isEmpty) return line;
-    return line.substring(indentation);
-  }).join('\n');
-
-  expect(actual, useContains ? contains(expected) : equals(expected));
+      .toList();
 }
+
+/// Removes all leading space from [line].
+String _unindent(String line) => line.trimLeft();
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index af3b759..31c5b98 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -1,5 +1,7 @@
 ## 0.4.14-dev
 
+* Update the github reporter to output the platform in the test names when
+  multiple platforms are used.
 * Fix `spawnHybridUri` support for `package:` uris.
 
 ## 0.4.13
diff --git a/pkgs/test_core/lib/src/runner/configuration/reporters.dart b/pkgs/test_core/lib/src/runner/configuration/reporters.dart
index 7b9cad1..7c9cd67 100644
--- a/pkgs/test_core/lib/src/runner/configuration/reporters.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/reporters.dart
@@ -48,7 +48,8 @@
       'A custom reporter for GitHub Actions (the default reporter when running on GitHub Actions).',
       (config, engine, sink) => GithubReporter.watch(engine, sink,
           printPath: config.paths.length > 1 ||
-              Directory(config.paths.single.testPath).existsSync())),
+              Directory(config.paths.single.testPath).existsSync(),
+          printPlatform: config.suiteDefaults.runtimes.length > 1)),
   'json': ReporterDetails(
       'A machine-readable format (see '
       'https://dart.dev/go/test-docs/json_reporter.md).',
diff --git a/pkgs/test_core/lib/src/runner/reporter/github.dart b/pkgs/test_core/lib/src/runner/reporter/github.dart
index a5850a3..e9d2f8b 100644
--- a/pkgs/test_core/lib/src/runner/reporter/github.dart
+++ b/pkgs/test_core/lib/src/runner/reporter/github.dart
@@ -29,6 +29,9 @@
   /// Whether the path to each test's suite should be printed.
   final bool _printPath;
 
+  /// Whether the platform each test is running on should be printed.
+  final bool _printPlatform;
+
   /// Whether the reporter is paused.
   var _paused = false;
 
@@ -46,10 +49,12 @@
     Engine engine,
     StringSink sink, {
     required bool printPath,
+    required bool printPlatform,
   }) =>
-      GithubReporter._(engine, sink, printPath);
+      GithubReporter._(engine, sink, printPath, printPlatform);
 
-  GithubReporter._(this._engine, this._sink, this._printPath) {
+  GithubReporter._(
+      this._engine, this._sink, this._printPath, this._printPlatform) {
     _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted));
     _subscriptions.add(_engine.success.asStream().listen(_onDone));
 
@@ -143,6 +148,9 @@
         name = '${test.suite.path}: $name';
       }
     }
+    if (_printPlatform) {
+      name = '[${test.suite.platform.runtime.name}] $name';
+    }
     _sink.writeln(_GithubMarkup.startGroup('$prefix $name$statusSuffix'));
     for (var message in messages) {
       _sink.writeln(message.text);