Skip to content

Commit

Permalink
[FIXED JENKINS-24515] Now uses ModifiableTopLevelItemGroup, which all…
Browse files Browse the repository at this point in the history
…ows free from cloudbees-folder plugin.
  • Loading branch information
ikedam committed Sep 3, 2014
1 parent 1dbfa0a commit 01e96c6
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 49 deletions.
3 changes: 2 additions & 1 deletion pom.xml
Expand Up @@ -3,6 +3,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<!-- ModifiableTopLevelItemGroup is since 1.480.3 -->
<version>1.480.3</version><!-- which version of Jenkins is this plugin built against? -->
</parent>

Expand Down Expand Up @@ -40,7 +41,7 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>cloudbees-folder</artifactId>
<version>4.0</version>
<optional>true</optional>
<scope>test</scope>
</dependency>
<dependency>
<!--Depended by cloudbees-folder, to suppress annoying messages on tests-->
Expand Down
Expand Up @@ -23,7 +23,10 @@
*/
package jp.ikedam.jenkins.plugins.jobcopy_builder;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;

import hudson.Extension;
import hudson.XmlFile;
Expand All @@ -44,16 +47,16 @@
import hudson.util.FormValidation;
import hudson.tasks.Builder;
import hudson.tasks.BuildStepDescriptor;
import jenkins.model.ModifiableTopLevelItemGroup;
import jenkins.model.Jenkins;

import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import com.cloudbees.hudson.plugins.folder.Folder;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;

import java.io.InputStream;
import java.io.ByteArrayInputStream;
Expand Down Expand Up @@ -226,7 +229,7 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
listener.getLogger().println(String.format("Copying %s to %s", fromJobNameExpanded, toJobNameExpanded));

// Reteive the job to be copied from.
TopLevelItem fromJob = Jenkins.getInstance().getItem(fromJobNameExpanded, context, TopLevelItem.class);
TopLevelItem fromJob = getRelative(fromJobNameExpanded, context, TopLevelItem.class);

if(fromJob == null)
{
Expand All @@ -240,7 +243,7 @@ else if(!(fromJob instanceof Job<?,?>))
}

