Skip to content

Commit e37d19b

Browse files
kopporclaude
andauthored
Add markdownlint-cli2 CI check, clean up README, support rule IDs in --no-warn (#8)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent fcc7d53 commit e37d19b

4 files changed

Lines changed: 92 additions & 40 deletions

File tree

.github/workflows/markdownlint.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Markdown lint
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
14+
15+
jobs:
16+
markdownlint:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v7
21+
22+
- name: Run markdownlint-cli2
23+
uses: DavidAnson/markdownlint-cli2-action@v24

.markdownlint-cli2.jsonc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"config": {
3+
// Long lines are fine
4+
"MD013": false,
5+
"MD060": { "style": "aligned" }
6+
},
7+
"globs": ["**/*.md"],
8+
"ignores": [
9+
// Sample MADRs intentionally violate Markdown conventions
10+
"madr-samples/**",
11+
"**/build/**"
12+
]
13+
}

README.md

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
# madr-linter
22

33
A Java-based linter for Markdown Architectural Decision Records (MADR).
4-
Learn more about MADR [here](https://www.ozimmer.ch/practices/2022/11/22/MADRTemplatePrimer.html).
4+
Learn more about MADR in the [MADR template primer](https://www.ozimmer.ch/practices/2022/11/22/MADRTemplatePrimer.html).
55

66
## Run with JBang
77

88
With [JBang](https://www.jbang.dev/) installed (requires JRE 21 or newer), the
99
linter can be run directly from this repository without cloning:
1010

11-
```
11+
```shell
1212
jbang madrlint@adr/madrlint <madrFile>
1313
```
1414

1515
Or install it as a local command:
1616

17-
```
17+
```shell
1818
jbang app install madrlint@adr/madrlint
1919
madrlint <madrFile>
2020
```
@@ -24,17 +24,20 @@ madrlint <madrFile>
2424
1. Build and grab dependencies with: `.\gradlew build`
2525
2. Test the tool with: `.\gradlew run --args="[Options] <madrFile>"`
2626

27-
**Arguments**
28-
```
27+
### Arguments
28+
29+
```text
2930
<madrFile> Path to the Markdown Architectural Decision Record
3031
(MADR) file to lint.
3132
```
32-
**Options**
3333

34-
```
34+
### Options
35+
36+
```text
3537
-h, --help Show help message and exit.
3638
-V, --version Print version information and exit.
37-
-n, --no-warn <disabledRules> Disable warnings for certain rules.
39+
-n, --no-warn <disabledRules> Disable warnings for certain rules, given as rule
40+
number or rule ID (e.g -n1 or -nMADR01).
3841
They can either be declared separately(e.g -n1 -n2) or
3942
chained together separated by comma(e.g -n1,2).
4043
-o, --out <outputFile> Output the diagnostics to a file. If that file does
@@ -46,50 +49,50 @@ madrlint <madrFile>
4649
-q, --quiet Information not relevant to the lint results will be
4750
suppressed.
4851
```
52+
4953
## Rules
5054

55+
Violations are reported with a rule ID such as `MADR01a`: the rule number, optionally followed by a letter identifying the specific check within that rule.
56+
To disable a rule, pass its ID or number to `-n`/`--no-warn` (e.g., `-n MADR01` or `-n 1` disables all `MADR01` checks).
57+
5158
### Structural integrity
5259

53-
```
54-
01. Mandatory sections: Title (a), Context and Problem Statement (b),
55-
Considered Options (c), Decision Outcome (d) must be present.
56-
02. No sections may be empty.
57-
03. Chosen option must be mentioned first (b) inside Decision Outcome (a). Expected format: 'Chosen option: <chosen option>, because <rationale>'.
58-
04. Statement of chosen option must be followed by rationale in this format 'Chosen option: <chosen option>, because <rationale>'.
59-
05. Only the title is allowed to have heading level 1.
60-
06. Headings must have levels conforming to template's
61-
07. Consequences (a) and Confirmation (b), if present, must be H3 headings under Decision Outcome
62-
```
60+
| ID | Description |
61+
|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
62+
| `MADR01` | The mandatory sections must be present: Title (`a`), Context and Problem Statement (`b`), Considered Options (`c`), and Decision Outcome (`d`). |
63+
| `MADR02` | No section may be empty. |
64+
| `MADR03` | The chosen option must be stated inside Decision Outcome (`a`), and it must come first in that section (`b`). Expected format: `Chosen option: <chosen option>, because <rationale>`. |
65+
| `MADR04` | The statement of the chosen option must be followed by a rationale: `Chosen option: <chosen option>, because <rationale>`. |
66+
| `MADR05` | Only the title may have heading level 1. |
67+
| `MADR06` | Headings must have the levels given in the MADR template. |
68+
| `MADR07` | Consequences (`a`) and Confirmation (`b`), if present, must be level-3 headings under Decision Outcome. |
6369

6470
### Link validity
6571

66-
```
67-
11. Internet links must be valid.
68-
12. Local links (Anchor links, local paths to resources, etc) must be valid.
69-
```
72+
| ID | Description |
73+
|----------|---------------------------------------------------------------------------|
74+
| `MADR11` | Internet links must be valid. |
75+
| `MADR12` | Local links (anchor links, local paths to resources, etc.) must be valid. |
7076

7177
### Syntactic validity
7278

73-
```
74-
21. Metadata content must have proper syntax adhering to YAML rules.
75-
```
79+
| ID | Description |
80+
|----------|------------------------------------------------------------------|
81+
| `MADR21` | Metadata content must have proper syntax adhering to YAML rules. |
7682

7783
### Stylistic neutrality
7884

79-
```
80-
31. Asterisks (*) must be used as list markers.
81-
```
85+
| ID | Description |
86+
|----------|-----------------------------------------------|
87+
| `MADR31` | Asterisks (`*`) must be used as list markers. |
8288

8389
### Organizational soundness
8490

85-
```
86-
41. The numberings of ADRs within the ADR directory must start with either 0000 or
87-
0001 (a) and feature no skips (b).
88-
42. No 'foreign' files may be present inside ADR directory.
89-
43. No collisions of numberings between MADRs in the same folder.
90-
44. MADRs must follow the naming scheme: 'XXXX-brief-description.md'
91-
```
92-
The rules marked with * are rules for which checks are yet to be implemented.
93-
94-
See [here](https://github.com/adr/madr/blob/develop/template/adr-template.md) for the MADR template on which the rules are based.
91+
| ID | Description |
92+
|----------|--------------------------------------------------------------------------------------------------------------------------|
93+
| `MADR41` | The numbering of ADRs within the ADR directory must start with either `0000` or `0001` (`a`) and feature no skips (`b`). |
94+
| `MADR42` | No 'foreign' files may be present inside the ADR directory. |
95+
| `MADR43` | Numberings must not collide between MADRs in the same folder. |
96+
| `MADR44` | MADRs must follow the naming scheme `NNNN-brief-description.md`. |
9597

98+
The rules are based on the [MADR template](https://github.com/adr/madr/blob/develop/template/adr-template.md).

app/src/main/java/neutra1/linter/Main.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
name = "madrlint",
4242
description = "Lint MADR files",
4343
mixinStandardHelpOptions = true,
44-
customSynopsis = "madrlint [-hOqV] [-n <ruleNumber>[,ruleNumber...]>] [-o <outputFile>] [--output-format <format>] <madrFile>",
44+
customSynopsis = "madrlint [-hOqV] [-n <rule>[,rule...]] [-o <outputFile>] [--output-format <format>] <madrFile>",
4545
version="1.0.0"
4646
)
4747
public class Main implements Runnable {
@@ -58,7 +58,7 @@ public class Main implements Runnable {
5858
private boolean override;
5959
@Option(names = {"-q", "--quiet"}, description = "Information not relevant to the lint results will be suppressed.")
6060
boolean quietMode;
61-
@Option(names = {"-n", "--no-warn"}, description = "Disable warnings for certain rules. They can either be declared separately(e.g -n1 -n2) or chained together separated by comma(e.g -n1,2)", split = ",")
61+
@Option(names = {"-n", "--no-warn"}, description = "Disable warnings for certain rules, given as rule number or rule ID (e.g -n1 or -nMADR01). They can either be declared separately(e.g -n1 -n2) or chained together separated by comma(e.g -n1,2)", split = ",", converter = RuleIdConverter.class)
6262
private Set<Integer> disabledRules = new HashSet<>();
6363
@Option(names = {"--output-format"}, description = "Format of the diagnostics. Valid values: errorformat, github-actions. Defaults to errorformat.", converter = OutputFormatConverter.class)
6464
private OutputFormat outputFormat = OutputFormat.ERRORFORMAT;
@@ -135,6 +135,19 @@ public static void main(String[] args) {
135135
System.exit(exitCode);
136136
}
137137

138+
static class RuleIdConverter implements CommandLine.ITypeConverter<Integer> {
139+
@Override
140+
public Integer convert(String value) {
141+
String number = value.toUpperCase().startsWith("MADR") ? value.substring(4) : value;
142+
try {
143+
return Integer.parseInt(number);
144+
}
145+
catch (NumberFormatException e){
146+
throw new CommandLine.TypeConversionException("Invalid rule '" + value + "'. Expected a rule number (e.g. 1) or a rule ID (e.g. MADR01).");
147+
}
148+
}
149+
}
150+
138151
static class OutputFormatConverter implements CommandLine.ITypeConverter<OutputFormat> {
139152
@Override
140153
public OutputFormat convert(String value) {

0 commit comments

Comments
 (0)