Skip to content

Commit

Permalink
[JENKINS-17875] Added option whether to use predefined variables. Thi…
Browse files Browse the repository at this point in the history
…s can allow users to have a workaround when a problem happened retrieving project.
  • Loading branch information
ikedam committed Dec 7, 2013
1 parent 3fed072 commit 9bf438c
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 47 deletions.
Expand Up @@ -85,7 +85,11 @@ public SystemGroovyChoiceListProvider newInstance(StaplerRequest req, JSONObject
throws hudson.model.Descriptor.FormException
{
SystemGroovyChoiceListProvider provider = (SystemGroovyChoiceListProvider)super.newInstance(req, formData);
provider.setProject(req.findAncestorObject(AbstractProject.class));
if(provider.isUsePredefinedVariables())
{
// set project only when variables is requested.
provider.setProject(req.findAncestorObject(AbstractProject.class));
}
return provider;
}

Expand All @@ -108,15 +112,22 @@ public String getDisplayName()
* @param scriptText
* @return the selection of a default choice
*/
public ListBoxModel doFillDefaultChoiceItems(StaplerRequest req, @QueryParameter String scriptText)
public ListBoxModel doFillDefaultChoiceItems(StaplerRequest req, @QueryParameter String scriptText, @QueryParameter boolean usePredefinedVariables)
{
ListBoxModel ret = new ListBoxModel();
ret.add(Messages.ExtensibleChoiceParameterDefinition_NoDefaultChoice(), NoDefaultChoice);

List<String> choices = null;
AbstractProject<?,?> project = null;

if(usePredefinedVariables && req != null)
{
project = req.findAncestorObject(AbstractProject.class);
}

try
{
choices = runScript(scriptText, (req != null)?req.findAncestorObject(AbstractProject.class):null);
choices = runScript(scriptText, usePredefinedVariables, project);
}
catch(Exception e)
{
Expand All @@ -134,12 +145,19 @@ public ListBoxModel doFillDefaultChoiceItems(StaplerRequest req, @QueryParameter
return ret;
}

public FormValidation doTest(StaplerRequest req, @QueryParameter String scriptText)
public FormValidation doTest(StaplerRequest req, @QueryParameter String scriptText, @QueryParameter boolean usePredefinedVariables)
{
List<String> choices = null;
AbstractProject<?,?> project = null;

if(usePredefinedVariables && req != null)
{
project = req.findAncestorObject(AbstractProject.class);
}

try
{
choices = runScript(scriptText, (req != null)?req.findAncestorObject(AbstractProject.class):null);
choices = runScript(scriptText, usePredefinedVariables, project);
}
catch(Exception e)
{
Expand All @@ -166,7 +184,7 @@ public List<String> getChoiceList()
{
List<String> ret = null;
AbstractProject<?,?> project = getProject();
if(project == null)
if(isUsePredefinedVariables() && project == null)
{
// try to retrieve from current request.
if(Stapler.getCurrentRequest() != null)
Expand All @@ -177,7 +195,7 @@ public List<String> getChoiceList()

try
{
ret = runScript(getScriptText(), project);
ret = runScript(getScriptText(), isUsePredefinedVariables(), project);
}
catch(Exception e)
{
Expand All @@ -186,7 +204,7 @@ public List<String> getChoiceList()
return (ret != null)?ret:new ArrayList<String>(0);
}

private static List<String> runScript(String scriptText, AbstractProject<?,?> project) {
private static List<String> runScript(String scriptText, boolean usePredefinedVariables, AbstractProject<?,?> project) {
CompilerConfiguration compilerConfig = new CompilerConfiguration();

// see RemotingDiagnostics.Script
Expand All @@ -197,8 +215,11 @@ private static List<String> runScript(String scriptText, AbstractProject<?,?> pr
}

Binding binding = new Binding();
binding.setVariable("jenkins", Jenkins.getInstance());
binding.setVariable("project", project);
if(usePredefinedVariables)
{
binding.setVariable("jenkins", Jenkins.getInstance());
binding.setVariable("project", project);
}
GroovyShell shell =
new GroovyShell(cl, binding, compilerConfig);

Expand All @@ -220,7 +241,7 @@ private static List<String> runScript(String scriptText, AbstractProject<?,?> pr
}
return ret;
}
private String scriptText;
private final String scriptText;

/**
* The list of choices, joined into a string.
Expand All @@ -234,7 +255,7 @@ public String getScriptText()
return scriptText;
}

private String defaultChoice = null;
private final String defaultChoice;

/**
* Returns the default choice.
Expand All @@ -256,12 +277,30 @@ public String getDefaultChoice()
* and no constructor is used.
*
* @param scriptText the text where choices are written in each line.
* @param defaultChoice
* @param usePredefinedVariables
*/
@DataBoundConstructor
public SystemGroovyChoiceListProvider(String scriptText, String defaultChoice)
public SystemGroovyChoiceListProvider(String scriptText, String defaultChoice, boolean usePredefinedVariables)
{
this.scriptText = scriptText;
this.defaultChoice = (!NoDefaultChoice.equals(defaultChoice))?defaultChoice:null;
this.usePredefinedVariables = usePredefinedVariables;
}

public SystemGroovyChoiceListProvider(String scriptText, String defaultChoice)
{
this(scriptText, defaultChoice, false);
}

private final boolean usePredefinedVariables;

/**
* @return whether to use predefined variables
*/
public boolean isUsePredefinedVariables()
{
return usePredefinedVariables;
}

/**
Expand All @@ -280,7 +319,10 @@ protected void setProject(AbstractProject<?,?> project)
}

/**
* @return
* Return the project where this is configured.
* This is set only when {@link SystemGroovyChoiceListProvider#isUsePredefinedVariables()} is true.
*
* @return project
*/
protected AbstractProject<?,?> getProject()
{
Expand Down
Expand Up @@ -25,11 +25,14 @@ THE SOFTWARE.
<f:entry title="${%Groovy System Script}" field="scriptText">
<f:expandableTextbox />
</f:entry>
<f:entry field="usePredefinedVariables">
<f:checkbox title="${%Use predefined variables in scripts}" />
</f:entry>
<f:validateButton
method="test"
title="${%Run the Script Now}"
progress="${%Running...}"
with="scriptText"
with="scriptText,usePredefinedVariables"
/>
<f:entry title="${%Default Choice}" field="defaultChoice" help="/plugin/extensible-choice-parameter/help/defaultChoice.html">
<f:select />
Expand Down
Expand Up @@ -28,4 +28,7 @@ Default\ Choice=\u30c7\u30d5\u30a9\u30eb\u30c8\u5024
Run\ the\ Script\ Now=\u30b9\u30af\u30ea\u30d7\u30c8\u306e\u30c6\u30b9\u30c8\u5b9f\u884c
# Running...=処理中
Running...=\u51e6\u7406\u4e2d
# Use\ predefined\ variables\ in\ scripts=予約変数を使用する
Use\ predefined\ variables\ in\ scripts=\u4e88\u7d04\u5909\u6570\u3092\u4f7f\u7528\u3059\u308b


Expand Up @@ -6,14 +6,6 @@
<li>Null is ignored (not appeared in choices).</li>
<li>When exception occurred or returned a non-list value, choices will be empty.</li>
</ul>
<p>following variables are pre-defined:</p>
<dl>
<dt>jenkins</dt>
<dd>The instance of <a href="http://javadoc.jenkins-ci.org/jenkins/model/Jenkins.html">Jenkins</a>. Just a short cut for Jenkins.getInstance().</dd>
<dt>project</dt>
<dd>The project. An instance of <a href="http://javadoc.jenkins-ci.org/hudson/model/AbstractProject.html">AbstractProject</a>.</dd>
</dl>
<br>
<br>
<p>Here is an example:</p>
<code style="white-space: pre-wrap;">
Expand Down
Expand Up @@ -5,13 +5,6 @@
<li>null要素は無視します(選択肢に表示しません)</li>
<li>例外が発生したり、配列でない値を返した場合、選択肢は空になります。</li>
</ul>
<p>スクリプト内では以下の変数が事前に定義されています。</p>
<dl>
<dt>jenkins</dt>
<dd><a href="http://javadoc.jenkins-ci.org/jenkins/model/Jenkins.html">Jenkins</a> のインスタンス。 Jenkins.getInstance() のショートカットです。</dd>
<dt>project</dt>
<dd>対象のプロジェクト。<a href="http://javadoc.jenkins-ci.org/hudson/model/AbstractProject.html">AbstractProject</a> のインスタンス。</dd>
</dl>
<br>
<p>スクリプトの例:</p>
<code style="white-space: pre-wrap;">
Expand Down
@@ -0,0 +1,9 @@
<div>
<p>Enable following pre-defined variables:</p>
<dl>
<dt>jenkins</dt>
<dd>The instance of <a href="http://javadoc.jenkins-ci.org/jenkins/model/Jenkins.html">Jenkins</a>. Just a short cut for Jenkins.getInstance().</dd>
<dt>project</dt>
<dd>The project. An instance of <a href="http://javadoc.jenkins-ci.org/hudson/model/AbstractProject.html">AbstractProject</a>.</dd>
</dl>
</div>
@@ -0,0 +1,9 @@
<div>
<p>スクリプト内で以下の変数が使用できるようになります。</p>
<dl>
<dt>jenkins</dt>
<dd><a href="http://javadoc.jenkins-ci.org/jenkins/model/Jenkins.html">Jenkins</a> のインスタンス。 Jenkins.getInstance() のショートカットです。</dd>
<dt>project</dt>
<dd>対象のプロジェクト。<a href="http://javadoc.jenkins-ci.org/hudson/model/AbstractProject.html">AbstractProject</a> のインスタンス。</dd>
</dl>
</div>
Expand Up @@ -84,7 +84,7 @@ public void testDescriptor_doFillDefaultChoiceItems()

// Proper script
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, properScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, properScript, false);
assertEquals("Script returned an unexpected list", properScriptReturn.size() + 1, ret.size());
for(int i = 0; i < properScriptReturn.size(); ++i)
{
Expand All @@ -94,7 +94,7 @@ public void testDescriptor_doFillDefaultChoiceItems()

// Non-string list script
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, nonstringScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, nonstringScript, false);
assertEquals("Script returned an unexpected list", nonstringScriptReturn.size() + 1, ret.size());
for(int i = 0; i < nonstringScriptReturn.size(); ++i)
{
Expand All @@ -104,49 +104,49 @@ public void testDescriptor_doFillDefaultChoiceItems()

// non-list script
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, nonlistScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, nonlistScript, false);
assertEquals("Script returning non-list must return an empty list", 1, ret.size());
}

// Empty list script
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, emptyListScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, emptyListScript, false);
assertEquals("Script must return an empty list", 1, ret.size());
}

// Null script
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, nullScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, nullScript, false);
assertEquals("Script with null must return an empty list", 1, ret.size());
}

// emptyScript
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, emptyScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, emptyScript, false);
assertEquals("empty script must return an empty list", 1, ret.size());
}

// blankScript
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, blankScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, blankScript, false);
assertEquals("blank script must return an empty list", 1, ret.size());
}

// Syntax broken script
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, syntaxBrokenScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, syntaxBrokenScript, false);
assertEquals("Syntax-broken-script must return an empty list", 1, ret.size());
}

// exceptionScript
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, exceptionScript);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, exceptionScript, false);
assertEquals("Script throwing an exception must return an empty list", 1, ret.size());
}

// null
{
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, null);
ListBoxModel ret = descriptor.doFillDefaultChoiceItems(null, null, false);
assertEquals("null must return an empty list", 1, ret.size());
}
}
Expand All @@ -158,31 +158,31 @@ public void testDescriptor_doTest()

// Proper script
{
FormValidation formValidation = descriptor.doTest(null, properScript);
FormValidation formValidation = descriptor.doTest(null, properScript, false);
assertEquals("Test for proper script must succeed", FormValidation.Kind.OK, formValidation.kind);
}

// Syntax broken script
{
FormValidation formValidation = descriptor.doTest(null, syntaxBrokenScript);
FormValidation formValidation = descriptor.doTest(null, syntaxBrokenScript, false);
assertEquals("Test for broken script must fail", FormValidation.Kind.ERROR, formValidation.kind);
}

// Script raising an exception
{
FormValidation formValidation = descriptor.doTest(null, exceptionScript);
FormValidation formValidation = descriptor.doTest(null, exceptionScript, false);
assertEquals("Test for script raising an exception must fail", FormValidation.Kind.ERROR, formValidation.kind);
}