// Check whether the job to be copied to is already exists.
TopLevelItem toJob = Jenkins.getInstance().getItem(toJobNameExpanded, context, TopLevelItem.class);
TopLevelItem toJob = getRelative(toJobNameExpanded, context, TopLevelItem.class);
if(toJob != null){
listener.getLogger().println(String.format("Already exists: %s", toJobNameExpanded));
if(!isOverwrite()){
Expand Down Expand Up @@ -282,51 +285,27 @@ else if(!(fromJob instanceof Job<?,?>))
// Create the job copied to.
listener.getLogger().println(String.format("Creating %s", toJobNameExpanded));
InputStream is = new ByteArrayInputStream(jobConfigXmlString.getBytes(encoding));
String parentName = null;
String itemName = null;
ItemGroup<?> toContext = context;
if(toJobNameExpanded.lastIndexOf('/') >= 0)
{
int pos = toJobNameExpanded.lastIndexOf('/');
parentName = toJobNameExpanded.substring(0, pos);
itemName = toJobNameExpanded.substring(pos + 1);
}
else
{
parentName = null;
itemName = toJobNameExpanded;
}
if(StringUtils.isBlank(parentName) && context == Jenkins.getInstance().getItemGroup())
{
toJob = Jenkins.getInstance().createProjectFromXML(itemName, is);
}
else
{
if(!isFolderPluginInstalled())
String parentName = toJobNameExpanded.substring(0, pos);
toJobNameExpanded = toJobNameExpanded.substring(pos + 1);

toContext = getRelative(parentName, context, ItemGroup.class);
if(toContext == null)
{
listener.getLogger().println("Error: Cloudbees folder plugin should be installed to create a project in an item group.");
listener.getLogger().println(String.format("Error: Target folder '%s' was not found.", parentName));
return false;
}
Folder folder = null;
if(!StringUtils.isBlank(parentName))
{
folder = Jenkins.getInstance().getItem(parentName, context, Folder.class);
if(folder == null)
{
listener.getLogger().println(String.format("Error: Target folder '%s' was not found.", parentName));
return false;
}
}
else
{
if(!(context instanceof Folder))
{
listener.getLogger().println("Error: Jobcopy builder works only with cloudbees-folder");
return false;
}
folder = (Folder)context;
}
toJob = folder.createProjectFromXML(itemName, is);
}

if(!(toContext instanceof ModifiableTopLevelItemGroup))
{
listener.getLogger().println(String.format("Error: Target folder '%s' does not support ModifiableTopLevelItemGroup", toContext.getFullName()));
}

toJob = ((ModifiableTopLevelItemGroup)toContext).createProjectFromXML(toJobNameExpanded, is);
if(toJob == null)
{
listener.getLogger().println(String.format("Failed to create %s", toJobNameExpanded));
Expand Down Expand Up @@ -393,12 +372,70 @@ else if(!(fromJob instanceof Job<?,?>))
}

/**
* @return whether cloudbees-folder installed
* Reimplementation of {@link Jenkins#getItem(String, ItemGroup, Class)}
*
* Existing implementation has following problems:
* * Falls back to {@link Jenkins#getItemByFullName(String)}
* * Cannot get {@link ItemGroup}
*
* @param pathName
* @param context
* @param klass
* @return
*/
public static boolean isFolderPluginInstalled()
public static <T> T getRelative(String pathName, ItemGroup<?> context, Class<T> klass)
{
hudson.Plugin plugin = Jenkins.getInstance().getPlugin("cloudbees-folder");
return plugin != null ? plugin.getWrapper().isActive() : false;
if(context==null)
{
context = Jenkins.getInstance().getItemGroup();
}
if (pathName==null)
{
return null;
}

if (pathName.startsWith("/"))
{
// absolute
Item item = Jenkins.getInstance().getItemByFullName(pathName);
return klass.isInstance(item)?klass.cast(item):null;
}

Object/*Item|ItemGroup*/ ctx = context;

StringTokenizer tokens = new StringTokenizer(pathName,"/");
while(tokens.hasMoreTokens())
{
String s = tokens.nextToken();
if(s.equals(".."))
{
if(!(ctx instanceof Item))
{
// can't go up further
return null;
}
ctx = ((Item)ctx).getParent();
continue;
}
if(s.equals("."))
{
continue;
}

if(!(ctx instanceof ItemGroup))
{
return null;
}
ItemGroup<?> g = (ItemGroup<?>)ctx;
Item i = g.getItem(s);
if (i == null || !i.hasPermission(Item.READ))
{
return null;
}
ctx=i;
}

return klass.isInstance(ctx)?klass.cast(ctx):null;
}

/**
Expand Down Expand Up @@ -465,7 +502,7 @@ public DescriptorExtensionList<JobcopyOperation,Descriptor<JobcopyOperation>> ge
public ComboBoxModel doFillFromJobNameItems(@AncestorInPath AbstractProject<?,?> project)
{
final ItemGroup<?> context = (project != null)?project.getParent():Jenkins.getInstance().getItemGroup();
return new ComboBoxModel(Collections2.transform(
List<String> itemList = new ArrayList<String>(Lists.transform(
Jenkins.getInstance().getAllItems(),
new Function<Item, String>()
{
Expand All @@ -475,6 +512,8 @@ public String apply(Item input)
}
}
));
Collections.sort(itemList);
return new ComboBoxModel(itemList);
}

/**
Expand Down Expand Up @@ -561,7 +600,7 @@ public FormValidation doCheckJobName(AbstractProject<?,?> project, String jobNam
return FormValidation.ok();
}

TopLevelItem job = Jenkins.getInstance().getItem(jobName, context, TopLevelItem.class);
TopLevelItem job = getRelative(jobName, context, TopLevelItem.class);
if(job != null)
{
// job exists
Expand Down

0 comments on commit 01e96c6

Please sign in to comment.