How to Easily Create CLIs Using OCLIF (and How We Did It for the Adobe I/O CLI)

Terminals and command-line apps are hot, hot, hot right now. Microsoft just released their new Terminal, and it’s even open-sourced. If this makes you want to create your own CLI (Command Line Interface) app, we’re here to help. For simple CLIs, you can use something like TJ Holowaychuk’s (of express.js fame) commander; in fact, that’s what we started out with when we were first constructing the Adobe I/O CLI.

We needed a fully extensible CLI in the form of plugins, though, so we started work on a whole plugin system (which was not available in commander). That led to us to the solution below. Follow along to see how we created our own CLI app using OCLIF.

Meet OCLIF (Open CLI Framework)

OCLIF (Open CLI Framework) was released in March of 2018, and that’s when we came to an inflection point. Do we continue with all the work we had been doing with commander, or should we adopt OCLIF with its plugin system (and other advantages)?

Even though it meant that we would have to abandon most of our work, it was a no-brainer for our team. Our extensive experience in contributing to open source (with Adobe PhoneGap, Apache Cordova, and Apache OpenWhisk) made the decision easier: adopt OCLIF. NIH (Not Invented Here) syndrome was never in our blood.

Fun fact: Heroku was once our neighbor in San Francisco, just across the street from Adobe on Townsend Street.

OCLIF is open-sourced, MIT-licensed, and was written by Heroku. OCLIF is a CLI framework based on node.js (TypeScript or JavaScript), with a fully extensible plugin system and automatic documentation generation. It favors convention over configuration, and is very easy to develop for. Here’s everything you need to know about its implementation:

OCLIF plugins

Some of the plugins available from OCLIF include:

  1. @oclif/plugin-not-found — Display a friendly “did you mean” message if a command is not found.
  2. @oclif/plugin-plugins — Allow users to add plugins to extend your CLI.
  3. @oclif/plugin-update — Add autoupdate support to the CLI.
  4. @oclif/plugin-warn-if-update-available — Show a warning message if user is running an out of date CLI.
  5. @oclif/plugin-autocomplete — Add bash/zsh autocomplete.
  6. @oclif/plugin-help — Help plugin for oclif.

OCLIF user interface components

A CLI also has other requirements, like UI functionality to better format the output or better notify the user. These node modules below work well with OCLIF:

  1. cli-ux
  • tree — formats data in a tree
  • action — shows a spinner
  • table — format data in columns
  • open — open in browser

2. node-notifier for cross-platform OS notifications

3. listr for complex workflows like checklists

Convention over configuration

What does ‘convention over configuration’ mean with regards to OCLIF? Here is an example folder structure for a command called “giphy,” with its sub-commands. Note that to create the command, all you need is a folder with the same name, and the sub-commands as ‘.js’ JavaScript modules inside the folder.

Examples:

  • $ my-cli giphy:random
  • $ my-cli giphy:search ‘cats’
  • $ my-cli giphy:trending — size=10
  • $ my-cli giphy

What’s with the colon (:) used to separate the command from the sub-commands?

OCLIF’s philosophy is that​ colons help the user know which arguments are the command and which are arguments to that command. However, it is ​harder to get adoption from hardened CLI users that are used to space-separated commands and sub-commands.

However, we solved it in aio-cli with our custom changes to support both space-separated and colon-separated commands.

An example command

const { Command, flags } = require(‘@oclif/command’)
 
class RandomCommand extends Command {
 async run () {
 const { flags, args } = this.parse(RandomCommand)
 this.log(`args: ${JSON.stringify(args)}`)
 this.log(`flags: ${JSON.stringify(flags)}`)
 // TODO: call the Giphy API and get the first random gif
 }
}
 
RandomCommand.description = ‘Grabs a random gif from giphy’
 
RandomCommand.args = [
 { 
 name: ‘tag’, 
 description: ‘filters results by the specified tag’,
 required: false
 }
]
 
RandomCommand.flags = {
 rating: flags.string({ 
 char: ‘r’, 
 description: ‘filters results by specified rating’, 
 default: ‘g’,
 options: [ ‘y’, ‘g’, ‘pg’, ‘pg-13’, ‘r’ ]
 })
}
 
module.exports = RandomCommand

You can play with this example command at: https://github.com/shazron/giphy-cli

Distribution

So how do you distribute your app once you’ve finished it? Do users need to install node.js beforehand on their machines? No, you will have the option to create operating system-specific binaries or containers for your CLI app:

  1. npm registry
  2. Windows Installer
  3. macOS Installer
  4. Ubuntu/Debian packages
  5. Snap packages (snapcraft.io)

The Adobe I/O CLI

The Adobe I/O CLI currently has four plugins:

  1. @adobe/aio-cli-plugin-config
  2. @adobe/aio-cli-plugin-jwt-auth
  3. @adobe/aio-cli-plugin-console
  4. @adobe/aio-cli-plugin-runtime

The adobe/aio-cli-plugin-console plugin helps list and select Adobe I/O Runtime integrations.

The aio-cli-plugin-runtime plugin is a direct replacement for the ‘wsk’ and ‘wskdeploy’ CLI for Apache OpenWhisk. You can use this with Adobe I/O Runtime as well.

To install the CLI, run:

  • npm install -g @adobe/aio-cli

After the CLI is installed, to install the runtime plugin, run:

  • aio plugins:install @adobe/aio-cli-plugin-runtime

To see how to use the commands, run:

  • aio — help
  • aio [command] — help
  • aio runtime — help

More resources for you

I hope this shows you how easy it is to create your own extensible CLI, or how to create plugins for any existing OCLIF cli. Please see the links below, they provide everything you need to get started.

  1. https://github.com/topics/adobe-io-cli
  2. https://github.com/AdobeDocs/adobeio-runtime/blob/stage/reference/cli_use.md
  3. https://oclif.io
  4. https://github.com/shazron/giphy-cli

Follow the Adobe Tech Blog for more developer stories and resources, and check out Adobe Developers on Twitter for the latest news and developer products.

Adobe Tech Blog

News, updates, and thoughts related to Adobe, developers, and technology.

Shazron Abdullah

Written by

Base class: human. Day job: Adobe I/O. Night job: Incredible Coding Man. Now based in Singapore, previously San Francisco Bay Area, and Vancouver, BC.

Adobe Tech Blog

News, updates, and thoughts related to Adobe, developers, and technology.