• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / 4542

18 Apr 2025 08:41AM UTC coverage: 77.769% (-0.08%) from 77.848%
4542

push

github

adangel
.ci/tools/release-notes: use login name if no name is found

17611 of 23618 branches covered (74.57%)

Branch coverage included in aggregate %.

38580 of 48636 relevant lines covered (79.32%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.83
/pmd-core/src/main/java/net/sourceforge/pmd/renderers/internal/sarif/SarifLogBuilder.java
1
/*
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.renderers.internal.sarif;
6

7
import java.util.ArrayList;
8
import java.util.Arrays;
9
import java.util.Collections;
10
import java.util.HashSet;
11
import java.util.List;
12

13
import net.sourceforge.pmd.PMDVersion;
14
import net.sourceforge.pmd.lang.rule.RulePriority;
15
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ArtifactLocation;
16
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.AssociatedRule;
17
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Component;
18
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Exception;
19
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Invocation;
20
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Location;
21
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Message;
22
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.MultiformatMessage;
23
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.PhysicalLocation;
24
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.PropertyBag;
25
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Region;
26
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ReportingConfiguration;
27
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ReportingDescriptor;
28
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Result;
29
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Run;
30
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Tool;
31
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ToolConfigurationNotification;
32
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ToolExecutionNotification;
33
import net.sourceforge.pmd.reporting.Report;
34
import net.sourceforge.pmd.reporting.RuleViolation;
35

36
public class SarifLogBuilder {
1✔
37
    private final List<ReportingDescriptor> rules = new ArrayList<>();
1✔
38
    private final List<Result> results = new ArrayList<>();
1✔
39
    private final List<ToolConfigurationNotification> toolConfigurationNotifications = new ArrayList<>();
1✔
40
    private final List<ToolExecutionNotification> toolExecutionNotifications = new ArrayList<>();
1✔
41

42
    public static SarifLogBuilder sarifLogBuilder() {
43
        return new SarifLogBuilder();
1✔
44
    }
45

46
    public SarifLogBuilder add(RuleViolation violation) {
47
        final ReportingDescriptor ruleDescriptor = getReportingDescriptor(violation);
1✔
48
        int ruleIndex = rules.indexOf(ruleDescriptor);
1✔
49
        if (ruleIndex == -1) {
1✔
50
            rules.add(ruleDescriptor);
1✔
51
            ruleIndex = rules.size() - 1;
1✔
52
        }
53

54
        final Location location = getRuleViolationLocation(violation);
1✔
55
        final Result result = resultFrom(ruleDescriptor, ruleIndex, location, violation.getRule().getPriority());
1✔
56
        results.add(result);
1✔
57

58
        return this;
1✔
59
    }
60

61
    public SarifLogBuilder addRunTimeError(Report.ProcessingError error) {
62
        ArtifactLocation artifactLocation = ArtifactLocation.builder()
1✔
63
                .uri(error.getFileId().getUriString())
1✔
64
                .build();
1✔
65

66
        PhysicalLocation physicalLocation = PhysicalLocation.builder()
1✔
67
                .artifactLocation(artifactLocation)
1✔
68
                .build();
1✔
69

70
        Location location = Location
71
                .builder()
1✔
72
                .physicalLocation(physicalLocation)
1✔
73
                .build();
1✔
74

75
        Message message = Message.builder()
1✔
76
                .text(error.getMsg())
1✔
77
                .build();
1✔
78

79
        Exception exception = Exception.builder()
1✔
80
                .message(error.getDetail())
1✔
81
                .build();
1✔
82

83
        ToolExecutionNotification toolExecutionNotification = ToolExecutionNotification.builder()
1✔
84
                .locations(Collections.singletonList(location))
1✔
85
                .message(message)
1✔
86
                .exception(exception)
1✔
87
                .build();
1✔
88

89
        toolExecutionNotifications.add(toolExecutionNotification);
1✔
90

91
        return this;
1✔
92
    }
93

94
    public SarifLogBuilder addConfigurationError(Report.ConfigurationError error) {
95
        AssociatedRule associatedRule = AssociatedRule.builder()
1✔
96
                .id(error.rule().getName())
1✔
97
                .build();
1✔
98

99
        Message message = Message.builder().text(error.issue()).build();
1✔
100

101
        ToolConfigurationNotification toolConfigurationNotification = ToolConfigurationNotification.builder()
1✔
102
                .associatedRule(associatedRule)
1✔
103
                .message(message)
1✔
104
                .build();
1✔
105

106
        toolConfigurationNotifications.add(toolConfigurationNotification);
1✔
107

108
        return this;
1✔
109
    }
110

111
    public SarifLog build() {
112
        final Component driver = getDriverComponent().toBuilder().rules(rules).build();
1✔
113
        final Tool tool = Tool.builder().driver(driver).build();
1✔
114
        final Invocation invocation = Invocation.builder()
1✔
115
                .toolExecutionNotifications(toolExecutionNotifications)
1✔
116
                .toolConfigurationNotifications(toolConfigurationNotifications)
1✔
117
                .executionSuccessful(isExecutionSuccessful())
1✔
118
                .build();
1✔
119
        final Run run = Run.builder()
1✔
120
                .tool(tool)
1✔
121
                .results(results)
1✔
122
                .invocations(Collections.singletonList(invocation))
1✔
123
                .build();
1✔
124

125
        List<Run> runs = Collections.singletonList(run);
1✔
126

127
        return SarifLog.builder().runs(runs).build();
1✔
128
    }
129

130
    private boolean isExecutionSuccessful() {
131
        return toolExecutionNotifications.isEmpty() && toolConfigurationNotifications.isEmpty();
1✔
132
    }
133

134
    private Result resultFrom(ReportingDescriptor rule, Integer ruleIndex, Location location, RulePriority rulePriority) {
135
        final Result result = Result.builder()
1✔
136
                .ruleId(rule.getId())
1✔
137
                .ruleIndex(ruleIndex)
1✔
138
                .level(pmdPriorityToSarifSeverityLevel(rulePriority))
1✔
139
                .build();
1✔
140

141
        final Message message = Message.builder()
1✔
142
                .text(rule.getShortDescription().getText())
1✔
143
                .build();
1✔
144

145
        result.setMessage(message);
1✔
146
        result.setLocations(Collections.singletonList(location));
1✔
147

148
        return result;
1✔
149
    }
150

151
    private Location getRuleViolationLocation(RuleViolation rv) {
152
        ArtifactLocation artifactLocation = ArtifactLocation.builder()
1✔
153
                .uri(rv.getFileId().getUriString())
1✔
154
                .build();
1✔
155

156
        Region region = Region.builder()
1✔
157
            .startLine(rv.getBeginLine())
1✔
158
            .endLine(rv.getEndLine())
1✔
159
            .startColumn(rv.getBeginColumn())
1✔
160
            .endColumn(rv.getEndColumn())
1✔
161
            .build();
1✔
162

163
        PhysicalLocation physicalLocation = PhysicalLocation.builder()
1✔
164
                .artifactLocation(artifactLocation)
1✔
165
                .region(region)
1✔
166
                .build();
1✔
167

168
        return Location.builder()
1✔
169
            .physicalLocation(physicalLocation)
1✔
170
            .build();
1✔
171
    }
172

173
    private ReportingDescriptor getReportingDescriptor(RuleViolation rv) {
174
        return ReportingDescriptor.builder()
1✔
175
            .id(rv.getRule().getName())
1✔
176
            .shortDescription(new MultiformatMessage(rv.getDescription()))
1✔
177
            .fullDescription(new MultiformatMessage(rv.getRule().getDescription()))
1✔
178
            .helpUri(rv.getRule().getExternalInfoUrl())
1✔
179
            .help(new MultiformatMessage(rv.getRule().getDescription()))
1✔
180
            .properties(getRuleProperties(rv))
1✔
181
            .defaultConfiguration(getDefaultConfigForRuleViolation(rv))
1✔
182
            .build();
1✔
183
    }
184

185
    private ReportingConfiguration getDefaultConfigForRuleViolation(RuleViolation rv) {
186
        return ReportingConfiguration.builder()
1✔
187
                // get pmd level from rv and translate it to sarif level (for the config)
188
                .level(pmdPriorityToSarifSeverityLevel(rv.getRule().getPriority()))
1✔
189
                .build();
1✔
190
    }
191

192
    private PropertyBag getRuleProperties(RuleViolation rv) {
193
        return PropertyBag.builder()
1✔
194
                .ruleset(rv.getRule().getRuleSetName())
1✔
195
                .priority(rv.getRule().getPriority().getPriority())
1✔
196
                .tags(new HashSet<>(Arrays.asList(rv.getRule().getRuleSetName())))
1✔
197
                .build();
1✔
198
    }
199

200
    private Component getDriverComponent() {
201
        return Component.builder()
1✔
202
                .name("PMD")
1✔
203
                .version(PMDVersion.VERSION)
1✔
204
                .informationUri("https://docs.pmd-code.org/latest/")
1✔
205
                .build();
1✔
206
    }
207

208

209
    /**
210
     * Converts PMD's rule priority into the corresponding Sarif severity level.
211
     * @param rulePriority of a rule violation.
212
     * @return sarif's severity level.
213
     * @see net.sourceforge.pmd.lang.rule.RulePriority
214
     */
215
    private String pmdPriorityToSarifSeverityLevel(RulePriority rulePriority) {
216
        switch (rulePriority) {
1!
217
        case HIGH:
218
        case MEDIUM_HIGH:
219
            return "error";
1✔
220
        case MEDIUM:
221
            return "warning";
×
222
        case MEDIUM_LOW:
223
        case LOW:
224
            return "note";
1✔
225
        default:
226
            return "none"; // should not occur
×
227
        }
228
    }
229
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc