De-async health checks (#208)

* De-async health checks

* add debug

* Delay client

* Use non-delayed client

* Shorter duration

* Make client private

* Add changelog
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..b76d2fd
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,24 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "health",
+            "program": "pkgs/firehose/bin/health.dart",
+            "request": "launch",
+            "type": "dart",
+            "env": {
+                "GITHUB_REPOSITORY": "dart-lang/ecosystem",
+                "ISSUE_NUMBER": "173",
+                "GITHUB_SHA": "null",
+                "GITHUB_STEP_SUMMARY": "/tmp/github_step_summary_mock.md",
+            },
+            "args": [
+                "--checks",
+                "version,changelog,license,coverage,do-not-submit"
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/pkgs/firehose/CHANGELOG.md b/pkgs/firehose/CHANGELOG.md
index 147c4e4..cac9a63 100644
--- a/pkgs/firehose/CHANGELOG.md
+++ b/pkgs/firehose/CHANGELOG.md
@@ -1,7 +1,8 @@
-## 0.4.1-wip
+## 0.4.1
 
 - Ensure that packages are listed in lexical order.
 - Require the latest `package:http`.
+- Delay Github requests by a small delay to avoid http errors.
 
 ## 0.4.0
 
diff --git a/pkgs/firehose/lib/src/delayed_client.dart b/pkgs/firehose/lib/src/delayed_client.dart
new file mode 100644
index 0000000..93cb251
--- /dev/null
+++ b/pkgs/firehose/lib/src/delayed_client.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'dart:typed_data';
+
+import 'package:http/http.dart' as http;
+
+class DelayedClient implements http.Client {
+  final http.Client _client;
+  final Duration duration;
+
+  factory DelayedClient(Duration duration) => DelayedClient._(
+        client: http.Client(),
+        duration: duration,
+      );
+
+  DelayedClient._({required this.duration, required http.Client client})
+      : _client = client;
+
+  @override
+  void close() => _client.close();
+
+  @override
+  Future<http.Response> delete(Uri url,
+          {Map<String, String>? headers, Object? body, Encoding? encoding}) =>
+      Future.delayed(
+          duration,
+          () => _client.delete(url,
+              body: body, encoding: encoding, headers: headers));
+
+  @override
+  Future<http.Response> get(Uri url, {Map<String, String>? headers}) =>
+      Future.delayed(duration, () => _client.get(url, headers: headers));
+
+  @override
+  Future<http.Response> head(Uri url, {Map<String, String>? headers}) =>
+      Future.delayed(duration, () => _client.head(url, headers: headers));
+
+  @override
+  Future<http.Response> patch(Uri url,
+          {Map<String, String>? headers, Object? body, Encoding? encoding}) =>
+      Future.delayed(
+          duration,
+          () => _client.patch(url,
+              headers: headers, body: body, encoding: encoding));
+
+  @override
+  Future<http.Response> post(Uri url,
+          {Map<String, String>? headers, Object? body, Encoding? encoding}) =>
+      Future.delayed(
+          duration,
+          () => _client.post(url,
+              headers: headers, body: body, encoding: encoding));
+  @override
+  Future<http.Response> put(Uri url,
+          {Map<String, String>? headers, Object? body, Encoding? encoding}) =>
+      Future.delayed(
+          duration,
+          () => _client.put(url,
+              headers: headers, body: body, encoding: encoding));
+  @override
+  Future<String> read(Uri url, {Map<String, String>? headers}) =>
+      Future.delayed(duration, () => _client.read(url, headers: headers));
+
+  @override
+  Future<Uint8List> readBytes(Uri url, {Map<String, String>? headers}) =>
+      Future.delayed(duration, () => _client.readBytes(url, headers: headers));
+
+  @override
+  Future<http.StreamedResponse> send(http.BaseRequest request) =>
+      Future.delayed(duration, () => _client.send(request));
+}
diff --git a/pkgs/firehose/lib/src/github.dart b/pkgs/firehose/lib/src/github.dart
index cf1b31a..f2d763b 100644
--- a/pkgs/firehose/lib/src/github.dart
+++ b/pkgs/firehose/lib/src/github.dart
@@ -6,8 +6,10 @@
 import 'dart:io';
 
 import 'package:github/github.dart';
+import 'package:http/http.dart' as http;
 import 'package:path/path.dart' as path;
 
+import 'delayed_client.dart';
 import 'repo.dart';
 
 class GithubApi {
@@ -24,9 +26,14 @@
       : _repoSlug = repoSlug,
         _issueNumber = issueNumber;
 
+  final http.Client _client = DelayedClient(const Duration(milliseconds: 50));
+
   late GitHub github = githubAuthToken != null
-      ? GitHub(auth: Authentication.withToken(githubAuthToken))
-      : GitHub();
+      ? GitHub(
+          auth: Authentication.withToken(githubAuthToken),
+          client: _client,
+        )
+      : GitHub(client: _client);
 
   String? get githubAuthToken => _env['GITHUB_TOKEN'];
 
diff --git a/pkgs/firehose/lib/src/health/health.dart b/pkgs/firehose/lib/src/health/health.dart
index 774c4df..9e4831b 100644
--- a/pkgs/firehose/lib/src/health/health.dart
+++ b/pkgs/firehose/lib/src/health/health.dart
@@ -47,7 +47,6 @@
     var github = GithubApi();
 
     // Do basic validation of our expected env var.
-    if (!expectEnv(github.githubAuthToken, 'GITHUB_TOKEN')) return;
     if (!expectEnv(github.repoSlug?.fullName, 'GITHUB_REPOSITORY')) return;
     if (!expectEnv(github.issueNumber?.toString(), 'ISSUE_NUMBER')) return;
     if (!expectEnv(github.sha, 'GITHUB_SHA')) return;
@@ -78,10 +77,11 @@
           !github.prLabels.contains('skip-do-not-submit-check'))
         doNotSubmitCheck,
     ];
-
-    var checked =
-        await Future.wait(checks.map((check) => check(github)).toList());
-    await writeInComment(github, checked);
+    final results = <HealthCheckResult>[];
+    for (var check in checks) {
+      results.add(await check(github));
+    }
+    await writeInComment(github, results);
   }
 
   Future<HealthCheckResult> validateCheck(GithubApi github) async {
diff --git a/pkgs/firehose/pubspec.yaml b/pkgs/firehose/pubspec.yaml
index 0479b3b..4f26573 100644
--- a/pkgs/firehose/pubspec.yaml
+++ b/pkgs/firehose/pubspec.yaml
@@ -1,6 +1,6 @@
 name: firehose
 description: A tool to automate publishing of Pub packages from GitHub actions.
-version: 0.4.1-wip
+version: 0.4.1
 repository: https://github.com/dart-lang/ecosystem/tree/main/pkgs/firehose
 
 environment: