diff --git a/.README/globalconfig.png b/.README/globalconfig.png index 5307e8ef..d390eb95 100644 Binary files a/.README/globalconfig.png and b/.README/globalconfig.png differ diff --git a/README.md b/README.md index d04b1b8a..a8989dec 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Plugin is used to send actionable messages in [Outlook](http://outlook.com), [Of #### Global configuration values used as default in jobs -![GlobalConfigurationDefault](.README/globalconfigdefault.png?raw=true) +![GlobalConfiguratio![img.png](.README/globalconfig.png)nDefault](.README/globalconfigdefault.png?raw=true) ### Microsoft Teams diff --git a/src/main/java/jenkins/plugins/office365connector/HttpWorker.java b/src/main/java/jenkins/plugins/office365connector/HttpWorker.java index 504e0a84..ce6088ba 100644 --- a/src/main/java/jenkins/plugins/office365connector/HttpWorker.java +++ b/src/main/java/jenkins/plugins/office365connector/HttpWorker.java @@ -43,17 +43,20 @@ public class HttpWorker implements Runnable { private final PrintStream logger; + private final ProxyConfiguration pluginProxy; + private final String url; private final String data; private final int timeout; private static final int RETRIES = 3; - public HttpWorker(String url, String data, int timeout, PrintStream logger) { + public HttpWorker(String url, String data, int timeout, PrintStream logger, ProxyConfiguration pluginProxy) { this.url = url; this.data = data; this.timeout = timeout; this.logger = logger; + this.pluginProxy = pluginProxy; } /** @@ -105,8 +108,15 @@ public void run() { private HttpClient getHttpClient() { HttpClient client = new HttpClient(); Jenkins jenkins = Jenkins.get(); - if (jenkins != null) { + if (!StringUtils.isEmpty(pluginProxy.getName())) { + client.getHostConfiguration().setProxy(pluginProxy.getName(), pluginProxy.getPort()); + if (StringUtils.isNotBlank(pluginProxy.getUserName())) { + client.getState().setProxyCredentials(AuthScope.ANY, + new UsernamePasswordCredentials(pluginProxy.getUserName(), pluginProxy.getPassword())); + } + } else if (jenkins != null) { ProxyConfiguration proxy = jenkins.proxy; + // Check job proxy first if (proxy != null) { List noHostProxyPatterns = proxy.getNoProxyHostPatterns(); if (!isNoProxyHost(this.url, noHostProxyPatterns)) { diff --git a/src/main/java/jenkins/plugins/office365connector/Office365ConnectorWebhookNotifier.java b/src/main/java/jenkins/plugins/office365connector/Office365ConnectorWebhookNotifier.java index 2c9cbd13..1c402b4d 100644 --- a/src/main/java/jenkins/plugins/office365connector/Office365ConnectorWebhookNotifier.java +++ b/src/main/java/jenkins/plugins/office365connector/Office365ConnectorWebhookNotifier.java @@ -23,6 +23,7 @@ import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import hudson.ProxyConfiguration; import hudson.model.AbstractBuild; import hudson.model.Job; import hudson.model.Run; @@ -112,7 +113,14 @@ private void executeWorker(Webhook webhook, Card card) { try { String url = run.getEnvironment(taskListener).expand(webhook.getUrl()); String data = gson.toJson(card); - HttpWorker worker = new HttpWorker(url, data, webhook.getTimeout(), taskListener.getLogger()); + + Integer port = 0; + if (!StringUtils.isEmpty(webhook.getDescriptor().getPort())) { + port = Integer.parseInt(webhook.getDescriptor().getPort()); + } + + ProxyConfiguration pluginProxy = new ProxyConfiguration(webhook.getDescriptor().getHost(), port, webhook.getDescriptor().getUsername(), webhook.getDescriptor().getPassword()); + HttpWorker worker = new HttpWorker(url, data, webhook.getTimeout(), taskListener.getLogger(), pluginProxy); worker.submit(); } catch (IOException | InterruptedException | RejectedExecutionException e) { log(String.format("Failed to notify webhook: %s", webhook.getName())); diff --git a/src/main/java/jenkins/plugins/office365connector/Webhook.java b/src/main/java/jenkins/plugins/office365connector/Webhook.java index e26b6862..6af71020 100644 --- a/src/main/java/jenkins/plugins/office365connector/Webhook.java +++ b/src/main/java/jenkins/plugins/office365connector/Webhook.java @@ -183,6 +183,11 @@ public static class DescriptorImpl extends Descriptor { private String globalUrl; private String globalName; + private String host; + private String port; + private String username; + private String password; + public DescriptorImpl() { load(); } @@ -193,6 +198,43 @@ public String getDisplayName() { return "Webhook"; } + public String getHost() { + return Util.fixNull(host); + } + + @DataBoundSetter + public void setHost(String host) { + this.host = Util.fixNull(host); + } + + @Nonnull + public String getPort() { + return Util.fixNull(port); + } + + @DataBoundSetter + public void setPort(String port) { + this.port = Util.fixNull(port); + } + + public String getUsername() { + return Util.fixNull(username); + } + + @DataBoundSetter + public void setUsername(String username) { + this.username = Util.fixNull(username); + } + + public String getPassword() { + return Util.fixNull(password); + } + + @DataBoundSetter + public void setPassword(String password) { + this.password = Util.fixNull(password); + } + public int getDefaultTimeout() { return Webhook.DEFAULT_TIMEOUT; } @@ -201,7 +243,7 @@ public FormValidation doCheckUrl(@QueryParameter String value) { return FormUtils.formValidateUrl(value); } - public FormValidation doCheckGlobalUrl(@QueryParameter String value) { + public FormValidation doCheckGlobalUrl(@QueryParameter String value) { if(StringUtils.isNotBlank(value)) { return FormUtils.formValidateUrl(value); } else { diff --git a/src/main/resources/jenkins/plugins/office365connector/Webhook/global.jelly b/src/main/resources/jenkins/plugins/office365connector/Webhook/global.jelly index 09b3ecba..79142b9d 100755 --- a/src/main/resources/jenkins/plugins/office365connector/Webhook/global.jelly +++ b/src/main/resources/jenkins/plugins/office365connector/Webhook/global.jelly @@ -7,5 +7,25 @@ + + + + This section defines the Office365Connector proxy settings that will apply to all webhook notifications. This + proxy configuration will be prioritized over the Jenkins global proxy config + + + + + + + + + + + + + + + diff --git a/src/main/resources/jenkins/plugins/office365connector/Webhook/help-host.html b/src/main/resources/jenkins/plugins/office365connector/Webhook/help-host.html new file mode 100644 index 00000000..87a8c3bb --- /dev/null +++ b/src/main/resources/jenkins/plugins/office365connector/Webhook/help-host.html @@ -0,0 +1 @@ +
The hostname or ip address of the proxy server
diff --git a/src/main/resources/jenkins/plugins/office365connector/Webhook/help-port.html b/src/main/resources/jenkins/plugins/office365connector/Webhook/help-port.html new file mode 100644 index 00000000..fb85fe51 --- /dev/null +++ b/src/main/resources/jenkins/plugins/office365connector/Webhook/help-port.html @@ -0,0 +1 @@ +
This field works in conjunction with the host field to specify the HTTP proxy port.
diff --git a/src/main/resources/jenkins/plugins/office365connector/Webhook/help-username.html b/src/main/resources/jenkins/plugins/office365connector/Webhook/help-username.html new file mode 100644 index 00000000..ee67c430 --- /dev/null +++ b/src/main/resources/jenkins/plugins/office365connector/Webhook/help-username.html @@ -0,0 +1 @@ +
This field works in conjunction with the proxy server field to specify the username used to authenticate with the proxy.
diff --git a/src/test/java/jenkins/plugins/office365connector/HttpWorkerTest.java b/src/test/java/jenkins/plugins/office365connector/HttpWorkerTest.java index 7b9039f1..f2e0ee23 100644 --- a/src/test/java/jenkins/plugins/office365connector/HttpWorkerTest.java +++ b/src/test/java/jenkins/plugins/office365connector/HttpWorkerTest.java @@ -33,11 +33,12 @@ public void setUp() { } @Test - public void HttpWorker_getHttpClient_NoProxy() throws NoSuchMethodException { + public void HttpWorker_getHttpClient_NoJenkinsProxy() throws NoSuchMethodException { // given // from @Before - HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out); + ProxyConfiguration thisPluginProxy = new ProxyConfiguration("", 0, "", ""); + HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out, thisPluginProxy); Method method = HttpWorker.class.getDeclaredMethod("getHttpClient"); method.setAccessible(true); @@ -50,15 +51,16 @@ public void HttpWorker_getHttpClient_NoProxy() throws NoSuchMethodException { } @Test - public void HttpWorker_getHttpClient_Proxy() throws NoSuchMethodException { + public void HttpWorker_getHttpClient_JenkinsProxy() throws NoSuchMethodException { // given // from @Before + ProxyConfiguration thisPluginProxy = new ProxyConfiguration("", 0, "", ""); Jenkins jenkins = Jenkins.get(); ProxyConfiguration proxyConfiguration = new ProxyConfiguration("name", 123, null, null, "*mockwebsite.com*"); jenkins.proxy = proxyConfiguration; - HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out); + HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out, thisPluginProxy); Method method = HttpWorker.class.getDeclaredMethod("getHttpClient"); method.setAccessible(true); @@ -71,15 +73,16 @@ public void HttpWorker_getHttpClient_Proxy() throws NoSuchMethodException { } @Test - public void HttpWorker_getHttpClient_Proxy_Ignored() throws NoSuchMethodException { + public void HttpWorker_getHttpClient_JenkinsProxy_Ignored() throws NoSuchMethodException { // given // from @Before + ProxyConfiguration thisPluginProxy = new ProxyConfiguration("", 0, "", ""); Jenkins jenkins = Jenkins.get(); ProxyConfiguration proxyConfiguration = new ProxyConfiguration("name", 123, null, null, "*mockwebsite.com*"); jenkins.proxy = proxyConfiguration; - HttpWorker httpWorker = new HttpWorker("http://mockwebsite.com", "{}", 30, System.out); + HttpWorker httpWorker = new HttpWorker("http://mockwebsite.com", "{}", 30, System.out, thisPluginProxy); Method method = HttpWorker.class.getDeclaredMethod("getHttpClient"); method.setAccessible(true); @@ -90,4 +93,22 @@ public void HttpWorker_getHttpClient_Proxy_Ignored() throws NoSuchMethodExceptio assertThat(httpClient.getHostConfiguration().getProxyHost()).isNull(); assertThat(httpClient.getHostConfiguration().getProxyPort()).isEqualTo(-1); } -} + + @Test + public void HttpWorker_getHttpClient_PluginProxy() throws NoSuchMethodException { + + // given + // from @Before + ProxyConfiguration thisPluginProxy = new ProxyConfiguration("10.0.0.1", 12345, "", ""); + HttpWorker httpWorker = new HttpWorker("http://127.0.0.1", "{}", 30, System.out, thisPluginProxy); + Method method = HttpWorker.class.getDeclaredMethod("getHttpClient"); + method.setAccessible(true); + + // when + HttpClient httpClient = (HttpClient) ReflectionUtils.invokeMethod(method, httpWorker); + + // then + assertThat(httpClient.getHostConfiguration().getProxyHost()).isEqualTo(thisPluginProxy.getName()); + assertThat(httpClient.getHostConfiguration().getProxyPort()).isEqualTo(thisPluginProxy.getPort()); + } +} \ No newline at end of file diff --git a/src/test/java/jenkins/plugins/office365connector/WebhookTest.java b/src/test/java/jenkins/plugins/office365connector/WebhookTest.java index 9bdd45d2..e4beb190 100644 --- a/src/test/java/jenkins/plugins/office365connector/WebhookTest.java +++ b/src/test/java/jenkins/plugins/office365connector/WebhookTest.java @@ -2,16 +2,23 @@ import java.util.Arrays; import java.util.List; + +import hudson.model.AbstractBuild; +import hudson.model.Job; +import hudson.model.Result; import jenkins.model.Jenkins; import jenkins.plugins.office365connector.model.FactDefinition; import jenkins.plugins.office365connector.model.Macro; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.anyObject; import static org.powermock.api.mockito.PowerMockito.mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; @@ -23,6 +30,16 @@ @RunWith(PowerMockRunner.class) @PrepareForTest(Jenkins.class) public class WebhookTest { + @Before + public void setUp() throws Exception { + + Webhook.DescriptorImpl mockDescriptor = mock(Webhook.DescriptorImpl.class); + + Jenkins jenkins = mock(Jenkins.class); + mockStatic(Jenkins.class); + Mockito.when(Jenkins.get()).thenReturn(jenkins); + Mockito.when(jenkins.getDescriptorOrDie(anyObject())).thenReturn(mockDescriptor); + } @Test public void getUrl_ReturnsUrl() { diff --git a/src/test/java/jenkins/plugins/office365connector/workflow/DevelopersIT.java b/src/test/java/jenkins/plugins/office365connector/workflow/DevelopersIT.java index e4340c50..63604a4c 100644 --- a/src/test/java/jenkins/plugins/office365connector/workflow/DevelopersIT.java +++ b/src/test/java/jenkins/plugins/office365connector/workflow/DevelopersIT.java @@ -1,15 +1,14 @@ package jenkins.plugins.office365connector.workflow; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.when; - import java.util.List; import hudson.model.AbstractBuild; import hudson.model.Job; import hudson.scm.ChangeLogSet; +import jenkins.model.Jenkins; import jenkins.plugins.office365connector.FileUtils; import jenkins.plugins.office365connector.Office365ConnectorWebhookNotifier; +import jenkins.plugins.office365connector.Webhook; import jenkins.plugins.office365connector.helpers.AffectedFileBuilder; import org.junit.Before; import org.junit.Test; @@ -18,12 +17,14 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import static org.powermock.api.mockito.PowerMockito.*; + /** * @author Damian Szczepanik (damianszczepanik@github) */ @PowerMockIgnore("jdk.internal.reflect.*") @RunWith(PowerMockRunner.class) -@PrepareForTest(Office365ConnectorWebhookNotifier.class) +@PrepareForTest({Office365ConnectorWebhookNotifier.class, Jenkins.class}) public class DevelopersIT extends AbstractTest { private static final String JOB_NAME = "simple job"; @@ -31,8 +32,16 @@ public class DevelopersIT extends AbstractTest { @Before public void setUp() { + Webhook.DescriptorImpl mockDescriptor = mock(Webhook.DescriptorImpl.class); + when(mockDescriptor.getName()).thenReturn("testName"); + + mockStatic(Jenkins.class); + Jenkins jenkins = mock(Jenkins.class); mockListener(); + when(jenkins.getDescriptorOrDie(Webhook.class)).thenReturn(mockDescriptor); + when(Jenkins.get()).thenReturn(jenkins); + run = mockRun(); mockDisplayURLProvider(JOB_NAME, BUILD_NUMBER); diff --git a/src/test/java/jenkins/plugins/office365connector/workflow/PullRequestIT.java b/src/test/java/jenkins/plugins/office365connector/workflow/PullRequestIT.java index 1821add8..4c68c6cd 100644 --- a/src/test/java/jenkins/plugins/office365connector/workflow/PullRequestIT.java +++ b/src/test/java/jenkins/plugins/office365connector/workflow/PullRequestIT.java @@ -47,10 +47,17 @@ public class PullRequestIT extends AbstractTest { @Before public void setUp() { + + Webhook.DescriptorImpl mockDescriptor = mock(Webhook.DescriptorImpl.class); + when(mockDescriptor.getName()).thenReturn("testName"); + mockStatic(Jenkins.class); Jenkins jenkins = mock(Jenkins.class); mockListener(); + when(jenkins.getDescriptorOrDie(Webhook.class)).thenReturn(mockDescriptor); + when(Jenkins.get()).thenReturn(jenkins); + run = mockRun(); mockCause("Branch indexing"); mockCommitters(); @@ -59,15 +66,7 @@ public void setUp() { mockEnvironment(); mockHttpWorker(); mockGetChangeSets(); - mockPullRequest(); - - when(Jenkins.get()).thenReturn(jenkins); - - Webhook.DescriptorImpl mockDescriptor = mock(Webhook.DescriptorImpl.class); - when(mockDescriptor.getName()).thenReturn("testName"); - - when(jenkins.getDescriptorOrDie(Webhook.class)).thenReturn(mockDescriptor); } private AbstractBuild mockRun() { diff --git a/src/test/java/jenkins/plugins/office365connector/workflow/SampleIT.java b/src/test/java/jenkins/plugins/office365connector/workflow/SampleIT.java index cd06d2e6..8ff6e71f 100644 --- a/src/test/java/jenkins/plugins/office365connector/workflow/SampleIT.java +++ b/src/test/java/jenkins/plugins/office365connector/workflow/SampleIT.java @@ -41,10 +41,16 @@ public class SampleIT extends AbstractTest { @Before public void setUp() { + Webhook.DescriptorImpl mockDescriptor = mock(Webhook.DescriptorImpl.class); + when(mockDescriptor.getName()).thenReturn("testName"); + mockStatic(Jenkins.class); Jenkins jenkins = mock(Jenkins.class); mockListener(); + when(jenkins.getDescriptorOrDie(Webhook.class)).thenReturn(mockDescriptor); + when(Jenkins.get()).thenReturn(jenkins); + run = mockRun(); mockCause(CAUSE_DESCRIPTION); @@ -52,13 +58,6 @@ public void setUp() { mockEnvironment(); mockHttpWorker(); mockGetChangeSets(); - - when(Jenkins.get()).thenReturn(jenkins); - - Webhook.DescriptorImpl mockDescriptor = mock(Webhook.DescriptorImpl.class); - when(mockDescriptor.getName()).thenReturn("testName"); - - when(jenkins.getDescriptorOrDie(Webhook.class)).thenReturn(mockDescriptor); } private AbstractBuild mockRun() { diff --git a/src/test/java/jenkins/plugins/office365connector/workflow/WebhookJobPropertyTest.java b/src/test/java/jenkins/plugins/office365connector/workflow/WebhookJobPropertyTest.java index ac28719f..6d43b93e 100644 --- a/src/test/java/jenkins/plugins/office365connector/workflow/WebhookJobPropertyTest.java +++ b/src/test/java/jenkins/plugins/office365connector/workflow/WebhookJobPropertyTest.java @@ -1,16 +1,19 @@ package jenkins.plugins.office365connector.workflow; import static org.assertj.core.api.Assertions.assertThat; -import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.*; +import static org.powermock.api.mockito.PowerMockito.when; import java.util.Collections; import java.util.List; import hudson.model.AbstractBuild; +import jenkins.model.Jenkins; import jenkins.plugins.office365connector.Office365ConnectorWebhookNotifier; import jenkins.plugins.office365connector.Webhook; import jenkins.plugins.office365connector.WebhookJobProperty; import jenkins.plugins.office365connector.helpers.WebhookBuilder; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PowerMockIgnore; @@ -22,9 +25,21 @@ */ @PowerMockIgnore("jdk.internal.reflect.*") @RunWith(PowerMockRunner.class) -@PrepareForTest({Office365ConnectorWebhookNotifier.class, WebhookJobProperty.class}) +@PrepareForTest({Office365ConnectorWebhookNotifier.class, WebhookJobProperty.class, Jenkins.class}) public class WebhookJobPropertyTest extends AbstractTest { + @Before + public void setUp() { + Webhook.DescriptorImpl mockDescriptor = mock(Webhook.DescriptorImpl.class); + when(mockDescriptor.getName()).thenReturn("testName"); + + mockStatic(Jenkins.class); + Jenkins jenkins = mock(Jenkins.class); + mockListener(); + + when(jenkins.getDescriptorOrDie(Webhook.class)).thenReturn(mockDescriptor); + when(Jenkins.get()).thenReturn(jenkins); + } @Test public void getWebhooks_ReturnsHook() {