-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
IssueFieldsSetter.java
341 lines (307 loc) · 12.3 KB
/
IssueFieldsSetter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.issue;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ServerSide;
import org.sonar.api.server.rule.RuleTagFormat;
import org.sonar.api.user.User;
import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.DefaultIssueComment;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.core.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
* Updates issue fields and chooses if changes must be kept in history.
*/
@ServerSide
@ComputeEngineSide
public class IssueFieldsSetter {
public static final String UNUSED = "";
public static final String SEVERITY = "severity";
public static final String TYPE = "type";
public static final String ASSIGNEE = "assignee";
public static final String RESOLUTION = "resolution";
public static final String STATUS = "status";
public static final String AUTHOR = "author";
public static final String FILE = "file";
/**
* It should be renamed to 'effort', but it hasn't been done to prevent a massive update in database
*/
public static final String TECHNICAL_DEBT = "technicalDebt";
public static final String TAGS = "tags";
private static final Joiner CHANGELOG_TAG_JOINER = Joiner.on(" ").skipNulls();
public boolean setType(DefaultIssue issue, RuleType type, IssueChangeContext context) {
if (!Objects.equals(type, issue.type())) {
issue.setFieldChange(context, TYPE, issue.type(), type);
issue.setType(type);
issue.setUpdateDate(context.date());
issue.setChanged(true);
return true;
}
return false;
}
public boolean setSeverity(DefaultIssue issue, String severity, IssueChangeContext context) {
if (issue.manualSeverity()) {
throw new IllegalStateException("Severity can't be changed");
}
if (!Objects.equals(severity, issue.severity())) {
issue.setFieldChange(context, SEVERITY, issue.severity(), severity);
issue.setSeverity(severity);
issue.setUpdateDate(context.date());
issue.setChanged(true);
return true;
}
return false;
}
public boolean setPastSeverity(DefaultIssue issue, @Nullable String previousSeverity, IssueChangeContext context) {
String currentSeverity = issue.severity();
issue.setSeverity(previousSeverity);
return setSeverity(issue, currentSeverity, context);
}
public boolean setManualSeverity(DefaultIssue issue, String severity, IssueChangeContext context) {
if (!issue.manualSeverity() || !Objects.equals(severity, issue.severity())) {
issue.setFieldChange(context, SEVERITY, issue.severity(), severity);
issue.setSeverity(severity);
issue.setManualSeverity(true);
issue.setUpdateDate(context.date());
issue.setChanged(true);
issue.setSendNotifications(true);
return true;
}
return false;
}
public boolean assign(DefaultIssue issue, @Nullable User user, IssueChangeContext context) {
String sanitizedAssignee = null;
if (user != null) {
sanitizedAssignee = StringUtils.defaultIfBlank(user.login(), null);
}
if (!Objects.equals(sanitizedAssignee, issue.assignee())) {
String newAssigneeName = user != null ? user.name() : null;
issue.setFieldChange(context, ASSIGNEE, UNUSED, newAssigneeName);
issue.setAssignee(sanitizedAssignee);
issue.setUpdateDate(context.date());
issue.setChanged(true);
issue.setSendNotifications(true);
return true;
}
return false;
}
/**
* Used to set the assignee when it was null
*/
public boolean setNewAssignee(DefaultIssue issue, @Nullable String newAssignee, IssueChangeContext context) {
if (newAssignee == null) {
return false;
}
checkState(issue.assignee() == null, "It's not possible to update the assignee with this method, please use assign()");
issue.setFieldChange(context, ASSIGNEE, UNUSED, newAssignee);
issue.setAssignee(newAssignee);
issue.setUpdateDate(context.date());
issue.setChanged(true);
issue.setSendNotifications(true);
return true;
}
public boolean setLine(DefaultIssue issue, @Nullable Integer line) {
if (!Objects.equals(line, issue.line())) {
issue.setLine(line);
issue.setChanged(true);
return true;
}
return false;
}
public boolean setPastLine(DefaultIssue issue, @Nullable Integer previousLine) {
Integer currentLine = issue.line();
issue.setLine(previousLine);
return setLine(issue, currentLine);
}
public boolean setLocations(DefaultIssue issue, @Nullable Object locations) {
if (!Objects.equals(locations, issue.getLocations())) {
issue.setLocations(locations);
issue.setChanged(true);
return true;
}
return false;
}
public boolean setPastLocations(DefaultIssue issue, @Nullable Object previousLocations) {
Object currentLocations = issue.getLocations();
issue.setLocations(previousLocations);
return setLocations(issue, currentLocations);
}
public boolean setResolution(DefaultIssue issue, @Nullable String resolution, IssueChangeContext context) {
if (!Objects.equals(resolution, issue.resolution())) {
issue.setFieldChange(context, RESOLUTION, issue.resolution(), resolution);
issue.setResolution(resolution);
issue.setUpdateDate(context.date());
issue.setChanged(true);
issue.setSendNotifications(true);
return true;
}
return false;
}
public boolean setStatus(DefaultIssue issue, String status, IssueChangeContext context) {
if (!Objects.equals(status, issue.status())) {
issue.setFieldChange(context, STATUS, issue.status(), status);
issue.setStatus(status);
issue.setUpdateDate(context.date());
issue.setChanged(true);
issue.setSendNotifications(true);
return true;
}
return false;
}
public boolean setAuthorLogin(DefaultIssue issue, @Nullable String authorLogin, IssueChangeContext context) {
if (!Objects.equals(authorLogin, issue.authorLogin())) {
issue.setFieldChange(context, AUTHOR, issue.authorLogin(), authorLogin);
issue.setAuthorLogin(authorLogin);
issue.setUpdateDate(context.date());
issue.setChanged(true);
// do not send notifications to prevent spam when installing the developer cockpit plugin
return true;
}
return false;
}
/**
* Used to set the author when it was null
*/
public boolean setNewAuthor(DefaultIssue issue, @Nullable String newAuthorLogin, IssueChangeContext context) {
if (isNullOrEmpty(newAuthorLogin)) {
return false;
}
checkState(issue.authorLogin() == null, "It's not possible to update the author with this method, please use setAuthorLogin()");
issue.setFieldChange(context, AUTHOR, null, newAuthorLogin);
issue.setAuthorLogin(newAuthorLogin);
issue.setUpdateDate(context.date());
issue.setChanged(true);
// do not send notifications to prevent spam when installing the developer cockpit plugin
return true;
}
public boolean setMessage(DefaultIssue issue, @Nullable String s, IssueChangeContext context) {
if (!Objects.equals(s, issue.message())) {
issue.setMessage(s);
issue.setUpdateDate(context.date());
issue.setChanged(true);
return true;
}
return false;
}
public boolean setPastMessage(DefaultIssue issue, @Nullable String previousMessage, IssueChangeContext context) {
String currentMessage = issue.message();
issue.setMessage(previousMessage);
return setMessage(issue, currentMessage, context);
}
public void addComment(DefaultIssue issue, String text, IssueChangeContext context) {
issue.addComment(DefaultIssueComment.create(issue.key(), context.login(), text));
issue.setUpdateDate(context.date());
issue.setChanged(true);
}
public void setCloseDate(DefaultIssue issue, @Nullable Date d, IssueChangeContext context) {
Date dateWithoutMilliseconds = d == null ? null : Date.from(d.toInstant().truncatedTo(ChronoUnit.SECONDS));
if (!Objects.equals(dateWithoutMilliseconds, issue.closeDate())) {
issue.setCloseDate(d);
issue.setUpdateDate(context.date());
issue.setChanged(true);
}
}
public boolean setGap(DefaultIssue issue, @Nullable Double d, IssueChangeContext context) {
if (!Objects.equals(d, issue.gap())) {
issue.setGap(d);
issue.setUpdateDate(context.date());
issue.setChanged(true);
// Do not send notifications to prevent spam when installing the SQALE plugin,
// and do not complete the changelog (for the moment)
return true;
}
return false;
}
public boolean setPastGap(DefaultIssue issue, @Nullable Double previousGap, IssueChangeContext context) {
Double currentGap = issue.gap();
issue.setGap(previousGap);
return setGap(issue, currentGap, context);
}
public boolean setEffort(DefaultIssue issue, @Nullable Duration value, IssueChangeContext context) {
Duration oldValue = issue.effort();
if (!Objects.equals(value, oldValue)) {
issue.setEffort(value != null ? value : null);
issue.setFieldChange(context, TECHNICAL_DEBT, oldValue != null ? oldValue.toMinutes() : null, value != null ? value.toMinutes() : null);
issue.setUpdateDate(context.date());
issue.setChanged(true);
return true;
}
return false;
}
public boolean setPastEffort(DefaultIssue issue, @Nullable Duration previousEffort, IssueChangeContext context) {
Duration currentEffort = issue.effort();
issue.setEffort(previousEffort);
return setEffort(issue, currentEffort, context);
}
public boolean setAttribute(DefaultIssue issue, String key, @Nullable String value, IssueChangeContext context) {
String oldValue = issue.attribute(key);
if (!Objects.equals(oldValue, value)) {
issue.setFieldChange(context, key, oldValue, value);
issue.setAttribute(key, value);
issue.setUpdateDate(context.date());
issue.setChanged(true);
return true;
}
return false;
}
public boolean setTags(DefaultIssue issue, Collection<String> tags, IssueChangeContext context) {
Set<String> newTags = tags.stream()
.filter(Objects::nonNull)
.filter(tag -> !tag.isEmpty())
.map(tag -> RuleTagFormat.validate(tag.toLowerCase(Locale.ENGLISH)))
.collect(Collectors.toSet());
Set<String> oldTags = Sets.newHashSet(issue.tags());
if (!oldTags.equals(newTags)) {
issue.setFieldChange(context, TAGS,
oldTags.isEmpty() ? null : CHANGELOG_TAG_JOINER.join(oldTags),
newTags.isEmpty() ? null : CHANGELOG_TAG_JOINER.join(newTags));
issue.setTags(newTags);
issue.setUpdateDate(context.date());
issue.setChanged(true);
issue.setSendNotifications(true);
return true;
}
return false;
}
public boolean setIssueMoved(DefaultIssue issue, String newComponentUuid, IssueChangeContext context) {
if (!Objects.equals(newComponentUuid, issue.componentUuid())) {
issue.setFieldChange(context, FILE, issue.componentUuid(), newComponentUuid);
issue.setComponentUuid(newComponentUuid);
issue.setUpdateDate(context.date());
issue.setChanged(true);
return true;
}
return false;
}
}