Skip to content
Permalink
Browse files

Merge pull request #12 from ikedam/feature/JENKINS-27375_DisableProvi…

…ders

[JENKINS-27375] Add options to enable / disable choice providers
  • Loading branch information...
ikedam committed May 15, 2015
2 parents 8c3df42 + 5b1ff21 commit 74176e38f536a58ce32d03552885ccb7e434d43c
Showing with 921 additions and 470 deletions.
  1. +91 −0 ...main/java/jp/ikedam/jenkins/plugins/extensible_choice_parameter/ChoiceListProviderDescriptor.java
  2. +130 −8 ...va/jp/ikedam/jenkins/plugins/extensible_choice_parameter/ExtensibleChoiceParameterDefinition.java
  3. +1 −2 .../java/jp/ikedam/jenkins/plugins/extensible_choice_parameter/GlobalTextareaChoiceListProvider.java
  4. +1 −28 ...edam/jenkins/plugins/extensible_choice_parameter/ExtensibleChoiceParameterDefinition/config.jelly
  5. +42 −0 ...edam/jenkins/plugins/extensible_choice_parameter/ExtensibleChoiceParameterDefinition/global.jelly
  6. +1 −0 ...ources/jp/ikedam/jenkins/plugins/extensible_choice_parameter/FilenameChoiceListProvider/help.html
  7. +0 −2 .../ikedam/jenkins/plugins/extensible_choice_parameter/GlobalTextareaChoiceListProvider/global.jelly
  8. +613 −3 ...m/jenkins/plugins/extensible_choice_parameter/ExtensibleChoiceParameterDefinitionJenkinsTest.java
  9. +0 −427 ...am/jenkins/plugins/extensible_choice_parameter/ExtensibleChoiceParameterDefinitionSimpleTest.java
  10. +13 −0 ...a/jp/ikedam/jenkins/plugins/extensible_choice_parameter/ExtensibleChoiceParameterJenkinsRule.java
  11. +9 −0 ...ensibleChoiceParameterDefinitionJenkinsTest/EnableConfigurableMockChoiceListProvider/config.jelly
  12. +11 −0 ...ensibleChoiceParameterDefinitionJenkinsTest/EnableConfigurableMockChoiceListProvider/global.jelly
  13. +9 −0 ...oice_parameter/ExtensibleChoiceParameterDefinitionJenkinsTest/MockChoiceListProvider/config.jelly
@@ -0,0 +1,91 @@
/*
* The MIT License
*
* Copyright (c) 2014 IKEDA Yasuyuki
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package jp.ikedam.jenkins.plugins.extensible_choice_parameter;

import hudson.model.Descriptor;

/**
* Descriptor for {@link ChoiceListProvider}s.
*/
public abstract class ChoiceListProviderDescriptor extends Descriptor<ChoiceListProvider>
{
protected ChoiceListProviderDescriptor()
{
super();
}

/**
* @param clazz
*/
protected ChoiceListProviderDescriptor(Class<? extends ChoiceListProvider> clazz)
{
super(clazz);
}


/**
* Returns whether this provider should be enabled by default (that is, just after that provider is installed).
*
* Override this method and return false if you want to disable your provider
* and want administrators enable that explicitly.
*
* @return
*/
public boolean isEnabledByDefault()
{
return true;
}

/**
* Disables the global configuration page and replaces with {@link #getGlobalConfigPageForChoiceListProvider()}
*
* @return false
* @see hudson.model.Descriptor#getGlobalConfigPage()
*/
@Override
public String getGlobalConfigPage()
{
return null;
}

/**
* @return a view page displayed in the system configuration page under the section of {@link ExtensibleChoiceParameterDefinition}
*/
public String getGlobalConfigPageForChoiceListProvider()
{
for (String cand: getPossibleViewNames("global")) {
String page = getViewPage(clazz, cand);
// Unfortunately, Descriptor#getViewPage returns passed value
// when that view is not found.
// When found, path to that file is returned,
// so I can check whether found
// by comparing passing value and returned value.
if (page != null && !page.equals(cand)) {
return page;
}
}
return null;
}
}
@@ -24,7 +24,13 @@
package jp.ikedam.jenkins.plugins.extensible_choice_parameter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import jenkins.model.Jenkins;
@@ -33,6 +39,7 @@
import hudson.Util;
import hudson.model.Descriptor;
import hudson.model.Describable;
import hudson.model.DescriptorVisibilityFilter;
import hudson.model.ParameterValue;
import hudson.model.StringParameterValue;
import hudson.model.SimpleParameterDefinition;
@@ -43,6 +50,7 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import net.sf.json.JSONObject;

/**
@@ -52,6 +60,7 @@
public class ExtensibleChoiceParameterDefinition extends SimpleParameterDefinition
{
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(ExtensibleChoiceParameterDefinition.class.getName());

private static final Pattern namePattern = Pattern.compile("[A-Za-z_][A-Za-z_0-9]*");

@@ -79,6 +88,67 @@ public static Pattern getNamePattern()
@Extension
public static class DescriptorImpl extends ParameterDescriptor
{
private Map<String,Boolean> choiceListEnabledMap;

public DescriptorImpl()
{
setChoiceListEnabledMap(Collections.<String, Boolean>emptyMap());
load();
}

protected void setChoiceListEnabledMap(Map<String, Boolean> choiceListEnabledMap)
{
this.choiceListEnabledMap = choiceListEnabledMap;
}

protected Map<String, Boolean> getChoiceListEnabledMap()
{
return choiceListEnabledMap;
}

@Override
public boolean configure(StaplerRequest req, JSONObject json) throws hudson.model.Descriptor.FormException
{
Map<String, Boolean> configuredChoiceListEnableMap = new HashMap<String, Boolean>();
for(Descriptor<ChoiceListProvider> d: getChoiceListProviderList())
{
String name = d.getJsonSafeClassName();
JSONObject o = json.optJSONObject(name);

if(o != null)
{
configuredChoiceListEnableMap.put(d.getId(), true);
if(d instanceof ChoiceListProviderDescriptor)
{
d.configure(req, o);
}
}
else
{
configuredChoiceListEnableMap.put(d.getId(), false);
}
}
setChoiceListEnabledMap(configuredChoiceListEnableMap);

save();

return super.configure(req, json);
}

public boolean isProviderEnabled(Descriptor<?> d)
{
Boolean b = getChoiceListEnabledMap().get(d.getId());
if(b != null)
{
return b.booleanValue();
}
if(!(d instanceof ChoiceListProviderDescriptor))
{
return true;
}
return ((ChoiceListProviderDescriptor)d).isEnabledByDefault();
}

/**
* Create a new instance of {@link SystemGroovyChoiceListProvider} from user inputs.
*
@@ -121,12 +191,13 @@ public ExtensibleChoiceParameterDefinition newInstance(StaplerRequest req,
if (formData == null || formData.isNullObject()) {
return null;
}
if (!formData.has("stapler-class")) {
throw new FormException("No stapler-class is specified", fieldName);
String staplerClazzName = formData.optString("$class", null);
if (staplerClazzName == null) {
// Fall back on the legacy stapler-class attribute.
staplerClazzName = formData.optString("stapler-class", null);
}
String staplerClazzName = formData.getString("stapler-class");
if (staplerClazzName == null) {
throw new FormException("No stapler-class is specified", fieldName);
throw new FormException("No $stapler nor stapler-class is specified", fieldName);
}
try {
@SuppressWarnings("unchecked")
@@ -161,15 +232,25 @@ public String getDisplayName()
/**
* Returns all the available methods to provide choices.
*
* Used for showing dropdown for users to select a choice provider.
*
* @return DescriptorExtensionList of ChoiceListProvider subclasses.
*/
public DescriptorExtensionList<ChoiceListProvider,Descriptor<ChoiceListProvider>> getChoiceListProviderList()
{
return ChoiceListProvider.all();
}

/**
* Returns all the available methods to provide choices that are enabled in the global configuration.
*
* Used for showing dropdown for users to select a choice provider.
*
* @return DescriptorExtensionList of ChoiceListProvider subclasses.
*/
public List<Descriptor<ChoiceListProvider>> getEnabledChoiceListProviderList()
{
return DescriptorVisibilityFilter.apply(this, ChoiceListProvider.all());
}

public FormValidation doCheckName(@QueryParameter String name){
if(StringUtils.isBlank(name))
{
@@ -202,6 +283,21 @@ public String resolve(String name)
}
}

@Extension
public static class DescriptorVisibilityFilterImpl extends DescriptorVisibilityFilter
{
@SuppressWarnings("unchecked")
@Override
public boolean filter(Object context, @SuppressWarnings("rawtypes") Descriptor descriptor)
{
if(!(context instanceof DescriptorImpl))
{
return true;
}
return ((DescriptorImpl)context).isProviderEnabled(descriptor);
}
}

private boolean editable = false;

/**
@@ -226,14 +322,39 @@ public ChoiceListProvider getChoiceListProvider()
return choiceListProvider;
}

/**
* @return choice provider only when it's enabled
* @see DescriptorImpl#isProviderEnabled(Descriptor)
*/
public ChoiceListProvider getEnabledChoiceListProvider()
{
ChoiceListProvider p = getChoiceListProvider();
if(p == null)
{
return null;
}

// filter providers.
List<Descriptor<ChoiceListProvider>> testList = DescriptorVisibilityFilter.apply(
getDescriptor(),
Arrays.asList(p.getDescriptor())
);
if(testList.isEmpty())
{
LOGGER.log(Level.WARNING, "{0} is configured but disabled in the system configuration.", p.getDescriptor().getDisplayName());
return null;
}
return p;
}

/**
* Return choices available for this parameter.
*
* @return list of choices. never null.
*/
public List<String> getChoiceList()
{
ChoiceListProvider provider = getChoiceListProvider();
ChoiceListProvider provider = getEnabledChoiceListProvider();
List<String> choiceList = (provider != null)?provider.getChoiceList():null;
return (choiceList != null)?choiceList:new ArrayList<String>(0);
}
@@ -323,7 +444,8 @@ public ParameterValue createValue(String value) throws IllegalArgumentException
@Override
public ParameterValue getDefaultParameterValue()
{
String defaultChoice = (getChoiceListProvider() != null)?getChoiceListProvider().getDefaultChoice():null;
ChoiceListProvider p = getEnabledChoiceListProvider();
String defaultChoice = (p != null)?p.getDefaultChoice():null;
if(defaultChoice != null)
{
return createValue(defaultChoice);
@@ -31,7 +31,6 @@

import hudson.Extension;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.util.ListBoxModel;

import org.apache.commons.collections.CollectionUtils;
@@ -73,7 +72,7 @@
* </dl>
*/
@Extension
public static class DescriptorImpl extends Descriptor<ChoiceListProvider>
public static class DescriptorImpl extends ChoiceListProviderDescriptor
{
/**
* Restore from the global configuration
@@ -31,34 +31,7 @@ THE SOFTWARE.
<f:entry title="${%Description}" field="description" help="/help/parameter/description.html">
<f:textarea />
</f:entry>
<f:dropdownList title="${%Choice Provider}" name="choiceListProvider" help="${descriptor.getHelpFile('choiceListProvider')}">
<j:forEach
var="curDescriptor"
items="${descriptor.choiceListProviderList.iterator()}"
varStatus="loop">
<j:scope>
<j:set
var="choiceListProvider"
value="${curDescriptor==instance.choiceListProvider.descriptor?instance.choiceListProvider:null}"
/>
<f:dropdownListBlock
title="${curDescriptor.displayName}"
value="${loop.index}"
selected="${choiceListProvider != null}"
staplerClass="${curDescriptor.clazz.name}"
><j:scope>
<!-- Shown only when corresponding ChoiceProvider is selected. -->
<j:set var="descriptor" value="${curDescriptor}" />
<j:set var="instance" value="${choiceListProvider}" />
<!--
Call config.jelly of the ChoiceProvider subclass.
Do nothing if config.jelly is not provided.
-->
<st:include page="config.jelly" class="${curDescriptor.clazz}" optional="${true}" />
</j:scope></f:dropdownListBlock>
</j:scope>
</j:forEach>
</f:dropdownList>
<f:dropdownDescriptorSelector title="${%Choice Provider}" field="choiceListProvider" descriptors="${descriptor.enabledChoiceListProviderList}" />
<f:entry title="${%Editable}" field="editable">
<f:checkbox />
</f:entry>
Oops, something went wrong.

0 comments on commit 74176e3

Please sign in to comment.
You can’t perform that action at this time.