]> source.dussan.org Git - sonarqube.git/blob
8c8f367a88b49c7f7048e5b967e9e3159be5350b
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 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.computation.task.projectanalysis.api.posttask;
21
22 import java.util.Collection;
23 import java.util.Date;
24 import java.util.Map;
25 import java.util.Optional;
26 import java.util.Set;
27 import java.util.stream.Collectors;
28 import javax.annotation.CheckForNull;
29 import javax.annotation.Nullable;
30 import org.sonar.api.ce.posttask.Analysis;
31 import org.sonar.api.ce.posttask.Branch;
32 import org.sonar.api.ce.posttask.CeTask;
33 import org.sonar.api.ce.posttask.PostProjectAnalysisTask;
34 import org.sonar.api.ce.posttask.Project;
35 import org.sonar.api.ce.posttask.QualityGate;
36 import org.sonar.api.ce.posttask.ScannerContext;
37 import org.sonar.api.utils.System2;
38 import org.sonar.api.utils.log.Logger;
39 import org.sonar.api.utils.log.Loggers;
40 import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder;
41 import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader;
42 import org.sonar.server.computation.task.projectanalysis.qualitygate.Condition;
43 import org.sonar.server.computation.task.projectanalysis.qualitygate.ConditionStatus;
44 import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateHolder;
45 import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateStatus;
46 import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateStatusHolder;
47 import org.sonar.server.computation.task.step.ComputationStepExecutor;
48
49 import static java.lang.String.format;
50 import static java.util.Objects.requireNonNull;
51 import static java.util.Optional.empty;
52 import static java.util.Optional.of;
53 import static java.util.Optional.ofNullable;
54 import static org.sonar.api.ce.posttask.CeTask.Status.FAILED;
55 import static org.sonar.api.ce.posttask.CeTask.Status.SUCCESS;
56
57 /**
58  * Responsible for calling {@link PostProjectAnalysisTask} implementations (if any).
59  */
60 public class PostProjectAnalysisTasksExecutor implements ComputationStepExecutor.Listener {
61   private static final PostProjectAnalysisTask[] NO_POST_PROJECT_ANALYSIS_TASKS = new PostProjectAnalysisTask[0];
62
63   private static final Logger LOG = Loggers.get(PostProjectAnalysisTasksExecutor.class);
64
65   private final org.sonar.ce.queue.CeTask ceTask;
66   private final AnalysisMetadataHolder analysisMetadataHolder;
67   private final QualityGateHolder qualityGateHolder;
68   private final QualityGateStatusHolder qualityGateStatusHolder;
69   private final PostProjectAnalysisTask[] postProjectAnalysisTasks;
70   private final BatchReportReader reportReader;
71   private final System2 system2;
72
73   /**
74    * Constructor used by Pico when there is no {@link PostProjectAnalysisTask} in the container.
75    */
76   public PostProjectAnalysisTasksExecutor(org.sonar.ce.queue.CeTask ceTask,
77     AnalysisMetadataHolder analysisMetadataHolder,
78     QualityGateHolder qualityGateHolder, QualityGateStatusHolder qualityGateStatusHolder,
79     BatchReportReader reportReader, System2 system2) {
80     this(ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader, system2, null);
81   }
82
83   public PostProjectAnalysisTasksExecutor(org.sonar.ce.queue.CeTask ceTask,
84     AnalysisMetadataHolder analysisMetadataHolder,
85     QualityGateHolder qualityGateHolder, QualityGateStatusHolder qualityGateStatusHolder,
86     BatchReportReader reportReader, System2 system2,
87     @Nullable PostProjectAnalysisTask[] postProjectAnalysisTasks) {
88     this.analysisMetadataHolder = analysisMetadataHolder;
89     this.qualityGateHolder = qualityGateHolder;
90     this.qualityGateStatusHolder = qualityGateStatusHolder;
91     this.ceTask = ceTask;
92     this.reportReader = reportReader;
93     this.postProjectAnalysisTasks = postProjectAnalysisTasks == null ? NO_POST_PROJECT_ANALYSIS_TASKS : postProjectAnalysisTasks;
94     this.system2 = system2;
95   }
96
97   @Override
98   public void finished(boolean allStepsExecuted) {
99     if (postProjectAnalysisTasks.length == 0) {
100       return;
101     }
102
103     ProjectAnalysisImpl projectAnalysis = createProjectAnalysis(allStepsExecuted ? SUCCESS : FAILED);
104     for (PostProjectAnalysisTask postProjectAnalysisTask : postProjectAnalysisTasks) {
105       executeTask(projectAnalysis, postProjectAnalysisTask);
106     }
107   }
108
109   private static void executeTask(ProjectAnalysisImpl projectAnalysis, PostProjectAnalysisTask postProjectAnalysisTask) {
110     try {
111       postProjectAnalysisTask.finished(projectAnalysis);
112     } catch (Exception e) {
113       LOG.error("Execution of task " + postProjectAnalysisTask.getClass() + " failed", e);
114     }
115   }
116
117   private ProjectAnalysisImpl createProjectAnalysis(CeTask.Status status) {
118     return new ProjectAnalysisImpl(
119       new CeTaskImpl(this.ceTask.getUuid(), status),
120       createProject(this.ceTask),
121       getAnalysis().orElse(null),
122       getAnalysis().map(a -> a.getDate().getTime()).orElse(system2.now()),
123       ScannerContextImpl.from(reportReader.readContextProperties()),
124       status == SUCCESS ? createQualityGate() : null,
125       createBranch());
126   }
127
128   private Optional<Analysis> getAnalysis() {
129     Long analysisDate = getAnalysisDate();
130
131     if (analysisDate != null) {
132       return of(new AnalysisImpl(analysisMetadataHolder.getUuid(), analysisDate));
133     } else {
134       return empty();
135     }
136   }
137
138   private static Project createProject(org.sonar.ce.queue.CeTask ceTask) {
139     return new ProjectImpl(
140       ceTask.getComponentUuid(),
141       ceTask.getComponentKey(),
142       ceTask.getComponentName());
143   }
144
145   @CheckForNull
146   private Long getAnalysisDate() {
147     if (this.analysisMetadataHolder.hasAnalysisDateBeenSet()) {
148       return this.analysisMetadataHolder.getAnalysisDate();
149     }
150     return null;
151   }
152
153   @CheckForNull
154   private QualityGateImpl createQualityGate() {
155     com.google.common.base.Optional<org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGate> qualityGateOptional = this.qualityGateHolder.getQualityGate();
156     if (qualityGateOptional.isPresent()) {
157       org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGate qualityGate = qualityGateOptional.get();
158
159       return new QualityGateImpl(
160         String.valueOf(qualityGate.getId()),
161         qualityGate.getName(),
162         convert(qualityGateStatusHolder.getStatus()),
163         convert(qualityGate.getConditions(), qualityGateStatusHolder.getStatusPerConditions()));
164     }
165     return null;
166   }
167
168   @CheckForNull
169   private BranchImpl createBranch() {
170     Optional<org.sonar.server.computation.task.projectanalysis.analysis.Branch> analysisBranchOpt = analysisMetadataHolder.getBranch();
171     if (analysisBranchOpt.isPresent() && !analysisBranchOpt.get().isLegacyFeature()) {
172       org.sonar.server.computation.task.projectanalysis.analysis.Branch branch = analysisBranchOpt.get();
173       return new BranchImpl(branch.isMain(), branch.getName(), Branch.Type.valueOf(branch.getType().name()));
174     }
175     return null;
176   }
177
178   private static QualityGate.Status convert(QualityGateStatus status) {
179     switch (status) {
180       case OK:
181         return QualityGate.Status.OK;
182       case WARN:
183         return QualityGate.Status.WARN;
184       case ERROR:
185         return QualityGate.Status.ERROR;
186       default:
187         throw new IllegalArgumentException(format(
188           "Unsupported value '%s' of QualityGateStatus can not be converted to QualityGate.Status",
189           status));
190     }
191   }
192
193   private static Collection<QualityGate.Condition> convert(Set<Condition> conditions, Map<Condition, ConditionStatus> statusPerConditions) {
194     return conditions.stream()
195       .map(new ConditionToCondition(statusPerConditions)::apply).collect(Collectors.toList());
196   }
197
198   private static class ProjectAnalysisImpl implements PostProjectAnalysisTask.ProjectAnalysis {
199     private final CeTask ceTask;
200     private final Project project;
201     private final long date;
202     private final ScannerContext scannerContext;
203     @Nullable
204     private final QualityGate qualityGate;
205     @Nullable
206     private final Branch branch;
207     @Nullable
208     private final Analysis analysis;
209
210     private ProjectAnalysisImpl(CeTask ceTask, Project project,
211       @Nullable Analysis analysis, long date,
212       ScannerContext scannerContext, @Nullable QualityGate qualityGate, @Nullable Branch branch) {
213       this.ceTask = requireNonNull(ceTask, "ceTask can not be null");
214       this.project = requireNonNull(project, "project can not be null");
215       this.analysis = analysis;
216       this.date = date;
217       this.scannerContext = requireNonNull(scannerContext, "scannerContext can not be null");
218       this.qualityGate = qualityGate;
219       this.branch = branch;
220     }
221
222     @Override
223     public CeTask getCeTask() {
224       return ceTask;
225     }
226
227     @Override
228     public Project getProject() {
229       return project;
230     }
231
232     @Override
233     public Optional<Branch> getBranch() {
234       return ofNullable(branch);
235     }
236
237     @Override
238     @CheckForNull
239     public QualityGate getQualityGate() {
240       return qualityGate;
241     }
242
243     @Override
244     public Date getDate() {
245       return new Date(date);
246     }
247
248     @Override
249     public Optional<Date> getAnalysisDate() {
250       return analysis == null ? empty() : ofNullable(analysis.getDate());
251     }
252
253     @Override
254     public Optional<Analysis> getAnalysis() {
255       return ofNullable(analysis);
256     }
257
258     @Override
259     public ScannerContext getScannerContext() {
260       return scannerContext;
261     }
262
263     @Override
264     public String toString() {
265       return "ProjectAnalysis{" +
266         "ceTask=" + ceTask +
267         ", project=" + project +
268         ", date=" + date +
269         ", scannerContext=" + scannerContext +
270         ", qualityGate=" + qualityGate +
271         ", analysis=" + analysis +
272         '}';
273     }
274   }
275
276   private static class AnalysisImpl implements Analysis {
277
278     private final String analysisUuid;
279     private final long date;
280
281     private AnalysisImpl(String analysisUuid, long date) {
282       this.analysisUuid = analysisUuid;
283       this.date = date;
284     }
285
286     @Override
287     public String getAnalysisUuid() {
288       return analysisUuid;
289     }
290
291     @Override
292     public Date getDate() {
293       return new Date(date);
294     }
295   }
296 }