@@ -26,6 +26,19 @@ import org.sonar.api.config.Configuration; | |||
import static java.util.Objects.requireNonNull; | |||
public interface WebHooks { | |||
/** | |||
* Tells whether any webHook is configured at all for the specified {@link Configuration}. | |||
* | |||
* <p> | |||
* This can be used to not do consuming operations before calling | |||
* {@link #sendProjectAnalysisUpdate(Configuration, Analysis, Supplier)} | |||
*/ | |||
boolean isEnabled(Configuration configuration); | |||
/** | |||
* Calls all WebHooks configured in the specified {@link Configuration} for the specified analysis with the | |||
* {@link WebhookPayload} provided by the specified Supplier. | |||
*/ | |||
void sendProjectAnalysisUpdate(Configuration configuration, Analysis analysis, Supplier<WebhookPayload> payloadSupplier); | |||
final class Analysis { |
@@ -48,22 +48,13 @@ public class WebHooksImpl implements WebHooks { | |||
} | |||
@Override | |||
public void sendProjectAnalysisUpdate(Configuration configuration, Analysis analysis, Supplier<WebhookPayload> payloadSupplier) { | |||
List<Webhook> webhooks = loadWebhooks(analysis, configuration); | |||
if (webhooks.isEmpty()) { | |||
return; | |||
} | |||
WebhookPayload payload = payloadSupplier.get(); | |||
webhooks.forEach(webhook -> { | |||
WebhookDelivery delivery = caller.call(webhook, payload); | |||
log(delivery); | |||
deliveryStorage.persist(delivery); | |||
}); | |||
deliveryStorage.purge(analysis.getProjectUuid()); | |||
public boolean isEnabled(Configuration config) { | |||
return readWebHooksFrom(config) | |||
.findAny() | |||
.isPresent(); | |||
} | |||
private List<Webhook> loadWebhooks(Analysis analysis, Configuration config) { | |||
private static Stream<NameUrl> readWebHooksFrom(Configuration config) { | |||
return Stream.concat( | |||
getWebhookProperties(config, WebhookProperties.GLOBAL_KEY).stream(), | |||
getWebhookProperties(config, WebhookProperties.PROJECT_KEY).stream()) | |||
@@ -71,13 +62,12 @@ public class WebHooksImpl implements WebHooks { | |||
webHookProperty -> { | |||
String name = config.get(format(WEBHOOK_PROPERTY_FORMAT, webHookProperty, WebhookProperties.NAME_FIELD)).orElse(null); | |||
String url = config.get(format(WEBHOOK_PROPERTY_FORMAT, webHookProperty, WebhookProperties.URL_FIELD)).orElse(null); | |||
if (name != null && url != null) { | |||
return new Webhook(analysis.getProjectUuid(), analysis.getCeTaskUuid(), name, url); | |||
if (name == null || url == null) { | |||
return null; | |||
} | |||
return null; | |||
return new NameUrl(name, url); | |||
}) | |||
.filter(Objects::nonNull) | |||
.collect(MoreCollectors.toList()); | |||
.filter(Objects::nonNull); | |||
} | |||
private static List<String> getWebhookProperties(Configuration config, String propertyKey) { | |||
@@ -88,6 +78,24 @@ public class WebHooksImpl implements WebHooks { | |||
.collect(MoreCollectors.toList(webhookIds.length)); | |||
} | |||
@Override | |||
public void sendProjectAnalysisUpdate(Configuration config, Analysis analysis, Supplier<WebhookPayload> payloadSupplier) { | |||
List<Webhook> webhooks = readWebHooksFrom(config) | |||
.map(nameUrl -> new Webhook(analysis.getProjectUuid(), analysis.getCeTaskUuid(), nameUrl.getName(), nameUrl.getUrl())) | |||
.collect(MoreCollectors.toList()); | |||
if (webhooks.isEmpty()) { | |||
return; | |||
} | |||
WebhookPayload payload = payloadSupplier.get(); | |||
webhooks.forEach(webhook -> { | |||
WebhookDelivery delivery = caller.call(webhook, payload); | |||
log(delivery); | |||
deliveryStorage.persist(delivery); | |||
}); | |||
deliveryStorage.purge(analysis.getProjectUuid()); | |||
} | |||
private static void log(WebhookDelivery delivery) { | |||
Optional<String> error = delivery.getErrorMessage(); | |||
if (error.isPresent()) { | |||
@@ -98,4 +106,22 @@ public class WebHooksImpl implements WebHooks { | |||
delivery.getWebhook().getName(), delivery.getWebhook().getUrl(), delivery.getDurationInMs().orElse(-1), delivery.getHttpStatus().orElse(-1)); | |||
} | |||
} | |||
private static final class NameUrl { | |||
private final String name; | |||
private final String url; | |||
private NameUrl(String name, String url) { | |||
this.name = name; | |||
this.url = url; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public String getUrl() { | |||
return url; | |||
} | |||
} | |||
} |
@@ -49,6 +49,61 @@ public class WebHooksImplTest { | |||
private final WebhookPayload mock = mock(WebhookPayload.class); | |||
private final WebHooksImpl underTest = new WebHooksImpl(caller, deliveryStorage); | |||
@Test | |||
public void isEnabled_returns_false_if_no_webHoolds() { | |||
assertThat(underTest.isEnabled(settings.asConfig())).isFalse(); | |||
} | |||
@Test | |||
public void isEnabled_returns_true_if_one_valid_global_webhook() { | |||
settings.setProperty("sonar.webhooks.global", "1"); | |||
settings.setProperty("sonar.webhooks.global.1.name", "First"); | |||
settings.setProperty("sonar.webhooks.global.1.url", "http://url1"); | |||
assertThat(underTest.isEnabled(settings.asConfig())).isTrue(); | |||
} | |||
@Test | |||
public void isEnabled_returns_false_if_only_one_global_webhook_without_url() { | |||
settings.setProperty("sonar.webhooks.global", "1"); | |||
settings.setProperty("sonar.webhooks.global.1.name", "First"); | |||
assertThat(underTest.isEnabled(settings.asConfig())).isFalse(); | |||
} | |||
@Test | |||
public void isEnabled_returns_false_if_only_one_global_webhook_without_name() { | |||
settings.setProperty("sonar.webhooks.global", "1"); | |||
settings.setProperty("sonar.webhooks.global.1.url", "http://url1"); | |||
assertThat(underTest.isEnabled(settings.asConfig())).isFalse(); | |||
} | |||
@Test | |||
public void isEnabled_returns_true_if_one_valid_project_webhook() { | |||
settings.setProperty("sonar.webhooks.project", "1"); | |||
settings.setProperty("sonar.webhooks.project.1.name", "First"); | |||
settings.setProperty("sonar.webhooks.project.1.url", "http://url1"); | |||
assertThat(underTest.isEnabled(settings.asConfig())).isTrue(); | |||
} | |||
@Test | |||
public void isEnabled_returns_false_if_only_one_project_webhook_without_url() { | |||
settings.setProperty("sonar.webhooks.project", "1"); | |||
settings.setProperty("sonar.webhooks.project.1.name", "First"); | |||
assertThat(underTest.isEnabled(settings.asConfig())).isFalse(); | |||
} | |||
@Test | |||
public void isEnabled_returns_false_if_only_one_project_webhook_without_name() { | |||
settings.setProperty("sonar.webhooks.project", "1"); | |||
settings.setProperty("sonar.webhooks.project.1.url", "http://url1"); | |||
assertThat(underTest.isEnabled(settings.asConfig())).isFalse(); | |||
} | |||
@Test | |||
public void do_nothing_if_no_webhooks() { | |||
underTest.sendProjectAnalysisUpdate(settings.asConfig(), new WebHooks.Analysis(PROJECT_UUID, "#1"), () -> mock); |