// Script returning non-list
{
FormValidation formValidation = descriptor.doTest(null, nonlistScript);
FormValidation formValidation = descriptor.doTest(null, nonlistScript, false);
assertEquals("Test for script returning non-list must fail", FormValidation.Kind.ERROR, formValidation.kind);
}

// Script returning null
{
FormValidation formValidation = descriptor.doTest(null, nullScript);
FormValidation formValidation = descriptor.doTest(null, nullScript, false);
assertEquals("Test for script retuning null must fail", FormValidation.Kind.ERROR, formValidation.kind);
}
}
Expand Down Expand Up @@ -305,7 +305,7 @@ public void testVariables() throws Exception
FreeStyleProject p = j.createFreeStyleProject();
p.addProperty(new ParametersDefinitionProperty(new ExtensibleChoiceParameterDefinition(
"test",
new SystemGroovyChoiceListProvider("[jenkins.rootDir.absolutePath, project.fullName]", null),
new SystemGroovyChoiceListProvider("[jenkins.rootDir.absolutePath, project.fullName]", null, true),
false,
"test"
)));
Expand All @@ -329,7 +329,7 @@ public void testProjectVariable() throws Exception
CaptureEnvironmentBuilder ceb = new CaptureEnvironmentBuilder();
p.addProperty(new ParametersDefinitionProperty(new ExtensibleChoiceParameterDefinition(
"test",
new SystemGroovyChoiceListProvider("return [(project != null)?project.fullName:\"none\"]", null),
new SystemGroovyChoiceListProvider("return [(project != null)?project.fullName:\"none\"]", null, true),
false,
"test"
)));
Expand Down

0 comments on commit 9bf438c

Please sign in to comment.