Merge pull request #328 from jenkinsci/improvement/JENKINS-36580

JENKINS-36580# PUT .../pipelines/:id/favorite/ enhancements
This commit is contained in:
vivek 2016-07-11 16:54:33 -07:00 committed by GitHub
commit 5b1cf811bd
10 changed files with 112 additions and 42 deletions

View File

@ -26,7 +26,8 @@ public class FavoriteContainerImpl extends BlueFavoriteContainer {
}
@Override
public BlueFavorite get(final String name) {
public BlueFavorite get(String name) {
name = FavoriteUtil.decodeFullName(name);
if(user.isFavorite(name)){
Item item = Jenkins.getInstance().getItemByFullName(name);
if(FavoriteUtil.isFavorableItem(item)) {

View File

@ -1,12 +1,12 @@
package io.jenkins.blueocean.service.embedded.rest;
import hudson.Util;
import hudson.model.Item;
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.BlueFavorite;
import jenkins.model.Jenkins;
import io.jenkins.blueocean.service.embedded.util.FavoriteUtil;
/**
* @author Vivek Pandey
@ -15,11 +15,15 @@ public class FavoriteImpl extends BlueFavorite {
private final Object item;
private final Link self;
private final LinkResolver linkResolver;
public FavoriteImpl(Object item, Link self) {
this.self = self;
this.item = item;
}
public FavoriteImpl(Item item, Reachable parent) {
this.self = parent.getLink().rel(Util.rawEncode(item.getFullName()));
this.linkResolver = Jenkins.getInstance().getInjector().getInstance(LinkResolver.class);
this.self = parent.getLink().rel(FavoriteUtil.encodeFullName(item.getFullName()));
LinkResolver linkResolver = Jenkins.getInstance().getInjector().getInstance(LinkResolver.class);
final Link link = linkResolver.resolve(item);

View File

@ -10,6 +10,7 @@ import io.jenkins.blueocean.rest.Navigable;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueActionProxy;
import io.jenkins.blueocean.rest.model.BlueFavorite;
import io.jenkins.blueocean.rest.model.BlueFavoriteAction;
import io.jenkins.blueocean.rest.model.BlueMultiBranchPipeline;
import io.jenkins.blueocean.rest.model.BluePipeline;
@ -52,7 +53,7 @@ public class MultiBranchPipelineImpl extends BlueMultiBranchPipeline {
@Override
public void favorite(@JsonBody BlueFavoriteAction favoriteAction) {
public BlueFavorite favorite(@JsonBody BlueFavoriteAction favoriteAction) {
if(favoriteAction == null) {
throw new ServiceException.BadRequestExpception("Must provide pipeline name");
}
@ -62,7 +63,8 @@ public class MultiBranchPipelineImpl extends BlueMultiBranchPipeline {
throw new ServiceException.BadRequestExpception("no master branch to favorite");
}
FavoriteUtil.favoriteJob(job.getFullName(), favoriteAction.isFavorite());
Link link = FavoriteUtil.favoriteJob(job.getFullName(), favoriteAction.isFavorite());
return new FavoriteImpl(new BranchImpl(job, getLink().rel("branches")), link);
}
@Override

View File

@ -7,6 +7,7 @@ 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.BlueActionProxy;
import io.jenkins.blueocean.rest.model.BlueFavorite;
import io.jenkins.blueocean.rest.model.BlueFavoriteAction;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BluePipelineContainer;
@ -87,12 +88,13 @@ public class PipelineFolderImpl extends BluePipelineFolder {
@Override
public void favorite(@JsonBody BlueFavoriteAction favoriteAction) {
public BlueFavorite favorite(@JsonBody BlueFavoriteAction favoriteAction) {
if(favoriteAction == null) {
throw new ServiceException.BadRequestExpception("Must provide pipeline name");
}
FavoriteUtil.favoriteJob(folder.getFullName(), favoriteAction.isFavorite());
Link link = FavoriteUtil.favoriteJob(folder.getFullName(), favoriteAction.isFavorite());
return new FavoriteImpl(this, link);
}
@Override

View File

@ -9,6 +9,7 @@ import io.jenkins.blueocean.rest.Navigable;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueActionProxy;
import io.jenkins.blueocean.rest.model.BlueFavorite;
import io.jenkins.blueocean.rest.model.BlueFavoriteAction;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BlueQueueContainer;
@ -103,12 +104,13 @@ public class PipelineImpl extends BluePipeline {
@Override
public void favorite(@JsonBody BlueFavoriteAction favoriteAction) {
public BlueFavorite favorite(@JsonBody BlueFavoriteAction favoriteAction) {
if(favoriteAction == null) {
throw new ServiceException.BadRequestExpception("Must provide pipeline name");
}
FavoriteUtil.favoriteJob(job.getFullName(), favoriteAction.isFavorite());
Link link = FavoriteUtil.favoriteJob(job.getFullName(), favoriteAction.isFavorite());
return new FavoriteImpl(this, link);
}
@Override

View File

@ -1,5 +1,6 @@
package io.jenkins.blueocean.service.embedded.util;
import hudson.Util;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Job;
@ -7,21 +8,23 @@ import hudson.model.User;
import hudson.plugins.favorite.FavoritePlugin;
import hudson.plugins.favorite.user.FavoriteUserProperty;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.service.embedded.rest.UserImpl;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
import org.kohsuke.stapler.Stapler;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
/**
* @author Ivan Meredith
*/
public class FavoriteUtil {
public static void favoriteJob(String fullName, boolean favorite) {
public static Link favoriteJob(String fullName, boolean favorite) {
User user = User.current();
if(user == null) {
throw new ServiceException.ForbiddenException("Must be logged in to use set favotites");
throw new ServiceException.ForbiddenException("Must be logged in to use set favorites");
}
boolean set = false;
FavoriteUserProperty fup = user.getProperty(FavoriteUserProperty.class);
@ -31,7 +34,7 @@ public class FavoriteUtil {
//TODO: FavoritePlugin is null
FavoritePlugin plugin = Jenkins.getInstance().getPlugin(FavoritePlugin.class);
if(plugin == null) {
throw new ServiceException.UnexpectedErrorException("Can not find instance of favorites plugin");
throw new ServiceException.UnexpectedErrorException("Can not find instance of Favorite Plugin");
}
if(favorite != set) {
try {
@ -40,25 +43,23 @@ public class FavoriteUtil {
throw new ServiceException.UnexpectedErrorException("Something went wrong setting the favorite", e);
}
}
}
public static String generateBlueUrl(String org, Item i) {
String url = "/organizations/" + org + "/pipelines/";
if(i instanceof WorkflowJob) {
WorkflowJob job = (WorkflowJob)i;
ItemGroup it = job.getParent();
if(it instanceof WorkflowMultiBranchProject) {
url += ((WorkflowMultiBranchProject) it).getName() + "/branches/" + job.getName();
} else {
url += job.getName();
}
} else {
url += i.getName();
}
return url;
return new UserImpl(user).getLink().rel("favorites/"+ Util.rawEncode(FavoriteUtil.encodeFullName(fullName)));
}
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");
} catch (UnsupportedEncodingException e) {
throw new ServiceException.UnexpectedErrorException("Something went wrong URL decoding fullName: "+name, e);
}
}
}

View File

@ -428,11 +428,13 @@ public class MultiBranchTest extends BaseTest{
WorkflowJob p = scheduleAndFindBranchProject(mp, "master");
j.waitUntilNoActivity();
new RequestBuilder(baseUrl)
Map m = new RequestBuilder(baseUrl)
.put("/organizations/jenkins/pipelines/p/favorite")
.auth("alice", "alice")
.data(ImmutableMap.of("favorite", true))
.build(String.class);
.build(Map.class);
validatePipeline(p, (Map) m.get("item"));
List l = new RequestBuilder(baseUrl)
.get("/users/"+user.getId()+"/favorites/")
@ -467,11 +469,16 @@ public class MultiBranchTest extends BaseTest{
WorkflowJob p = scheduleAndFindBranchProject(mp, "master");
j.waitUntilNoActivity();
new RequestBuilder(baseUrl)
WorkflowJob p1 = scheduleAndFindBranchProject(mp, "feature2");
Map map = new RequestBuilder(baseUrl)
.put("/organizations/jenkins/pipelines/p/branches/feature2/favorite")
.auth("alice", "alice")
.data(ImmutableMap.of("favorite", true))
.build(String.class);
.build(Map.class);
validatePipeline(p1, (Map) map.get("item"));
List l = new RequestBuilder(baseUrl)
.get("/users/"+user.getId()+"/favorites/")
@ -480,7 +487,6 @@ public class MultiBranchTest extends BaseTest{
Assert.assertEquals(l.size(), 1);
WorkflowJob p1 = scheduleAndFindBranchProject(mp, "feature2");
Map branch = (Map)((Map)l.get(0)).get("item");
validatePipeline(p1, branch);

View File

@ -92,12 +92,13 @@ public class ProfileApiTest extends BaseTest{
user.setFullName("Alice Cooper");
Project p = j.createFreeStyleProject("pipeline1");
new RequestBuilder(baseUrl)
Map map = new RequestBuilder(baseUrl)
.put("/organizations/jenkins/pipelines/pipeline1/favorite")
.auth("alice", "alice")
.data(ImmutableMap.of("favorite", true))
.build(String.class);
.build(Map.class);
validatePipeline(p, (Map) map.get("item"));
List l = new RequestBuilder(baseUrl)
.get("/users/"+user.getId()+"/favorites/")
.auth("alice","alice")

View File

@ -1119,19 +1119,68 @@ This will show up as a download in the browser.
Unit testing...
## Favorite API
Favorite API can be used to favorite a pipeline (Multi-branch, branch, pipeline or even folder) for a logged in user.
If favorite request is successful then the repsonse is favorited item.
curl -u alice:xxx -H"Content-Type:application/json" -XPUT -d '{"favorite":true} ttp://localhost:56748/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/favorite
{
"_class" : "io.jenkins.blueocean.service.embedded.rest.FavoriteImpl",
"_links" : {
"self" : {
"_class" : "io.jenkins.blueocean.rest.hal.Link",
"href" : "/blue/rest/users/alice/favorites/pipeline1/"
}
},
"item" : {
"displayName" : "pipeline1",
"_links" : {
"runs" : {
"href" : "/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/",
"_class" : "io.jenkins.blueocean.rest.hal.Link"
},
"self" : {
"href" : "/blue/rest/organizations/jenkins/pipelines/pipeline1/",
"_class" : "io.jenkins.blueocean.rest.hal.Link"
},
"queue" : {
"href" : "/blue/rest/organizations/jenkins/pipelines/pipeline1/queue/",
"_class" : "io.jenkins.blueocean.rest.hal.Link"
},
"actions" : {
"_class" : "io.jenkins.blueocean.rest.hal.Link",
"href" : "/blue/rest/organizations/jenkins/pipelines/pipeline1/actions/"
}
},
"organization" : "jenkins",
"latestRun" : null,
"name" : "pipeline1",
"actions" : [],
"weatherScore" : 100,
"_class" : "io.jenkins.blueocean.service.embedded.rest.PipelineImpl",
"fullName" : "pipeline1",
"lastSuccessfulRun" : null,
"estimatedDurationInMillis" : -1
}
}
## 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
## Favorite a multibranch pipeline
## Favorite a multi branch pipeline
Must be authenticated.
This favorites the master branch. Returns 200 on success. 500 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
## Favorite a multibranch pipeline branch
## 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

View File

@ -1,5 +1,6 @@
package io.jenkins.blueocean.rest.model;
import io.jenkins.blueocean.commons.stapler.TreeResponse;
import io.jenkins.blueocean.rest.Navigable;
import io.jenkins.blueocean.rest.annotation.Capability;
import org.kohsuke.stapler.WebMethod;
@ -96,5 +97,6 @@ public abstract class BluePipeline extends Resource {
@PUT
@WebMethod(name="favorite")
public abstract void favorite(@JsonBody BlueFavoriteAction favoriteAction);
@TreeResponse
public abstract BlueFavorite favorite(@JsonBody BlueFavoriteAction favoriteAction);
}