Skip to content

Commit fcc7d53

Browse files
kopporclaude
andauthored
Add --output-format option with errorformat and github-actions (#7)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent f47090c commit fcc7d53

5 files changed

Lines changed: 71 additions & 14 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ madrlint <madrFile>
4141
not exist, it will be created.
4242
-O, --override If the given output file already exists, it will be
4343
overwritten.
44+
--output-format <format> Format of the diagnostics. Valid values: errorformat,
45+
github-actions. Defaults to errorformat.
4446
-q, --quiet Information not relevant to the lint results will be
4547
suppressed.
4648
```

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import neutra1.linter.core.Reporter;
1414
import neutra1.linter.helper.IgnoreFileHandler;
1515
import neutra1.linter.helper.LintContext;
16+
import neutra1.linter.models.enums.OutputFormat;
1617
import neutra1.linter.rules.AbstractRule;
1718
import neutra1.linter.rules.IFileRule;
1819
import neutra1.linter.rules.impl.file.Rule01;
@@ -40,7 +41,7 @@
4041
name = "madrlint",
4142
description = "Lint MADR files",
4243
mixinStandardHelpOptions = true,
43-
customSynopsis = "madrlint [-hOqV] [-n <ruleNumber>[,ruleNumber...]>] [-o <outputFile>] <madrFile>",
44+
customSynopsis = "madrlint [-hOqV] [-n <ruleNumber>[,ruleNumber...]>] [-o <outputFile>] [--output-format <format>] <madrFile>",
4445
version="1.0.0"
4546
)
4647
public class Main implements Runnable {
@@ -59,6 +60,8 @@ public class Main implements Runnable {
5960
boolean quietMode;
6061
@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 = ",")
6162
private Set<Integer> disabledRules = new HashSet<>();
63+
@Option(names = {"--output-format"}, description = "Format of the diagnostics. Valid values: errorformat, github-actions. Defaults to errorformat.", converter = OutputFormatConverter.class)
64+
private OutputFormat outputFormat = OutputFormat.ERRORFORMAT;
6265
@Option(names = {"-r", "--root"}, description = "Set the root directory of the project. Defaults to current working directory if not specified.")
6366
private String root;
6467
@Override
@@ -116,11 +119,11 @@ else if (Files.isDirectory(Paths.get(internalPath))){
116119
int disabledRuleCount = disabledRules.size();
117120
int totalRuleCount = rules.size();
118121
int disabledRelevantRuleCount = rules.stream().filter(rule -> disabledRules.contains(rule.getRuleNumber())).toList().size();
119-
if (outputFile == null){
120-
reporter.outputDiagnostics(disabledRuleCount, disabledRelevantRuleCount, totalRuleCount, quietMode);
121-
}
122+
if (outputFile == null){
123+
reporter.outputDiagnostics(disabledRuleCount, disabledRelevantRuleCount, totalRuleCount, quietMode, outputFormat);
124+
}
122125
else {
123-
reporter.outputDiagnostics(outputFile, disabledRuleCount, disabledRelevantRuleCount, totalRuleCount, override, quietMode);
126+
reporter.outputDiagnostics(outputFile, disabledRuleCount, disabledRelevantRuleCount, totalRuleCount, override, quietMode, outputFormat);
124127
}
125128
}
126129

@@ -132,6 +135,18 @@ public static void main(String[] args) {
132135
System.exit(exitCode);
133136
}
134137

138+
static class OutputFormatConverter implements CommandLine.ITypeConverter<OutputFormat> {
139+
@Override
140+
public OutputFormat convert(String value) {
141+
try {
142+
return OutputFormat.fromLabel(value);
143+
}
144+
catch (IllegalArgumentException e){
145+
throw new CommandLine.TypeConversionException(e.getMessage());
146+
}
147+
}
148+
}
149+
135150
private String readFile(String filePath) throws IOException{
136151
Path path = Paths.get(filePath);
137152
if (!path.isAbsolute()){

app/src/main/java/neutra1/linter/core/Reporter.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.List;
44

55
import neutra1.linter.helper.LintContext;
6+
import neutra1.linter.models.enums.OutputFormat;
67
import neutra1.linter.models.records.Violation;
78

89
import java.io.IOException;
@@ -33,16 +34,16 @@ public void report(Violation violation) {
3334
violationList.add(violation);
3435
}
3536

36-
public void outputDiagnostics(int disabledRuleCount, int disabledRelevantRuleCount, int totalRuleCount, boolean quietMode) {
37-
StringBuilder diagnosis = getDiagnosis();
37+
public void outputDiagnostics(int disabledRuleCount, int disabledRelevantRuleCount, int totalRuleCount, boolean quietMode, OutputFormat outputFormat) {
38+
StringBuilder diagnosis = getDiagnosis(outputFormat);
3839
System.out.println(diagnosis.toString());
3940
if (!quietMode){
4041
printInformation(totalRuleCount, disabledRelevantRuleCount, disabledRuleCount);
4142
}
4243
}
4344

44-
public void outputDiagnostics(String outputFile, int disabledRuleCount, int disabledRelevantRuleCount, int totalRuleCount, boolean override, boolean quietMode){
45-
StringBuilder diagnosis = getDiagnosis();
45+
public void outputDiagnostics(String outputFile, int disabledRuleCount, int disabledRelevantRuleCount, int totalRuleCount, boolean override, boolean quietMode, OutputFormat outputFormat){
46+
StringBuilder diagnosis = getDiagnosis(outputFormat);
4647
Path currentDir = Paths.get(System.getProperty("user.dir"));
4748
Path outputPath = Paths.get(outputFile);
4849
if (!outputPath.isAbsolute()){
@@ -60,27 +61,39 @@ public void outputDiagnostics(String outputFile, int disabledRuleCount, int disa
6061
System.out.println("WARNING: writing to " + outputPath.toString() + " not successful." + "\n" +
6162
"Output defaults to stdout. You can add flag \"--override\" to overwrite it.\n" +
6263
"If this message still shows up after adding that flag, check path validity and/or write access.\n");
63-
outputDiagnostics(disabledRuleCount, disabledRelevantRuleCount, totalRuleCount, quietMode);
64+
outputDiagnostics(disabledRuleCount, disabledRelevantRuleCount, totalRuleCount, quietMode, outputFormat);
6465
}
6566
if (!quietMode){
6667
printInformation(totalRuleCount, disabledRelevantRuleCount, disabledRuleCount);
6768
}
6869
}
6970

70-
private StringBuilder getDiagnosis() {
71+
private StringBuilder getDiagnosis(OutputFormat outputFormat) {
7172
StringBuilder diagnosis = new StringBuilder();
7273
violationList.sort(Comparator.comparingInt(Violation::lineNumber));
7374
for (Violation v : violationList) {
74-
if (v.representativeMadr().isEmpty()){
75-
diagnosis.append(LintContext.USER_PATH + ":" + v.lineNumber() + " " + "[" + v.ruleId() + "]" + " " + v.description() + "\n");
75+
String file = v.representativeMadr().orElse(LintContext.USER_PATH);
76+
if (outputFormat == OutputFormat.GITHUB_ACTIONS){
77+
diagnosis.append("::error file=" + escapeGithubProperty(file) + ",line=" + v.lineNumber() +
78+
",title=" + escapeGithubProperty(v.ruleId()) + "::" + escapeGithubData(v.description()) + "\n");
7679
}
7780
else {
78-
diagnosis.append(v.representativeMadr().get() + ":" + v.lineNumber() + " " + "[" + v.ruleId() + "]" + " " + v.description() + "\n");
81+
diagnosis.append(file + ":" + v.lineNumber() + " " + "[" + v.ruleId() + "]" + " " + v.description() + "\n");
7982
}
8083
}
8184
return diagnosis;
8285
}
8386

87+
// Escaping mandated by GitHub Actions workflow commands, see
88+
// https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands
89+
private String escapeGithubData(String value){
90+
return value.replace("%", "%25").replace("\r", "%0D").replace("\n", "%0A");
91+
}
92+
93+
private String escapeGithubProperty(String value){
94+
return escapeGithubData(value).replace(":", "%3A").replace(",", "%2C");
95+
}
96+
8497
private void printInformation(int totalRuleCount, int disabledRelevantRuleCount, int disabledRuleCount){
8598
StringBuilder info = new StringBuilder();
8699
int violationCount = violationList.size();
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package neutra1.linter.models.enums;
2+
3+
public enum OutputFormat {
4+
ERRORFORMAT("errorformat"),
5+
GITHUB_ACTIONS("github-actions");
6+
7+
private final String label;
8+
9+
OutputFormat(String label) {
10+
this.label = label;
11+
}
12+
13+
@Override
14+
public String toString() {
15+
return label;
16+
}
17+
18+
public static OutputFormat fromLabel(String label) {
19+
for (OutputFormat format : values()) {
20+
if (format.label.equalsIgnoreCase(label)) {
21+
return format;
22+
}
23+
}
24+
throw new IllegalArgumentException("expected one of: " + ERRORFORMAT + ", " + GITHUB_ACTIONS);
25+
}
26+
}

madrlint.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//SOURCES app/src/main/java/neutra1/linter/models/enums/LinkType.java
1111
//SOURCES app/src/main/java/neutra1/linter/models/enums/MandatorySection.java
1212
//SOURCES app/src/main/java/neutra1/linter/models/enums/OptionalSection.java
13+
//SOURCES app/src/main/java/neutra1/linter/models/enums/OutputFormat.java
1314
//SOURCES app/src/main/java/neutra1/linter/models/enums/ResourceType.java
1415
//SOURCES app/src/main/java/neutra1/linter/models/records/BulletListItemInfo.java
1516
//SOURCES app/src/main/java/neutra1/linter/models/records/HeadingInfo.java

0 commit comments

Comments
 (0)