Introduce a health checking workflow (#115)

* add health workflow

* add health check

* Add license check

* Add unified comment

* Add health check

* dart pub global run mono_repo generate

* Add internal on

* Add firehose version

* Add health tag

* switch to branch name

* Switch to different tag to not delete comment

* Fix formatting

* Switch to different tag

* Remove "great..."  message

* Details on error

* fix formatting in details

* fix formatting in details 2

* Add changelog check

* add line breaks to paths in changelog

* add line breaks to paths in changelog 2

* Add changelog entry

* Add debug info

* add debug msg

* Remove debug messages

* Remove debug messages 2

* Remove changelog entry

* Add new file

* Add file_licenser to health check

* Remove license from test file again

* Remove unnecessary stuff from workflow

* Add messages for stdout

* Switch internal to ref

* use local

* add branch

* Rename workflow

* Fix typo...

* Make configurable

* Add stdout

* Remove spaces

* Add arg

* Tweak docs

* Fix copy-paste typo

* Switch `open` to details

* dart pub global run mono_repo generate (#116)

* Changes as per review

* Add description in readme

* add main to fake test

* Add changelog entry + version rev

* Remove empty test

---------

Co-authored-by: Devon Carew <devoncarew@google.com>
diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml
index 7ad3370..aaf0d46 100644
--- a/.github/workflows/dart.yml
+++ b/.github/workflows/dart.yml
@@ -20,7 +20,7 @@
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable"
@@ -28,37 +28,37 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: stable
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - name: mono_repo self validate
         run: dart pub global activate mono_repo 6.5.7
       - name: mono_repo self validate
         run: dart pub global run mono_repo generate --validate
   job_002:
-    name: "analyze_and_format; Dart 2.19.0; PKGS: pkgs/corpus, pkgs/dart_flutter_team_lints, pkgs/firehose, pkgs/repo_manage; `dart analyze --fatal-infos .`"
+    name: "analyze_and_format; Dart 2.19.0; PKGS: pkgs/corpus, pkgs/dart_flutter_team_lints, pkgs/repo_manage; `dart analyze --fatal-infos .`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
-          key: "os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus-pkgs/dart_flutter_team_lints-pkgs/firehose-pkgs/repo_manage;commands:analyze"
+          key: "os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus-pkgs/dart_flutter_team_lints-pkgs/repo_manage;commands:analyze"
           restore-keys: |
-            os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus-pkgs/dart_flutter_team_lints-pkgs/firehose-pkgs/repo_manage
+            os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus-pkgs/dart_flutter_team_lints-pkgs/repo_manage
             os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: "2.19.0"
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_corpus_pub_upgrade
         name: pkgs/corpus; dart pub upgrade
         run: dart pub upgrade
@@ -77,15 +77,6 @@
         run: dart analyze --fatal-infos .
         if: "always() && steps.pkgs_dart_flutter_team_lints_pub_upgrade.conclusion == 'success'"
         working-directory: pkgs/dart_flutter_team_lints
-      - id: pkgs_firehose_pub_upgrade
-        name: pkgs/firehose; dart pub upgrade
-        run: dart pub upgrade
-        if: "always() && steps.checkout.conclusion == 'success'"
-        working-directory: pkgs/firehose
-      - name: "pkgs/firehose; dart analyze --fatal-infos ."
-        run: dart analyze --fatal-infos .
-        if: "always() && steps.pkgs_firehose_pub_upgrade.conclusion == 'success'"
-        working-directory: pkgs/firehose
       - id: pkgs_repo_manage_pub_upgrade
         name: pkgs/repo_manage; dart pub upgrade
         run: dart pub upgrade
@@ -98,11 +89,43 @@
     needs:
       - job_001
   job_003:
+    name: "analyze_and_format; Dart 3.0.0; PKG: pkgs/firehose; `dart analyze --fatal-infos .`"
+    runs-on: ubuntu-latest
+    steps:
+      - name: Cache Pub hosted dependencies
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
+        with:
+          path: "~/.pub-cache/hosted"
+          key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/firehose;commands:analyze"
+          restore-keys: |
+            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/firehose
+            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0
+            os:ubuntu-latest;pub-cache-hosted
+            os:ubuntu-latest
+      - name: Setup Dart SDK
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
+        with:
+          sdk: "3.0.0"
+      - id: checkout
+        name: Checkout repository
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
+      - id: pkgs_firehose_pub_upgrade
+        name: pkgs/firehose; dart pub upgrade
+        run: dart pub upgrade
+        if: "always() && steps.checkout.conclusion == 'success'"
+        working-directory: pkgs/firehose
+      - name: "pkgs/firehose; dart analyze --fatal-infos ."
+        run: dart analyze --fatal-infos .
+        if: "always() && steps.pkgs_firehose_pub_upgrade.conclusion == 'success'"
+        working-directory: pkgs/firehose
+    needs:
+      - job_001
+  job_004:
     name: "analyze_and_format; Dart dev; PKGS: pkgs/corpus, pkgs/dart_flutter_team_lints, pkgs/firehose, pkgs/repo_manage; `dart analyze --fatal-infos .`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/corpus-pkgs/dart_flutter_team_lints-pkgs/firehose-pkgs/repo_manage;commands:analyze"
@@ -112,12 +135,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: dev
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_corpus_pub_upgrade
         name: pkgs/corpus; dart pub upgrade
         run: dart pub upgrade
@@ -156,12 +179,12 @@
         working-directory: pkgs/repo_manage
     needs:
       - job_001
-  job_004:
+  job_005:
     name: "analyze_and_format; Dart dev; PKGS: pkgs/corpus, pkgs/dart_flutter_team_lints, pkgs/firehose, pkgs/repo_manage; `dart format --output=none --set-exit-if-changed .`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/corpus-pkgs/dart_flutter_team_lints-pkgs/firehose-pkgs/repo_manage;commands:format"
@@ -171,12 +194,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: dev
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_corpus_pub_upgrade
         name: pkgs/corpus; dart pub upgrade
         run: dart pub upgrade
@@ -215,12 +238,12 @@
         working-directory: pkgs/repo_manage
     needs:
       - job_001
-  job_005:
+  job_006:
     name: "unit_test; Dart 2.19.0; PKG: pkgs/corpus; `dart test`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus;commands:test_1"
@@ -230,12 +253,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: "2.19.0"
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_corpus_pub_upgrade
         name: pkgs/corpus; dart pub upgrade
         run: dart pub upgrade
@@ -250,12 +273,13 @@
       - job_002
       - job_003
       - job_004
-  job_006:
+      - job_005
+  job_007:
     name: "unit_test; Dart 2.19.0; PKG: pkgs/dart_flutter_team_lints; `dart test`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/dart_flutter_team_lints;commands:test_1"
@@ -265,12 +289,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: "2.19.0"
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_dart_flutter_team_lints_pub_upgrade
         name: pkgs/dart_flutter_team_lints; dart pub upgrade
         run: dart pub upgrade
@@ -285,27 +309,28 @@
       - job_002
       - job_003
       - job_004
-  job_007:
-    name: "unit_test; Dart 2.19.0; PKG: pkgs/firehose; `dart test`"
+      - job_005
+  job_008:
+    name: "unit_test; Dart 3.0.0; PKG: pkgs/firehose; `dart test`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
-          key: "os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/firehose;commands:test_1"
+          key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/firehose;commands:test_1"
           restore-keys: |
-            os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/firehose
-            os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0
+            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/firehose
+            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
-          sdk: "2.19.0"
+          sdk: "3.0.0"
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_firehose_pub_upgrade
         name: pkgs/firehose; dart pub upgrade
         run: dart pub upgrade
@@ -320,12 +345,13 @@
       - job_002
       - job_003
       - job_004
-  job_008:
+      - job_005
+  job_009:
     name: "unit_test; Dart dev; PKG: pkgs/corpus; `dart test`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/corpus;commands:test_1"
@@ -335,12 +361,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: dev
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_corpus_pub_upgrade
         name: pkgs/corpus; dart pub upgrade
         run: dart pub upgrade
@@ -355,12 +381,13 @@
       - job_002
       - job_003
       - job_004
-  job_009:
+      - job_005
+  job_010:
     name: "unit_test; Dart dev; PKG: pkgs/dart_flutter_team_lints; `dart test`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/dart_flutter_team_lints;commands:test_1"
@@ -370,12 +397,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: dev
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_dart_flutter_team_lints_pub_upgrade
         name: pkgs/dart_flutter_team_lints; dart pub upgrade
         run: dart pub upgrade
@@ -390,12 +417,13 @@
       - job_002
       - job_003
       - job_004
-  job_010:
+      - job_005
+  job_011:
     name: "unit_test; Dart dev; PKG: pkgs/firehose; `dart test`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/firehose;commands:test_1"
@@ -405,12 +433,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: dev
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_firehose_pub_upgrade
         name: pkgs/firehose; dart pub upgrade
         run: dart pub upgrade
@@ -425,12 +453,13 @@
       - job_002
       - job_003
       - job_004
-  job_011:
+      - job_005
+  job_012:
     name: "analyze_format; Dart dev; PKG: pkgs/blast_repo; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos .`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/blast_repo;commands:format-analyze"
@@ -440,12 +469,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: dev
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_blast_repo_pub_upgrade
         name: pkgs/blast_repo; dart pub upgrade
         run: dart pub upgrade
@@ -470,12 +499,13 @@
       - job_008
       - job_009
       - job_010
-  job_012:
+      - job_011
+  job_013:
     name: "test; Dart dev; PKG: pkgs/blast_repo; `dart test --test-randomize-ordering-seed=random`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+        uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
         with:
           path: "~/.pub-cache/hosted"
           key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/blast_repo;commands:test_0"
@@ -485,12 +515,12 @@
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
         with:
           sdk: dev
       - id: checkout
         name: Checkout repository
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
       - id: pkgs_blast_repo_pub_upgrade
         name: pkgs/blast_repo; dart pub upgrade
         run: dart pub upgrade
@@ -512,3 +542,4 @@
       - job_009
       - job_010
       - job_011
+      - job_012
diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml
new file mode 100644
index 0000000..49f964d
--- /dev/null
+++ b/.github/workflows/health.yaml
@@ -0,0 +1,71 @@
+# A CI configuration to check PR health.
+
+name: Health
+
+# Callers of this workflow should use it as follows:
+#
+# name: Health
+# on:
+#   pull_request:
+#     branches: [ main ]
+#     types: [opened, synchronize, reopened, labeled, unlabeled]
+# jobs:
+#   health:
+#     uses: dart-lang/ecosystem/.github/workflows/health.yaml@main
+
+# Callers may optionally specify the version of the SDK to use when running the
+# health check. This can be useful if your package has a very recent minimum SDK
+# constraint. This is done via the `sdk` input parameter. Note that this
+# parameter is not required; it defaults to `stable` - using the most recent
+# stable release of the Dart SDK.
+# 
+# The checks can also be restricted to any subset of version, changelog, and license,
+# if needed.
+#
+# jobs:
+#   health:
+#     uses: dart-lang/ecosystem/.github/workflows/health.yaml@main
+#     with:
+#       sdk: beta
+#       checks: "version,changelog,license"
+
+on:
+  workflow_call:
+    inputs:
+      sdk:
+        description: >-
+          The channel, or a specific version from a channel, to install
+          ('2.19.0','stable', 'beta', 'dev'). Using one of the three channels
+          will give you the latest version published to that channel.
+        default: "stable"
+        required: false
+        type: string
+      checks:
+        description: What to check for in the PR health check - any subset of "version,changelog,license"
+        default: "version,changelog,license"
+        type: string
+        required: false
+
+jobs:
+  health:
+    # These permissions are required for us to create comments on PRs.
+    permissions:
+      pull-requests: write
+
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
+      - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
+        with:
+          sdk: ${{ inputs.sdk }}
+
+      - name: Install firehose
+        run: dart pub global activate --source git https://github.com/dart-lang/ecosystem.git --git-path pkgs/firehose/ --git-ref=unifiedWorkflow #TODO remove, just for testing
+
+      - name: Validate packages
+        if: ${{ github.event_name == 'pull_request' }}
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          ISSUE_NUMBER: ${{ github.event.number }}
+          PR_LABELS: "${{ join(github.event.pull_request.labels.*.name) }}"
+        run: dart pub global run firehose --health ${{ inputs.checks }}
diff --git a/.github/workflows/health_internal.yaml b/.github/workflows/health_internal.yaml
new file mode 100644
index 0000000..81616c5
--- /dev/null
+++ b/.github/workflows/health_internal.yaml
@@ -0,0 +1,12 @@
+# A CI configuration to check PR health.
+
+name: Health
+on:
+  pull_request:
+    branches: [ main ]
+    types: [opened, synchronize, reopened, labeled, unlabeled]
+jobs:
+  health:
+    uses: ./.github/workflows/health.yaml
+    with:
+      checks: "changelog,license"
\ No newline at end of file
diff --git a/pkgs/firehose/CHANGELOG.md b/pkgs/firehose/CHANGELOG.md
index 44c2b1c..2fca507 100644
--- a/pkgs/firehose/CHANGELOG.md
+++ b/pkgs/firehose/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.3.18-wip
+- Add Github workflow for PR health.
+
 ## 0.3.17
 
 - Correctly parse pre-release versions from the CHANGELOG.
diff --git a/pkgs/firehose/README.md b/pkgs/firehose/README.md
index e923f9f..18134bf 100644
--- a/pkgs/firehose/README.md
+++ b/pkgs/firehose/README.md
@@ -1,11 +1,12 @@
 [![pub package](https://img.shields.io/pub/v/firehose.svg)](https://pub.dev/packages/firehose)
 [![package publisher](https://img.shields.io/pub/publisher/firehose.svg)](https://pub.dev/packages/firehose/publisher)
 
-## What's this?
+## firehose
+### What's this?
 
 This is a tool to automate publishing of pub packages from GitHub actions.
 
-## Conventions and setup
+### Conventions and setup
 
 When run from a PR, this tool will validate the package pubspecs and
 changelogs and indicate whether the criteria for publishing has been met.
@@ -15,18 +16,18 @@
 When run in response to a git tag event (a tag with a pattern like `v1.2.3` or
 `name_v1.2.3` for monorepos), this tool will publish the indicated package.
 
-## Pre-release versions
+### Pre-release versions
 
 Pre-release versions (aka, `'1.2.3-dev'`) are handled specially; this tool will
 validate the package but will not auto-publish it. This can be used to
 accumulate several changes and later publish them as a group.
 
-## Disabling auto-publishing
+### Disabling auto-publishing
 
 In order to disable package validation and auto-publishing, add the
 `publish_to: none` key to your pubspec.
 
-## PR branch actions
+### PR branch actions
 
 For PRs, this tool:
 
@@ -34,7 +35,7 @@
 - validates that the changelog version equals the pubspec version
 - performs a `dart pub publish --dry-run`
 
-## Git tag actions
+### Git tag actions
 
 In response to a git tag event, this tool:
 
@@ -42,7 +43,7 @@
 - determines the indicated package
 - attempts to publish that package (`dart pub publish --force`)
 
-## Mono-repos
+### Mono-repos
 
 This tool can work with either single package repos or with mono-repos (repos
 containing several packages). It will scan for and detect packages in a mono
@@ -52,7 +53,7 @@
 For single package repos, the tag pattern should be `v1.2.3`. For mono-repos,
 the tag pattern must be prefixed with the package name, e.g. `foo-v1.2.3`.
 
-## Integrating this tool into a repo
+### Integrating this tool into a repo
 
 - copy the yaml below into a `.github/workflows/publish.yaml` file in your repo
 - update the target branch below if necessary (currently, `main`)
@@ -78,7 +79,7 @@
     uses: dart-lang/ecosystem/.github/workflows/publish.yaml@main
 ```
 
-## Publishing from a specific version of the SDK
+### Publishing from a specific version of the SDK
 
 Callers may optionally specify the version of the SDK to use when publishing a
 package. This can be useful if your package has a very recent minimum SDK
@@ -94,7 +95,49 @@
       sdk: beta
 ```
 
-## Workflow docs
+### Workflow docs
 
 The description of the common workflow for repos using this tool can be found at
 https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.
+
+<br/>
+
+## health
+
+### What's this?
+
+This is a Github workflow to check PR health.
+
+### Conventions and setup
+
+When run from a PR, this tool will check a configurable subset of the following
+
+* If the package versioning is correct and consistent, see `firehose` description above.
+* If a changelog entry has been added.
+* If all `.dart` files have a license header.
+
+This tool can work with either single package repos or with mono-repos (repos
+containing several packages).
+
+### Integrating this tool into a repo
+
+- copy the yaml below into a `.github/workflows/health.yaml` file in your repo
+- update the target branch below if necessary (currently, `main`)
+
+```yaml
+name: Health
+on:
+  pull_request:
+    branches: [ main ]
+    types: [opened, synchronize, reopened, labeled, unlabeled]
+jobs:
+  health:
+    uses: dart-lang/ecosystem/.github/workflows/health.yaml@main
+#   with:
+#     checks: "version,changelog,license" 
+```
+
+### Workflow docs
+
+The description of the common workflow for repos using this tool can be found at
+https://github.com/dart-lang/ecosystem/wiki/Pull-Request-Health.
\ No newline at end of file
diff --git a/pkgs/firehose/bin/firehose.dart b/pkgs/firehose/bin/firehose.dart
index e561bd9..5e01d27 100644
--- a/pkgs/firehose/bin/firehose.dart
+++ b/pkgs/firehose/bin/firehose.dart
@@ -20,10 +20,11 @@
 
     var validate = argResults['validate'] == true;
     var publish = argResults['publish'] == true;
+    var health = argResults['health'] != null;
 
-    if (!validate && !publish) {
-      _usage(argParser,
-          error: 'Error: one of --validate or --publish must be specified.');
+    if (!validate && !publish && !health) {
+      _usage(argParser, error: '''
+Error: one of --validate, --publish, or --health must be specified.''');
       exit(1);
     }
 
@@ -41,6 +42,8 @@
       await firehose.validate();
     } else if (publish) {
       await firehose.publish();
+    } else if (health) {
+      await firehose.healthCheck(argResults['health'] as List);
     }
   } on ArgParserException catch (e) {
     _usage(argParser, error: e.message);
@@ -73,6 +76,11 @@
       help: 'Validate packages and indicate whether --publish would publish '
           'anything.',
     )
+    ..addMultiOption(
+      'health',
+      defaultsTo: ['version', 'license', 'changelog'],
+      help: 'Check PR health.',
+    )
     ..addFlag(
       'publish',
       negatable: false,
diff --git a/pkgs/firehose/lib/firehose.dart b/pkgs/firehose/lib/firehose.dart
index 73c2740..56a51d4 100644
--- a/pkgs/firehose/lib/firehose.dart
+++ b/pkgs/firehose/lib/firehose.dart
@@ -2,9 +2,13 @@
 // 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.
 
+// ignore_for_file: always_declare_return_types
+
 import 'dart:io';
+import 'dart:math';
 
 import 'package:firehose/src/repo.dart';
+import 'package:path/path.dart' as path;
 
 import 'src/github.dart';
 import 'src/pub.dart';
@@ -15,6 +19,13 @@
 const String _githubActionsUser = 'github-actions[bot]';
 
 const String _publishBotTag = '## Package publishing';
+const String _publishBotTag2 = '### Package publish validation';
+
+const String _licenseBotTag = '### License Headers';
+
+const String _changelogBotTag = '### Changelog entry';
+
+const String _prHealthTag = '## PR Health';
 
 const String _ignoreWarningsLabel = 'publish-ignore-warnings';
 
@@ -23,6 +34,178 @@
 
   Firehose(this.directory);
 
+  Future<void> healthCheck(List argResult) async {
+    print('Start health check for the checks $argResult');
+    var checks = [
+      if (argResult.contains('version')) validateCheck,
+      if (argResult.contains('license')) licenseCheck,
+      if (argResult.contains('changelog')) changelogCheck,
+    ];
+    await _healthCheck(checks);
+  }
+
+  Future<void> _healthCheck(
+      List<Future<HealthCheckResult> Function(Github)> checks) async {
+    var github = Github();
+
+    // Do basic validation of our expected env var.
+    if (!_expectEnv(github.githubAuthToken, 'GITHUB_TOKEN')) return;
+    if (!_expectEnv(github.repoSlug, 'GITHUB_REPOSITORY')) return;
+    if (!_expectEnv(github.issueNumber, 'ISSUE_NUMBER')) return;
+    if (!_expectEnv(github.sha, 'GITHUB_SHA')) return;
+
+    if ((github.actor ?? '').endsWith(_botSuffix)) {
+      print('Skipping package validation for ${github.actor} PRs.');
+      return;
+    }
+
+    var checked =
+        await Future.wait(checks.map((check) => check(github)).toList());
+    await writeInComment(github, checked);
+
+    github.close();
+  }
+
+  Future<HealthCheckResult> validateCheck(Github github) async {
+    var results = await _validate(github);
+
+    var markdownTable = '''
+| Package | Version | Status | Publish tag (post-merge) |
+| :--- | ---: | :--- | ---: |
+${results.describeAsMarkdown}
+
+    ''';
+
+    return HealthCheckResult(
+      _publishBotTag2,
+      results.severity,
+      markdownTable,
+    );
+  }
+
+  Future<HealthCheckResult> licenseCheck(Github github) async {
+    final license = '''
+// Copyright (c) ${DateTime.now().year}, 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.''';
+
+    var filePaths = await _getFilesWithoutLicenses(github);
+
+    var markdownResult = '''
+Some `.dart` files were found to not have license headers. Please add the following header to all listed files:
+```
+$license
+```
+
+| Files |
+| :--- |
+${filePaths.map((e) => '|$e|').join('\n')}
+
+Either manually or by running the following in your repository directory
+
+```
+dart pub global activate --source git https://github.com/mosuem/file_licenser
+dart pub global run file_licenser .
+```
+
+'''; //TODO: replace by pub.dev version
+
+    return HealthCheckResult(
+      _licenseBotTag,
+      filePaths.isNotEmpty ? Severity.error : Severity.success,
+      markdownResult,
+    );
+  }
+
+  Future<HealthCheckResult> changelogCheck(Github github) async {
+    var filePaths = await _packagesWithoutChangelog(github);
+
+    final markdownResult = '''
+Changes to these files need to be accounted for in their respective changelogs:
+
+| Package | Files |
+| :--- | :--- |
+${filePaths.entries.map((e) => '| package:${e.key.name} | ${e.value.map((e) => path.relative(e, from: Directory.current.path)).join('<br />')} |').join('\n')}
+''';
+
+    return HealthCheckResult(
+      _changelogBotTag,
+      filePaths.isNotEmpty ? Severity.error : Severity.success,
+      markdownResult,
+    );
+  }
+
+  Future<Map<Package, List<String>>> _packagesWithoutChangelog(
+      Github github) async {
+    final repo = Repository();
+    final packages = repo.locatePackages();
+
+    final files = await github.listFilesForPR();
+    print('Collecting packages without changed changelogs:');
+    final packagesWithoutChangedChangelog = packages.where((package) {
+      var changelogPath = package.changelog.file.path;
+      var changelog =
+          path.relative(changelogPath, from: Directory.current.path);
+      return !files.contains(changelog);
+    }).toList();
+    print('Done, found ${packagesWithoutChangedChangelog.length} packages.');
+
+    print('Collecting files without license headers in those packages:');
+    var packagesWithChanges = <Package, List<String>>{};
+    for (final file in files) {
+      for (final package in packagesWithoutChangedChangelog) {
+        if (fileNeedsEntryInChangelog(package, file)) {
+          print(file);
+          packagesWithChanges.update(
+            package,
+            (changedFiles) => [...changedFiles, file],
+            ifAbsent: () => [file],
+          );
+        }
+      }
+    }
+    print('''
+Done, found ${packagesWithChanges.length} packages with a need for a changelog.''');
+    return packagesWithChanges;
+  }
+
+  bool fileNeedsEntryInChangelog(Package package, String file) {
+    final directoryPath = package.directory.path;
+    final directory =
+        path.relative(directoryPath, from: Directory.current.path);
+    final isInPackage = path.isWithin(directory, file);
+    final isInLib = path.isWithin(path.join(directory, 'lib'), file);
+    final isInBin = path.isWithin(path.join(directory, 'bin'), file);
+    final isPubspec = file.endsWith('pubspec.yaml');
+    final isReadme = file.endsWith('README.md');
+    return isInPackage && (isInLib || isInBin || isPubspec || isReadme);
+  }
+
+  Future<List<String>> _getFilesWithoutLicenses(Github github) async {
+    var dir = Directory.current;
+    var dartFiles = await dir
+        .list(recursive: true)
+        .where((f) => f.path.endsWith('.dart'))
+        .toList();
+    print('Collecting files without license headers:');
+    var filesWithoutLicenses = dartFiles
+        .map((file) {
+          var fileContents = File(file.path).readAsStringSync();
+          var fileContainsCopyright = fileContents.contains('// Copyright (c)');
+          if (!fileContainsCopyright) {
+            var relativePath =
+                path.relative(file.path, from: Directory.current.path);
+            print(relativePath);
+            return relativePath;
+          }
+        })
+        .whereType<String>()
+        .toList();
+    print('''
+Done, found ${filesWithoutLicenses.length} files without license headers''');
+    return filesWithoutLicenses;
+  }
+
   /// Validate the packages in the repository.
   ///
   /// This method is intended to run in the context of a PR. It will:
@@ -53,8 +236,6 @@
 
 Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.
 ''';
-
-    // Write the publish info status to the job summary.
     github.appendStepSummary(markdownTable);
 
     var existingCommentId = await allowFailure(
@@ -99,6 +280,59 @@
     github.close();
   }
 
+  Future<void> writeInComment(
+    Github github,
+    List<HealthCheckResult> results,
+  ) async {
+    var commentText = results.map((e) {
+      var markdown = e.markdown;
+      var s = '''
+<details${e.severity == Severity.error ? ' open' : ''}>
+<summary>
+Details
+</summary>
+
+$markdown
+</details>
+
+''';
+      return '${e.tag} ${e.severity.emoji}\n\n$s';
+    }).join('\n');
+
+    var summary = '$_prHealthTag\n\n$commentText';
+    github.appendStepSummary(summary);
+
+    var repoSlug = github.repoSlug!;
+    var issueNumber = github.issueNumber!;
+
+    var existingCommentId = await allowFailure(
+      github.findCommentId(
+        repoSlug,
+        issueNumber,
+        user: _githubActionsUser,
+        searchTerm: _prHealthTag,
+      ),
+      logError: print,
+    );
+
+    if (existingCommentId == null) {
+      await allowFailure(
+        github.createComment(repoSlug, issueNumber, summary),
+        logError: print,
+      );
+    } else {
+      await allowFailure(
+        github.updateComment(repoSlug, existingCommentId, summary),
+        logError: print,
+      );
+    }
+
+    if (results.any((result) => result.severity == Severity.error) &&
+        exitCode == 0) {
+      exitCode = 1;
+    }
+  }
+
   Future<VerificationResults> _validate(Github github) async {
     var repo = Repository();
     var packages = repo.locatePackages();
@@ -289,6 +523,9 @@
 
   void addResult(Result result) => results.add(result);
 
+  Severity get severity =>
+      Severity.values[results.map((e) => e.severity.index).reduce(max)];
+
   bool get hasSuccess => results.any((r) => r.severity == Severity.success);
 
   bool get hasError => results.any((r) => r.severity == Severity.error);
@@ -310,6 +547,14 @@
   }
 }
 
+class HealthCheckResult {
+  final String tag;
+  final Severity severity;
+  final String markdown;
+
+  HealthCheckResult(this.tag, this.severity, this.markdown);
+}
+
 class Result {
   final Severity severity;
   final Package package;
@@ -343,4 +588,10 @@
   success,
   info,
   error;
+
+  String get emoji => switch (this) {
+        Severity.info => ':heavy_check_mark:',
+        Severity.error => ':exclamation:',
+        success => ':heavy_check_mark:',
+      };
 }
diff --git a/pkgs/firehose/lib/src/github.dart b/pkgs/firehose/lib/src/github.dart
index 822d5e2..76a57a4 100644
--- a/pkgs/firehose/lib/src/github.dart
+++ b/pkgs/firehose/lib/src/github.dart
@@ -192,6 +192,19 @@
         'https://api.github.com/repos/$repoSlug/issues/comments/$commentId'));
   }
 
+  Future<List<String>> listFilesForPR() async {
+    var result = await callRestApiGet(
+      Uri.parse(
+          'https://api.github.com/repos/$repoSlug/pulls/$issueNumber/files'),
+    );
+    var json = jsonDecode(result) as List;
+    var filenames = json
+        .map((e) => e as Map<String, dynamic>)
+        .map((e) => e['filename'] as String)
+        .toList();
+    return filenames;
+  }
+
   void close() {
     _httpClient?.close();
   }
diff --git a/pkgs/firehose/pubspec.yaml b/pkgs/firehose/pubspec.yaml
index 9cf472a..205f46e 100644
--- a/pkgs/firehose/pubspec.yaml
+++ b/pkgs/firehose/pubspec.yaml
@@ -1,10 +1,10 @@
 name: firehose
 description: A tool to automate publishing of Pub packages from GitHub actions.
-version: 0.3.17
+version: 0.3.18-wip
 repository: https://github.com/dart-lang/ecosystem/tree/main/pkgs/firehose
 
 environment:
-  sdk: '>=2.19.0 <3.0.0'
+  sdk: ^3.0.0
 
 executables:
   firehose: firehose