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;
+}