How to extend Jenkins job page with new links and icons

后端 未结 5 1047
难免孤独
难免孤独 2021-02-14 13:29

I\'m developing my first Jenkins plugin and followed the tutorial at wiki.jenkins-ci.org. After adding a BuildStep and generating the results I now want to publish them to the u

相关标签:
5条回答
  • 2021-02-14 13:39

    As it happens, there was a plugin workshop by Steven Christou at the recent Jenkins User Conference in Boston, which covered this case. You need to add a new RootAction, as shown in the following code from the JUC session

    package org.jenkinsci.plugins.JUCBeer;
    
    import hudson.Extension;
    import hudson.model.RootAction;
    
    @Extension
    public class JenkinsRootAction implements RootAction {
        public String getIconFileName() {
            return "/images/jenkins.png";
        }
    
        public String getDisplayName() {
            return "Jenkins home page";
        }
    
        public String getUrlName() {
            return "http://jenkins-ci.org";
        }
    }
    
    0 讨论(0)
  • 2021-02-14 13:47

    After a lot of trial and error I figured out the solution.

    All in all you need two different things in your project:

    1) A class that inherits from ProminentProjectAction:

    import hudson.model.ProminentProjectAction;
    
    public class MyProjectAction implements ProminentProjectAction {
    
        @Override
        public String getIconFileName() {
            // return the path to the icon file
            return "/images/jenkins.png";
        }
    
        @Override
        public String getDisplayName() {
            // return the label for your link
            return "MyActionLink";
        }
    
        @Override
        public String getUrlName() {
            // defines the suburl, which is appended to ...jenkins/job/jobname
            return "myactionpage";
        }
    }
    

    2) Even more important is that you add this action somehow to your project.

    In my case I wanted to show the link if and only if the related build step of my plugin is configured for the actual project. So I took my Builder class and overwrote the getProjectActionsMethod.

    public class MyBuilder extends Builder {
    
        ...
    
        @Override
        public Collection<? extends Action> getProjectActions(AbstractProject<?,?> project) {
            List<Action> actions = new ArrayList<>();
            actions.add(new MyProjectAction());
    
            return actions;
        }
    }
    

    Maybe this is not the perfect solution yet (because I'm still trying to figure out how all the artifacts are working together), but it might give people which want to implement the same a good starting point.

    The page, which is loaded after clicking the link is defined as index.jelly file under source/main/resources and an underlying package with the name of the package of your Action class appended by its class name (e.g. src/main/resources/org/example/myplugin/MyProjectAction).

    0 讨论(0)
  • 2021-02-14 13:57

    An addition to @dchang comment:

    I managed to make this functionality work also on pipelines by extending TransientActionFactory<WorkflowJob>:

    @Extension
    public static class PipelineLatestConsoleProjectActionFactory extends TransientActionFactory<WorkflowJob> {
    
        @Override
        public Class<WorkflowJob> type() {
            return WorkflowJob.class;
        }
    
        @Nonnull
        @Override
        public Collection<? extends Action> createFor(@Nonnull WorkflowJob job) {
            return Collections.singletonList(new LatestConsoleProjectAction(job));
        }
    }
    
    0 讨论(0)
  • 2021-02-14 14:02

    Root Action and Actions are different. The first one goes only to initial page (root), the second one can be attach to a Project/Job or to a Build.

    To create a Root Action, just need to create a class that it's:

    1. Annotated with @Extension (so it can be found and automatically loaded by Jenkins)
    2. Implements RootAction Interface
    3. Override 3 methods: getIconFileName(), getDisplayName() and getUrlName()

    For example:

    @Extension
    public class GoogleRootAction implements RootAction{
    
        @Override
        public String getIconFileName() {
            return "clipboard.png";
        }
    
        @Override
        public String getDisplayName() {
            return "Google URL";
        }
    
        @Override
        public String getUrlName() {
            return "http://www.google.pt";
        }    
    }
    

    To create an Action at a Project it's more complicated, and there's more than a way, depending of what you want.

    But first, the class Action itself is the easy part, since it's very similar to a class RootAction. It's not annotated with @Extension and implements Action interface instead of RootAction.

    For example:

    public class LatestConsoleProjectAction implements Action {
    
        private AbstractProject<?, ?> project;
    
        @Override
        public String getIconFileName() {
            return (Jenkins.RESOURCE_PATH + "/images/48x48/terminal.png").replaceFirst("^/", "");
        }
    
        @Override
        public String getDisplayName() {
            return Messages.Latest_Console_Project_Action();
        }
    
        @Override
        public String getUrlName() {
            return "lastBuild/console";
        }
    
        public LatestConsoleProjectAction(final AbstractProject<?, ?> project) {
            this.project = project;
        }
    
    }
    

    The tricky part is to inform jenkins that this class Action exists. As I said, there are different ways.

    For instance, one can associate an Action to a Builder or Publisher or other by just overriding getProjectAction() method at those classes.

    For example:

    @Override
    public Action getProjectAction(AbstractProject<?, ?> project) {
        return new LatestConsoleProjectAction(project);
    }
    

    But this way, the Action link will only show on Project left menu, if the corresponding Builder or Publisher is used by the job (or selected at Job configurations).

    Another way, that always shows your Action link on left menu, it's create a factory class to inform jenkins. There are many factories, but at my example I will use TransientProjectActionFactory class.

    For this, one will need to create a class that:

    1. It's annotated with @Extensions
    2. Extends TransientProjectActionFactory class (or another Factory class)
    3. Override createFor method to create your class Action associated with Project object

    For example:

    @Extension
    public class LatestConsoleProjectActionFactory extends TransientProjectActionFactory {
    
        @Override
        public Collection<? extends Action> createFor(AbstractProject abstractProject) {
    
            return Collections.singletonList(new LatestConsoleProjectAction(abstractProject));
        }
    }
    

    One can still filter project object to just the projects types you want. The one you don't want, just return Collections.emptyList().

    Beside this two ways, I think there are others. You can see this link to reference: https://wiki.jenkins-ci.org/display/JENKINS/Action+and+its+family+of+subtypes

    Although, they refer to addAction method and others, but I couldn't use it (I have 2.19.2 Jenkins version). Also they refer groovy, but I didn't try it, since I want to stick with Java :)

    Btw, my example will create an action link to open console page of last build. Useful to avoid selecting last build and then select his console page.

    0 讨论(0)
  • 2021-02-14 14:03

    https://github.com/jenkinsci/s3explorer-plugin is my Jenkins plugin that adds an S3 Explorer link to all Jenkins project's side-panel.

    0 讨论(0)
提交回复
热议问题