Skip to content
Permalink
Browse files
Merge pull request #4 from jenkinsci/multibranch-workflow-JENKINS-26129
[JENKINS-26129] Prepare for multibranch workflows
  • Loading branch information
jglick committed Jul 27, 2015
2 parents 83a7d32 + 403a5c2 commit 06f1e2f8f3a22fd94b80a7306f4bb79be014c4e2
@@ -29,7 +29,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.509</version>
<version>1.580.3</version> <!-- SCMTriggerItem -->
</parent>

<artifactId>branch-api</artifactId>
@@ -102,7 +102,7 @@
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>1.3.9</version>
<version>3.0.0</version>
</dependency>
<!-- plugin dependencies -->
<dependency>
@@ -166,7 +166,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.5.2</version>
<version>3.0.1</version>
<configuration>
<excludeFilterFile>src/findbugs/excludesFilter.xml</excludeFilterFile>
<failOnError>${maven.findbugs.failure.strict}</failOnError>
@@ -28,13 +28,13 @@
import hudson.ExtensionPoint;
import hudson.BulkChange;
import hudson.XmlFile;
import hudson.model.AbstractBuild;
import hudson.model.AbstractDescribableImpl;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.model.Item;
import hudson.model.Job;
import hudson.model.JobProperty;
import hudson.model.Project;
import hudson.model.Run;
import hudson.model.Saveable;
import hudson.model.TopLevelItem;
import hudson.tasks.BuildWrapper;
@@ -56,8 +56,8 @@
* @param <R> the type of the builds of the branch projects.
* @author Stephen Connolly
*/
public abstract class BranchProjectFactory<P extends AbstractProject<P, R> & TopLevelItem,
R extends AbstractBuild<P, R>>
public abstract class BranchProjectFactory<P extends Job<P, R> & TopLevelItem,
R extends Run<P, R>>
extends AbstractDescribableImpl<BranchProjectFactory<?, ?>> implements Saveable, ExtensionPoint {

/**
@@ -106,7 +106,7 @@ public void setOwner(MultiBranchProject<P, R> owner) {
/**
* Gets the {@link Branch} that a specific project was configured for.
*
* @param project the project.
* @param project the project; should assume {@link #isProject} has already been tested on it
* @return the {@link Branch} that the project was configured for.
*/
@NonNull
@@ -172,14 +172,14 @@ public void setRevisionHash(P project, SCMRevision revision) throws IOException
}

