]> source.dussan.org Git - sonarqube.git/blob
2e0e7f9b2236c08111d76a65b69ad55221a989f4
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.pushapi.issues;
21
22 import com.google.gson.Gson;
23 import com.google.gson.GsonBuilder;
24 import java.util.Collection;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Set;
28 import java.util.stream.Collectors;
29 import javax.annotation.CheckForNull;
30 import javax.annotation.Nullable;
31 import org.sonar.api.server.ServerSide;
32 import org.sonar.core.issue.DefaultIssue;
33 import org.sonar.core.issue.FieldDiffs.Diff;
34 import org.sonar.core.util.issue.Issue;
35 import org.sonar.core.util.issue.IssueChangedEvent;
36 import org.sonar.db.DbClient;
37 import org.sonar.db.DbSession;
38 import org.sonar.db.component.BranchDto;
39 import org.sonar.db.component.ComponentDto;
40 import org.sonar.db.pushevent.PushEventDto;
41
42 import static java.nio.charset.StandardCharsets.UTF_8;
43 import static org.elasticsearch.common.Strings.isNullOrEmpty;
44 import static org.sonar.api.issue.DefaultTransitions.CONFIRM;
45 import static org.sonar.api.issue.DefaultTransitions.FALSE_POSITIVE;
46 import static org.sonar.api.issue.DefaultTransitions.UNCONFIRM;
47 import static org.sonar.api.issue.DefaultTransitions.WONT_FIX;
48 import static org.sonar.db.component.BranchType.BRANCH;
49
50 @ServerSide
51 public class IssueChangeEventServiceImpl implements IssueChangeEventService {
52   private static final Gson GSON = new GsonBuilder().create();
53
54   private static final String EVENT_NAME = "IssueChanged";
55   private static final String FALSE_POSITIVE_KEY = "FALSE-POSITIVE";
56   private static final String WONT_FIX_KEY = "WONTFIX";
57
58   private static final String RESOLUTION_KEY = "resolution";
59   private static final String SEVERITY_KEY = "severity";
60   private static final String TYPE_KEY = "type";
61
62   private final DbClient dbClient;
63
64   public IssueChangeEventServiceImpl(DbClient dbClient) {
65     this.dbClient = dbClient;
66   }
67
68   @Override
69   public void distributeIssueChangeEvent(DefaultIssue issue, @Nullable String severity, @Nullable String type, @Nullable String transition,
70     BranchDto branch, String projectKey) {
71     Issue changedIssue = new Issue(issue.key(), branch.getKey());
72
73     Boolean resolved = isResolved(transition);
74
75     if (severity == null && type == null && resolved == null) {
76       return;
77     }
78
79     IssueChangedEvent event = new IssueChangedEvent(projectKey, new Issue[]{changedIssue},
80       resolved, severity, type);
81
82     persistEvent(event, issue.projectUuid());
83   }
84
85   @Override
86   public void distributeIssueChangeEvent(Collection<DefaultIssue> issues, Map<String, ComponentDto> projectsByUuid,
87     Map<String, BranchDto> branchesByProjectUuid) {
88
89     for (Entry<String, ComponentDto> entry : projectsByUuid.entrySet()) {
90       String projectKey = entry.getValue().getKey();
91
92       Set<DefaultIssue> issuesInProject = issues
93         .stream()
94         .filter(i -> i.projectUuid().equals(entry.getKey()))
95         .collect(Collectors.toSet());
96
97       Issue[] issueChanges = issuesInProject.stream()
98         .filter(i -> branchesByProjectUuid.get(i.projectUuid()).getBranchType().equals(BRANCH))
99         .map(i -> new Issue(i.key(), branchesByProjectUuid.get(i.projectUuid()).getKey()))
100         .toArray(Issue[]::new);
101
102       if (issueChanges.length == 0) {
103         continue;
104       }
105
106       IssueChangedEvent event = getIssueChangedEvent(projectKey, issuesInProject, issueChanges);
107
108       if (event != null) {
109         persistEvent(event, entry.getValue().projectUuid());
110       }
111     }
112   }
113
114   @CheckForNull
115   private static IssueChangedEvent getIssueChangedEvent(String projectKey, Set<DefaultIssue> issuesInProject, Issue[] issueChanges) {
116     DefaultIssue firstIssue = issuesInProject.stream().iterator().next();
117
118     if (firstIssue.currentChange() == null) {
119       return null;
120     }
121
122     Boolean resolved = null;
123     String severity = null;
124     String type = null;
125
126     boolean isRelevantEvent = false;
127     Map<String, Diff> diffs = firstIssue.currentChange().diffs();
128
129     if (diffs.containsKey(RESOLUTION_KEY)) {
130       resolved = diffs.get(RESOLUTION_KEY).newValue() == null ? false : isResolved(diffs.get(RESOLUTION_KEY).newValue().toString());
131       isRelevantEvent = true;
132     }
133
134     if (diffs.containsKey(SEVERITY_KEY)) {
135       severity = diffs.get(SEVERITY_KEY).newValue() == null ? null : diffs.get(SEVERITY_KEY).newValue().toString();
136       isRelevantEvent = true;
137     }
138
139     if (diffs.containsKey(TYPE_KEY)) {
140       type = diffs.get(TYPE_KEY).newValue() == null ? null : diffs.get(TYPE_KEY).newValue().toString();
141       isRelevantEvent = true;
142     }
143
144     if (!isRelevantEvent) {
145       return null;
146     }
147
148     return new IssueChangedEvent(projectKey, issueChanges, resolved, severity, type);
149   }
150
151   @CheckForNull
152   private static Boolean isResolved(@Nullable String transitionOrStatus) {
153     if (isNullOrEmpty(transitionOrStatus)) {
154       return null;
155     }
156
157     if (transitionOrStatus.equals(CONFIRM) || transitionOrStatus.equals(UNCONFIRM)) {
158       return null;
159     }
160
161     return transitionOrStatus.equals(WONT_FIX) || transitionOrStatus.equals(FALSE_POSITIVE) ||
162       transitionOrStatus.equals(FALSE_POSITIVE_KEY) || transitionOrStatus.equals(WONT_FIX_KEY);
163   }
164
165   private void persistEvent(IssueChangedEvent event, String entry) {
166     try (DbSession dbSession = dbClient.openSession(false)) {
167       PushEventDto eventDto = new PushEventDto()
168         .setName(EVENT_NAME)
169         .setProjectUuid(entry)
170         .setPayload(serializeIssueToPushEvent(event));
171       dbClient.pushEventDao().insert(dbSession, eventDto);
172       dbSession.commit();
173     }
174   }
175
176   private static byte[] serializeIssueToPushEvent(IssueChangedEvent event) {
177     return GSON.toJson(event).getBytes(UTF_8);
178   }
179 }