Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #2173 from jglick/JENKINS-33759-misc
Copy item in folder fixes
  • Loading branch information
jglick committed Mar 29, 2016
2 parents 6219c8f + 86503c2 commit bcbc019
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 14 deletions.
9 changes: 2 additions & 7 deletions core/src/main/java/hudson/model/ItemGroupMixIn.java
Expand Up @@ -137,7 +137,7 @@ public String call(Item item) {
};

/**
* Creates a {@link TopLevelItem} from the submission of the '/lib/hudson/newFromList/formList'
* Creates a {@link TopLevelItem} for example from the submission of the {@code /lib/hudson/newFromList/form} tag
* or throws an exception if it fails.
*/
public synchronized TopLevelItem createTopLevelItem( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
Expand Down Expand Up @@ -170,12 +170,7 @@ public synchronized TopLevelItem createTopLevelItem( StaplerRequest req, Stapler
String from = req.getParameter("from");

// resolve a name to Item
Item src = null;
if (!from.startsWith("/"))
src = parent.getItem(from);
if (src==null)
src = Jenkins.getInstance().getItemByFullName(from);

Item src = Jenkins.getInstance().getItem(from, parent);
if(src==null) {
if(Util.fixEmpty(from)==null)
throw new Failure("Specify which job to copy");
Expand Down
26 changes: 21 additions & 5 deletions core/src/main/java/hudson/model/ViewDescriptor.java
Expand Up @@ -26,12 +26,14 @@
import hudson.views.ListViewColumn;
import hudson.views.ListViewColumnDescriptor;
import hudson.views.ViewJobFilter;
import java.util.Iterator;
import java.util.List;
import jenkins.model.DirectlyModifiableTopLevelItemGroup;
import jenkins.model.Jenkins;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.AncestorInPath;

import java.util.List;
import org.kohsuke.stapler.QueryParameter;

/**
* {@link Descriptor} for {@link View}.
Expand Down Expand Up @@ -76,8 +78,22 @@ protected ViewDescriptor() {
* Auto-completion for the "copy from" field in the new job page.
*/
@Restricted(DoNotUse.class)
public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter final String value, @AncestorInPath ItemGroup container) {
return AutoCompletionCandidates.ofJobNames(TopLevelItem.class, value, container);
public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter final String value, @AncestorInPath ItemGroup<?> container) {
AutoCompletionCandidates candidates = AutoCompletionCandidates.ofJobNames(TopLevelItem.class, value, container);
if (container instanceof DirectlyModifiableTopLevelItemGroup) {
DirectlyModifiableTopLevelItemGroup modifiableContainer = (DirectlyModifiableTopLevelItemGroup) container;
Iterator<String> it = candidates.getValues().iterator();
while (it.hasNext()) {
TopLevelItem item = Jenkins.getInstance().getItem(it.next(), container, TopLevelItem.class);
if (item == null) {
continue; // ?
}
if (!modifiableContainer.canAdd(item)) {
it.remove();
}
}
}
return candidates;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/resources/hudson/model/AllView/noJob.jelly
Expand Up @@ -32,7 +32,7 @@ THE SOFTWARE.
<j:choose xmlns:j="jelly:core">
<!-- Only show the create new jobs link to those users that have permission to use it. -->
<j:getStatic var="permission" className="hudson.model.Item" field="CREATE"/>
<j:when test="${h.hasPermission(permission)}">
<j:when test="${h.hasPermission(it.owner, permission)}">
<div class="call-to-action">${%newJob}</div>
</j:when>
<j:otherwise>
Expand Down
16 changes: 15 additions & 1 deletion test/src/test/java/hudson/jobs/CreateItemTest.java
Expand Up @@ -23,7 +23,7 @@
*/
package hudson.jobs;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;

import java.net.URL;
import java.text.MessageFormat;
Expand All @@ -37,6 +37,8 @@
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.HttpMethod;
import com.gargoylesoftware.htmlunit.WebRequest;
import hudson.model.FreeStyleProject;
import org.jvnet.hudson.test.MockFolder;

/**
* Tests the /createItem REST API.
Expand Down Expand Up @@ -82,4 +84,16 @@ public void testCreateItemFromCopy() throws Exception {
private void deleteContentTypeHeader(WebRequest request) {
request.setEncodingType(null);
}

@Test
public void createWithFolderPaths() throws Exception {
rule.jenkins.setCrumbIssuer(null);
rule.createFolder("d1").createProject(FreeStyleProject.class, "p");
MockFolder d2 = rule.createFolder("d2");
rule.createWebClient().getPage(new WebRequest(new URL(d2.getAbsoluteUrl() + "createItem?mode=copy&name=p2&from=../d1/p"), HttpMethod.POST));
assertNotNull(d2.getItem("p2"));
rule.createWebClient().getPage(new WebRequest(new URL(d2.getAbsoluteUrl() + "createItem?mode=copy&name=p3&from=/d1/p"), HttpMethod.POST));
assertNotNull(d2.getItem("p3"));
}

}
78 changes: 78 additions & 0 deletions test/src/test/java/hudson/model/ViewDescriptorTest.java
@@ -0,0 +1,78 @@
/*
* The MIT License
*
* Copyright 2016 CloudBees, Inc.
*
* 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 hudson.model;

import java.util.Arrays;
import java.util.TreeSet;
import jenkins.model.DirectlyModifiableTopLevelItemGroup;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockFolder;
import org.jvnet.hudson.test.TestExtension;

public class ViewDescriptorTest {

@Rule
public JenkinsRule r = new JenkinsRule();

/** Checks that {@link ViewDescriptor#doAutoCompleteCopyNewItemFrom} honors {@link DirectlyModifiableTopLevelItemGroup#canAdd}. */
@Test
public void canAdd() throws Exception {
MockFolder d1 = r.createFolder("d1");
d1.createProject(MockFolder.class, "sub");
d1.createProject(FreeStyleProject.class, "prj");
MockFolder d2 = r.jenkins.createProject(RestrictiveFolder.class, "d2");
assertContains(r.jenkins.getDescriptorByType(AllView.DescriptorImpl.class).doAutoCompleteCopyNewItemFrom("../d1/", d2), "../d1/prj");
}

@SuppressWarnings({"unchecked", "rawtypes"}) // the usual API mistakes
public static class RestrictiveFolder extends MockFolder {

public RestrictiveFolder(ItemGroup parent, String name) {
super(parent, name);
}

@Override
public boolean canAdd(TopLevelItem item) {
return item instanceof FreeStyleProject;
}

@TestExtension("canAdd") public static class DescriptorImpl extends TopLevelItemDescriptor {

@Override public TopLevelItem newInstance(ItemGroup parent, String name) {
return new RestrictiveFolder(parent, name);
}

}

}

private void assertContains(AutoCompletionCandidates c, String... values) {
assertEquals(new TreeSet<>(Arrays.asList(values)), new TreeSet<>(c.getValues()));
}

}

0 comments on commit bcbc019

Please sign in to comment.