Skip to content

Commit

Permalink
JENKINS-44524 Support configuring a site on a folder
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Saville committed Jun 5, 2017
1 parent 45e79b3 commit b1408fe
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 37 deletions.
30 changes: 30 additions & 0 deletions src/main/java/hudson/plugins/jira/EmptyFriendlyURLConverter.java
@@ -0,0 +1,30 @@
package hudson.plugins.jira;

import org.apache.commons.beanutils.Converter;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* It's little hackish.
*/
@Restricted(NoExternalUse.class)
public class EmptyFriendlyURLConverter implements Converter {
private static final Logger LOGGER = Logger
.getLogger(JiraProjectProperty.class.getName());

public Object convert(Class aClass, Object o) {
if (o == null || "".equals(o) || "null".equals(o)) {
return null;
}
try {
return new URL(o.toString());
} catch (MalformedURLException e) {
LOGGER.log(Level.WARNING, "{0} is not a valid URL", o);
return null;
}
}
}
82 changes: 82 additions & 0 deletions src/main/java/hudson/plugins/jira/JiraFolderProperty.java
@@ -0,0 +1,82 @@
package hudson.plugins.jira;

import com.cloudbees.hudson.plugins.folder.AbstractFolder;
import com.cloudbees.hudson.plugins.folder.AbstractFolderProperty;
import com.cloudbees.hudson.plugins.folder.AbstractFolderPropertyDescriptor;
import hudson.Extension;
import hudson.model.Descriptor;
import hudson.util.CopyOnWriteList;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;

import javax.annotation.Nonnull;
import java.util.List;

/**
* Provides folder level JIRA configuration.
*/
public class JiraFolderProperty extends AbstractFolderProperty<AbstractFolder<?>> {
/**
* Hold the JIRA sites configuration.
*/
private final CopyOnWriteList<JiraSite> sites = new CopyOnWriteList<JiraSite>();

/**
* Constructor.
*/
@DataBoundConstructor
public JiraFolderProperty() {
}

@Override
public AbstractFolderProperty<?> reconfigure(StaplerRequest req, JSONObject formData)
throws Descriptor.FormException {
if (formData == null) {
return null;
}
//Fix^H^H^HDirty hack for empty string to URL conversion error
//Should check for existing handler etc, but since this is a dirty hack,
//we won't
Stapler.CONVERT_UTILS.deregister(java.net.URL.class);
Stapler.CONVERT_UTILS.register(new EmptyFriendlyURLConverter(), java.net.URL.class);
//End hack

sites.replaceBy(req.bindJSONToList(JiraSite.class, formData.get("sites")));
return this;
}

/**
* Return the JIRA sites.
*
* @return the JIRA sites
*/
public JiraSite[] getSites() {
return sites.toArray(new JiraSite[0]);
}

/**
* Adds a JIRA site.
*
* @param site the JIRA site
*/
@DataBoundSetter
public void setSites(JiraSite site) {
sites.add(site);
}

/**
* Descriptor class.
*/
@Extension
public static class DescriptorImpl extends AbstractFolderPropertyDescriptor {

@Nonnull
@Override
public String getDisplayName() {
return Messages.JiraFolderProperty_DisplayName();
}
}
}
27 changes: 0 additions & 27 deletions src/main/java/hudson/plugins/jira/JiraProjectProperty.java
Expand Up @@ -6,16 +6,10 @@
import hudson.model.JobPropertyDescriptor;
import hudson.util.CopyOnWriteList;
import net.sf.json.JSONObject;
import org.apache.commons.beanutils.Converter;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
Expand Down Expand Up @@ -122,26 +116,5 @@ public boolean configure(StaplerRequest req, JSONObject formData) {
save();
return true;
}

/**
* It's little hackish
*/
@Restricted(NoExternalUse.class)
public static class EmptyFriendlyURLConverter implements Converter {
public Object convert(Class aClass, Object o) {
if (o == null || "".equals(o) || "null".equals(o)) {
return null;
}
try {
return new URL(o.toString());
} catch (MalformedURLException e) {
LOGGER.log(Level.WARNING, "{0} is not a valid URL", o);
return null;
}
}
}
}

private static final Logger LOGGER = Logger
.getLogger(JiraProjectProperty.class.getName());
}
29 changes: 25 additions & 4 deletions src/main/java/hudson/plugins/jira/JiraSite.java
Expand Up @@ -5,15 +5,13 @@
import com.atlassian.jira.rest.client.api.domain.Issue;
import com.atlassian.jira.rest.client.api.domain.Version;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
import com.google.common.base.*;
import com.cloudbees.hudson.plugins.folder.AbstractFolder;
import com.google.common.base.Objects;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import hudson.Extension;
import hudson.Util;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.model.Job;
import hudson.model.*;
import hudson.plugins.jira.model.JiraIssue;
import hudson.plugins.jira.model.JiraVersion;
import hudson.util.FormValidation;
Expand Down Expand Up @@ -384,12 +382,35 @@ public Set<String> getProjectKeys() {
public static JiraSite get(Job<?, ?> p) {
JiraProjectProperty jpp = p.getProperty(JiraProjectProperty.class);
if (jpp != null) {
// Looks in global configuration for the site configured
JiraSite site = jpp.getSite();
if (site != null) {
return site;
}
}

// Check up the folder chain if a site is defined there
// This only supports one site per folder
ItemGroup parent = p.getParent();
while (parent != null) {
if (parent instanceof AbstractFolder) {
AbstractFolder folder = (AbstractFolder) parent;
JiraFolderProperty jfp = (JiraFolderProperty) folder.getProperties().get(JiraFolderProperty.class);
if (jfp != null) {
JiraSite[] sites = jfp.getSites();
if (sites != null && sites.length > 0) {
return sites[0];
}
}
}

if (parent instanceof Item) {
parent = ((Item) parent).getParent();
} else {
parent = null;
}
}

// none is explicitly configured. try the default ---
// if only one is configured, that must be it.
JiraSite[] sites = JiraProjectProperty.DESCRIPTOR.getSites();
Expand Down
@@ -0,0 +1,7 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:section title="JIRA">
<f:entry title="${%JIRA sites}" description="">
<f:repeatableProperty field="sites"/>
</f:entry>
</f:section>
</j:jelly>
1 change: 1 addition & 0 deletions src/main/resources/hudson/plugins/jira/Messages.properties
@@ -1,4 +1,5 @@
JiraIssueUpdater.DisplayName=JIRA: Update relevant issues
JiraFolderProperty.DisplayName=Associated JIRA
JiraProjectProperty.DisplayName=Associated JIRA
JiraProjectProperty.JiraUrlMandatory=JIRA URL is a mandatory field
JiraProjectProperty.NotAJiraUrl=This is a valid URL but it doesn''t look like JIRA
Expand Down
Expand Up @@ -26,35 +26,35 @@ public class EmptyFriendlyURLConverterTest {
@WithoutJenkins
public void shouldHandleURLClass() throws Exception {
URL someUrl = new URL(SOME_VALID_URL);
assertThat(new JiraProjectProperty.DescriptorImpl.EmptyFriendlyURLConverter()
assertThat(new EmptyFriendlyURLConverter()
.convert(URL.class, someUrl), Matchers.<Object>is(someUrl));
}

@Test
@WithoutJenkins
public void shouldHandleStringClass() throws Exception {
assertThat(new JiraProjectProperty.DescriptorImpl.EmptyFriendlyURLConverter()
assertThat(new EmptyFriendlyURLConverter()
.convert(URL.class, SOME_VALID_URL), Matchers.<Object>is(new URL(SOME_VALID_URL)));
}

@Test
@WithoutJenkins
public void shouldHandleNull() throws Exception {
assertThat(new JiraProjectProperty.DescriptorImpl.EmptyFriendlyURLConverter()
assertThat(new EmptyFriendlyURLConverter()
.convert(URL.class, null), nullValue());
}

@Test
@WithoutJenkins
public void shouldHandleEmptyString() throws Exception {
assertThat(new JiraProjectProperty.DescriptorImpl.EmptyFriendlyURLConverter()
assertThat(new EmptyFriendlyURLConverter()
.convert(URL.class, StringUtils.EMPTY), nullValue());
}

@Test
@WithoutJenkins
public void shouldHandleNullAsString() throws Exception {
assertThat(new JiraProjectProperty.DescriptorImpl.EmptyFriendlyURLConverter()
assertThat(new EmptyFriendlyURLConverter()
.convert(URL.class, "null"), nullValue());
}

Expand All @@ -63,7 +63,7 @@ public void shouldHandleNullAsString() throws Exception {
*/
@Test
public void shouldHandleMalformedUrlAsString() throws Exception {
assertThat(new JiraProjectProperty.DescriptorImpl.EmptyFriendlyURLConverter()
assertThat(new EmptyFriendlyURLConverter()
.convert(URL.class, "bla"), nullValue());
}

Expand Down

0 comments on commit b1408fe

Please sign in to comment.