Skip to content
Permalink
Browse files

Merge remote-tracking branch 'primary/2.0' into JENKINS-33800-initial…

…-password-file-not-found
  • Loading branch information...
kzantow committed Mar 29, 2016
2 parents 91b5590 + e322322 commit ae5c36979a3e1ad93ef66f2090898bfdf6de1d18
@@ -496,10 +496,7 @@ private void resolve(Class c) {
@SuppressWarnings({"unchecked", "ChainOfInstanceofChecks"})
@Override
protected void configure() {
int id=0;

for (final IndexItem<?,Object> item : index) {
id++;
boolean optional = isOptional(item.annotation());
try {
AnnotatedElement e = item.element();
@@ -524,8 +521,8 @@ protected void configure() {

resolve(extType);

// use arbitrary id to make unique key, because Guice wants that.
Key key = Key.get(extType, Names.named(String.valueOf(id)));
// make unique key, because Guice wants that.
Key key = Key.get(extType, Names.named(item.className() + "." + item.memberName()));
annotations.put(key,a);
bind(key).toProvider(new Provider() {
public Object get() {
@@ -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 {
@@ -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");
@@ -35,6 +35,7 @@
import hudson.Util;
import hudson.model.Descriptor.FormException;
import hudson.model.labels.LabelAtomPropertyDescriptor;
import hudson.model.listeners.ItemListener;
import hudson.scm.ChangeLogSet;
import hudson.scm.ChangeLogSet.Entry;
import hudson.search.CollectionSearchIndex;
@@ -50,6 +51,7 @@
import hudson.util.DescribableList;
import hudson.util.DescriptorList;
import hudson.util.FormApply;
import hudson.util.FormValidation;
import hudson.util.RunList;
import hudson.util.XStream2;
import hudson.views.ListViewColumn;
@@ -110,6 +112,7 @@
import static jenkins.model.Jenkins.*;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.QueryParameter;
import org.xml.sax.SAXException;

/**
@@ -1005,6 +1008,36 @@ public synchronized void doDoDelete(StaplerRequest req, StaplerResponse rsp) thr
*/
public abstract Item doCreateItem( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException;

/**
* Makes sure that the given name is good as a job name.
* For use from {@code newJob}.
*/
@Restricted(DoNotUse.class) // called from newJob view
public FormValidation doCheckJobName(@QueryParameter String value) {
// this method can be used to check if a file exists anywhere in the file system,
// so it should be protected.
getOwner().checkPermission(Item.CREATE);

if (Util.fixEmpty(value) == null) {
return FormValidation.ok();
}

try {
Jenkins.checkGoodName(value);
value = value.trim(); // why trim *after* checkGoodName? not sure, but ItemGroupMixIn.createTopLevelItem does the same
Jenkins.getInstance().getProjectNamingStrategy().checkName(value);
} catch (Failure e) {
return FormValidation.error(e.getMessage());
}

if (getOwnerItemGroup().getItem(value) != null) {
return FormValidation.error(Messages.Hudson_JobAlreadyExists(value));
}

// looks good
return FormValidation.ok();
}

/**
* An API REST method to get the allowed {$link TopLevelItem}s and its categories.
*
@@ -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}.
@@ -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;
}

/**
@@ -3581,20 +3581,6 @@ public static void checkGoodName(String name) throws Failure {
// looks good
}

/**
* Makes sure that the given name is good as a job name.
* @return trimmed name if valid; throws Failure if not
*/
private String checkJobName(String name) throws Failure {
checkGoodName(name);
name = name.trim();
projectNamingStrategy.checkName(name);
if(getItem(name)!=null)
throw new Failure(Messages.Hudson_JobAlreadyExists(name));
// looks good
return name;
}

private static String toPrintableName(String name) {
StringBuilder printableName = new StringBuilder();
for( int i=0; i<name.length(); i++ ) {
@@ -4122,25 +4108,6 @@ public FormValidation doDefaultJDKCheck(StaplerRequest request, @QueryParameter
return FormValidation.errorWithMarkup(Messages.Hudson_NoJavaInPath(request.getContextPath()));
}

/**
* Makes sure that the given name is good as a job name.
*/
public FormValidation doCheckJobName(@QueryParameter String value) {
// this method can be used to check if a file exists anywhere in the file system,
// so it should be protected.
checkPermission(Item.CREATE);

if(fixEmpty(value)==null)
return FormValidation.ok();

try {
checkJobName(value);
return FormValidation.ok();
} catch (Failure e) {
return FormValidation.error(e.getMessage());
}
}

/**
* Checks if a top-level view with the given name exists and
* make sure that the name is good as a view name.
@@ -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>
@@ -71,7 +71,7 @@ THE SOFTWARE.
<j:otherwise>
<!-- We don't seem to have this icon in the IconSet... fallback again... -->
<j:set var="iconUrl" value="${it.getImageOf(iconSize)}"/>
<l:icon src="${iconUrl}" alt="${it.description}" tooltip="${it.description}" style="${attrs.style}" />
<l:icon src="${iconUrl}" class="${iconSizeClass}" alt="${it.description}" tooltip="${it.description}" style="${attrs.style}" />
</j:otherwise>
</j:choose>
</j:otherwise>
@@ -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;
@@ -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.
@@ -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"));
}

}
@@ -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()));
}

}
Oops, something went wrong.

0 comments on commit ae5c369

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