From 619618213ca17f34ddd6ed240c5172c6ec5a22dc Mon Sep 17 00:00:00 2001 From: Vivek Pandey Date: Tue, 26 Jul 2016 15:40:55 -0700 Subject: [PATCH] JENKINS-36967# Favorite object self link fix --- .../pipeline/MultiBranchPipelineImpl.java | 14 +-- .../rest/impl/pipeline/MultiBranchTest.java | 75 +++++++++-- .../rest/impl/pipeline/PipelineBaseTest.java | 7 ++ .../service/embedded/util/FavoriteUtil.java | 28 +---- .../blueocean/service/embedded/BaseTest.java | 57 ++------- .../service/embedded/ProfileApiTest.java | 116 +++++++++++++++++- blueocean-rest/README.md | 25 +++- 7 files changed, 230 insertions(+), 92 deletions(-) diff --git a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineImpl.java index d40d0e85..6647121a 100644 --- a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineImpl.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineImpl.java @@ -9,6 +9,7 @@ import io.jenkins.blueocean.commons.ServiceException; import io.jenkins.blueocean.rest.Navigable; import io.jenkins.blueocean.rest.Reachable; import io.jenkins.blueocean.rest.hal.Link; +import io.jenkins.blueocean.rest.hal.LinkResolver; import io.jenkins.blueocean.rest.model.BlueActionProxy; import io.jenkins.blueocean.rest.model.BlueFavorite; import io.jenkins.blueocean.rest.model.BlueFavoriteAction; @@ -69,12 +70,8 @@ public class MultiBranchPipelineImpl extends BlueMultiBranchPipeline { } FavoriteUtil.favoriteJob(mbp.getFullName(), favoriteAction.isFavorite()); - return FavoriteUtil.getFavorite(mbp, new Reachable() { - @Override - public Link getLink() { - return getLink().rel("branches"); - } - }); + + return new FavoriteImpl(new BranchImpl(job,getLink().rel("branches")), getLink().rel("favorite")); } @Override @@ -351,7 +348,10 @@ public class MultiBranchPipelineImpl extends BlueMultiBranchPipeline { Job job = project.getItem("master"); if(job != null){ Resource resource = BluePipelineFactory.resolve(job); - return new FavoriteImpl(resource, FavoriteUtil.getFavoriteLink(item.getFullName())); + Link l = LinkResolver.resolveLink(project); + if(l != null) { + return new FavoriteImpl(resource, l.rel("favorite")); + } } } return null; diff --git a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchTest.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchTest.java index 4e39e0ac..a60d1ae2 100644 --- a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchTest.java +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchTest.java @@ -446,7 +446,7 @@ public class MultiBranchTest extends PipelineBaseTest { .auth("alice","alice") .build(List.class); - Assert.assertEquals(l.size(), 1); + Assert.assertEquals(1,l.size()); branch = (Map)((Map)l.get(0)).get("item"); validatePipeline(p, branch); @@ -454,6 +454,30 @@ public class MultiBranchTest extends PipelineBaseTest { c = (String) branch.get("_class"); Assert.assertEquals(BranchImpl.class.getName(), c); + Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/favorite/", getHrefFromLinks((Map)l.get(0), "self")); + + String ref = getHrefFromLinks((Map)l.get(0), "self"); + + m = new RequestBuilder(baseUrl) + .put(getUrlFromHref(ref)) + .auth("alice", "alice") + .data(ImmutableMap.of("favorite", false)) + .build(Map.class); + + branch = (Map) m.get("item"); + validatePipeline(p, branch); + c = (String) branch.get("_class"); + Assert.assertEquals(BranchImpl.class.getName(), c); + + + l = new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("alice","alice") + .build(List.class); + + Assert.assertEquals(0,l.size()); + + new RequestBuilder(baseUrl) .get("/users/"+user.getId()+"/favorites/") .auth("bob","bob") @@ -488,20 +512,44 @@ public class MultiBranchTest extends PipelineBaseTest { validatePipeline(p1, (Map) map.get("item")); + Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/feature2/favorite/", getHrefFromLinks(map, "self")); + List l = new RequestBuilder(baseUrl) .get("/users/"+user.getId()+"/favorites/") .auth("alice","alice") .build(List.class); - Assert.assertEquals(l.size(), 1); + Assert.assertEquals(1, l.size()); Map branch = (Map)((Map)l.get(0)).get("item"); + Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/feature2/favorite/", getHrefFromLinks((Map)l.get(0), "self")); + validatePipeline(p1, branch); String c = (String) branch.get("_class"); Assert.assertEquals(BranchImpl.class.getName(), c); + + map = new RequestBuilder(baseUrl) + .put(getUrlFromHref(getHrefFromLinks((Map)l.get(0), "self"))) + .auth("alice", "alice") + .data(ImmutableMap.of("favorite", false)) + .build(Map.class); + + + validatePipeline(p1, (Map) map.get("item")); + + Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/feature2/favorite/", getHrefFromLinks(map, "self")); + + l = new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("alice","alice") + .build(List.class); + + Assert.assertEquals(0, l.size()); + + new RequestBuilder(baseUrl) .get("/users/"+user.getId()+"/favorites/") .auth("bob","bob") @@ -548,15 +596,28 @@ public class MultiBranchTest extends PipelineBaseTest { String c = (String) branch.get("_class"); Assert.assertEquals(BranchImpl.class.getName(), c); - String ref = getHrefFromLinks((Map)l.get(0), "self"); + String href = getHrefFromLinks((Map)l.get(0), "self"); + Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/favorite/", href); - Map r = new RequestBuilder(baseUrl) - .get(ref.substring("/blue/rest".length())) - .auth("alice","alice") + + + Map m = new RequestBuilder(baseUrl) + .put(getUrlFromHref(getUrlFromHref(href))) + .auth("alice", "alice") + .data(ImmutableMap.of("favorite", false)) .build(Map.class); - validatePipeline(p, (Map)r.get("item")); + branch = (Map) m.get("item"); + validatePipeline(p, branch); + c = (String) branch.get("_class"); + Assert.assertEquals(BranchImpl.class.getName(), c); + l = new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("alice","alice") + .build(List.class); + + Assert.assertEquals(0,l.size()); } @Test diff --git a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineBaseTest.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineBaseTest.java index 738cdeb2..55c820ca 100644 --- a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineBaseTest.java +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineBaseTest.java @@ -332,6 +332,13 @@ public abstract class PipelineBaseTest{ return (String) l.get("href"); } + protected String getUrlFromHref(String href){ + if(href.startsWith("/blue/rest")){ + return href.substring("/blue/rest".length()); + } + return href; + } + protected List getParallelNodes(FlowGraphTable nodeGraphTable){ List parallelNodes = new ArrayList<>(); diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/util/FavoriteUtil.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/util/FavoriteUtil.java index 6d9b6b01..8b27acc8 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/util/FavoriteUtil.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/util/FavoriteUtil.java @@ -1,9 +1,6 @@ package io.jenkins.blueocean.service.embedded.util; -import hudson.Util; import hudson.model.Item; -import hudson.model.ItemGroup; -import hudson.model.Job; import hudson.model.User; import hudson.plugins.favorite.FavoritePlugin; import hudson.plugins.favorite.user.FavoriteUserProperty; @@ -16,7 +13,6 @@ import io.jenkins.blueocean.rest.model.BluePipeline; import io.jenkins.blueocean.service.embedded.rest.BlueFavoriteResolver; import io.jenkins.blueocean.service.embedded.rest.BluePipelineFactory; import io.jenkins.blueocean.service.embedded.rest.FavoriteImpl; -import io.jenkins.blueocean.service.embedded.rest.UserImpl; import jenkins.model.Jenkins; import org.kohsuke.stapler.Stapler; @@ -53,22 +49,6 @@ public class FavoriteUtil { } } - public static Link getFavoriteLink(String fullName){ - User user = User.current(); - if(user != null) { - return new UserImpl(user).getLink().rel("favorites/"+ FavoriteUtil.encodeFullName(fullName)); - } - return null; - } - - public static boolean isFavorableItem(Item i){ - return i!= null && (i instanceof Job || i instanceof ItemGroup); - } - - public static String encodeFullName(String name){ - return Util.rawEncode(Util.rawEncode(name)); - } - public static String decodeFullName(String name){ try { return URLDecoder.decode(URLDecoder.decode(name, "UTF-8"), "UTF-8"); @@ -119,15 +99,9 @@ public class FavoriteUtil { } } - //otherwise, default - Link favouriteLink = getFavoriteLink(item.getFullName()); - if(favouriteLink == null){ - return null; - } - BluePipeline pipeline = BluePipelineFactory.getPipelineInstance(item, parent); if(pipeline != null){ - return new FavoriteImpl(pipeline,favouriteLink); + return new FavoriteImpl(pipeline,pipeline.getLink().rel("favorite")); } return null; diff --git a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/BaseTest.java b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/BaseTest.java index d05f2f63..1a3916de 100644 --- a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/BaseTest.java +++ b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/BaseTest.java @@ -15,6 +15,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.MockFolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -227,24 +228,6 @@ public abstract class BaseTest { throw new RuntimeException(e); } } -// -// protected void validateMultiBranchPipeline(WorkflowMultiBranchProject p, Map resp, int numBranches){ -// validateMultiBranchPipeline(p, resp, numBranches, -1, -1); -// } -// protected void validateMultiBranchPipeline(WorkflowMultiBranchProject p, Map resp, int numBranches, int numSuccBranches, int numOfFailingBranches){ -// Assert.assertEquals("jenkins", resp.get("organization")); -// Assert.assertEquals(p.getName(), resp.get("name")); -// Assert.assertEquals(p.getDisplayName(), resp.get("displayName")); -// Assert.assertNull(resp.get("lastSuccessfulRun")); -// Assert.assertEquals(numBranches, resp.get("totalNumberOfBranches")); -// if(numOfFailingBranches >= 0) { -// Assert.assertEquals(numOfFailingBranches, resp.get("numberOfFailingBranches")); -// } -// if(numSuccBranches >= 0) { -// Assert.assertEquals(numSuccBranches, resp.get("numberOfSuccessfulBranches")); -// } -// Assert.assertEquals(p.getBuildHealth().getScore(), resp.get("weatherScore")); -// } protected void validatePipeline(Job p, Map resp){ Assert.assertEquals("jenkins", resp.get("organization")); @@ -271,6 +254,17 @@ public abstract class BaseTest { } } + + protected void validateFolder(MockFolder folder, Map resp){ + Assert.assertEquals("jenkins", resp.get("organization")); + Assert.assertEquals(folder.getName(), resp.get("name")); + Assert.assertEquals(folder.getDisplayName(), resp.get("displayName")); + Assert.assertEquals(folder.getFullName(), resp.get("fullName")); + Assert.assertNull(resp.get("lastSuccessfulRun")); + Assert.assertEquals(folder.getAllJobs().size(), resp.get("numberOfPipelines")); + Assert.assertEquals(folder.getAllJobs().size(), resp.get("numberOfPipelines")); + } + protected void validateRun(Run r, Map resp){ validateRun(r,resp, "FINISHED"); } @@ -285,39 +279,12 @@ public abstract class BaseTest { Assert.assertEquals(state, resp.get("state")); } -// protected String getNodeName(FlowNode n){ -// return n.getAction(ThreadNameAction.class) != null -// ? n.getAction(ThreadNameAction.class).getThreadName() -// : n.getDisplayName(); -// } private String getBaseUrl(String path){ return baseUrl + path; } -// protected List getStages(FlowGraphTable nodeGraphTable){ -// List nodes = new ArrayList<>(); -// for(FlowGraphTable.Row row: nodeGraphTable.getRows()){ -// if(PipelineNodeUtil.isStage(row.getNode()) || -// PipelineNodeUtil.isParallelBranch(row.getNode())){ -// nodes.add(row.getNode()); -// } -// } -// return nodes; -// } - -// protected List getParallelNodes(FlowGraphTable nodeGraphTable){ -// List parallelNodes = new ArrayList<>(); -// -// for(FlowGraphTable.Row row: nodeGraphTable.getRows()){ -// if(PipelineNodeUtil.isParallelBranch(row.getNode())){ -// parallelNodes.add(row.getNode()); -// } -// } -// return parallelNodes; -// } - protected String getHrefFromLinks(Map resp, String link){ Map links = (Map) resp.get("_links"); if(links == null){ diff --git a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/ProfileApiTest.java b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/ProfileApiTest.java index 9b787dc2..eeea0855 100644 --- a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/ProfileApiTest.java +++ b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/ProfileApiTest.java @@ -2,11 +2,13 @@ package io.jenkins.blueocean.service.embedded; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import hudson.model.FreeStyleProject; import hudson.model.Project; import hudson.model.User; import hudson.tasks.Mailer; import org.junit.Assert; import org.junit.Test; +import org.jvnet.hudson.test.MockFolder; import java.util.Collections; import java.util.List; @@ -90,8 +92,10 @@ public class ProfileApiTest extends BaseTest{ j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); hudson.model.User user = j.jenkins.getUser("alice"); user.setFullName("Alice Cooper"); + Project p = j.createFreeStyleProject("pipeline1"); + Map map = new RequestBuilder(baseUrl) .put("/organizations/jenkins/pipelines/pipeline1/favorite") .auth("alice", "alice") @@ -104,11 +108,121 @@ public class ProfileApiTest extends BaseTest{ .auth("alice","alice") .build(List.class); - Assert.assertEquals(l.size(), 1); + Assert.assertEquals(1, l.size()); Map pipeline = (Map)((Map)l.get(0)).get("item"); validatePipeline(p, pipeline); + String href = getHrefFromLinks((Map)l.get(0),"self"); + Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/pipeline1/favorite/", href); + map = new RequestBuilder(baseUrl) + .put(href.substring("/blue/rest".length())) + .auth("alice", "alice") + .data(ImmutableMap.of("favorite", false)) + .build(Map.class); + + validatePipeline(p, (Map) map.get("item")); + + l = new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("alice","alice") + .build(List.class); + + Assert.assertEquals(0, l.size()); + + + new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("bob","bob") + .status(403) + .build(String.class); + + } + + @Test + public void createUserFavouriteFolderTest() throws Exception { + j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); + hudson.model.User user = j.jenkins.getUser("alice"); + user.setFullName("Alice Cooper"); + + MockFolder folder1 = j.createFolder("folder1"); + Project p = folder1.createProject(FreeStyleProject.class, "pipeline1"); + + Map map = new RequestBuilder(baseUrl) + .put("/organizations/jenkins/pipelines/folder1/pipelines/pipeline1/favorite/") + .auth("alice", "alice") + .data(ImmutableMap.of("favorite", true)) + .build(Map.class); + + validatePipeline(p, (Map) map.get("item")); + List l = new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("alice","alice") + .build(List.class); + + Assert.assertEquals(1, l.size()); + Map pipeline = (Map)((Map)l.get(0)).get("item"); + + validatePipeline(p, pipeline); + + String href = getHrefFromLinks((Map)l.get(0),"self"); + + Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/pipeline1/favorite/", href); + + map = new RequestBuilder(baseUrl) + .put(href.substring("/blue/rest".length())) + .auth("alice", "alice") + .data(ImmutableMap.of("favorite", false)) + .build(Map.class); + + validatePipeline(p, (Map) map.get("item")); + + l = new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("alice","alice") + .build(List.class); + + Assert.assertEquals(0, l.size()); + + + map = new RequestBuilder(baseUrl) + .put("/organizations/jenkins/pipelines/folder1/favorite/") + .auth("alice", "alice") + .data(ImmutableMap.of("favorite", true)) + .build(Map.class); + + validateFolder(folder1, (Map) map.get("item")); + l = new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("alice","alice") + .build(List.class); + + Assert.assertEquals(1, l.size()); + Map folder = (Map)((Map)l.get(0)).get("item"); + + validateFolder(folder1, folder); + + href = getHrefFromLinks((Map)l.get(0),"self"); + + Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/favorite/", href); + + map = new RequestBuilder(baseUrl) + .put(href.substring("/blue/rest".length())) + .auth("alice", "alice") + .data(ImmutableMap.of("favorite", false)) + .build(Map.class); + + validateFolder(folder1, (Map) map.get("item")); + + l = new RequestBuilder(baseUrl) + .get("/users/"+user.getId()+"/favorites/") + .auth("alice","alice") + .build(List.class); + + Assert.assertEquals(0, l.size()); + + + new RequestBuilder(baseUrl) .get("/users/"+user.getId()+"/favorites/") .auth("bob","bob") diff --git a/blueocean-rest/README.md b/blueocean-rest/README.md index 88a8cc62..d5404c17 100644 --- a/blueocean-rest/README.md +++ b/blueocean-rest/README.md @@ -56,7 +56,9 @@ - [Favorite API](#favorite-api) - [Favorite a pipeline](#favorite-a-pipeline) - [Favorite a multi branch pipeline](#favorite-a-multi-branch-pipeline) + - [Un-favorite a multi branch pipeline](#un-favorite-a-multi-branch-pipeline) - [Favorite a multi branch pipeline branch](#favorite-a-multi-branch-pipeline-branch) + - [Un-favorite a multi branch pipeline branch](#un-favorite-a-multi-branch-pipeline-branch) - [Fetch user favorites](#fetch-user-favorites) - [Log API](#log-api) - [Fetching logs](#fetching-logs) @@ -1279,7 +1281,7 @@ If favorite request is successful then the repsonse is favorited item. "_links" : { "self" : { "_class" : "io.jenkins.blueocean.rest.hal.Link", - "href" : "/blue/rest/users/alice/favorites/pipeline1/" + "href" : "/blue/rest/organizations/jenkins/pipelines/pipeline1/favorite/" } }, "item" : { @@ -1319,19 +1321,32 @@ If favorite request is successful then the repsonse is favorited item. ## Favorite a pipeline Returns 200 on success. Must be authenticated. - curl -u bob:bob -H"Content-Type:application/json" -XPUT -d '{"favorite":true} ttp://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/favorite + curl -u bob:bob -H"Content-Type:application/json" -XPUT -d '{"favorite":true} ttp://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/favorite/ ## Favorite a multi branch pipeline Must be authenticated. -This favorites the master branch. Returns 200 on success. 500 if master does not exist +Favorited multi-branch pipeline returns master branch as favorited item. Returns 200 on success. 400 if master does not exist + + curl -u bob:bob -H"Content-Type:application/json" -XPUT -d '{"favorite":true} http://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/favorite/ + +## Un-favorite a multi branch pipeline +Must be authenticated. + +This un-favorites the master branch. Returns 200 on success. 400 if master does not exist + + curl -u bob:bob -H"Content-Type:application/json" -XPUT -d '{"favorite":false} http://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/favorite/ - curl -u bob:bob -H"Content-Type:application/json" -XPUT -d '{"favorite":true} http://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/favorite ## Favorite a multi branch pipeline branch Returns 200 on success. Must be authenticated. - curl -H"Content-Type:application/json" -XPUT -d '{"favorite":true} http://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/branches/master/favorite + curl -H"Content-Type:application/json" -XPUT -d '{"favorite":true} http://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/branches/master/favorite/ + +## Un-favorite a multi branch pipeline branch +Returns 200 on success. Must be authenticated. + + curl -H"Content-Type:application/json" -XPUT -d '{"favorite":false} http://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/branches/master/favorite/ ## Fetch user favorites