Start working on ifchange
diff --git a/pkgs/firehose/lib/src/health/health.dart b/pkgs/firehose/lib/src/health/health.dart
index 042abd5..c86b07a 100644
--- a/pkgs/firehose/lib/src/health/health.dart
+++ b/pkgs/firehose/lib/src/health/health.dart
@@ -17,6 +17,7 @@
 import '../utils.dart';
 import 'changelog.dart';
 import 'coverage.dart';
+import 'if_then_change.dart';
 import 'license.dart';
 
 enum Check {
@@ -26,7 +27,8 @@
   coverage('Coverage', 'coverage'),
   breaking('Breaking changes', 'breaking'),
   leaking('API leaks', 'leaking'),
-  donotsubmit('Do Not Submit', 'do-not-submit');
+  donotsubmit('Do Not Submit', 'do-not-submit'),
+  ifthenchange('If then change', 'if-then-change');
 
   final String tag;
 
@@ -126,6 +128,7 @@
         Check.breaking => breakingCheck,
         Check.donotsubmit => doNotSubmitCheck,
         Check.leaking => leakingCheck,
+        Check.ifthenchange => ifThenChangeCheck,
       };
 
   Future<HealthCheckResult> validateCheck() async {
@@ -269,6 +272,35 @@
     );
   }
 
+  Future<HealthCheckResult> ifThenChangeCheck() async {
+    var files = await github.listFilesForPR(directory, ignoredPackages);
+    var allFilePaths = await getFilesWithIfThenChanges(
+      directory,
+      ignoredPackages,
+    );
+
+    var groupedPaths = allFilePaths.groupListsBy(
+        (filePath) => files.none((f) => f.filename == filePath.$2));
+
+    var unchangedFilesPaths = groupedPaths[true] ?? [];
+    var markdownResult = '''
+```
+$license
+```
+
+| Files |
+| :--- |
+${unchangedFilesPaths.isNotEmpty ? unchangedFilesPaths.map((e) => '|$e|').join('\n') : '| _no missing headers_  |'}
+
+''';
+
+    return HealthCheckResult(
+      Check.license,
+      unchangedFilesPaths.isNotEmpty ? Severity.error : Severity.success,
+      markdownResult,
+    );
+  }
+
   Future<HealthCheckResult> licenseCheck() async {
     var files = await github.listFilesForPR(directory, ignoredPackages);
     var allFilePaths = await getFilesWithoutLicenses(
diff --git a/pkgs/firehose/lib/src/health/if_then_change.dart b/pkgs/firehose/lib/src/health/if_then_change.dart
new file mode 100644
index 0000000..95561d9
--- /dev/null
+++ b/pkgs/firehose/lib/src/health/if_then_change.dart
@@ -0,0 +1,46 @@
+// 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:io';
+
+import 'package:collection/collection.dart';
+import 'package:glob/glob.dart';
+import 'package:path/path.dart' as path;
+
+final comment = r'(\\\\|#)';
+
+final ifThenChangeRegex =
+    RegExp('$comment LINT.IfChange(.|\n)+?$comment LINT.ThenChange((.+?))');
+
+Future<List<(String, String)>> getFilesWithIfThenChanges(
+  Directory repositoryDir,
+  List<Glob> ignoredFiles,
+) async {
+  var dartFiles = await repositoryDir
+      .list(recursive: true)
+      .where((file) => file.path.endsWith('.dart'))
+      .toList();
+  print('Collecting files with if-then-change blocks:');
+  var filesWhichNeedChanges = dartFiles
+      .expand((file) {
+        var relativePath = path.relative(file.path, from: repositoryDir.path);
+        var isIgnoredFile = ignoredFiles.none((glob) =>
+            glob.matches(path.relative(file.path, from: repositoryDir.path)));
+        if (isIgnoredFile) {
+          return <(String, String)>[];
+        }
+        var fileContents = File(file.path).readAsStringSync();
+        var matches = ifThenChangeRegex.allMatches(fileContents);
+        return matches
+            .map((match) => match[4])
+            .whereType<String>()
+            .expand((element) => element.split(','))
+            .map((e) => (relativePath, e));
+      })
+      .sortedBy((file) => file.$1)
+      .toList();
+  print('''
+Done, found ${filesWhichNeedChanges.length} files needing changes''');
+  return filesWhichNeedChanges;
+}