/**
* Decorates the project in with all the {@link BranchProperty#decorator(hudson.model.AbstractProject)} instances.
* Decorates the project in with all the {@link BranchProperty#decorator(hudson.model.Job)} instances.
* NOTE: This method should suppress saving the project and only affect the in-memory state.
* NOTE: Override if the default strategy is not appropriate for the specific project type.
*
* @param project the project.
* @return the project for nicer method chaining
*/
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({"ConstantConditions", "unchecked"})
public P decorate(P project) {
if (!isProject(project)) {
return project;
@@ -194,14 +194,14 @@ public P decorate(P project) {
List<BranchProperty> properties = new ArrayList<BranchProperty>(branch.getProperties());
Collections.sort(properties, DescriptorOrder.reverse(BranchProperty.class));
for (BranchProperty property : properties) {
ProjectDecorator<P, R> decorator = property.decorator(project);
JobDecorator<P, R> decorator = property.jobDecorator(project.getClass());
if (decorator != null) {
// if Project then we can feed the publishers and build wrappers
if (project instanceof Project) {
DescribableList<Publisher, Descriptor<Publisher>> publishersList = project.getPublishersList();
DescribableList buildWrappersList = Project.class.cast(project).getBuildWrappersList();
List<Publisher> publishers = decorator.publishers(publishersList.toList());
List<BuildWrapper> buildWrappers = decorator.buildWrappers(buildWrappersList.toList());
if (project instanceof Project && decorator instanceof ProjectDecorator) {
DescribableList<Publisher, Descriptor<Publisher>> publishersList = ((Project) project).getPublishersList();
DescribableList<BuildWrapper, Descriptor<BuildWrapper>> buildWrappersList = ((Project) project).getBuildWrappersList();
List<Publisher> publishers = ((ProjectDecorator) decorator).publishers(publishersList.toList());
List<BuildWrapper> buildWrappers = ((ProjectDecorator) decorator).buildWrappers(buildWrappersList.toList());
publishersList.replaceBy(publishers);
buildWrappersList.replaceBy(buildWrappers);
}
@@ -26,16 +26,20 @@
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.ExtensionPoint;
import hudson.model.AbstractBuild;
import hudson.Util;
import hudson.model.AbstractDescribableImpl;
import hudson.model.AbstractProject;
import hudson.model.Build;
import hudson.model.Job;
import hudson.model.Project;
import hudson.model.Run;

import java.util.ArrayList;
import java.util.List;

/**
* Additional information associated with {@link Branch}.
* <p/>
* <p>
* {@link jenkins.scm.api.SCMSource}s can use properties to convey additional implementation/SCM specific
* information that's not captured in the base {@link Branch} class.
*
@@ -44,28 +48,41 @@
public abstract class BranchProperty extends AbstractDescribableImpl<BranchProperty> implements ExtensionPoint {

/**
* Returns a {@link ProjectDecorator} for the supplied project instance.
* @param project the project instance.
* @param <P> the type of project.
* @param <B> the type of build of the project.
* @return a {@link ProjectDecorator} or {@code null} if none appropriate to this type of project.
* @deprecated Should have been typed to take {@link Project} and {@link Build} rather than {@link AbstractProject} and {@link AbstractBuild}.
*/
@CheckForNull
@SuppressWarnings("unchecked")
public final <P extends AbstractProject<P,B>,B extends AbstractBuild<P,B>> ProjectDecorator<P,B> decorator(P project) {
return (ProjectDecorator<P, B>) decorator(project.getClass());
@SuppressWarnings({"unchecked", "rawtypes"})
@Deprecated
public final ProjectDecorator decorator(AbstractProject project) {
return decorator(project.getClass());
}

/**
* Returns a {@link ProjectDecorator} for the specific project type.
* @param clazz the project class.
* @param <P> the type of project.
* @param <B> the type of build of the project.
* @return a {@link ProjectDecorator} or {@code null} if none appropriate to this type of project.
* @deprecated Should have been typed to take {@link Project} and {@link Build} rather than {@link AbstractProject} and {@link AbstractBuild}.
*/
@CheckForNull
public <P extends AbstractProject<P,B>,B extends AbstractBuild<P,B>> ProjectDecorator<P,B> decorator(Class<P> clazz) {
return null;
@SuppressWarnings({"unchecked", "rawtypes"})
@Deprecated
public ProjectDecorator decorator(Class clazz) {
JobDecorator d = jobDecorator(clazz);
return d instanceof ProjectDecorator ? (ProjectDecorator) d : null;
}

/**
* Returns a {@link JobDecorator} for the specific job type.
* @param clazz the job class.
* @param <P> the type of job.
* @param <B> the type of run of the job.
* @return a {@link JobDecorator} or {@code null} if none appropriate to this type of job.
*/
@CheckForNull
@SuppressWarnings("unchecked")
public /*abstract*/ <P extends Job<P,B>,B extends Run<P,B>> JobDecorator<P,B> jobDecorator(Class<P> clazz) {
if (Util.isOverridden(BranchProperty.class, getClass(), "decorator", Class.class) && AbstractProject.class.isAssignableFrom(clazz)) {
return decorator(clazz);
} else {
throw new AbstractMethodError("you must implement jobDecorator");
}
}

/**
@@ -24,12 +24,15 @@
package jenkins.branch;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.DescriptorExtensionList;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;
import hudson.model.DescriptorVisibilityFilter;

import java.util.ArrayList;
import java.util.List;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;

/**
* {@link Descriptor} for {@link BranchProperty}.
@@ -63,14 +66,15 @@ protected boolean isApplicable(@NonNull MultiBranchProjectDescriptor projectDesc

/**
* All the registered {@link BranchPropertyDescriptor}s.
* Probably unused.
*/
public static DescriptorExtensionList<BranchProperty, BranchPropertyDescriptor> all() {
return Jenkins.getInstance().getDescriptorList(BranchProperty.class);
public static List<BranchPropertyDescriptor> all() {
return ExtensionList.lookup(BranchPropertyDescriptor.class);
}

/**
* Gets all the {@link BranchPropertyDescriptor} instances applicable to the specified project.
*
* Probably unused.
* @param project the project
* @return all the {@link BranchPropertyDescriptor} instances applicable to the specified project.
*/
@@ -84,4 +88,26 @@ protected boolean isApplicable(@NonNull MultiBranchProjectDescriptor projectDesc
return result;
}

/**
* Ensures that the configuration screen of (for example) {@link DefaultBranchPropertyStrategy} shows only appropriate descriptors.
* TODO this trick does not work for {@link NamedExceptionsBranchPropertyStrategy} on initial configuration (i.e., when {@link DefaultBranchPropertyStrategy} was initially selected);
* seems {@code filterDescriptors} is not called when {@code instance == null} perhaps?
* Or perhaps {@code it == null} when {@code l:renderOnDemand} is in use (supposed to work due to {@code capture} attribute, but…)?
*/
@Restricted(DoNotUse.class)
@Extension
public static final class Visibility extends DescriptorVisibilityFilter {

@SuppressWarnings("rawtypes")
@Override
public boolean filter(Object context, Descriptor descriptor) {
if (context instanceof MultiBranchProject && descriptor instanceof BranchPropertyDescriptor) {
return ((BranchPropertyDescriptor) descriptor).isApplicable((MultiBranchProject) context);
} else {
return true;
}
}

}

}
@@ -24,16 +24,11 @@
package jenkins.branch;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.DescriptorExtensionList;
import hudson.ExtensionList;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;
import jenkins.scm.api.SCMSourceDescriptor;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.Stapler;

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

/**
@@ -84,8 +79,8 @@ protected boolean isApplicable(@NonNull MultiBranchProjectDescriptor projectDesc
*
* @return all the {@link BranchPropertyStrategyDescriptor} instances.
*/
public static DescriptorExtensionList<BranchPropertyStrategy, BranchPropertyStrategyDescriptor> all() {
return Jenkins.getInstance().getDescriptorList(BranchPropertyStrategy.class);
public static List<BranchPropertyStrategyDescriptor> all() {
return ExtensionList.lookup(BranchPropertyStrategyDescriptor.class);
}

/**
@@ -107,16 +102,4 @@ protected boolean isApplicable(@NonNull MultiBranchProjectDescriptor projectDesc
return result;
}

/**
* Utility stapler binding for {@link BranchPropertyDescriptor#all(MultiBranchProject)}.
*/
@SuppressWarnings("unused") // by stapler
@Restricted(DoNotUse.class)
public List<BranchPropertyDescriptor> getPropertyDescriptors() {
MultiBranchProject project = Stapler.getCurrentRequest().findAncestorObject(
MultiBranchProject.class);
return project == null
? Collections.<BranchPropertyDescriptor>emptyList()
: BranchPropertyDescriptor.all(project);
}
}
@@ -3,8 +3,6 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.BulkChange;
import hudson.Extension;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Job;
import hudson.model.Run;
import jenkins.model.BuildDiscarder;
@@ -32,8 +30,8 @@ public BuildDiscarder getBuildDiscarder() {
}

@Override
public <P extends AbstractProject<P,B>,B extends AbstractBuild<P,B>> ProjectDecorator<P,B> decorator(Class<P> jobType) {
return new ProjectDecorator<P, B>(){
public <P extends Job<P,B>,B extends Run<P,B>> JobDecorator<P,B> jobDecorator(Class<P> jobType) {
return new JobDecorator<P, B>(){
@NonNull
@Override
public P project(@NonNull final P project) {
@@ -24,9 +24,9 @@
package jenkins.branch;

import hudson.ExtensionPoint;
import hudson.model.AbstractBuild;
import hudson.model.AbstractDescribableImpl;
import hudson.model.AbstractProject;
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.TopLevelItem;

@@ -45,7 +45,7 @@
*/
private transient MultiBranchProject<?, ?> owner;

public abstract <P extends AbstractProject<P, R> & TopLevelItem, R extends AbstractBuild<P, R>>
public abstract <P extends Job<P, R> & TopLevelItem, R extends Run<P, R>>
void runDeadBranchCleanup(TaskListener listener, Map<String, P> deadBranches) throws IOException,
InterruptedException;

@@ -23,8 +23,8 @@
*/
package jenkins.branch;

import hudson.ExtensionList;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;

import java.util.ArrayList;
import java.util.List;
@@ -53,12 +53,9 @@ public boolean isApplicable(java.lang.Class<? extends MultiBranchProject> jobTyp
@SuppressWarnings("unused") // used by stapler
public static List<DeadBranchStrategyDescriptor> forProject(Class<? extends MultiBranchProject> jobType) {
List<DeadBranchStrategyDescriptor> result = new ArrayList<DeadBranchStrategyDescriptor>();
for (Descriptor<DeadBranchStrategy> d : Jenkins.getInstance().getDescriptorList(DeadBranchStrategy.class)) {
if (d instanceof DeadBranchStrategyDescriptor) {
DeadBranchStrategyDescriptor descriptor = (DeadBranchStrategyDescriptor) d;
if (descriptor.isApplicable(jobType)) {
result.add(descriptor);
}
for (DeadBranchStrategyDescriptor descriptor : ExtensionList.lookup(DeadBranchStrategyDescriptor.class)) {
if (descriptor.isApplicable(jobType)) {
result.add(descriptor);
}
}
return result;
@@ -26,8 +26,8 @@
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.TopLevelItem;
import hudson.tasks.LogRotator;
@@ -192,8 +192,8 @@ private static int fromString(@CheckForNull String s) {
/**
* {@inheritDoc}
*/
public <P extends AbstractProject<P, R> & TopLevelItem,
R extends AbstractBuild<P, R>> void runDeadBranchCleanup(TaskListener listener,
public <P extends Job<P, R> & TopLevelItem,
R extends Run<P, R>> void runDeadBranchCleanup(TaskListener listener,
Map<String, P> deadBranches)
throws IOException, InterruptedException {
final MultiBranchProject<P, R> owner = (MultiBranchProject<P, R>) getOwner();
@@ -75,7 +75,11 @@
* @param type the type.
*/
DescriptorOrder(Class<T> type) {
descriptors = Jenkins.getInstance().getDescriptorList(type);
Jenkins j = Jenkins.getInstance();
if (j == null) {
throw new IllegalStateException(); // TODO 1.590+ getActiveInstance
}
descriptors = j.getDescriptorList(type);
}

/**

0 comments on commit 06f1e2f

Please sign in to comment.