forked from imod/managed-scripts-plugin
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FIXED JENKINS-25079] Add support for Managed PowerShell files
- Loading branch information
Showing
11 changed files
with
567 additions
and
0 deletions.
There are no files selected for viewing
243 changes: 243 additions & 0 deletions
243
src/main/java/org/jenkinsci/plugins/managedscripts/PowerShellBuildStep.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
package org.jenkinsci.plugins.managedscripts; | ||
|
||
import org.jenkinsci.plugins.managedscripts.PowerShellConfig.Arg; | ||
import hudson.Extension; | ||
import hudson.ExtensionList; | ||
import hudson.model.AbstractProject; | ||
import hudson.tasks.BuildStepDescriptor; | ||
import hudson.tasks.Builder; | ||
import hudson.util.FormValidation; | ||
import org.jenkinsci.lib.configprovider.ConfigProvider; | ||
import org.kohsuke.stapler.QueryParameter; | ||
import org.kohsuke.stapler.bind.JavaScriptMethod; | ||
import org.kohsuke.stapler.DataBoundConstructor; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.Comparator; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.logging.Logger; | ||
import org.jenkinsci.lib.configprovider.model.Config; | ||
import hudson.FilePath; | ||
import hudson.tasks.CommandInterpreter; | ||
|
||
/** | ||
* A project that uses this builder can choose a build step from a list of predefined powershell files that are used as command line scripts. | ||
* <p> | ||
* | ||
* @author Arnaud Tamaillon (Greybird) | ||
* @see hudson.tasks.BatchFile | ||
*/ | ||
public class PowerShellBuildStep extends CommandInterpreter { | ||
|
||
private final String[] buildStepArgs; | ||
|
||
public static class ArgValue { | ||
public final String arg; | ||
|
||
@DataBoundConstructor | ||
public ArgValue(String arg) { | ||
this.arg = arg; | ||
} | ||
} | ||
|
||
public static class ScriptBuildStepArgs { | ||
public final boolean defineArgs; | ||
public final ArgValue[] buildStepArgs; | ||
|
||
@DataBoundConstructor | ||
public ScriptBuildStepArgs(boolean defineArgs, ArgValue[] buildStepArgs) | ||
{ | ||
this.defineArgs = defineArgs; | ||
this.buildStepArgs = buildStepArgs; | ||
} | ||
} | ||
|
||
/** | ||
* The constructor used at form submission | ||
* | ||
* @param buildStepId | ||
* the Id of the config file | ||
* @param scriptBuildStepArgs | ||
* whether to save the args and arg values (the boolean is required because of html form submission, which also sends hidden values) | ||
*/ | ||
@DataBoundConstructor | ||
public PowerShellBuildStep(String buildStepId, ScriptBuildStepArgs scriptBuildStepArgs) { | ||
super(buildStepId); | ||
List<String> l = null; | ||
if (scriptBuildStepArgs != null && scriptBuildStepArgs.defineArgs | ||
&& scriptBuildStepArgs.buildStepArgs != null) { | ||
l = new ArrayList<String>(); | ||
for (ArgValue arg : scriptBuildStepArgs.buildStepArgs) { | ||
l.add(arg.arg); | ||
} | ||
} | ||
this.buildStepArgs = l == null ? null : l.toArray(new String[l.size()]); | ||
} | ||
|
||
/** | ||
* The constructor | ||
* | ||
* @param buildStepId | ||
* the Id of the config file | ||
* @param buildStepArgs | ||
* list of arguments specified as buildStepargs | ||
*/ | ||
public PowerShellBuildStep(String buildStepId, String[] buildStepArgs) { | ||
super(buildStepId); // save buildStepId as command | ||
this.buildStepArgs = buildStepArgs; | ||
} | ||
|
||
public String getBuildStepId() { | ||
return getCommand(); | ||
} | ||
|
||
public String[] getBuildStepArgs() { | ||
return buildStepArgs; | ||
} | ||
|
||
@Override | ||
public String[] buildCommandLine(FilePath script) { | ||
List<String> cml = new ArrayList<String>(); | ||
cml.add("powershell.exe"); | ||
cml.add("-ExecutionPolicy"); | ||
cml.add("ByPass"); | ||
cml.add("& \'" + script.getRemote() + "\'"); | ||
|
||
// Add additional parameters set by user | ||
if (buildStepArgs != null) { | ||
for (String arg : buildStepArgs) { | ||
cml.add(arg); | ||
} | ||
} | ||
|
||
return (String[]) cml.toArray(new String[cml.size()]); | ||
} | ||
|
||
@Override | ||
protected String getContents() { | ||
Config buildStepConfig = getDescriptor().getBuildStepConfigById(getBuildStepId()); | ||
if (buildStepConfig == null) { | ||
throw new IllegalStateException(Messages.config_does_not_exist(getBuildStepId())); | ||
} | ||
return buildStepConfig.content + "\r\nexit $LastExitCode"; | ||
} | ||
|
||
@Override | ||
protected String getFileExtension() { | ||
return ".ps1"; | ||
} | ||
|
||
//Overridden for better type safety. | ||
@Override | ||
public DescriptorImpl getDescriptor() { | ||
return (DescriptorImpl) super.getDescriptor(); | ||
} | ||
|
||
/** | ||
* Descriptor for {@link PowerShellBuildStep}. | ||
*/ | ||
@Extension(ordinal = 60) | ||
public static final class DescriptorImpl extends BuildStepDescriptor<Builder> { | ||
final Logger logger = Logger.getLogger(PowerShellBuildStep.class.getName()); | ||
|
||
/** | ||
* Enables this builder for all kinds of projects. | ||
*/ | ||
@Override | ||
public boolean isApplicable(Class<? extends AbstractProject> aClass) { | ||
return true; | ||
} | ||
|
||
/** | ||
* This human readable name is used in the configuration screen. | ||
*/ | ||
@Override | ||
public String getDisplayName() { | ||
return Messages.powershell_buildstep_name(); | ||
} | ||
|
||
/** | ||
* Return all powershell files (templates) that the user can choose from when creating a build step. Ordered by name. | ||
* | ||
* @return A collection of batch files of type {@link PowerShellBatchConfig}. | ||
*/ | ||
public Collection<Config> getAvailableBuildTemplates() { | ||
List<Config> allConfigs = new ArrayList<Config>(getBuildStepConfigProvider().getAllConfigs()); | ||
Collections.sort(allConfigs, new Comparator<Config>() { | ||
public int compare(Config o1, Config o2) { | ||
return o1.name.compareTo(o2.name); | ||
} | ||
}); | ||
return allConfigs; | ||
} | ||
|
||
/** | ||
* Returns a Config object for a given config file Id. | ||
* | ||
* @param id | ||
* The Id of a config file. | ||
* @return If Id can be found a Config object that represents the given Id is returned. Otherwise null. | ||
*/ | ||
public PowerShellConfig getBuildStepConfigById(String id) { | ||
return (PowerShellConfig) getBuildStepConfigProvider().getConfigById(id); | ||
} | ||
|
||
/** | ||
* gets the argument description to be displayed on the screen when selecting a config in the dropdown | ||
* | ||
* @param configId | ||
* the config id to get the arguments description for | ||
* @return the description | ||
*/ | ||
@JavaScriptMethod | ||
public String getArgsDescription(String configId) { | ||
final PowerShellConfig config = getBuildStepConfigById(configId); | ||
if (config != null) { | ||
if (config.args != null && !config.args.isEmpty()) { | ||
StringBuilder sb = new StringBuilder("Required arguments: "); | ||
int i = 1; | ||
for (Iterator<Arg> iterator = config.args.iterator(); iterator.hasNext(); i++) { | ||
Arg arg = iterator.next(); | ||
sb.append(i).append(". ").append(arg.name); | ||
if (iterator.hasNext()) { | ||
sb.append(" | "); | ||
} | ||
} | ||
return sb.toString(); | ||
} else { | ||
return "No arguments required"; | ||
} | ||
} | ||
return "please select a script!"; | ||
} | ||
|
||
@JavaScriptMethod | ||
public List<Arg> getArgs(String configId) { | ||
final PowerShellConfig config = getBuildStepConfigById(configId); | ||
return config.args; | ||
} | ||
|
||
/** | ||
* validate that an existing config was chosen | ||
* | ||
* @param value | ||
* the configId | ||
* @return | ||
*/ | ||
public FormValidation doCheckBuildStepId(@QueryParameter String buildStepId) { | ||
final PowerShellConfig config = getBuildStepConfigById(buildStepId); | ||
if (config != null) { | ||
return FormValidation.ok(); | ||
} else { | ||
return FormValidation.error("you must select a valid powershell file"); | ||
} | ||
} | ||
|
||
private ConfigProvider getBuildStepConfigProvider() { | ||
ExtensionList<ConfigProvider> providers = ConfigProvider.all(); | ||
return providers.get(PowerShellConfig.PowerShellConfigProvider.class); | ||
} | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
src/main/java/org/jenkinsci/plugins/managedscripts/PowerShellConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package org.jenkinsci.plugins.managedscripts; | ||
|
||
import hudson.Extension; | ||
import org.jenkinsci.lib.configprovider.AbstractConfigProviderImpl; | ||
import org.jenkinsci.lib.configprovider.model.Config; | ||
import org.jenkinsci.lib.configprovider.model.ContentType; | ||
import org.kohsuke.stapler.DataBoundConstructor; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class PowerShellConfig extends Config { | ||
|
||
public final List<Arg> args; | ||
|
||
@DataBoundConstructor | ||
public PowerShellConfig(String id, String name, String comment, String content, List<Arg> args) { | ||
super(id, name, comment, content); | ||
|
||
if (args != null) { | ||
List<Arg> filteredArgs = new ArrayList<PowerShellConfig.Arg>(); | ||
for (Arg arg : args) { | ||
if (arg.name != null && arg.name.trim().length() > 0) { | ||
filteredArgs.add(arg); | ||
} | ||
} | ||
this.args = filteredArgs; | ||
} else { | ||
this.args = null; | ||
} | ||
} | ||
|
||
public static class Arg { | ||
public final String name; | ||
|
||
@DataBoundConstructor | ||
public Arg(final String name) { | ||
this.name = name; | ||
} | ||
} | ||
|
||
@Extension(ordinal = 70) | ||
public static class PowerShellConfigProvider extends AbstractConfigProviderImpl { | ||
|
||
public PowerShellConfigProvider() { | ||
load(); | ||
} | ||
|
||
@Override | ||
public ContentType getContentType() { | ||
return ContentType.DefinedType.HTML; | ||
} | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return Messages.powershell_buildstep_provider_name(); | ||
} | ||
|
||
@Override | ||
public Config newConfig() { | ||
String id = getProviderId() + System.currentTimeMillis(); | ||
return new PowerShellConfig(id, "Build Step", "", "Write-Host \"hello\";", null); | ||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
src/main/resources/org/jenkinsci/plugins/managedscripts/PowerShellBuildStep/config.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<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"> | ||
|
||
<st:adjunct assumes="org.kohsuke.stapler.framework.prototype.prototype" includes="org.kohsuke.stapler.bind"/> | ||
|
||
<st:once> | ||
<script type="text/javascript" src="${rootURL}/plugin/managed-scripts/js/managed-scripts.js" /> | ||
</st:once> | ||
<j:choose> | ||
<j:when test="${empty(descriptor.availableBuildTemplates)}"> | ||
<f:entry title=""> | ||
<div> | ||
No build templates are defined. Please define one | ||
<a href="/configfiles">here</a>. | ||
</div> | ||
</f:entry> | ||
</j:when> | ||
<j:otherwise> | ||
<f:entry title="${%Script}" field="buildStepContent"> | ||
<select name="buildStepId" onChange="ms_initDetailLink('${rootURL}', this);ms_showParams(this, this.value);"> | ||
<option value="">(Default)</option> | ||
<j:forEach var="inst" items="${descriptor.availableBuildTemplates}" varStatus="loop"> | ||
<j:choose> | ||
<j:when test="${inst.id == instance.buildStepId}"> | ||
<option value="${inst.id}" selected="selected">${inst.name} - ${inst.comment}</option> | ||
</j:when> | ||
<j:otherwise> | ||
<option value="${inst.id}">${inst.name} - ${inst.comment}</option> | ||
</j:otherwise> | ||
</j:choose> | ||
</j:forEach> | ||
</select> | ||
<a target="_blank" name="showDetailLink" href="" style="display:none;" onclick="window.open(this.href,'window','width=900,height=640,resizable,scrollbars,toolbar,menubar') ;return false;"> view selected script</a> | ||
<div name="argumentDescription" id="argumentDescription"/> | ||
<f:block> | ||
<table name="scriptBuildStepArgs" id="scriptBuildStepArgs"> | ||
<f:optionalBlock name="defineArgs" inline="true" title="${%Define arguments}" checked="${!empty(instance.buildStepArgs)}" help="/plugin/managed-scripts/help-defineArgs_powershell.html"> | ||
<f:entry> | ||
<f:repeatable var="arg" items="${instance.buildStepArgs}" name="buildStepArgs" noAddButton="true" minimum="1"> | ||
<table width="100%"> | ||
<f:entry> | ||
<div name="argName"><st:nbsp/></div> | ||
<input type="text" name="arg" value="${arg}" size="80"/> | ||
<input type="button" name="delete_button" value="${%Delete}" class="repeatable-delete show-if-not-only" style="margin-left: 1em;" /> | ||
<input type="button" name="add_button" onClick="ms_labelArgs()" value="${%Add argument}" class="repeatable-add show-if-last" /> | ||
</f:entry> | ||
</table> | ||
</f:repeatable> | ||
</f:entry> | ||
</f:optionalBlock> | ||
</table> | ||
</f:block> | ||
</f:entry> | ||
</j:otherwise> | ||
</j:choose> | ||
<st:bind var="desc" value="${descriptor}"/> | ||
<st:once> | ||
<script type="text/javascript"> | ||
Event.observe(window, 'load', function() { | ||
var all = new Array(); | ||
all = document.getElementsByName('buildStepId'); | ||
for(var i = 0; i < all.length; i++) { | ||
ms_initDetailLink('<j:out value="${rootURL}" />', all.item(i)); | ||
ms_showParams(all.item(i), all.item(i).value); | ||
ms_getArgs(all.item(i), all.item(i).value); | ||
} | ||
}); | ||
</script> | ||
</st:once> | ||
</j:jelly> |
4 changes: 4 additions & 0 deletions
4
src/main/resources/org/jenkinsci/plugins/managedscripts/PowerShellBuildStep/help.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<div> | ||
This step allows to reference and execute a centrally managed powershell script within your build. | ||
New files can be added in the <a href="/configfiles">global configuration</a>. | ||
</div> |
Oops, something went wrong.