Writing CLI commands

This site is the new docs site currently being tested. For the actual docs in use please go to https://www.jenkins.io/doc.

Plugins can contribute additional commands to Jenkins CLI.

This is useful for:

  • exposing administrative commands to admins, so that they can script some of the Jenkins babysitting work,

  • exposing data and operations to builds executing inside Jenkins, so that they can interact with Jenkins in a richer way.

Writing commands can be done in two ways.

Annotating a method with CLIMethod

If you are exposing behaviors of your model objects as CLI commands, the easiest way to achieve it is to put jenkinsdoc:CLIMethod[@CLIMethod] on a method of your model object. See jenkinsdoc:hudson.model.Queue#clear()[Queue.clear()] as an example. In addition to the command name as specified in the annotation, you also need to define "CLI.command-name.shortDescription" as a message resource, which captures one line human-readable explanation of the command (see jenkinsdoc:hudson.cli.CLICommand#getShortDescription()[CLICommand.getShortDescription()]).

public class AbstractItem {
    @CLIMethod(name="delete-job")
    public synchronized void delete() throws IOException, InterruptedException {
        performDelete();

        if (this instanceof TopLevelItem) {
            Jenkins.get().deleteJob((TopLevelItem)this);
        }
        Jenkins.get().rebuildDependencyGraph();
    }
    ...
}

Notice that the method is an instance method. So when the delete-job command is executed, which job is deleted? To resolve this, you also need to define a CLI resolver, which uses a portion of arguments and options to determine the instance object that receives a method call.

@CLIResolver
public static AbstractItem resolveForCLI(
        @Argument(required=true,metaVar="NAME",usage="Job name") String name) throws CmdLineException {
    AbstractItem item = Jenkins.get().getItemByFullName(name, AbstractItem.class);

    if (item==null)
        throw new CmdLineException(null,"No such job exists:"+name);
    return item;
}

Of all the resolver methods that are discovered, Jenkins picks the one that returns the best return type. It doesn’t matter where the resolver method is defined, or how it’s named.

Both resolver methods and CLI methods can have any number of args4j annotations, which causes the parameters and arguments to be injected upon a method invocation. All the other unannotated parameters receive null. Combined with the stapler method binding, this enables you to make your method invocable from both CLI and HTTP.

Extending CLICommand

You can also implement a CLI command as a subtype of jenkinsdoc:CLICommand[], and put jenkinsdoc:hudson.Extension[Extension]. You can use existing implementations in the core, such as jenkinsdoc:GroovyCommand[], as a starting point. CLICommand exposes a lower-level control of the CLI set up (such as a jenkinsdoc:component:remoting:hudson.remoting.Channel[Channel].)

This approach is suitable for the commands that require more serious terminal interaction and remote code execution.

See the jenkinsdoc:CLICommand[javadoc of CLICommand] for more details.