Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/Support for local plugin proxy #277

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .README/globalconfig.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
14 changes: 12 additions & 2 deletions src/main/java/jenkins/plugins/office365connector/HttpWorker.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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<Pattern> noHostProxyPatterns = proxy.getNoProxyHostPatterns();
if (!isNoProxyHost(this.url, noHostProxyPatterns)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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().getIp(), 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()));
Expand Down
45 changes: 44 additions & 1 deletion src/main/java/jenkins/plugins/office365connector/Webhook.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.List;
import javax.annotation.Nonnull;
import hudson.Extension;
import hudson.ProxyConfiguration;
import hudson.Util;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
Expand Down Expand Up @@ -183,6 +184,11 @@ public static class DescriptorImpl extends Descriptor<Webhook> {
private String globalUrl;
private String globalName;

private String ip;
private String port;
private String username;
rockleez marked this conversation as resolved.
Show resolved Hide resolved
private String password;

public DescriptorImpl() {
load();
}
Expand All @@ -193,6 +199,43 @@ public String getDisplayName() {
return "Webhook";
}

public String getIp() {
return Util.fixNull(ip);
}

@DataBoundSetter
public void setIp(String ip) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IP or address?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

settled on using the term host

this.ip = Util.fixNull(ip);
}

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);
}

@Nonnull
public String getPort() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reorder and put port together with ip/address

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return Util.fixNull(port);
}

@DataBoundSetter
public void setPort(String port) {
this.port = Util.fixNull(port);
}

public int getDefaultTimeout() {
return Webhook.DEFAULT_TIMEOUT;
}
Expand All @@ -201,7 +244,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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
This section defines for which build statuses the notification is sent.
</f:description>

<f:entry title="Notify Build Start" field="startNotification">
<f:entry title="Notify Build Start" field="startNotification" >
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

<f:checkbox/>
</f:entry>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,25 @@
<f:entry title="Name" field="globalName">
<f:textbox/>
</f:entry>
<f:advanced>
<f:section title="Proxy Config">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configuration

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

<f:description>
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
rockleez marked this conversation as resolved.
Show resolved Hide resolved
</f:description>
<f:entry title="IP" field="ip">
<f:textbox/>
</f:entry>
<f:entry title="Port" field="port">
<f:textbox/>
</f:entry>
<f:entry title="Username" field="username">
<f:textbox/>
</f:entry>
<f:entry title="Password" field="password">
<f:password/>
</f:entry>
</f:section>
</f:advanced>
</f:section>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div align="help">The IP address of the proxy server</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would the proxy.local.dev be valid value It does not look like IP address?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the description

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div align="help">This field works in conjunction with the ip field to specify the HTTP proxy port.</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div align="help">This field works in conjunction with the proxy server field to specify the username used to authenticate with the proxy.</div>
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);

Expand All @@ -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);

Expand All @@ -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());
}
}
17 changes: 17 additions & 0 deletions src/test/java/jenkins/plugins/office365connector/WebhookTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -18,21 +17,31 @@
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";
private static final int BUILD_NUMBER = 1;

@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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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() {
Expand Down
Loading