JENKINS-36278# Fixed Link generation of Multibranch project

Fixes:
- Link generation of multi branch project nested inside a folder
- BlueMultiBranchPipeline is a BluePipelineFolder now
- branches are reachable via /pipelines/:id/branches/:id or /pipelines/:id/pipelines/:id.
  This makes it consistent with generic folder as multibranch project is really a folder.
This commit is contained in:
Vivek Pandey 2016-06-28 16:22:40 -07:00
parent 5b7e4a4dc2
commit 317a9b1b35
9 changed files with 76 additions and 80 deletions

View File

@ -15,11 +15,12 @@ import java.util.List;
*/
public class BranchContainerImpl extends BluePipelineContainer {
private final MultiBranchPipelineImpl pipeline;
private final Link self;
public BranchContainerImpl(MultiBranchPipelineImpl pipeline) {
public BranchContainerImpl(MultiBranchPipelineImpl pipeline, Link self) {
this.pipeline = pipeline;
this.self = self;
}
//TODO: implement rest of the methods
@Override
public BluePipeline get(String name) {
@ -42,6 +43,6 @@ public class BranchContainerImpl extends BluePipelineContainer {
@Override
public Link getLink() {
return pipeline.getLink().rel("branches");
return self;
}
}

View File

@ -18,7 +18,7 @@ public class BranchImpl extends PipelineImpl {
private final Link parent;
public BranchImpl(Job job, Link parent) {
super(job, parent);
super(job);
this.parent = parent;
}

View File

@ -108,6 +108,21 @@ public class MultiBranchPipelineImpl extends BlueMultiBranchPipeline {
return countRunStatus(Result.SUCCESS, true);
}
@Override
public BluePipelineContainer getPipelines() {
return new BranchContainerImpl(this, getLink().rel("pipelines"));
}
@Override
public Integer getNumberOfFolders() {
return 0;
}
@Override
public Integer getNumberOfPipelines() {
return getTotalNumberOfBranches();
}
@Override
@SuppressWarnings("unchecked")
public Integer getWeatherScore(){
@ -168,7 +183,7 @@ public class MultiBranchPipelineImpl extends BlueMultiBranchPipeline {
@Override
@Navigable
public BluePipelineContainer getBranches() {
return new BranchContainerImpl(this);
return new BranchContainerImpl(this, getLink().rel("branches"));
}
@Override

View File

@ -1,17 +1,14 @@
package io.jenkins.blueocean.service.embedded.rest;
import hudson.model.BuildableItem;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Job;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BluePipelineContainer;
import io.jenkins.blueocean.rest.model.BluePipelineFactory;
import jenkins.branch.MultiBranchProject;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import javax.annotation.Nonnull;
import java.util.ArrayList;
@ -24,18 +21,27 @@ import java.util.List;
*/
public class PipelineContainerImpl extends BluePipelineContainer {
private final @Nonnull ItemGroup itemGroup;
private final Link self;
public PipelineContainerImpl() {
this.itemGroup = Jenkins.getInstance();
this(Jenkins.getInstance(),null);
}
public PipelineContainerImpl(ItemGroup itemGroup) {
this.itemGroup = itemGroup;
this(itemGroup,null);
}
public PipelineContainerImpl(ItemGroup itemGroup, Reachable parent) {
this.itemGroup = itemGroup;
if(parent!=null){
this.self = parent.getLink().rel("pipelines");
}else{
this.self = OrganizationImpl.INSTANCE.getLink().rel("pipelines");
}
}
@Override
public Link getLink() {
return OrganizationImpl.INSTANCE.getLink().rel("pipelines");
return self;
}
@Override
@ -49,39 +55,31 @@ public class PipelineContainerImpl extends BluePipelineContainer {
return get(item);
}
public BluePipeline get(Item item){
for(BluePipelineFactory factory:BluePipelineFactory.all()){
BluePipeline pipeline = factory.getPipeline(item, this);
if( pipeline!= null){
return pipeline;
}
}
// TODO: I'm going to turn this into a decorator annotation
throw new ServiceException.NotFoundException(String.format("Pipeline %s not found", item.getName()));
}
@Override
@SuppressWarnings("unchecked")
public Iterator<BluePipeline> iterator() {
return getPipelines(itemGroup.getItems());
}
protected static boolean isMultiBranchProjectJob(BuildableItem item){
return item instanceof WorkflowJob && item.getParent() instanceof MultiBranchProject;
}
protected Iterator<BluePipeline> getPipelines(Collection<? extends Item> items){
List<BluePipeline> pipelines = new ArrayList<>();
for (Item item : items) {
if(item instanceof MultiBranchProject){
pipelines.add(new MultiBranchPipelineImpl((MultiBranchProject) item, getLink()));
}else if(item instanceof BuildableItem && !isMultiBranchProjectJob((BuildableItem) item)
&& item instanceof Job){
pipelines.add(new PipelineImpl((Job) item, getLink()));
}else if(item instanceof ItemGroup){
pipelines.add(new PipelineFolderImpl((ItemGroup) item, getLink()));
BluePipeline pipeline = get(item);
if(pipeline != null){
pipelines.add(pipeline);
}
}
return pipelines.iterator();
}
private BluePipeline get(Item item){
for(BluePipelineFactory factory:BluePipelineFactory.all()){
BluePipeline pipeline = factory.getPipeline(item, this);
if( pipeline!= null){
return pipeline;
}
}
return null;
}
}

View File

@ -59,7 +59,7 @@ public class PipelineFolderImpl extends BluePipelineFolder {
@Override
public BluePipelineContainer getPipelines() {
return new PipelineContainerImpl(folder);
return new PipelineContainerImpl(folder, this);
}
@Override

View File

@ -2,9 +2,7 @@ package io.jenkins.blueocean.service.embedded.rest;
import hudson.Extension;
import hudson.model.Action;
import hudson.model.BuildableItem;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Job;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.Navigable;
@ -17,7 +15,6 @@ import io.jenkins.blueocean.rest.model.BlueQueueContainer;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.BlueRunContainer;
import io.jenkins.blueocean.service.embedded.util.FavoriteUtil;
import jenkins.branch.MultiBranchProject;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.WebMethod;
import org.kohsuke.stapler.export.ExportedBean;
@ -29,8 +26,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static io.jenkins.blueocean.service.embedded.rest.PipelineContainerImpl.isMultiBranchProjectJob;
/**
* @author Kohsuke Kawaguchi
*/
@ -38,23 +33,10 @@ import static io.jenkins.blueocean.service.embedded.rest.PipelineContainerImpl.i
public class PipelineImpl extends BluePipeline {
/*package*/ final Job job;
private final ItemGroup folder;
private final Link parent;
protected PipelineImpl(ItemGroup folder, Job job, Link parent) {
protected PipelineImpl(Job job) {
this.job = job;
this.folder = folder;
this.parent = null;
}
public PipelineImpl(ItemGroup folder, Link parent) {
this(folder, null,parent);
}
public PipelineImpl(Job job, Link parent) {
this(null, job, parent);
}
@Override
public String getOrganization() {
return OrganizationImpl.INSTANCE.getName();
@ -134,25 +116,6 @@ public class PipelineImpl extends BluePipeline {
return job.getFullName();
}
public BluePipeline getPipelines(String name){
assert folder != null;
return getPipeline(folder, name);
}
private BluePipeline getPipeline(ItemGroup itemGroup, String name){
Item item = itemGroup.getItem(name);
if(item instanceof BuildableItem){
if(item instanceof MultiBranchProject){
return new MultiBranchPipelineImpl((MultiBranchProject) item, getLink());
}else if(!isMultiBranchProjectJob((BuildableItem) item) && item instanceof Job){
return new PipelineImpl(itemGroup, (Job) item, parent);
}
}else if(item instanceof ItemGroup){
return new PipelineImpl((ItemGroup) item, null);
}
throw new ServiceException.NotFoundException(String.format("Pipeline %s not found", name));
}
@Override
public Link getLink() {
return OrganizationImpl.INSTANCE.getLink().rel("pipelines").rel(getRecursivePathFromFullName(this));
@ -183,7 +146,7 @@ public class PipelineImpl extends BluePipeline {
@Override
public BluePipeline getPipeline(Item item, Reachable parent) {
if (item instanceof Job) {
return new PipelineImpl((Job) item, parent.getLink());
return new PipelineImpl((Job) item);
}
return null;
}

View File

@ -23,6 +23,7 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.BuildWatcher;
import org.jvnet.hudson.test.MockFolder;
import java.io.IOException;
import java.text.SimpleDateFormat;
@ -75,6 +76,26 @@ public class MultiBranchTest extends BaseTest{
}
@Test
public void getMultiBranchPipelineInsideFolder() throws IOException, ExecutionException, InterruptedException {
MockFolder folder1 = j.createFolder("folder1");
WorkflowMultiBranchProject mp = folder1.createProject(WorkflowMultiBranchProject.class, "p");
mp.getSourcesList().add(new BranchSource(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", false),
new DefaultBranchPropertyStrategy(new BranchProperty[0])));
for (SCMSource source : mp.getSCMSources()) {
assertEquals(mp, source.getOwner());
}
mp.scheduleBuild2(0).getFuture().get();
Map r = get("/organizations/jenkins/pipelines/folder1/pipelines/p/");
validateMultiBranchPipeline(mp, r, 3);
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/p/",
((Map)((Map)r.get("_links")).get("self")).get("href"));
}
@Test
public void getBranchWithEncodedPath() throws IOException, ExecutionException, InterruptedException {
WorkflowMultiBranchProject mp = j.jenkins.createProject(WorkflowMultiBranchProject.class, "p");

View File

@ -12,7 +12,6 @@ import hudson.model.CauseAction;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Job;
import hudson.model.ParametersAction;
import hudson.model.ParametersDefinitionProperty;
@ -26,7 +25,6 @@ import hudson.tasks.Shell;
import hudson.tasks.junit.JUnitResultArchiver;
import hudson.tasks.junit.TestResultAction;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BluePipelineFactory;
import io.jenkins.blueocean.service.embedded.rest.PipelineImpl;
@ -560,7 +558,7 @@ public class PipelineApiTest extends BaseTest {
@Override
public BluePipeline getPipeline(Item item, Reachable parent) {
if(item instanceof Job){
return new TestPipelineImpl(null, (Job)item, parent.getLink());
return new TestPipelineImpl((Job)item);
}
return null;
}
@ -568,8 +566,8 @@ public class PipelineApiTest extends BaseTest {
public static class TestPipelineImpl extends PipelineImpl {
public TestPipelineImpl(ItemGroup folder, Job job, Link parent) {
super(folder, job, parent);
public TestPipelineImpl(Job job) {
super(job);
}
@Exported(name = "hello")

View File

@ -13,7 +13,7 @@ import java.util.Iterator;
*
* @author Vivek Pandey
*/
public abstract class BlueMultiBranchPipeline extends BluePipeline{
public abstract class BlueMultiBranchPipeline extends BluePipelineFolder{
public static final String TOTAL_NUMBER_OF_BRANCHES="totalNumberOfBranches";
public static final String NUMBER_OF_FAILING_BRANCHES="numberOfFailingBranches";
public static final String NUMBER_OF_SUCCESSFULT_BRANCHES="numberOfSuccessfulBranches";