Merge remote-tracking branch 'origin/master' into feature/JENKINS-36211
This commit is contained in:
commit
2b71744a94
|
@ -1,11 +1,12 @@
|
|||
node {
|
||||
deleteDir()
|
||||
checkout scm
|
||||
|
||||
|
||||
docker.image('cloudbees/java-build-tools').inside {
|
||||
withEnv(['GIT_COMMITTER_EMAIL=me@hatescake.com','GIT_COMMITTER_NAME=Hates','GIT_AUTHOR_NAME=Cake','GIT_AUTHOR_EMAIL=hates@cake.com']) {
|
||||
try {
|
||||
sh "mvn clean install -B -DcleanNode -Dmaven.test.failure.ignore"
|
||||
sh "node checkdeps.js"
|
||||
step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
|
||||
step([$class: 'ArtifactArchiver', artifacts: '*/target/*.hpi'])
|
||||
} catch(err) {
|
||||
|
@ -36,4 +37,3 @@ def sendhipchat() {
|
|||
hipchatSend message: message, color: color
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
connect,
|
||||
} from '../redux';
|
||||
|
||||
const { object, array, func, string, boolean } = PropTypes;
|
||||
const { object, array, func, string, bool } = PropTypes;
|
||||
|
||||
const EmptyState = ({ repoName, pipeline, showRunButton }) => (
|
||||
<main>
|
||||
|
@ -35,7 +35,7 @@ const EmptyState = ({ repoName, pipeline, showRunButton }) => (
|
|||
EmptyState.propTypes = {
|
||||
repoName: string,
|
||||
pipeline: object,
|
||||
showRunButton: boolean,
|
||||
showRunButton: bool,
|
||||
};
|
||||
|
||||
const RunNonMultiBranchPipeline = ({ pipeline, buttonText }) => (
|
||||
|
|
|
@ -24,41 +24,40 @@
|
|||
<artifactId>mailer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- Deadlock bug fix in WorkflowRun.doStop(). See https://github.com/jenkinsci/workflow-job-plugin/pull/2 -->
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-job</artifactId>
|
||||
<version>2.2-beta-1</version>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-cps</artifactId>
|
||||
<version>2.1</version>
|
||||
<version>2.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-api</artifactId>
|
||||
<version>2.0</version>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-step-api</artifactId>
|
||||
<version>2.0</version>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-support</artifactId>
|
||||
<version>2.0</version>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-multibranch</artifactId>
|
||||
<version>2.0</version>
|
||||
<version>2.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.jenkins.blueocean.service.embedded.rest;
|
|||
|
||||
import hudson.model.Action;
|
||||
import hudson.model.FreeStyleBuild;
|
||||
import hudson.model.Queue;
|
||||
import hudson.model.Run;
|
||||
import hudson.plugins.git.util.BuildData;
|
||||
import io.jenkins.blueocean.commons.ServiceException;
|
||||
|
@ -9,10 +10,12 @@ import io.jenkins.blueocean.rest.hal.Link;
|
|||
import io.jenkins.blueocean.rest.model.BlueActionProxy;
|
||||
import io.jenkins.blueocean.rest.model.BluePipelineNodeContainer;
|
||||
import io.jenkins.blueocean.rest.model.BluePipelineStepContainer;
|
||||
import io.jenkins.blueocean.rest.model.BlueQueueItem;
|
||||
import io.jenkins.blueocean.rest.model.BlueRun;
|
||||
import io.jenkins.blueocean.rest.model.Container;
|
||||
import io.jenkins.blueocean.rest.model.Containers;
|
||||
import io.jenkins.blueocean.rest.model.GenericResource;
|
||||
import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction;
|
||||
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
|
||||
import org.kohsuke.stapler.Stapler;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
|
@ -128,6 +131,24 @@ public class AbstractRunImpl<T extends Run> extends BlueRun {
|
|||
return new LogResource(run.getLogText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueQueueItem replay() {
|
||||
ReplayAction replayAction = run.getAction(ReplayAction.class);
|
||||
if(replayAction == null) {
|
||||
throw new ServiceException.BadRequestExpception("This run does not support replay");
|
||||
}
|
||||
|
||||
Queue.Item item = replayAction.run2(replayAction.getOriginalScript(), replayAction.getOriginalLoadedScripts());
|
||||
|
||||
BlueQueueItem queueItem = QueueContainerImpl.getQueuedItem(item, run.getParent());
|
||||
|
||||
if(queueItem == null) {
|
||||
throw new ServiceException.UnexpectedErrorException("Run was not added to queue.");
|
||||
} else {
|
||||
return queueItem;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Container<BlueArtifact> getArtifacts() {
|
||||
Map<String, BlueArtifact> m = new HashMap<String, BlueArtifact>();
|
||||
|
|
|
@ -77,4 +77,23 @@ public abstract class BluePipelineFactory implements ExtensionPoint {
|
|||
}
|
||||
return i == null ? target : i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives {@link BluePipeline} instance from the first pipeline found.
|
||||
*
|
||||
* @param item {@link Item} for which corresponding BlueOcean API object needs to be found
|
||||
* @param parent Parent {@link Reachable} object
|
||||
* @return {@link BluePipeline} if a map of item to BlueOcean API found, null otherwise.
|
||||
*
|
||||
*/
|
||||
public static BluePipeline getPipelineInstance(Item item, final Reachable parent){
|
||||
for(BluePipelineFactory factory:BluePipelineFactory.all()){
|
||||
BluePipeline pipeline = factory.getPipeline(item, parent);
|
||||
|
||||
if(pipeline != null){
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package io.jenkins.blueocean.service.embedded.rest;
|
||||
|
||||
import hudson.Util;
|
||||
import hudson.model.Item;
|
||||
import hudson.model.Job;
|
||||
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.branch.MultiBranchProject;
|
||||
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
|
||||
import jenkins.model.Jenkins;
|
||||
import io.jenkins.blueocean.service.embedded.util.FavoriteUtil;
|
||||
|
||||
/**
|
||||
* @author Vivek Pandey
|
||||
|
@ -17,26 +16,24 @@ public class FavoriteImpl extends BlueFavorite {
|
|||
private final Object item;
|
||||
private final Link self;
|
||||
|
||||
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.self = parent.getLink().rel(FavoriteUtil.encodeFullName(item.getFullName()));
|
||||
LinkResolver linkResolver = Jenkins.getInstance().getInjector().getInstance(LinkResolver.class);
|
||||
|
||||
final Link link = linkResolver.resolve(item);
|
||||
|
||||
this.item = BluePipelineFactory.getPipelineInstance(item, new Reachable() {
|
||||
@Override
|
||||
public Link getLink() {
|
||||
return link.ancestor();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: MBP nested inside folder won't work nor would a favorited folder is going to work
|
||||
//TODO: Needs https://issues.jenkins-ci.org/browse/JENKINS-36286 to be fixed,
|
||||
// it should use LinkResolver for it to work in all cases
|
||||
Object obj = null;
|
||||
if(item instanceof WorkflowJob){
|
||||
if(item.getParent() instanceof MultiBranchProject){
|
||||
Link s = OrganizationImpl.INSTANCE.getLink().rel(String.format("pipelines/%s/branches/",
|
||||
((MultiBranchProject) item.getParent()).getName()));
|
||||
obj = new BranchImpl((Job) item, s);
|
||||
}
|
||||
}
|
||||
if(obj == null){
|
||||
this.item = new PipelineImpl((Job) item);
|
||||
}else{
|
||||
this.item = obj;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -39,14 +39,12 @@ public class MultiBranchPipelineQueueContainer extends BlueQueueContainer {
|
|||
|
||||
if(item.task instanceof ExecutorStepExecution.PlaceholderTask) {
|
||||
ExecutorStepExecution.PlaceholderTask task = (ExecutorStepExecution.PlaceholderTask) item.task;
|
||||
int runNumber;
|
||||
if(task.run() == null){
|
||||
runNumber = pipeline.job.getNextBuildNumber();
|
||||
return QueueContainerImpl.getQueuedItem(item, pipeline.job);
|
||||
}else{
|
||||
runNumber = task.run().getNumber();
|
||||
return new QueueItemImpl(item, item.task.getOwnerTask().getName(), task.run().getNumber(),
|
||||
self.rel(String.valueOf(item.getId())));
|
||||
}
|
||||
return new QueueItemImpl(item, item.task.getOwnerTask().getName(), runNumber,
|
||||
self.rel(String.valueOf(item.getId())));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.jenkins.blueocean.service.embedded.rest;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
import hudson.model.BuildableItem;
|
||||
import hudson.model.Job;
|
||||
|
@ -10,7 +11,9 @@ import io.jenkins.blueocean.rest.model.BluePipeline;
|
|||
import io.jenkins.blueocean.rest.model.BlueQueueContainer;
|
||||
import io.jenkins.blueocean.rest.model.BlueQueueItem;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.jenkinsci.plugins.github.util.FluentIterableWrapper;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -28,7 +31,7 @@ public class QueueContainerImpl extends BlueQueueContainer {
|
|||
|
||||
@Override
|
||||
public BlueQueueItem get(String name) {
|
||||
for (BlueQueueItem blueQueueItem : getQueuedItems(job, pipeline)) {
|
||||
for (BlueQueueItem blueQueueItem : getQueuedItems(job)) {
|
||||
if(name.equals(blueQueueItem.getId())){
|
||||
return blueQueueItem;
|
||||
}
|
||||
|
@ -39,7 +42,7 @@ public class QueueContainerImpl extends BlueQueueContainer {
|
|||
|
||||
@Override
|
||||
public Iterator<BlueQueueItem> iterator() {
|
||||
return getQueuedItems(job, pipeline).iterator();
|
||||
return getQueuedItems(job).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,7 +53,9 @@ public class QueueContainerImpl extends BlueQueueContainer {
|
|||
*
|
||||
* @return List of items newest first
|
||||
*/
|
||||
public static List<BlueQueueItem> getQueuedItems(Job job, BluePipeline pipeline) {
|
||||
public static List<BlueQueueItem> getQueuedItems(Job job) {
|
||||
BluePipeline pipeline = new PipelineImpl(job);
|
||||
|
||||
if(job instanceof BuildableItem) {
|
||||
BuildableItem task = (BuildableItem)job;
|
||||
List<Queue.Item> items = Jenkins.getInstance().getQueue().getItems(task);
|
||||
|
@ -68,6 +73,15 @@ public class QueueContainerImpl extends BlueQueueContainer {
|
|||
}
|
||||
}
|
||||
|
||||
public static BlueQueueItem getQueuedItem(final Queue.Item item, Job job) {
|
||||
return FluentIterableWrapper.from(QueueContainerImpl.getQueuedItems(job))
|
||||
.firstMatch(new Predicate<BlueQueueItem>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable BlueQueueItem input) {
|
||||
return input.getId().equalsIgnoreCase(Long.toString(item.getId()));
|
||||
}
|
||||
}).orNull();
|
||||
}
|
||||
@Override
|
||||
public Link getLink() {
|
||||
return pipeline.getLink().rel("queue");
|
||||
|
|
|
@ -88,13 +88,7 @@ public class RunContainerImpl extends BlueRunContainer {
|
|||
if(scheduleResult.isAccepted()) {
|
||||
final Queue.Item item = scheduleResult.getItem();
|
||||
|
||||
BlueQueueItem queueItem = FluentIterableWrapper.from(QueueContainerImpl.getQueuedItems(job, pipeline))
|
||||
.firstMatch(new Predicate<BlueQueueItem>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable BlueQueueItem input) {
|
||||
return input.getId().equalsIgnoreCase(Long.toString(item.getId()));
|
||||
}
|
||||
}).orNull();
|
||||
BlueQueueItem queueItem = QueueContainerImpl.getQueuedItem(item, job);
|
||||
|
||||
if (queueItem == null) {
|
||||
throw new ServiceException.UnexpectedErrorException("The queue item does not exist in the queue");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
package io.jenkins.blueocean.service.embedded;
|
||||
|
||||
import hudson.model.Label;
|
||||
import hudson.model.Queue;
|
||||
import io.jenkins.blueocean.service.embedded.rest.PipelineImpl;
|
||||
import io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl;
|
||||
import io.jenkins.blueocean.service.embedded.scm.GitSampleRepoRule;
|
||||
import jenkins.branch.BranchProperty;
|
||||
import jenkins.branch.BranchSource;
|
||||
import jenkins.branch.DefaultBranchPropertyStrategy;
|
||||
import jenkins.plugins.git.GitSCMSource;
|
||||
import jenkins.scm.api.SCMSource;
|
||||
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
|
||||
import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction;
|
||||
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
|
||||
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
|
||||
import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Ivan Meredith
|
||||
*/
|
||||
public class AbstractRunImplTest extends BaseTest {
|
||||
@Rule
|
||||
public GitSampleRepoRule sampleRepo = new GitSampleRepoRule();
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception{
|
||||
super.setup();
|
||||
sampleRepo.init();
|
||||
}
|
||||
//Disabled, see JENKINS-36453
|
||||
//@Test
|
||||
public void replayRunTest() throws Exception {
|
||||
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
|
||||
j.createOnlineSlave(Label.get("remote"));
|
||||
job1.setDefinition(new CpsFlowDefinition(
|
||||
"node('remote') {\n" +
|
||||
" ws {\n" +
|
||||
" git($/" + sampleRepo + "/$)\n" +
|
||||
" }\n" +
|
||||
"}"));
|
||||
|
||||
|
||||
WorkflowRun b1 = job1.scheduleBuild2(0).get();
|
||||
j.assertBuildStatusSuccess(b1);
|
||||
|
||||
sampleRepo.write("file1", "");
|
||||
sampleRepo.git("add", "file1");
|
||||
sampleRepo.git("commit", "--message=init");
|
||||
|
||||
WorkflowRun b2 = job1.scheduleBuild2(0).get();
|
||||
j.assertBuildStatusSuccess(b2);
|
||||
|
||||
Assert.assertNotEquals(new PipelineRunImpl(b1, null).getCommitId(), new PipelineRunImpl(b2, null).getCommitId());
|
||||
|
||||
request().post("/organizations/jenkins/pipelines/pipeline1/runs/1/replay").build(String.class);
|
||||
|
||||
j.waitForCompletion(job1.getLastBuild());
|
||||
|
||||
Map r = request().get("/organizations/jenkins/pipelines/pipeline1/runs/3/").build(Map.class);
|
||||
Assert.assertEquals(r.get("commitId"), new PipelineRunImpl(b2,null).getCommitId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replayRunTestMB() throws Exception {
|
||||
j.createOnlineSlave(Label.get("remote"));
|
||||
|
||||
sampleRepo.write("Jenkinsfile", "node('remote') {\n" +
|
||||
" ws {\n" +
|
||||
" checkout scm\n" +
|
||||
" stage 'build'\n "+"node {echo 'Building'}\n"+
|
||||
" stage 'test'\nnode { echo 'Testing'}\n"+
|
||||
" stage 'deploy'\nnode { echo 'Deploying'}\n" +
|
||||
" }\n" +
|
||||
" }");
|
||||
sampleRepo.git("add", "Jenkinsfile");
|
||||
sampleRepo.git("commit", "--message=init");
|
||||
|
||||
WorkflowMultiBranchProject mp = j.jenkins.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();
|
||||
WorkflowJob job1 = mp.getItem("master");
|
||||
WorkflowRun b1 = job1.scheduleBuild2(0).waitForStart();
|
||||
j.waitForCompletion(b1);
|
||||
j.assertBuildStatusSuccess(b1);
|
||||
|
||||
sampleRepo.write("file1", "");
|
||||
sampleRepo.git("add", "file1");
|
||||
sampleRepo.git("commit", "--message=init");
|
||||
|
||||
WorkflowRun b2 = job1.scheduleBuild2(0).get();
|
||||
j.assertBuildStatusSuccess(b2);
|
||||
|
||||
Assert.assertNotEquals(new PipelineRunImpl(b1, null).getCommitId(), new PipelineRunImpl(b2, null).getCommitId());
|
||||
|
||||
Map replayBuild = request().post("/organizations/jenkins/pipelines/p/branches/master/runs/"+ b1.getNumber()+"/replay").build(Map.class);
|
||||
Queue.Item item = j.getInstance().getQueue().getItem(Long.parseLong((String)replayBuild.get("id")));
|
||||
|
||||
WorkflowRun replayedRun = (WorkflowRun)item.getFuture().get();
|
||||
|
||||
Map r = request().get("/organizations/jenkins/pipelines/p/branches/master/runs/"+replayedRun.getNumber()+"/").build(Map.class);
|
||||
Assert.assertEquals(new PipelineRunImpl(b1,null).getCommitId(), r.get("commitId"));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -2,7 +2,6 @@ package io.jenkins.blueocean.service.embedded;
|
|||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import hudson.model.Project;
|
||||
import hudson.model.User;
|
||||
import hudson.tasks.Mailer;
|
||||
|
@ -93,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")
|
||||
|
|
|
@ -349,6 +349,24 @@ Pipelines can be nested inside folder.
|
|||
"qeueudTime" : "2016-06-22T11:05:41.309+1200"
|
||||
}
|
||||
|
||||
## Replay a pipeline run
|
||||
|
||||
This will quueue up a replay of the pipeline run with the same commit id as the run used
|
||||
|
||||
curl -XPOST http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline3/runs/1/replay
|
||||
{
|
||||
"_class" : "io.jenkins.blueocean.service.embedded.rest.QueueItemImpl",
|
||||
"id" : "64",
|
||||
"expectedBuildNumber" : 10,
|
||||
"pipeline" : "bug%2FUX-334",
|
||||
"_links" : {
|
||||
"self" : {
|
||||
"_class" : "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href" : "/blue/rest/organizations/jenkins/pipelines/bo2/queue/64/"
|
||||
}
|
||||
},
|
||||
"queuedTime" : "2016-06-29T14:11:52.191-0700"
|
||||
}
|
||||
## Get all runs in a pipeline
|
||||
|
||||
curl -v -X GET http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/runs
|
||||
|
@ -1101,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
|
||||
|
|
|
@ -15,6 +15,7 @@ public final class Link {
|
|||
|
||||
public Link(String href) {
|
||||
this.href = Links.ensureTrailingSlash(href);
|
||||
assert this.href.endsWith("/");
|
||||
}
|
||||
|
||||
@Exported(name = "href")
|
||||
|
@ -28,4 +29,27 @@ public final class Link {
|
|||
public Link rel(String name) {
|
||||
return new Link(href+name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gives ancestor Link, for example, for link("/a/b/c/d"), ancestor is "a/b/c/".
|
||||
*/
|
||||
public Link ancestor(){
|
||||
int i = href.lastIndexOf("/");
|
||||
|
||||
if(i>0) {
|
||||
int j = href.substring(0, i).lastIndexOf("/");
|
||||
|
||||
if (j > 0) {
|
||||
return new Link(href.substring(0, j));
|
||||
}
|
||||
}
|
||||
|
||||
return new Link("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return href;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.kohsuke.stapler.WebMethod;
|
|||
import org.kohsuke.stapler.export.Exported;
|
||||
import org.kohsuke.stapler.export.ExportedBean;
|
||||
import org.kohsuke.stapler.json.JsonResponse;
|
||||
import org.kohsuke.stapler.verb.POST;
|
||||
import org.kohsuke.stapler.verb.PUT;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -193,6 +194,14 @@ public abstract class BlueRun extends Resource {
|
|||
@Navigable
|
||||
public abstract Object getLog();
|
||||
|
||||
/**
|
||||
* Replays a pipeline. The SCM commit/revision used in the existing and new runs should match.
|
||||
*
|
||||
* @return The queued item.
|
||||
*/
|
||||
@POST @TreeResponse @WebMethod(name = "replay")
|
||||
public abstract BlueQueueItem replay();
|
||||
|
||||
public enum BlueRunState {
|
||||
QUEUED,
|
||||
RUNNING,
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
"keymirror": "0.1.1",
|
||||
"moment": "2.13.0",
|
||||
"react": "15.1.0",
|
||||
"react-addons-css-transition-group": "15.0.1",
|
||||
"react-addons-css-transition-group": "15.1.0",
|
||||
"react-dom": "15.1.0",
|
||||
"react-redux": "4.4.5",
|
||||
"react-router": "2.3.0",
|
||||
|
|
19
checkdeps.js
19
checkdeps.js
|
@ -3,14 +3,16 @@
|
|||
/*********************************************************************************************
|
||||
**********************************************************************************************
|
||||
|
||||
Checks for version inconsistencies in top-level project dependencies.
|
||||
Checks for version inconsistencies in PROD dependencies for top-level
|
||||
projects, and a few first-party "blessed" deps like JDL etc.
|
||||
|
||||
Usage:
|
||||
|
||||
node checkdeps.js
|
||||
|
||||
If conflicting versions are detected, this will print them out as JSON on STDERR and
|
||||
exit(1). If no conflicts are detected, there is no output and normal exit
|
||||
Any conflicting PROD dependencies will be printed on STDERR, and it will exit(1)
|
||||
|
||||
If no conflicts, or only PEER/DEV conflicts, normal exit(0)
|
||||
|
||||
**********************************************************************************************
|
||||
*********************************************************************************************/
|
||||
|
@ -40,11 +42,16 @@ var packageFiles = [];
|
|||
packageFiles.push(require("./blueocean-dashboard/package.json"));
|
||||
packageFiles.push(require("./blueocean-web/package.json"));
|
||||
|
||||
// Add some expected dependencies, so we go another level deep just for these
|
||||
packageFiles.push(require("./blueocean-dashboard/node_modules/@jenkins-cd/design-language/package.json"));
|
||||
packageFiles.push(require("./blueocean-dashboard/node_modules/@jenkins-cd/sse-gateway/package.json"));
|
||||
packageFiles.push(require("./blueocean-dashboard/node_modules/@jenkins-cd/js-extensions/package.json"));
|
||||
|
||||
packageFiles.forEach(packageFile => {
|
||||
|
||||
addDependencies("prod", packageFile.dependencies);
|
||||
addDependencies("dev", packageFile.devDependencies);
|
||||
addDependencies("peer", packageFile.peerDependencies);
|
||||
// addDependencies("dev", packageFile.devDependencies);
|
||||
// addDependencies("peer", packageFile.peerDependencies);
|
||||
|
||||
function addDependencies(kind, deps) {
|
||||
if (deps) {
|
||||
|
@ -73,5 +80,5 @@ Object.keys(allDependencies).forEach(dependency => {
|
|||
|
||||
if (errs.length) {
|
||||
console.error(JSON.stringify(errs, null, 4));
|
||||
process.exit(1);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue