import org.sonar.server.computation.task.projectanalysis.source.SourceLinesRepositoryImpl; | import org.sonar.server.computation.task.projectanalysis.source.SourceLinesRepositoryImpl; | ||||
import org.sonar.server.computation.task.projectanalysis.step.ReportComputationSteps; | import org.sonar.server.computation.task.projectanalysis.step.ReportComputationSteps; | ||||
import org.sonar.server.computation.task.projectanalysis.step.SmallChangesetQualityGateSpecialCase; | import org.sonar.server.computation.task.projectanalysis.step.SmallChangesetQualityGateSpecialCase; | ||||
import org.sonar.server.computation.task.projectanalysis.webhook.WebhookPayloadFactoryImpl; | |||||
import org.sonar.server.computation.task.projectanalysis.webhook.WebhookPostTask; | import org.sonar.server.computation.task.projectanalysis.webhook.WebhookPostTask; | ||||
import org.sonar.server.computation.task.step.ComputationStepExecutor; | import org.sonar.server.computation.task.step.ComputationStepExecutor; | ||||
import org.sonar.server.computation.task.step.ComputationSteps; | import org.sonar.server.computation.task.step.ComputationSteps; | ||||
// webhooks | // webhooks | ||||
WebhookModule.class, | WebhookModule.class, | ||||
WebhookPayloadFactoryImpl.class, | |||||
WebhookPostTask.class); | WebhookPostTask.class); | ||||
} | } | ||||
*/ | */ | ||||
package org.sonar.server.computation.task.projectanalysis.webhook; | package org.sonar.server.computation.task.projectanalysis.webhook; | ||||
import java.util.Date; | |||||
import java.util.Optional; | |||||
import java.util.stream.Collectors; | |||||
import org.sonar.api.ce.posttask.PostProjectAnalysisTask; | import org.sonar.api.ce.posttask.PostProjectAnalysisTask; | ||||
import org.sonar.api.config.Configuration; | import org.sonar.api.config.Configuration; | ||||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | ||||
import org.sonar.server.webhook.Branch; | |||||
import org.sonar.server.webhook.CeTask; | |||||
import org.sonar.server.webhook.Project; | |||||
import org.sonar.server.webhook.QualityGate; | |||||
import org.sonar.server.webhook.WebHooks; | import org.sonar.server.webhook.WebHooks; | ||||
import org.sonar.server.webhook.WebhookPayloadFactory; | |||||
public class WebhookPostTask implements PostProjectAnalysisTask { | public class WebhookPostTask implements PostProjectAnalysisTask { | ||||
webHooks.sendProjectAnalysisUpdate( | webHooks.sendProjectAnalysisUpdate( | ||||
config, | config, | ||||
new WebHooks.Analysis(analysis.getProject().getUuid(), analysis.getCeTask().getId()), | new WebHooks.Analysis(analysis.getProject().getUuid(), analysis.getCeTask().getId()), | ||||
() -> payloadFactory.create(analysis)); | |||||
() -> payloadFactory.create(convert(analysis))); | |||||
} | |||||
private static org.sonar.server.webhook.ProjectAnalysis convert(ProjectAnalysis analysis) { | |||||
return new org.sonar.server.webhook.ProjectAnalysis( | |||||
new CeTask(analysis.getCeTask().getId(), CeTask.Status.valueOf(analysis.getCeTask().getStatus().name())), | |||||
new Project(analysis.getProject().getUuid(), analysis.getProject().getKey(), analysis.getProject().getName()), | |||||
analysis.getBranch().map(b -> new Branch(b.isMain(), b.getName().orElse(null), Branch.Type.valueOf(b.getType().name()))).orElse(null), | |||||
Optional.ofNullable(analysis.getQualityGate()) | |||||
.map(qg -> new QualityGate( | |||||
qg.getId(), | |||||
qg.getName(), | |||||
QualityGate.Status.valueOf(qg.getStatus().name()), | |||||
qg.getConditions().stream() | |||||
.map(c -> new QualityGate.Condition(QualityGate.EvaluationStatus.valueOf(c.getStatus().name()), c.getMetricKey(), QualityGate.Operator.valueOf(c.getOperator().name()), | |||||
c.getErrorThreshold(), c.getWarningThreshold(), c.isOnLeakPeriod(), | |||||
c.getStatus() == org.sonar.api.ce.posttask.QualityGate.EvaluationStatus.NO_VALUE ? null : c.getValue())) | |||||
.collect(Collectors.toSet()))) | |||||
.orElse(null), | |||||
analysis.getAnalysisDate().map(Date::getTime).orElse(null), | |||||
analysis.getScannerContext().getProperties()); | |||||
} | } | ||||
} | } |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import java.util.Objects; | |||||
import java.util.Optional; | |||||
import javax.annotation.Nullable; | |||||
import static java.util.Objects.requireNonNull; | |||||
public final class Branch { | |||||
private final boolean main; | |||||
private final String name; | |||||
private final Type type; | |||||
public Branch(boolean main, @Nullable String name, Type type) { | |||||
this.main = main; | |||||
this.name = name; | |||||
this.type = requireNonNull(type, "type can't be null"); | |||||
} | |||||
public boolean isMain() { | |||||
return main; | |||||
} | |||||
public Optional<String> getName() { | |||||
return Optional.ofNullable(name); | |||||
} | |||||
public Type getType() { | |||||
return type; | |||||
} | |||||
public enum Type { | |||||
LONG, SHORT | |||||
} | |||||
@Override | |||||
public boolean equals(Object o) { | |||||
if (this == o) { | |||||
return true; | |||||
} | |||||
if (o == null || getClass() != o.getClass()) { | |||||
return false; | |||||
} | |||||
Branch branch = (Branch) o; | |||||
return main == branch.main && | |||||
Objects.equals(name, branch.name) && | |||||
type == branch.type; | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return Objects.hash(main, name, type); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return "Branch{" + | |||||
"main=" + main + | |||||
", name='" + name + '\'' + | |||||
", type=" + type + | |||||
'}'; | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import java.util.Objects; | |||||
import static java.util.Objects.requireNonNull; | |||||
public final class CeTask { | |||||
private final String id; | |||||
private final Status status; | |||||
public CeTask(String id, Status status) { | |||||
this.id = requireNonNull(id, "id can't be null"); | |||||
this.status = requireNonNull(status, "status can't be null"); | |||||
} | |||||
public String getId() { | |||||
return id; | |||||
} | |||||
public Status getStatus() { | |||||
return status; | |||||
} | |||||
public enum Status { | |||||
SUCCESS, FAILED | |||||
} | |||||
@Override | |||||
public boolean equals(Object o) { | |||||
if (this == o) { | |||||
return true; | |||||
} | |||||
if (o == null || getClass() != o.getClass()) { | |||||
return false; | |||||
} | |||||
CeTask task = (CeTask) o; | |||||
return Objects.equals(id, task.id) && | |||||
status == task.status; | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return Objects.hash(id, status); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return "CeTask{" + | |||||
"id='" + id + '\'' + | |||||
", status=" + status + | |||||
'}'; | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import java.util.Objects; | |||||
import static java.util.Objects.requireNonNull; | |||||
public final class Project { | |||||
private final String uuid; | |||||
private final String key; | |||||
private final String name; | |||||
public Project(String uuid, String key, String name) { | |||||
this.uuid = requireNonNull(uuid, "uuid can't be null"); | |||||
this.key = requireNonNull(key, "key can't be null"); | |||||
this.name = requireNonNull(name, "name can't be null"); | |||||
} | |||||
public String getUuid() { | |||||
return uuid; | |||||
} | |||||
public String getKey() { | |||||
return key; | |||||
} | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
@Override | |||||
public boolean equals(Object o) { | |||||
if (this == o) { | |||||
return true; | |||||
} | |||||
if (o == null || getClass() != o.getClass()) { | |||||
return false; | |||||
} | |||||
Project project = (Project) o; | |||||
return Objects.equals(uuid, project.uuid) && | |||||
Objects.equals(key, project.key) && | |||||
Objects.equals(name, project.name); | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return Objects.hash(uuid, key, name); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return "Project{" + | |||||
"uuid='" + uuid + '\'' + | |||||
", key='" + key + '\'' + | |||||
", name='" + name + '\'' + | |||||
'}'; | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import java.util.Date; | |||||
import java.util.Map; | |||||
import java.util.Objects; | |||||
import java.util.Optional; | |||||
import javax.annotation.Nullable; | |||||
import static com.google.common.collect.ImmutableMap.copyOf; | |||||
import static java.util.Objects.requireNonNull; | |||||
public class ProjectAnalysis { | |||||
private final CeTask ceTask; | |||||
private final Project project; | |||||
private final Branch branch; | |||||
private final QualityGate qualityGate; | |||||
private final Long date; | |||||
private final Map<String, String> properties; | |||||
public ProjectAnalysis(CeTask ceTask, Project project, | |||||
@Nullable Branch branch, @Nullable QualityGate qualityGate, @Nullable Long date, Map<String, String> properties) { | |||||
this.ceTask = requireNonNull(ceTask, "ceTask can't be null"); | |||||
this.project = requireNonNull(project, "project can't be null"); | |||||
this.branch = branch; | |||||
this.qualityGate = qualityGate; | |||||
this.date = date; | |||||
this.properties = copyOf(requireNonNull(properties, "properties can't be null")); | |||||
} | |||||
public CeTask getCeTask() { | |||||
return ceTask; | |||||
} | |||||
public Project getProject() { | |||||
return project; | |||||
} | |||||
public Optional<Branch> getBranch() { | |||||
return Optional.ofNullable(branch); | |||||
} | |||||
public Optional<QualityGate> getQualityGate() { | |||||
return Optional.ofNullable(qualityGate); | |||||
} | |||||
public Optional<Date> getAnalysisDate() { | |||||
return Optional.ofNullable(date).map(Date::new); | |||||
} | |||||
public Map<String, String> getProperties() { | |||||
return properties; | |||||
} | |||||
@Override | |||||
public boolean equals(Object o) { | |||||
if (this == o) { | |||||
return true; | |||||
} | |||||
if (o == null || getClass() != o.getClass()) { | |||||
return false; | |||||
} | |||||
ProjectAnalysis that = (ProjectAnalysis) o; | |||||
return Objects.equals(ceTask, that.ceTask) && | |||||
Objects.equals(project, that.project) && | |||||
Objects.equals(branch, that.branch) && | |||||
Objects.equals(qualityGate, that.qualityGate) && | |||||
Objects.equals(date, that.date) && | |||||
Objects.equals(properties, that.properties); | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return Objects.hash(ceTask, project, branch, qualityGate, date, properties); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return "ProjectAnalysis{" + | |||||
"ceTask=" + ceTask + | |||||
", project=" + project + | |||||
", branch=" + branch + | |||||
", qualityGate=" + qualityGate + | |||||
", date=" + date + | |||||
", properties=" + properties + | |||||
'}'; | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import com.google.common.collect.ImmutableSet; | |||||
import java.util.Collection; | |||||
import java.util.Objects; | |||||
import java.util.Optional; | |||||
import java.util.Set; | |||||
import javax.annotation.Nullable; | |||||
import static java.util.Objects.requireNonNull; | |||||
public final class QualityGate { | |||||
private final String id; | |||||
private final String name; | |||||
private final Status status; | |||||
private final Set<Condition> conditions; | |||||
public QualityGate(String id, String name, Status status, Set<Condition> conditions) { | |||||
this.id = requireNonNull(id, "id can't be null"); | |||||
this.name = requireNonNull(name, "name can't be null"); | |||||
this.status = requireNonNull(status, "status can't be null"); | |||||
this.conditions = ImmutableSet.copyOf(requireNonNull(conditions, "conditions can't be null")); | |||||
} | |||||
public String getId() { | |||||
return id; | |||||
} | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
public Status getStatus() { | |||||
return status; | |||||
} | |||||
public Collection<Condition> getConditions() { | |||||
return conditions; | |||||
} | |||||
@Override | |||||
public boolean equals(Object o) { | |||||
if (this == o) { | |||||
return true; | |||||
} | |||||
if (o == null || getClass() != o.getClass()) { | |||||
return false; | |||||
} | |||||
QualityGate that = (QualityGate) o; | |||||
return Objects.equals(id, that.id) && | |||||
Objects.equals(name, that.name) && | |||||
status == that.status && | |||||
Objects.equals(conditions, that.conditions); | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return Objects.hash(id, name, status, conditions); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return "QualityGate{" + | |||||
"id='" + id + '\'' + | |||||
", name='" + name + '\'' + | |||||
", status=" + status + | |||||
", conditions=" + conditions + | |||||
'}'; | |||||
} | |||||
public enum Status { | |||||
OK, | |||||
WARN, | |||||
ERROR | |||||
} | |||||
public static final class Condition { | |||||
private final EvaluationStatus status; | |||||
private final String metricKey; | |||||
private final Operator operator; | |||||
private final String errorThreshold; | |||||
private final String warnThreshold; | |||||
private final boolean onLeakPeriod; | |||||
private final String value; | |||||
public Condition(EvaluationStatus status, String metricKey, Operator operator, | |||||
@Nullable String errorThreshold, @Nullable String warnThreshold, | |||||
boolean onLeakPeriod, @Nullable String value) { | |||||
this.status = requireNonNull(status, "status can't be null"); | |||||
this.metricKey = requireNonNull(metricKey, "metricKey can't be null"); | |||||
this.operator = requireNonNull(operator, "operator can't be null"); | |||||
this.errorThreshold = errorThreshold; | |||||
this.warnThreshold = warnThreshold; | |||||
this.onLeakPeriod = onLeakPeriod; | |||||
this.value = value; | |||||
} | |||||
public EvaluationStatus getStatus() { | |||||
return status; | |||||
} | |||||
public String getMetricKey() { | |||||
return metricKey; | |||||
} | |||||
public Operator getOperator() { | |||||
return operator; | |||||
} | |||||
public Optional<String> getErrorThreshold() { | |||||
return Optional.ofNullable(errorThreshold); | |||||
} | |||||
public Optional<String> getWarningThreshold() { | |||||
return Optional.ofNullable(warnThreshold); | |||||
} | |||||
public boolean isOnLeakPeriod() { | |||||
return onLeakPeriod; | |||||
} | |||||
public Optional<String> getValue() { | |||||
return Optional.ofNullable(value); | |||||
} | |||||
@Override | |||||
public boolean equals(Object o) { | |||||
if (this == o) { | |||||
return true; | |||||
} | |||||
if (o == null || getClass() != o.getClass()) { | |||||
return false; | |||||
} | |||||
Condition condition = (Condition) o; | |||||
return onLeakPeriod == condition.onLeakPeriod && | |||||
status == condition.status && | |||||
Objects.equals(metricKey, condition.metricKey) && | |||||
operator == condition.operator && | |||||
Objects.equals(errorThreshold, condition.errorThreshold) && | |||||
Objects.equals(warnThreshold, condition.warnThreshold) && | |||||
Objects.equals(value, condition.value); | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return Objects.hash(status, metricKey, operator, errorThreshold, warnThreshold, onLeakPeriod, value); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return "Condition{" + | |||||
"status=" + status + | |||||
", metricKey='" + metricKey + '\'' + | |||||
", operator=" + operator + | |||||
", errorThreshold='" + errorThreshold + '\'' + | |||||
", warnThreshold='" + warnThreshold + '\'' + | |||||
", onLeakPeriod=" + onLeakPeriod + | |||||
", value='" + value + '\'' + | |||||
'}'; | |||||
} | |||||
} | |||||
/** | |||||
* Quality Gate condition operator. | |||||
*/ | |||||
public enum Operator { | |||||
EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN | |||||
} | |||||
/** | |||||
* Quality gate condition evaluation status. | |||||
*/ | |||||
public enum EvaluationStatus { | |||||
/** | |||||
* No measure found or measure had no value. The condition has not been evaluated and therefor ignored in | |||||
* the computation of the Quality Gate status. | |||||
*/ | |||||
NO_VALUE, | |||||
/** | |||||
* Condition evaluated as OK, neither error nor warning thresholds have been reached. | |||||
*/ | |||||
OK, | |||||
/** | |||||
* Condition evaluated as WARN, only warning thresholds has been reached. | |||||
*/ | |||||
WARN, | |||||
/** | |||||
* Condition evaluated as ERROR, error thresholds has been reached (and most likely warning thresholds too). | |||||
*/ | |||||
ERROR | |||||
} | |||||
} |
add( | add( | ||||
WebhookCallerImpl.class, | WebhookCallerImpl.class, | ||||
WebhookDeliveryStorage.class, | WebhookDeliveryStorage.class, | ||||
WebHooksImpl.class); | |||||
WebHooksImpl.class, | |||||
WebhookPayloadFactoryImpl.class); | |||||
} | } | ||||
} | } |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.computation.task.projectanalysis.webhook; | |||||
import org.sonar.api.ce.posttask.PostProjectAnalysisTask; | |||||
import org.sonar.server.webhook.WebhookPayload; | |||||
package org.sonar.server.webhook; | |||||
@FunctionalInterface | @FunctionalInterface | ||||
public interface WebhookPayloadFactory { | public interface WebhookPayloadFactory { | ||||
WebhookPayload create(PostProjectAnalysisTask.ProjectAnalysis analysis); | |||||
WebhookPayload create(ProjectAnalysis analysis); | |||||
} | } |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.computation.task.projectanalysis.webhook; | |||||
package org.sonar.server.webhook; | |||||
import java.io.StringWriter; | import java.io.StringWriter; | ||||
import java.io.UnsupportedEncodingException; | import java.io.UnsupportedEncodingException; | ||||
import java.io.Writer; | import java.io.Writer; | ||||
import java.net.URLEncoder; | import java.net.URLEncoder; | ||||
import java.util.Date; | import java.util.Date; | ||||
import javax.annotation.Nullable; | |||||
import java.util.Map; | |||||
import org.sonar.api.ce.ComputeEngineSide; | import org.sonar.api.ce.ComputeEngineSide; | ||||
import org.sonar.api.ce.posttask.Branch; | |||||
import org.sonar.api.ce.posttask.CeTask; | |||||
import org.sonar.api.ce.posttask.PostProjectAnalysisTask; | |||||
import org.sonar.api.ce.posttask.Project; | |||||
import org.sonar.api.ce.posttask.QualityGate; | |||||
import org.sonar.api.ce.posttask.ScannerContext; | |||||
import org.sonar.api.platform.Server; | import org.sonar.api.platform.Server; | ||||
import org.sonar.api.utils.System2; | import org.sonar.api.utils.System2; | ||||
import org.sonar.api.utils.text.JsonWriter; | import org.sonar.api.utils.text.JsonWriter; | ||||
import org.sonar.server.webhook.WebhookPayload; | |||||
import static java.lang.String.format; | import static java.lang.String.format; | ||||
import static org.sonar.core.config.WebhookProperties.ANALYSIS_PROPERTY_PREFIX; | import static org.sonar.core.config.WebhookProperties.ANALYSIS_PROPERTY_PREFIX; | ||||
} | } | ||||
@Override | @Override | ||||
public WebhookPayload create(PostProjectAnalysisTask.ProjectAnalysis analysis) { | |||||
public WebhookPayload create(ProjectAnalysis analysis) { | |||||
Writer string = new StringWriter(); | Writer string = new StringWriter(); | ||||
try (JsonWriter writer = JsonWriter.of(string)) { | try (JsonWriter writer = JsonWriter.of(string)) { | ||||
writer.beginObject(); | writer.beginObject(); | ||||
writeDates(writer, analysis, system2); | writeDates(writer, analysis, system2); | ||||
writeProject(analysis, writer, analysis.getProject()); | writeProject(analysis, writer, analysis.getProject()); | ||||
analysis.getBranch().ifPresent(b -> writeBranch(writer, analysis.getProject(), b)); | analysis.getBranch().ifPresent(b -> writeBranch(writer, analysis.getProject(), b)); | ||||
writeQualityGate(writer, analysis.getQualityGate()); | |||||
writeAnalysisProperties(writer, analysis.getScannerContext()); | |||||
analysis.getQualityGate().ifPresent(qualityGate -> writeQualityGate(writer, qualityGate)); | |||||
writeAnalysisProperties(writer, analysis.getProperties()); | |||||
writer.endObject().close(); | writer.endObject().close(); | ||||
return new WebhookPayload(analysis.getProject().getKey(), string.toString()); | return new WebhookPayload(analysis.getProject().getKey(), string.toString()); | ||||
} | } | ||||
writer.prop("serverUrl", server.getPublicRootUrl()); | writer.prop("serverUrl", server.getPublicRootUrl()); | ||||
} | } | ||||
private static void writeDates(JsonWriter writer, PostProjectAnalysisTask.ProjectAnalysis analysis, System2 system2) { | |||||
private static void writeDates(JsonWriter writer, ProjectAnalysis analysis, System2 system2) { | |||||
analysis.getAnalysisDate().ifPresent(date -> writer.propDateTime("analysedAt", date)); | analysis.getAnalysisDate().ifPresent(date -> writer.propDateTime("analysedAt", date)); | ||||
writer.propDateTime("changedAt", analysis.getAnalysisDate().orElseGet(() -> new Date(system2.now()))); | writer.propDateTime("changedAt", analysis.getAnalysisDate().orElseGet(() -> new Date(system2.now()))); | ||||
} | } | ||||
private void writeProject(PostProjectAnalysisTask.ProjectAnalysis analysis, JsonWriter writer, Project project) { | |||||
private void writeProject(ProjectAnalysis analysis, JsonWriter writer, Project project) { | |||||
writer | writer | ||||
.name("project") | .name("project") | ||||
.beginObject() | .beginObject() | ||||
.endObject(); | .endObject(); | ||||
} | } | ||||
private static void writeAnalysisProperties(JsonWriter writer, ScannerContext scannerContext) { | |||||
private static void writeAnalysisProperties(JsonWriter writer, Map<String, String> properties) { | |||||
writer | writer | ||||
.name("properties") | .name("properties") | ||||
.beginObject(); | .beginObject(); | ||||
scannerContext.getProperties().entrySet() | |||||
properties.entrySet() | |||||
.stream() | .stream() | ||||
.filter(prop -> prop.getKey().startsWith(ANALYSIS_PROPERTY_PREFIX)) | .filter(prop -> prop.getKey().startsWith(ANALYSIS_PROPERTY_PREFIX)) | ||||
.forEach(prop -> writer.prop(prop.getKey(), prop.getValue())); | .forEach(prop -> writer.prop(prop.getKey(), prop.getValue())); | ||||
} | } | ||||
} | } | ||||
private static void writeQualityGate(JsonWriter writer, @Nullable QualityGate gate) { | |||||
if (gate != null) { | |||||
private static void writeQualityGate(JsonWriter writer, QualityGate gate) { | |||||
writer | |||||
.name("qualityGate") | |||||
.beginObject() | |||||
.prop("name", gate.getName()) | |||||
.prop("status", gate.getStatus().toString()) | |||||
.name("conditions") | |||||
.beginArray(); | |||||
for (QualityGate.Condition condition : gate.getConditions()) { | |||||
writer | writer | ||||
.name("qualityGate") | |||||
.beginObject() | .beginObject() | ||||
.prop("name", gate.getName()) | |||||
.prop("status", gate.getStatus().toString()) | |||||
.name("conditions") | |||||
.beginArray(); | |||||
for (QualityGate.Condition condition : gate.getConditions()) { | |||||
writer | |||||
.beginObject() | |||||
.prop("metric", condition.getMetricKey()) | |||||
.prop("operator", condition.getOperator().name()); | |||||
if (condition.getStatus() != QualityGate.EvaluationStatus.NO_VALUE) { | |||||
writer.prop("value", condition.getValue()); | |||||
} | |||||
writer | |||||
.prop("status", condition.getStatus().name()) | |||||
.prop("onLeakPeriod", condition.isOnLeakPeriod()) | |||||
.prop("errorThreshold", condition.getErrorThreshold()) | |||||
.prop("warningThreshold", condition.getWarningThreshold()) | |||||
.endObject(); | |||||
} | |||||
.prop("metric", condition.getMetricKey()) | |||||
.prop("operator", condition.getOperator().name()); | |||||
condition.getValue().ifPresent(t -> writer.prop("value", t)); | |||||
writer | writer | ||||
.endArray() | |||||
.prop("status", condition.getStatus().name()) | |||||
.prop("onLeakPeriod", condition.isOnLeakPeriod()) | |||||
.prop("errorThreshold", condition.getErrorThreshold().orElse(null)) | |||||
.prop("warningThreshold", condition.getWarningThreshold().orElse(null)) | |||||
.endObject(); | .endObject(); | ||||
} | } | ||||
writer | |||||
.endArray() | |||||
.endObject(); | |||||
} | } | ||||
private static String encode(String toEncode) { | private static String encode(String toEncode) { |
*/ | */ | ||||
package org.sonar.server.computation.task.projectanalysis.webhook; | package org.sonar.server.computation.task.projectanalysis.webhook; | ||||
import java.util.Collections; | |||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.Random; | import java.util.Random; | ||||
import java.util.function.Supplier; | import java.util.function.Supplier; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.mockito.ArgumentCaptor; | import org.mockito.ArgumentCaptor; | ||||
import org.sonar.api.ce.posttask.CeTask; | import org.sonar.api.ce.posttask.CeTask; | ||||
import org.sonar.api.ce.posttask.PostProjectAnalysisTask; | |||||
import org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester; | import org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester; | ||||
import org.sonar.api.ce.posttask.Project; | import org.sonar.api.ce.posttask.Project; | ||||
import org.sonar.api.config.Configuration; | import org.sonar.api.config.Configuration; | ||||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | ||||
import org.sonar.server.webhook.ProjectAnalysis; | |||||
import org.sonar.server.webhook.WebHooks; | import org.sonar.server.webhook.WebHooks; | ||||
import org.sonar.server.webhook.WebhookPayload; | import org.sonar.server.webhook.WebhookPayload; | ||||
import org.sonar.server.webhook.WebhookPayloadFactory; | |||||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
@Before | @Before | ||||
public void wireMocks() throws Exception { | public void wireMocks() throws Exception { | ||||
when(payloadFactory.create(any(PostProjectAnalysisTask.ProjectAnalysis.class))).thenReturn(webhookPayload); | |||||
when(payloadFactory.create(any(ProjectAnalysis.class))).thenReturn(webhookPayload); | |||||
when(configurationRepository.getConfiguration()).thenReturn(configuration); | when(configurationRepository.getConfiguration()).thenReturn(configuration); | ||||
} | } | ||||
.setStatus(CeTask.Status.values()[new Random().nextInt(CeTask.Status.values().length)]) | .setStatus(CeTask.Status.values()[new Random().nextInt(CeTask.Status.values().length)]) | ||||
.setId(randomAlphanumeric(6)) | .setId(randomAlphanumeric(6)) | ||||
.build(); | .build(); | ||||
Date date = new Date(); | |||||
PostProjectAnalysisTask.ProjectAnalysis projectAnalysis = PostProjectAnalysisTaskTester.of(underTest) | |||||
.at(new Date()) | |||||
PostProjectAnalysisTaskTester.of(underTest) | |||||
.at(date) | |||||
.withCeTask(ceTask) | .withCeTask(ceTask) | ||||
.withProject(project) | .withProject(project) | ||||
.withScannerContext(newScannerContextBuilder().build()) | .withScannerContext(newScannerContextBuilder().build()) | ||||
assertThat(supplierCaptor.getValue().get()).isSameAs(webhookPayload); | assertThat(supplierCaptor.getValue().get()).isSameAs(webhookPayload); | ||||
verify(payloadFactory).create(same(projectAnalysis)); | |||||
verify(payloadFactory).create(new ProjectAnalysis( | |||||
new org.sonar.server.webhook.CeTask(ceTask.getId(), | |||||
org.sonar.server.webhook.CeTask.Status.valueOf(ceTask.getStatus().name())), | |||||
new org.sonar.server.webhook.Project(project.getUuid(), project.getKey(), project.getName()), | |||||
null, | |||||
null, | |||||
date.getTime(), | |||||
Collections.emptyMap())); | |||||
} | } | ||||
} | } |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import java.util.Random; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
public class BranchTest { | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private Branch underTest = new Branch(true, "b", Branch.Type.SHORT); | |||||
@Test | |||||
public void constructor_throws_NPE_if_type_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("type can't be null"); | |||||
new Branch(new Random().nextBoolean(), "s", null); | |||||
} | |||||
@Test | |||||
public void verify_getters() { | |||||
assertThat(underTest.isMain()).isTrue(); | |||||
assertThat(underTest.getName()).contains("b"); | |||||
assertThat(underTest.getType()).isEqualTo(Branch.Type.SHORT); | |||||
Branch underTestWithNull = new Branch(false, null, Branch.Type.LONG); | |||||
assertThat(underTestWithNull.isMain()).isFalse(); | |||||
assertThat(underTestWithNull.getName()).isEmpty(); | |||||
assertThat(underTestWithNull.getType()).isEqualTo(Branch.Type.LONG); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
public class CeTaskTest { | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private CeTask underTest = new CeTask("A", CeTask.Status.SUCCESS); | |||||
@Test | |||||
public void constructor_throws_NPE_if_id_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("id can't be null"); | |||||
new CeTask(null, CeTask.Status.SUCCESS); | |||||
} | |||||
@Test | |||||
public void constructor_throws_NPE_if_status_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("status can't be null"); | |||||
new CeTask("B", null); | |||||
} | |||||
@Test | |||||
public void verify_getters() { | |||||
assertThat(underTest.getId()).isEqualTo("A"); | |||||
assertThat(underTest.getStatus()).isEqualTo(CeTask.Status.SUCCESS); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import com.google.common.collect.ImmutableMap; | |||||
import java.util.Date; | |||||
import java.util.Map; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import static java.util.Collections.emptyMap; | |||||
import static java.util.Collections.emptySet; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
public class ProjectAnalysisTest { | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private final CeTask ceTask = new CeTask("id", CeTask.Status.SUCCESS); | |||||
private final Project project = new Project("uuid", "key", "name"); | |||||
private final Branch branch = new Branch(true, "name", Branch.Type.SHORT); | |||||
private final QualityGate qualityGate = new QualityGate("id", "name", QualityGate.Status.WARN, emptySet()); | |||||
private final Map<String, String> properties = ImmutableMap.of("a", "b"); | |||||
private ProjectAnalysis underTest = new ProjectAnalysis(ceTask, | |||||
project, | |||||
branch, | |||||
qualityGate, | |||||
1L, | |||||
properties); | |||||
@Test | |||||
public void constructor_throws_NPE_if_ceTask_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("ceTask can't be null"); | |||||
new ProjectAnalysis(null, | |||||
project, | |||||
branch, | |||||
qualityGate, | |||||
1L, | |||||
emptyMap()); | |||||
} | |||||
@Test | |||||
public void constructor_throws_NPE_if_project_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("project can't be null"); | |||||
new ProjectAnalysis(ceTask, | |||||
null, | |||||
branch, | |||||
qualityGate, | |||||
1L, | |||||
emptyMap()); | |||||
} | |||||
@Test | |||||
public void constructor_throws_NPE_if_properties_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("properties can't be null"); | |||||
new ProjectAnalysis(ceTask, | |||||
project, | |||||
branch, | |||||
qualityGate, | |||||
1L, | |||||
null); | |||||
} | |||||
@Test | |||||
public void verify_getters() { | |||||
assertThat(underTest.getCeTask()).isSameAs(ceTask); | |||||
assertThat(underTest.getProject()).isSameAs(project); | |||||
assertThat(underTest.getBranch().get()).isSameAs(branch); | |||||
assertThat(underTest.getQualityGate().get()).isSameAs(qualityGate); | |||||
assertThat(underTest.getAnalysisDate()).contains(new Date(1L)); | |||||
assertThat(underTest.getProperties()).isEqualTo(properties); | |||||
ProjectAnalysis underTestWithNulls = new ProjectAnalysis(ceTask, project, null, null, null, emptyMap()); | |||||
assertThat(underTestWithNulls.getBranch()).isEmpty(); | |||||
assertThat(underTestWithNulls.getQualityGate()).isEmpty(); | |||||
assertThat(underTestWithNulls.getAnalysisDate()).isEmpty(); | |||||
assertThat(underTestWithNulls.getProperties()).isEmpty(); | |||||
} | |||||
@Test | |||||
public void defines_equals_based_on_all_fields() { | |||||
assertThat(underTest).isEqualTo(underTest); | |||||
assertThat(underTest).isEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, 1L, properties)); | |||||
assertThat(underTest).isNotEqualTo(null); | |||||
assertThat(underTest).isNotEqualTo(new Object()); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(new CeTask("2", CeTask.Status.SUCCESS), project, branch, qualityGate, 1L, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, new Project("A", "B", "C"), branch, qualityGate, 1L, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, new Project("A", "B", "C"), branch, qualityGate, 1L, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, project, null, qualityGate, 1L, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, project, new Branch(false, "B", Branch.Type.SHORT), qualityGate, 1L, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, null, 1L, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, new QualityGate("A", "B", QualityGate.Status.WARN, emptySet()), 1L, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, null, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, 2L, properties)); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, 1L, emptyMap())); | |||||
assertThat(underTest).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, 1L, ImmutableMap.of("A", "B"))); | |||||
} | |||||
@Test | |||||
public void defines_hashcode_based_on_all_fields() { | |||||
assertThat(underTest.hashCode()).isEqualTo(underTest.hashCode()); | |||||
assertThat(underTest.hashCode()).isEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, 1L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(new CeTask("2", CeTask.Status.SUCCESS), project, branch, qualityGate, 1L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, new Project("A", "B", "C"), branch, qualityGate, 1L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, new Project("A", "B", "C"), branch, qualityGate, 1L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, project, null, qualityGate, 1L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, project, new Branch(false, "B", Branch.Type.SHORT), qualityGate, 1L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, null, 1L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()) | |||||
.isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, new QualityGate("A", "B", QualityGate.Status.WARN, emptySet()), 1L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, null, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, 2L, properties).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, 1L, emptyMap()).hashCode()); | |||||
assertThat(underTest.hashCode()).isNotEqualTo(new ProjectAnalysis(ceTask, project, branch, qualityGate, 1L, ImmutableMap.of("B", "C")).hashCode()); | |||||
} | |||||
@Test | |||||
public void verify_toString() { | |||||
assertThat(underTest.toString()).isEqualTo( | |||||
"ProjectAnalysis{ceTask=CeTask{id='id', status=SUCCESS}, project=Project{uuid='uuid', key='key', name='name'}, branch=Branch{main=true, name='name', type=SHORT}, qualityGate=QualityGate{id='id', name='name', status=WARN, conditions=[]}, date=1, properties={a=b}}"); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
public class ProjectTest { | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private Project underTest = new Project("a", "b", "c"); | |||||
@Test | |||||
public void constructor_throws_NPE_if_uuid_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("uuid can't be null"); | |||||
new Project(null, "b", "c"); | |||||
} | |||||
@Test | |||||
public void constructor_throws_NPE_if_key_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("key can't be null"); | |||||
new Project("a", null, "c"); | |||||
} | |||||
@Test | |||||
public void constructor_throws_NPE_if_name_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("name can't be null"); | |||||
new Project("a", "b", null); | |||||
} | |||||
@Test | |||||
public void verify_getters() { | |||||
assertThat(underTest.getUuid()).isEqualTo("a"); | |||||
assertThat(underTest.getKey()).isEqualTo("b"); | |||||
assertThat(underTest.getName()).isEqualTo("c"); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import java.util.Random; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import static java.util.Collections.singleton; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
public class QualityGateTest { | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private final Random random = new Random(); | |||||
private boolean onLeak = random.nextBoolean(); | |||||
private QualityGate.EvaluationStatus randomEvaluationStatus = QualityGate.EvaluationStatus.values()[random.nextInt(QualityGate.EvaluationStatus.values().length)]; | |||||
private QualityGate.Condition condition = new QualityGate.Condition( | |||||
randomEvaluationStatus, "k", QualityGate.Operator.GREATER_THAN, "l", "m", onLeak, "val"); | |||||
private QualityGate.Status randomStatus = QualityGate.Status.values()[random.nextInt(QualityGate.Status.values().length)]; | |||||
private QualityGate underTest = new QualityGate("i", "j", randomStatus, singleton(condition)); | |||||
@Test | |||||
public void constructor_throws_NPE_if_id_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("id can't be null"); | |||||
new QualityGate(null, "j", QualityGate.Status.WARN, singleton(condition)); | |||||
} | |||||
@Test | |||||
public void constructor_throws_NPE_if_name_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("name can't be null"); | |||||
new QualityGate("i", null, QualityGate.Status.WARN, singleton(condition)); | |||||
} | |||||
@Test | |||||
public void constructor_throws_NPE_if_status_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("status can't be null"); | |||||
new QualityGate("i", "j", null, singleton(condition)); | |||||
} | |||||
@Test | |||||
public void constructor_throws_NPE_if_conditions_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("conditions can't be null"); | |||||
new QualityGate("i", "j", QualityGate.Status.WARN, null); | |||||
} | |||||
@Test | |||||
public void condition_constructor_throws_NPE_if_evaluation_status_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("status can't be null"); | |||||
new QualityGate.Condition(null, "k", QualityGate.Operator.GREATER_THAN, "l", "m", onLeak, "val"); | |||||
} | |||||
@Test | |||||
public void condition_constructor_throws_NPE_if_metricKey_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("metricKey can't be null"); | |||||
new QualityGate.Condition(randomEvaluationStatus, null, QualityGate.Operator.GREATER_THAN, "l", "m", onLeak, "val"); | |||||
} | |||||
@Test | |||||
public void condition_constructor_throws_NPE_if_operator_status_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("operator can't be null"); | |||||
new QualityGate.Condition(randomEvaluationStatus, "k", null, "l", "m", onLeak, "val"); | |||||
} | |||||
@Test | |||||
public void verify_getters() { | |||||
assertThat(underTest.getId()).isEqualTo("i"); | |||||
assertThat(underTest.getName()).isEqualTo("j"); | |||||
assertThat(underTest.getStatus()).isEqualTo(randomStatus); | |||||
assertThat(underTest.getConditions()).isEqualTo(singleton(condition)); | |||||
} | |||||
@Test | |||||
public void verify_condition_getters() { | |||||
assertThat(condition.getStatus()).isEqualTo(randomEvaluationStatus); | |||||
assertThat(condition.getMetricKey()).isEqualTo("k"); | |||||
assertThat(condition.getErrorThreshold()).contains("l"); | |||||
assertThat(condition.getWarningThreshold()).contains("m"); | |||||
assertThat(condition.isOnLeakPeriod()).isEqualTo(onLeak); | |||||
assertThat(condition.getValue()).contains("val"); | |||||
QualityGate.Condition conditionWithNulls = new QualityGate.Condition( | |||||
randomEvaluationStatus, "k", QualityGate.Operator.GREATER_THAN, null, null, onLeak, null); | |||||
assertThat(conditionWithNulls.getErrorThreshold()).isEmpty(); | |||||
assertThat(conditionWithNulls.getWarningThreshold()).isEmpty(); | |||||
assertThat(conditionWithNulls.getValue()).isEmpty(); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info 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.webhook; | |||||
import org.sonar.api.ce.posttask.PostProjectAnalysisTask; | |||||
import org.sonar.server.computation.task.projectanalysis.webhook.WebhookPayloadFactory; | |||||
public class TestWebhookPayloadFactory implements WebhookPayloadFactory { | |||||
private static final String FAKE_JSON = "{\"payload\": true}"; | |||||
@Override | |||||
public WebhookPayload create(PostProjectAnalysisTask.ProjectAnalysis analysis) { | |||||
return new WebhookPayload(analysis.getProject().getKey(), FAKE_JSON); | |||||
} | |||||
} |
underTest.configure(container); | underTest.configure(container); | ||||
assertThat(container.size()).isEqualTo(3 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER); | |||||
assertThat(container.size()).isEqualTo(4 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER); | |||||
} | } | ||||
} | } |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.computation.task.projectanalysis.webhook; | |||||
package org.sonar.server.webhook; | |||||
import com.google.common.collect.ImmutableMap; | import com.google.common.collect.ImmutableMap; | ||||
import java.util.Date; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Optional; | |||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.junit.Before; | import org.junit.Before; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.sonar.api.ce.posttask.Branch; | |||||
import org.sonar.api.ce.posttask.CeTask; | |||||
import org.sonar.api.ce.posttask.PostProjectAnalysisTask; | |||||
import org.sonar.api.ce.posttask.Project; | |||||
import org.sonar.api.ce.posttask.QualityGate; | |||||
import org.sonar.api.ce.posttask.ScannerContext; | |||||
import org.sonar.api.platform.Server; | import org.sonar.api.platform.Server; | ||||
import org.sonar.api.utils.System2; | import org.sonar.api.utils.System2; | ||||
import org.sonar.server.computation.task.projectanalysis.api.posttask.BranchImpl; | |||||
import org.sonar.server.webhook.WebhookPayload; | |||||
import static java.util.Collections.emptyMap; | import static java.util.Collections.emptyMap; | ||||
import static java.util.Collections.emptySet; | |||||
import static java.util.Collections.singleton; | |||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||
import static org.mockito.Mockito.when; | import static org.mockito.Mockito.when; | ||||
import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newCeTaskBuilder; | |||||
import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newConditionBuilder; | |||||
import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newProjectBuilder; | |||||
import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newQualityGateBuilder; | |||||
import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newScannerContextBuilder; | |||||
import static org.sonar.test.JsonAssert.assertJson; | import static org.sonar.test.JsonAssert.assertJson; | ||||
public class WebhookPayloadFactoryImplTest { | public class WebhookPayloadFactoryImplTest { | ||||
@Test | @Test | ||||
public void create_payload_for_successful_analysis() { | public void create_payload_for_successful_analysis() { | ||||
CeTask task = newCeTaskBuilder() | |||||
.setStatus(CeTask.Status.SUCCESS) | |||||
.setId("#1") | |||||
.build(); | |||||
QualityGate gate = newQualityGateBuilder() | |||||
.setId("G1") | |||||
.setName("Gate One") | |||||
.setStatus(QualityGate.Status.WARN) | |||||
.add(newConditionBuilder() | |||||
.setMetricKey("coverage") | |||||
.setOperator(QualityGate.Operator.GREATER_THAN) | |||||
.setOnLeakPeriod(true) | |||||
.setWarningThreshold("75.0") | |||||
.setErrorThreshold("70.0") | |||||
.build(QualityGate.EvaluationStatus.WARN, "74.0")) | |||||
.build(); | |||||
PostProjectAnalysisTask.ProjectAnalysis analysis = newAnalysis(task, gate, null, 1_500_000_000_000L, emptyMap()); | |||||
CeTask task = new CeTask("#1", CeTask.Status.SUCCESS); | |||||
QualityGate gate = new QualityGate("G1", "Gate One", QualityGate.Status.WARN, singleton(new QualityGate.Condition( | |||||
QualityGate.EvaluationStatus.WARN, | |||||
"coverage", QualityGate.Operator.GREATER_THAN, "70.0", "75.0", true, "74.0"))); | |||||
ProjectAnalysis analysis = newAnalysis(task, gate, null, 1_500_000_000_000L, emptyMap()); | |||||
WebhookPayload payload = underTest.create(analysis); | WebhookPayload payload = underTest.create(analysis); | ||||
assertThat(payload.getProjectKey()).isEqualTo(PROJECT_KEY); | assertThat(payload.getProjectKey()).isEqualTo(PROJECT_KEY); | ||||
@Test | @Test | ||||
public void create_payload_with_gate_conditions_without_value() { | public void create_payload_with_gate_conditions_without_value() { | ||||
CeTask task = newCeTaskBuilder() | |||||
.setStatus(CeTask.Status.SUCCESS) | |||||
.setId("#1") | |||||
.build(); | |||||
QualityGate gate = newQualityGateBuilder() | |||||
.setId("G1") | |||||
.setName("Gate One") | |||||
.setStatus(QualityGate.Status.WARN) | |||||
.add(newConditionBuilder() | |||||
.setMetricKey("coverage") | |||||
.setOperator(QualityGate.Operator.GREATER_THAN) | |||||
.setWarningThreshold("75.0") | |||||
.setErrorThreshold("70.0") | |||||
.buildNoValue()) | |||||
.build(); | |||||
PostProjectAnalysisTask.ProjectAnalysis analysis = newAnalysis(task, gate, null, 1_500_000_000_000L, emptyMap()); | |||||
CeTask task = new CeTask("#1", CeTask.Status.SUCCESS); | |||||
QualityGate gate = new QualityGate("G1", "Gate One", QualityGate.Status.WARN, singleton( | |||||
new QualityGate.Condition(QualityGate.EvaluationStatus.NO_VALUE, "coverage", QualityGate.Operator.GREATER_THAN, "70.0", "75.0", false, null))); | |||||
ProjectAnalysis analysis = newAnalysis(task, gate, null, 1_500_000_000_000L, emptyMap()); | |||||
WebhookPayload payload = underTest.create(analysis); | WebhookPayload payload = underTest.create(analysis); | ||||
assertThat(payload.getProjectKey()).isEqualTo(PROJECT_KEY); | assertThat(payload.getProjectKey()).isEqualTo(PROJECT_KEY); | ||||
@Test | @Test | ||||
public void create_payload_with_analysis_properties() { | public void create_payload_with_analysis_properties() { | ||||
CeTask task = newCeTaskBuilder() | |||||
.setStatus(CeTask.Status.SUCCESS) | |||||
.setId("#1") | |||||
.build(); | |||||
QualityGate gate = newQualityGateBuilder() | |||||
.setId("G1") | |||||
.setName("Gate One") | |||||
.setStatus(QualityGate.Status.WARN) | |||||
.build(); | |||||
CeTask task = new CeTask("#1", CeTask.Status.SUCCESS); | |||||
QualityGate gate = new QualityGate("G1", "Gate One", QualityGate.Status.WARN, emptySet()); | |||||
Map<String, String> scannerProperties = ImmutableMap.of( | Map<String, String> scannerProperties = ImmutableMap.of( | ||||
"sonar.analysis.revision", "ab45d24", | "sonar.analysis.revision", "ab45d24", | ||||
"sonar.analysis.buildNumber", "B123", | "sonar.analysis.buildNumber", "B123", | ||||
"not.prefixed.with.sonar.analysis", "should be ignored", | "not.prefixed.with.sonar.analysis", "should be ignored", | ||||
"ignored", "should be ignored too"); | "ignored", "should be ignored too"); | ||||
PostProjectAnalysisTask.ProjectAnalysis analysis = newAnalysis(task, gate, null, 1_500_000_000_000L, scannerProperties); | |||||
ProjectAnalysis analysis = newAnalysis(task, gate, null, 1_500_000_000_000L, scannerProperties); | |||||
WebhookPayload payload = underTest.create(analysis); | WebhookPayload payload = underTest.create(analysis); | ||||
assertJson(payload.getJson()) | assertJson(payload.getJson()) | ||||
@Test | @Test | ||||
public void create_payload_for_failed_analysis() { | public void create_payload_for_failed_analysis() { | ||||
CeTask ceTask = newCeTaskBuilder().setStatus(CeTask.Status.FAILED).setId("#1").build(); | |||||
PostProjectAnalysisTask.ProjectAnalysis analysis = newAnalysis(ceTask, null, null, 1_500_000_000_000L, emptyMap()); | |||||
CeTask ceTask = new CeTask("#1", CeTask.Status.FAILED); | |||||
ProjectAnalysis analysis = newAnalysis(ceTask, null, null, 1_500_000_000_000L, emptyMap()); | |||||
WebhookPayload payload = underTest.create(analysis); | WebhookPayload payload = underTest.create(analysis); | ||||
@Test | @Test | ||||
public void create_payload_for_no_analysis_date() { | public void create_payload_for_no_analysis_date() { | ||||
CeTask ceTask = newCeTaskBuilder().setStatus(CeTask.Status.FAILED).setId("#1").build(); | |||||
PostProjectAnalysisTask.ProjectAnalysis analysis = newAnalysis(ceTask, null, null, null, emptyMap()); | |||||
CeTask ceTask = new CeTask("#1", CeTask.Status.FAILED); | |||||
ProjectAnalysis analysis = newAnalysis(ceTask, null, null, null, emptyMap()); | |||||
WebhookPayload payload = underTest.create(analysis); | WebhookPayload payload = underTest.create(analysis); | ||||
@Test | @Test | ||||
public void create_payload_on_short_branch() { | public void create_payload_on_short_branch() { | ||||
CeTask task = newCeTaskBuilder() | |||||
.setStatus(CeTask.Status.SUCCESS) | |||||
.setId("#1") | |||||
.build(); | |||||
PostProjectAnalysisTask.ProjectAnalysis analysis = newAnalysis(task, null, new BranchImpl(false, "feature/foo", Branch.Type.SHORT), 1_500_000_000_000L, emptyMap()); | |||||
CeTask task = new CeTask("#1", CeTask.Status.SUCCESS); | |||||
ProjectAnalysis analysis = newAnalysis(task, null, new Branch(false, "feature/foo", Branch.Type.SHORT), 1_500_000_000_000L, emptyMap()); | |||||
WebhookPayload payload = underTest.create(analysis); | WebhookPayload payload = underTest.create(analysis); | ||||
assertJson(payload.getJson()) | assertJson(payload.getJson()) | ||||
@Test | @Test | ||||
public void create_payload_on_long_branch() { | public void create_payload_on_long_branch() { | ||||
CeTask task = newCeTaskBuilder() | |||||
.setStatus(CeTask.Status.SUCCESS) | |||||
.setId("#1") | |||||
.build(); | |||||
PostProjectAnalysisTask.ProjectAnalysis analysis = newAnalysis(task, null, new BranchImpl(false, "feature/foo", Branch.Type.LONG), 1_500_000_000_000L, emptyMap()); | |||||
CeTask task = new CeTask("#1", CeTask.Status.SUCCESS); | |||||
ProjectAnalysis analysis = newAnalysis(task, null, new Branch(false, "feature/foo", Branch.Type.LONG), 1_500_000_000_000L, emptyMap()); | |||||
WebhookPayload payload = underTest.create(analysis); | WebhookPayload payload = underTest.create(analysis); | ||||
assertJson(payload.getJson()) | assertJson(payload.getJson()) | ||||
@Test | @Test | ||||
public void create_payload_on_main_branch_without_name() { | public void create_payload_on_main_branch_without_name() { | ||||
CeTask task = newCeTaskBuilder() | |||||
.setStatus(CeTask.Status.SUCCESS) | |||||
.setId("#1") | |||||
.build(); | |||||
PostProjectAnalysisTask.ProjectAnalysis analysis = newAnalysis(task, null, new BranchImpl(true, null, Branch.Type.LONG), 1_500_000_000_000L, emptyMap()); | |||||
CeTask task = new CeTask("#1", CeTask.Status.SUCCESS); | |||||
ProjectAnalysis analysis = newAnalysis(task, null, new Branch(true, null, Branch.Type.LONG), 1_500_000_000_000L, emptyMap()); | |||||
WebhookPayload payload = underTest.create(analysis); | WebhookPayload payload = underTest.create(analysis); | ||||
assertJson(payload.getJson()) | assertJson(payload.getJson()) | ||||
"}"); | "}"); | ||||
} | } | ||||
private static PostProjectAnalysisTask.ProjectAnalysis newAnalysis(CeTask task, @Nullable QualityGate gate, | |||||
private static ProjectAnalysis newAnalysis(CeTask task, @Nullable QualityGate gate, | |||||
@Nullable Branch branch, @Nullable Long analysisDate, Map<String, String> scannerProperties) { | @Nullable Branch branch, @Nullable Long analysisDate, Map<String, String> scannerProperties) { | ||||
return new PostProjectAnalysisTask.ProjectAnalysis() { | |||||
@Override | |||||
public CeTask getCeTask() { | |||||
return task; | |||||
} | |||||
@Override | |||||
public Project getProject() { | |||||
return newProjectBuilder() | |||||
.setUuid("P1_UUID") | |||||
.setKey(PROJECT_KEY) | |||||
.setName("Project One") | |||||
.build(); | |||||
} | |||||
@Override | |||||
public Optional<Branch> getBranch() { | |||||
return Optional.ofNullable(branch); | |||||
} | |||||
@Override | |||||
public QualityGate getQualityGate() { | |||||
return gate; | |||||
} | |||||
@Override | |||||
public Date getDate() { | |||||
throw new UnsupportedOperationException(); | |||||
} | |||||
@Override | |||||
public Optional<Date> getAnalysisDate() { | |||||
return Optional.ofNullable(analysisDate).map(Date::new); | |||||
} | |||||
@Override | |||||
public ScannerContext getScannerContext() { | |||||
return newScannerContextBuilder() | |||||
.addProperties(scannerProperties) | |||||
.build(); | |||||
} | |||||
}; | |||||
return new ProjectAnalysis(task, new Project("P1_UUID", PROJECT_KEY, "Project One"), branch, gate, analysisDate, scannerProperties); | |||||
} | } | ||||
} | } |