Skip to content

Commit

Permalink
JENKINS-40207 - Uninstalling alternative display url providers should…
Browse files Browse the repository at this point in the history
… keep issued URLs the same (#4)
  • Loading branch information
James William Dumay committed Dec 9, 2016
1 parent 638719d commit ffadcca
Show file tree
Hide file tree
Showing 11 changed files with 486 additions and 109 deletions.
19 changes: 19 additions & 0 deletions pom.xml
Expand Up @@ -56,6 +56,7 @@
<url>https://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>

<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand All @@ -68,6 +69,24 @@
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
@@ -0,0 +1,60 @@
package org.jenkinsci.plugins.displayurlapi;

import hudson.Extension;
import hudson.Util;
import hudson.model.Job;
import hudson.model.Run;
import hudson.tasks.junit.TestResult;
import hudson.tasks.test.AbstractTestResultAction;
import hudson.tasks.test.TestObject;

/**
* Display URL Provider for the Classical Jenkins UI
*/
@Extension
public class ClassicDisplayURLProvider extends DisplayURLProvider {
@Override
public String getRunURL(Run<?, ?> run) {
return getRoot() + Util.encode(run.getUrl());
}

@Override
public String getChangesURL(Run<?, ?> run) {
return getJobURL(run.getParent()) + "changes";
}

@Override
public String getJobURL(Job<?, ?> job) {
return getRoot() + Util.encode(job.getUrl());
}

@Override
public String getTestUrl(hudson.tasks.test.TestResult result) {
String buildUrl = getRunURL(result.getRun());
AbstractTestResultAction action = result.getTestResultAction();

TestObject parent = result.getParent();
TestResult testResultRoot = null;
while(parent != null) {
if (parent instanceof TestResult) {
testResultRoot = (TestResult) parent;
break;
}
parent = parent.getParent();
}

String testUrl = action.getUrlName()
+ (testResultRoot != null ? testResultRoot.getUrl() : "")
+ result.getUrl();

String[] pathComponents = testUrl.split("/");
StringBuilder buf = new StringBuilder();
for (String c : pathComponents) {
buf.append(Util.rawEncode(c)).append('/');
}
// remove last /
buf.deleteCharAt(buf.length() - 1);

return buildUrl + buf.toString();
}
}
@@ -1,44 +1,32 @@
package org.jenkinsci.plugins.displayurlapi;

import com.google.common.collect.Iterables;
import hudson.ExtensionPoint;
import hudson.Util;
import hudson.model.Item;
import hudson.model.Job;
import hudson.model.Project;
import hudson.model.Run;
import hudson.tasks.junit.TestResult;
import hudson.tasks.test.AbstractTestResultAction;
import hudson.tasks.test.TestObject;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.displayurlapi.actions.AbstractDisplayAction;

/**
* Generates URLs for well known UI locations for use in notifications (e.g. mailer, HipChat, Slack, IRC, etc)
* Extensible to allow plugins to override common URLs (e.g. Blue Ocean or another future secondary UI)
*/
public abstract class DisplayURLProvider implements ExtensionPoint {

private static final ClassicDisplayURLProvider CLASSIC_DISPLAY_URL_PROVIDER = new ClassicDisplayURLProvider();

/**
* Returns the first {@link DisplayURLProvider} found
* @return DisplayURLProvider
*/
public static DisplayURLProvider get() {
Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
throw new IllegalStateException("Jenkins has not started");
}
return Iterables.getFirst(jenkins.getExtensionList(DisplayURLProvider.class), CLASSIC_DISPLAY_URL_PROVIDER);
return DisplayURLProviderImpl.INSTANCE;
}

public static Iterable<DisplayURLProvider> all() {
return getJenkins().getExtensionList(DisplayURLProvider.class);
}

/** Fully qualified URL for the Root display URL */
public String getRoot() {
Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
throw new IllegalStateException("Jenkins has not started");
}
String root = jenkins.getRootUrl();
String root = getJenkins().getRootUrl();
if (root == null) {
root = "http://unconfigured-jenkins-location/";
}
Expand All @@ -52,56 +40,44 @@ public String getRoot() {
public abstract String getChangesURL(Run<?, ?> run);

/** Fully qualified URL for a Jobs home */
public abstract String getJobURL(Job<?, ?> project);
public abstract String getJobURL(Job<?, ?> job);

/** Fully qualified URL to the test details page for a given test result */
public abstract String getTestUrl(hudson.tasks.test.TestResult result);

/** URL Factory for the Classical Jenkins UI */
static class ClassicDisplayURLProvider extends DisplayURLProvider {
static class DisplayURLProviderImpl extends ClassicDisplayURLProvider {

public static final DisplayURLProvider INSTANCE = new DisplayURLProviderImpl();

public static final String DISPLAY_POSTFIX = AbstractDisplayAction.URL_NAME + "/redirect";

@Override
public String getRunURL(Run<?, ?> run) {
return getRoot() + Util.encode(run.getUrl());
return super.getRunURL(run) + DISPLAY_POSTFIX;
}

@Override
public String getChangesURL(Run<?, ?> run) {
return getJobURL(run.getParent()) + "changes";
return super.getRunURL(run) + DISPLAY_POSTFIX + "?page=changes";
}

@Override
public String getJobURL(Job<?, ?> project) {
return getRoot() + Util.encode(project.getUrl());
public String getJobURL(Job<?, ?> job) {
return super.getJobURL(job) + DISPLAY_POSTFIX;
}

@Override
public String getTestUrl(hudson.tasks.test.TestResult result) {
String buildUrl = getRunURL(result.getRun());
AbstractTestResultAction action = result.getTestResultAction();

TestObject parent = result.getParent();
TestResult testResultRoot = null;
while(parent != null) {
if (parent instanceof TestResult) {
testResultRoot = (TestResult) parent;
break;
}
parent = parent.getParent();
}

String testUrl = action.getUrlName()
+ (testResultRoot != null ? testResultRoot.getUrl() : "")
+ result.getUrl();

String[] pathComponents = testUrl.split("/");
StringBuilder buf = new StringBuilder();
for (String c : pathComponents) {
buf.append(Util.rawEncode(c)).append('/');
}
// remove last /
buf.deleteCharAt(buf.length() - 1);

return buildUrl + buf.toString();
Run<?, ?> run = result.getRun();
return super.getRunURL(run) + DISPLAY_POSTFIX + "?page=test&id=" + Util.rawEncode(result.getId());
}
}

private static Jenkins getJenkins() {
Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
throw new IllegalStateException("Jenkins has not started");
}
return jenkins;
}
}
@@ -0,0 +1,47 @@
package org.jenkinsci.plugins.displayurlapi.actions;

import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import hudson.model.Action;
import org.jenkinsci.plugins.displayurlapi.ClassicDisplayURLProvider;
import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public abstract class AbstractDisplayAction implements Action {

public static final String URL_NAME = "display";

@Override
public String getIconFileName() {
return null;
}

@Override
public String getDisplayName() {
return null;
}

@Override
public String getUrlName() {
return URL_NAME;
}

public final Object doRedirect(StaplerRequest req, StaplerResponse rsp) throws IOException {
DisplayURLProvider provider = lookupProvider();
rsp.sendRedirect(HttpServletResponse.SC_MOVED_TEMPORARILY, getRedirectURL(provider));
return null;
}

protected abstract String getRedirectURL(DisplayURLProvider provider);

DisplayURLProvider lookupProvider() {
Iterable<DisplayURLProvider> all = DisplayURLProvider.all();
DisplayURLProvider defaultProvider = Iterables.find(all, Predicates.instanceOf(ClassicDisplayURLProvider.class));
Iterable<DisplayURLProvider> availableProviders = Iterables.filter(all, Predicates.not(Predicates.instanceOf(ClassicDisplayURLProvider.class)));
return Iterables.getFirst(availableProviders, defaultProvider);
}
}
@@ -0,0 +1,38 @@
package org.jenkinsci.plugins.displayurlapi.actions;

import com.google.common.collect.ImmutableList;
import hudson.Extension;
import hudson.model.Action;
import hudson.model.Job;
import jenkins.model.TransientActionFactory;
import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider;

import javax.annotation.Nonnull;
import java.util.Collection;

public class JobDisplayAction extends AbstractDisplayAction {

private final Job job;

JobDisplayAction(Job job) {
this.job = job;
}

protected String getRedirectURL(DisplayURLProvider provider) {
return provider.getJobURL(job);
}

@Extension
public static class TransientActionFactoryImpl extends TransientActionFactory {
@Override
public Class type() {
return Job.class;
}

@Nonnull
@Override
public Collection<? extends Action> createFor(@Nonnull Object target) {
return ImmutableList.of(new JobDisplayAction((Job) target));
}
}
}
@@ -0,0 +1,61 @@
package org.jenkinsci.plugins.displayurlapi.actions;

import com.google.common.collect.ImmutableList;
import hudson.Extension;
import hudson.model.Action;
import hudson.model.Run;
import hudson.tasks.test.AbstractTestResultAction;
import hudson.tasks.test.TestResult;
import jenkins.model.TransientActionFactory;
import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;

import javax.annotation.Nonnull;
import java.util.Collection;

public class RunDisplayAction extends AbstractDisplayAction {
private final Run run;

RunDisplayAction(Run run) {
this.run = run;
}

@Override
protected String getRedirectURL(DisplayURLProvider provider) {
StaplerRequest req = Stapler.getCurrentRequest();
String page = req.getParameter("page");
String url;
if ("changes".equals(page)) {
url = provider.getChangesURL(run);
} else if ("test".equals(page)) {
String id = req.getParameter("id");
if (id == null) {
throw new IllegalArgumentException("id parameter not specified");
}
AbstractTestResultAction action = run.getAction(AbstractTestResultAction.class);
if (action == null) {
throw new IllegalStateException("No AbstractTestResultAction on this run");
}
TestResult result = action.findCorrespondingResult(id);
url = provider.getTestUrl(result);
} else {
url = provider.getRunURL(run);
}
return url;
}

@Extension
public static class TransientActionFactoryImpl extends TransientActionFactory {
@Override
public Class type() {
return Run.class;
}

@Nonnull
@Override
public Collection<? extends Action> createFor(@Nonnull Object target) {
return ImmutableList.of(new RunDisplayAction((Run) target));
}
}
}

0 comments on commit ffadcca

Please sign in to comment.