Skip to content

Commit

Permalink
Merge pull request #62 from oleg-nenashev/JENKINS-25011
Browse files Browse the repository at this point in the history
[JENKINS-25011] - Folders and the relative addressing support
  • Loading branch information
oleg-nenashev committed Aug 21, 2015
2 parents 0a0a569 + dfb5559 commit d8ef35e
Show file tree
Hide file tree
Showing 5 changed files with 565 additions and 33 deletions.
8 changes: 8 additions & 0 deletions pom.xml
Expand Up @@ -126,6 +126,14 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jenkins-ci.tools</groupId>
<artifactId>maven-hpi-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<compatibleSinceVersion>2.22</compatibleSinceVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
Expand Up @@ -24,6 +24,7 @@
package hudson.plugins.promoted_builds.parameters;

import hudson.Extension;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.AutoCompletionCandidates;
import hudson.model.Item;
Expand All @@ -36,28 +37,44 @@
import hudson.plugins.promoted_builds.PromotedBuildAction;
import hudson.plugins.promoted_builds.PromotedProjectAction;
import hudson.plugins.promoted_builds.PromotionProcess;
import hudson.plugins.promoted_builds.util.ItemPathResolver;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import hudson.util.ListBoxModel.Option;
import hudson.util.RunList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.export.Exported;

/**
* Defines a parameter that allows the user to select a promoted build
* from a drop down list.
*
* <p>
* Remarks on addressing:
* Starting from TODO, the field also supports folders and the relative addressing (JENKINS-25011).
* See {@link ItemPathResolver#getByPath(java.lang.String, hudson.model.Item, java.lang.Class)}
* for the documentation.
* @author Pete Hayes
*/
public class PromotedBuildParameterDefinition extends SimpleParameterDefinition {

/**
* Absolute path to the item starting from the root element.
* See format clarification in the {@link PromotedBuildParameterDefinition}.
*/
private final String projectName;
private final String promotionProcessName;

Expand All @@ -84,7 +101,7 @@ public PromotedBuildParameterValue createValue(String value) {

@Override
public PromotedBuildParameterValue getDefaultParameterValue() {
List builds = getBuilds();
final List builds = getBuilds();

if (builds.isEmpty()) {
return null;
Expand All @@ -103,6 +120,9 @@ public ParameterDefinition copyWithDefaultValue(ParameterValue defaultValue) {
}
}

/**
* Absolute path to the item starting from the root element.
*/
@Exported
public String getJobName() {
return projectName;
Expand All @@ -113,34 +133,60 @@ public String getProcess() {
return promotionProcessName;
}

/**
* Gets a list of promoted builds for the project.
* @return List of {@link AbstractBuild}s, which have been promoted
* @deprecated This method retrieves the base item for relative addressing from
* the {@link StaplerRequest}. The relative addressing may be malfunctional if
* you use this method outside {@link StaplerRequest}s.
* Use {@link #getBuilds(hudson.model.Item)} instead
*/
@Nonnull
@Deprecated
public List getBuilds() {
List builds = new ArrayList();
// Try to get ancestor from the object, otherwise pass null and disable the relative addressing
final StaplerRequest currentRequest = Stapler.getCurrentRequest();
final Item item = currentRequest != null ? currentRequest.findAncestorObject(Item.class) : null;
return getRuns(item);
}

/**
* Gets a list of promoted builds for the project.
* @param base Base item for the relative addressing
* @return List of {@link AbstractBuild}s, which have been promoted.
* May return an empty list if {@link Jenkins} instance is not ready
* @since TODO
*/
@Nonnull
public List<Run<?,?>> getRuns(@CheckForNull Item base) {
final List<Run<?,?>> runs = new ArrayList<Run<?,?>>();
final Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
return runs;
}

AbstractProject job = (AbstractProject) Jenkins.getInstance().getItem(projectName);
// JENKINS-25011: also look for jobs in folders.
final AbstractProject<?,?> job = ItemPathResolver.getByPath(projectName, base, AbstractProject.class);
if (job == null) {
return builds;
return runs;
}

PromotedProjectAction promotedProjectAction = job.getAction(PromotedProjectAction.class);
if (promotedProjectAction == null) {
return builds;
return runs;
}

for (Iterator iter = job.getBuilds().iterator(); iter.hasNext(); ) {
Run run = (Run) iter.next();

List buildActions = run.getActions(PromotedBuildAction.class);
for (int i = 0; i < buildActions.size(); i++) {
PromotedBuildAction buildAction = (PromotedBuildAction) buildActions.get(i);

for (Run<?,?> run : job.getBuilds()) {
List<PromotedBuildAction> actions = run.getActions(PromotedBuildAction.class);
for (PromotedBuildAction buildAction : actions) {
if (buildAction.contains(promotionProcessName)) {
builds.add(run);
runs.add(run);
break;
}
}
}

return builds;
return runs;
}

@Extension
Expand All @@ -160,33 +206,50 @@ public String getHelpFile() {
public ParameterDefinition newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return req.bindJSON(PromotedBuildParameterDefinition.class, formData);
}

/**
* Checks the job name.
*/
public FormValidation doCheckJobName(@AncestorInPath Item project, @QueryParameter String value ) {
final Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
return FormValidation.error("Jenkins instance is not ready");
}
if (!project.hasPermission(Item.CONFIGURE) && project.hasPermission(Item.EXTENDED_READ)) {
return FormValidation.ok();
}

project.checkPermission(Item.CONFIGURE);

if (StringUtils.isNotBlank(value)) {
AbstractProject p = Jenkins.getInstance().getItem(value,project,AbstractProject.class);
if(p==null)
// JENKINS-25011: also look for jobs in folders.
final AbstractProject p = ItemPathResolver.getByPath(value, project, AbstractProject.class);
if (p==null) {
// suggest full name so that getBuilds() can find item.
return FormValidation.error(hudson.tasks.Messages.BuildTrigger_NoSuchProject(value,
AbstractProject.findNearest(value, project.getParent()).getRelativeNameFrom(project)));
AbstractProject.findNearest(value, project.getParent()).getFullName()));
}

}

return FormValidation.ok();
}

public AutoCompletionCandidates doAutoCompleteJobName(@QueryParameter String value) {
AutoCompletionCandidates candidates = new AutoCompletionCandidates();
List<AbstractProject> jobs = Jenkins.getInstance().getItems(AbstractProject.class);
for (AbstractProject job: jobs) {
if (job.getFullName().startsWith(value)) {
@Restricted(NoExternalUse.class)
public AutoCompletionCandidates doAutoCompleteJobName(@AncestorInPath @CheckForNull Item project,
@QueryParameter String value) {
final AutoCompletionCandidates candidates = new AutoCompletionCandidates();
final Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null || project == null || !project.hasPermission(Item.CONFIGURE)) {
return candidates;
}

// JENKINS-25011: look for jobs in all folders.
//TODO: remove prefixes
for (AbstractProject job: jenkins.getAllItems(AbstractProject.class)) {
if (job.getFullName().contains(value)) {
if (job.hasPermission(Item.READ)) {
// suggest full name so that getBuilds() can find item.
candidates.add(job.getFullName());
}
}
Expand All @@ -198,25 +261,33 @@ public AutoCompletionCandidates doAutoCompleteJobName(@QueryParameter String val
* Fills in the available promotion processes.
*/
public ListBoxModel doFillProcessItems(@AncestorInPath Job defaultJob, @QueryParameter("jobName") String jobName) {
final ListBoxModel r = new ListBoxModel();
final Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
return r;
}
if (!defaultJob.hasPermission(Item.CONFIGURE) && defaultJob.hasPermission(Item.EXTENDED_READ)) {
return new ListBoxModel();
return r;
}
defaultJob.checkPermission(Item.CONFIGURE);

AbstractProject<?,?> j = null;
if (jobName!=null)
j = Jenkins.getInstance().getItem(jobName,defaultJob,AbstractProject.class);

ListBoxModel r = new ListBoxModel();
if (jobName != null) {
j = ItemPathResolver.getByPath(jobName, defaultJob, AbstractProject.class);
}

if (j!=null) {
JobPropertyImpl pp = j.getProperty(JobPropertyImpl.class);
if (pp!=null) {
for (PromotionProcess proc : pp.getActiveItems())
for (PromotionProcess proc : pp.getActiveItems()) {
// Note: why not list all items instead of active ones?
// this would allow to configure the job even
// if a promotion hasn't happened (yet).
r.add(new Option(proc.getDisplayName(),proc.getName()));
}
}
}
return r;
}
}

}
}

0 comments on commit d8ef35e

Please sign in to comment.