Skip to content

Commit 7c9292c

Browse files
authored
feat: include bot to update when exclusion table needs changes (#132)
* feat: include bot to update when exclusion table needs changes * revert: exclusion reasons * revert: format on save
1 parent 2a80995 commit 7c9292c

File tree

7 files changed

+149
-12
lines changed

7 files changed

+149
-12
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: bot_update_exclusions
2+
3+
on:
4+
# This should ideally trigger whenever there is a commit to the [Dart Linter rules](https://raw.githubusercontent.com/dart-lang/sdk/main/pkg/linter/tool/machine/rules.json).
5+
# However, this is not yet possible see: https://github.com/orgs/community/discussions/26323
6+
schedule:
7+
# At 08:06 on every day-of-week from Monday through Friday.
8+
- cron: "6 8 * * 1-5"
9+
workflow_dispatch:
10+
11+
jobs:
12+
build:
13+
defaults:
14+
run:
15+
working-directory: tool/linter_rules
16+
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: 📚 Git Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: 🎯 Setup Dart
24+
uses: dart-lang/setup-dart@v1
25+
26+
- name: 📦 Install Dependencies
27+
run: dart pub get
28+
29+
- name: 🔍 Check for changes
30+
id: make
31+
run: if dart lib/exclusion_reason_table.dart --set-exit-if-changed; then echo "did_change=false"; else echo "did_change=true"; fi >> $GITHUB_ENV
32+
33+
- name: 🔑 Config Git User
34+
if: ${{ env.did_change == 'true' }}
35+
run: |
36+
git config user.name VGV Bot
37+
git config user.email [email protected]
38+
39+
- name: ✍️ Make changes
40+
if: ${{ env.did_change == 'true' }}
41+
run: dart lib/exclusion_reason_table.dart
42+
43+
- name: 📝 Create Pull Request
44+
if: ${{ env.did_change == 'true' }}
45+
uses: peter-evans/[email protected]
46+
with:
47+
base: main
48+
branch: chore/update-spdx-license
49+
commit-message: "docs: update exclusion table"
50+
title: "docs: update exclusion table"
51+
body: |
52+
There are rules that require an update to their exclusion reasons.
53+
labels: bot
54+
author: VGV Bot <[email protected]>
55+
assignees: vgvbot
56+
committer: VGV Bot <[email protected]>

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,4 @@ Below is a list of rules that are not enabled by default together with the reaso
147147
[pub_badge_link]: https://pub.dartlang.org/packages/very_good_analysis
148148
[very_good_ventures_link]: https://verygood.ventures
149149
[very_good_ventures_link_dark]: https://verygood.ventures#gh-dark-mode-only
150-
[very_good_ventures_link_light]: https://verygood.ventures#gh-light-mode-only
150+
[very_good_ventures_link_light]: https://verygood.ventures#gh-light-mode-only

tool/linter_rules/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,23 @@ The reasons are defined in the [`exclusion_reasons.json`](exclusion_reasons.json
1919
To generate the exclusion reason table, run the following command (from `tool/linter_rules`, and don't forget to `dart pub get`):
2020

2121
```sh
22-
dart lib/exclusion_reason_table.dart $version
22+
dart lib/exclusion_reason_table.dart
2323
```
2424

25-
This command will update the README table for the rules that are not enabled by default in the specified `$version` of Very Good Analysis. The `$version` is a user specified argument and it should be in the format `x.y.z`. In addition, no longer excluded rules will be removed from the `exclusion_reasons.json` file. The command does not format the output, so it is recommended to format both files with your preferred formatter after running the command.
25+
This command will update the README table for the rules that are not enabled by default in the specified `$version` of Very Good Analysis.
26+
27+
In addition, no longer excluded rules will be removed from the `exclusion_reasons.json` file. The command does not format the output, so it is recommended to format both files with your preferred formatter after running the command.
2628

2729
Rules that are missing a reason in the `exclusion_reasons.json` file will be given the reason `Not specified`.
2830

31+
### Options
32+
33+
| Option | Description | Default |
34+
| ------------------- | --------------------------------------------------------------------- | --------------------------------------- |
35+
| version | The Very Good Analysis version to use. | latest (from lib/analysis_options.yaml) |
36+
| set-exit-if-changed | Set the exit code to 2 if there are changes to the exclusion reasons. | false |
37+
38+
2939
## Inspection 🔍
3040

3141
If you're looking to update Very Good Analysis you might want to inspect the health of the latest rule set. You can use the script at `bin/inspect.dart` to do exactly that.

tool/linter_rules/lib/exclusion_reason_table.dart

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import 'dart:io';
2+
3+
import 'package:args/args.dart';
4+
import 'package:collection/collection.dart';
15
import 'package:linter_rules/linter_rules.dart';
26

37
/// The reason to fallback to if no reason is found in the exclusion reasons
@@ -35,25 +39,41 @@ String _linterRuleLink(String rule) {
3539
/// with the version of the Very Good Analysis to update the documentation for
3640
/// as the first argument.
3741
///
38-
/// The version argument should be in the format of `x.y.z`. For example,
39-
/// `5.1.0`.
42+
/// The new table will be written to the README.md file. However, it might not
43+
/// follow the same formatting as the rest of the file, so it is recommended to
44+
/// manually format it after running the tool.
45+
///
46+
/// ## Usage
4047
///
4148
/// To use the tool run (from tool/linter_rules):
4249
/// ```sh
43-
/// dart lib/exclusion_reason_table.dart $version
50+
/// dart lib/exclusion_reason_table.dart
4451
/// ```
4552
///
46-
/// Where `$version` is the version of the Very Good Analysis to log the table
47-
/// for.
53+
/// ## Options
4854
///
49-
/// The new table will be written to the README.md file. However, it might not
50-
/// follow the same formatting as the rest of the file, so it is recommended to
51-
/// manually format it after running the tool.
55+
/// * `--version`: The version of the Very Good Analysis to update the table
56+
/// for, defaults to the latest version found in the lib analysis options file.
57+
/// * `--set-exit-if-changed`: Set the exit code to 2 if there are changes to
58+
/// the exclusion reasons.
5259
Future<void> main(
5360
List<String> args, {
5461
void Function(String) log = print,
5562
}) async {
56-
final version = args[0];
63+
final argsParser = ArgParser()
64+
..addOption(
65+
'version',
66+
help: 'The version of the Very Good Analysis to update the table for.',
67+
)
68+
..addFlag(
69+
'set-exit-if-changed',
70+
help:
71+
'''Set the exit code to 2 if there are changes to the exclusion reasons.''',
72+
);
73+
final parsedArgs = argsParser.parse(args);
74+
75+
final version = parsedArgs['version'] as String? ?? latestVgaVersion();
76+
final setExitIfChanged = parsedArgs['set-exit-if-changed'] as bool;
5777

5878
final linterRules = (await allLinterRules()).toSet();
5979
log('Found ${linterRules.length} available linter rules');
@@ -71,6 +91,14 @@ Future<void> main(
7191
for (final rule in excludedRules)
7292
rule: previousExclusionReasons[rule] ?? _noReasonFallback,
7393
};
94+
95+
final hasChanged = !const DeepCollectionEquality()
96+
.equals(previousExclusionReasons, exclusionReasons);
97+
if (!hasChanged) {
98+
log('No changes to the exclusion reasons');
99+
return;
100+
}
101+
74102
await writeExclusionReasons(exclusionReasons);
75103

76104
final markdownTable = generateMarkdownTable(
@@ -86,4 +114,8 @@ Future<void> main(
86114
await Readme().updateTagContent(_excludedRulesTableTag, '\n$markdownTable');
87115

88116
log('''Updated the README.md file with the excluded rules table.''');
117+
118+
if (hasChanged && setExitIfChanged) {
119+
exit(2);
120+
}
89121
}

tool/linter_rules/lib/linter_rules.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ library;
33

44
export 'src/all_linter_rules.dart';
55
export 'src/all_vga_rules.dart';
6+
export 'src/latest_vga_version.dart';
67
export 'src/linter_rules_reasons.dart';
78
export 'src/markdown_table_generator.dart';
89
export 'src/models/models.dart';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import 'dart:io';
2+
3+
import 'package:path/path.dart' as path;
4+
5+
/// The file path containing the latest Very Good Analysis options version.
6+
///
7+
/// It assumes that the current directory is the root of the `linter_rules`
8+
/// package (tool/linter_rules).
9+
final _latestVeryGoodAnalaysisFilePath = path.joinAll(
10+
['..', '..', 'lib', 'analysis_options.yaml'],
11+
);
12+
13+
/// Returns the latest Very Good Analysis version from the analysis options
14+
/// file.
15+
String latestVgaVersion() {
16+
final analysisOptionsFile = File(_latestVeryGoodAnalaysisFilePath);
17+
18+
if (!analysisOptionsFile.existsSync()) {
19+
throw ArgumentError(
20+
'''Could not find analysis options file at ${analysisOptionsFile.path}''',
21+
);
22+
}
23+
24+
final yaml = analysisOptionsFile.readAsStringSync();
25+
26+
final versionRegex = RegExp(r'analysis_options\.(\d+\.\d+\.\d+)\.yaml');
27+
final match = versionRegex.firstMatch(yaml);
28+
29+
if (match == null) {
30+
throw ArgumentError(
31+
'''Could not find Very Good Analysis version in ${analysisOptionsFile.path}''',
32+
);
33+
}
34+
35+
return match.group(1)!;
36+
}

tool/linter_rules/pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ environment:
77
sdk: ^3.4.0
88

99
dependencies:
10+
args: ^2.6.0
11+
collection: ^1.19.1
1012
http: ^1.2.1
1113
meta: ^1.16.0
1214
path: ^1.9.0

0 commit comments

Comments
 (0)