Developing a new plug-in
November 22, 2023 ยท View on GitHub
Before you begin this tutorial, make sure that you completed the Extending an existing plug-in tutorial.
Overview
This tutorial demonstrates creating a brand new Zowe CLI plug-in that uses Zowe CLI Node.js programmatic APIs.
At the end of this tutorial, you will have created a data set diff utility plug-in for Zowe CLI, from which you can pipe your plugin's output to another utility for a side-by-side diff of data set member contents.

Cloning the zowe-cli-sample-plugin source
Here you'll clone the sample repo, delete the irrelevant source, and make a brand new plug-in. Perform the following:
cdinto yourzowe-tutorialfoldergit clone https://github.com/zowe/zowe-cli-sample-plugin files-utilcd files-util- Delete the
.git(hidden) folder - Delete all content within the
src/api,src/cli, anddocsfolders - Delete all content within the
__tests__/__system__/api,__tests__/__system__/cli,__tests__/api, and__tests__/clifolders git initgit add .git commit -m "initial"
Changing package.json
Use a unique npm name for your plugin. Change package.json name field as follows:
"name": "@zowe/files-util",
- Issue the command
npm install
Adjusting Imperative CLI Framework configuration
Change pluginDef.ts to contain the following:
import { IImperativeConfig } from "@zowe/imperative";
const config: IImperativeConfig = {
commandModuleGlobs: ["**/cli/*/*.definition!(.d).*s"],
rootCommandDescription: "Files utilty plugin for Zowe CLI",
envVariablePrefix: "FILES_UTIL_PLUGIN",
defaultHome: "~/.files_util_plugin",
productDisplayName: "Files Util Plugin",
name: "files-util"
};
export = config;
Here we adjusted the description and other fields in the imperative JSON configuration to be relevant to this plug-in.
Adding third-party packages
npm install --save diffnpm install -D @types/diff
We'll use these packages to create a programmatic API.
Creating a Node.js programmatic API
In files-util/src/api create a file DataSetDiff.ts. The content of DataSetDiff.ts should be the following:
import { AbstractSession } from "@zowe/imperative";
import { Download, IDownloadOptions, IZosFilesResponse } from "@zowe/cli";
import * as diff from "diff";
import { readFileSync } from "fs";
export class DataSetDiff {
public static async diff(session: AbstractSession, oldDataSet: string, newDataSet: string) {
let error;
let response: IZosFilesResponse;
const options: IDownloadOptions = {
extension: "dat",
};
try {
response = await Download.dataSet(session, oldDataSet, options);
} catch (err) {
error = "oldDataSet: " + err;
throw error;
}
try {
response = await Download.dataSet(session, newDataSet, options);
} catch (err) {
error = "newDataSet: " + err;
throw error;
}
const regex = /\.|\(/gi; // Replace . and ( with /
const regex2 = /\)/gi; // Replace ) with .
// convert the old data set name to use as a path/file
let file = oldDataSet.replace(regex, "/");
file = file.replace(regex2, ".") + "dat";
// Load the downloaded contents of 'oldDataSet'
const oldContent = readFileSync(`${file}`).toString();
// convert the new data set name to use as a path/file
file = newDataSet.replace(regex, "/");
file = file.replace(regex2, ".") + "dat";
// Load the downloaded contents of 'oldDataSet'
const newContent = readFileSync(`${file}`).toString();
return diff.createTwoFilesPatch(oldDataSet, newDataSet, oldContent, newContent, "Old", "New");
}
}
Exporting your API
In files-util/src change index.ts to contain the following:
export * from "./api/DataSetDiff";
Checkpoint
At this point, you should be able to rebuild the plug-in without errors via npm run build. You have included third party dependencies, created a programmatic API, and customized this new plug-in project. Next, you'll define the command to invoke your programmatic API.
Defining commands
In files-util/src/cli create a folder named diff. Within the diff folder, create a file Diff.definition.ts. Its content should be as follows:
import { ICommandDefinition } from "@zowe/imperative";
import { DataSetsDefinition } from "./data-sets/DataSets.definition";
const IssueDefinition: ICommandDefinition = {
name: "diff",
summary: "Diff two data sets content",
description: "Uses open source diff packages to diff two data sets content",
type: "group",
children: [DataSetsDefinition]
};
export = IssueDefinition;
Also within the diff folder create a folder named data-sets. Within the data-sets folder create DataSets.definition.ts and DataSets.handler.ts.
DataSets.definition.ts should contain:
import { ICommandDefinition } from "@zowe/imperative";
export const DataSetsDefinition: ICommandDefinition = {
name: "data-sets",
aliases: ["ds"],
summary: "data sets to diff",
description: "diff the first data set with the second",
type: "command",
handler: __dirname + "/DataSets.handler",
positionals: [
{
name: "oldDataSet",
description: "The old data set",
type: "string"
},
{
name: "newDataSet",
description: "The new data set",
type: "string"
}
],
profile: {
required: ["zosmf"]
}
};
DataSets.handler.ts should contain the following:
import { ICommandHandler, IHandlerParameters, TextUtils, Session } from "@zowe/imperative";
import { DataSetDiff } from "../../../api/DataSetDiff";
export default class DataSetsDiffHandler implements ICommandHandler {
public async process(params: IHandlerParameters): Promise<void> {
const profile = params.profiles.get("zosmf");
const session = new Session({
type: "basic",
hostname: profile.host,
port: profile.port,
user: profile.user,
password: profile.pass,
base64EncodedAuth: profile.auth,
rejectUnauthorized: profile.rejectUnauthorized,
});
const resp = await DataSetDiff.diff(session, params.arguments.oldDataSet, params.arguments.newDataSet);
params.response.console.log(resp);
}
}
Trying your command
Be sure to build your plugin via npm run build.
Install your plug-in into Zowe CLI via 'zowe plugins install .'
Then issue the command zowe files-util diff data-sets "your-data-set(oldmem)" "your-data-set(newmem)"
The raw diff output is displayed as a command response:

Bringing together new tools!
The advantage of Zowe CLI and of the CLI approach in mainframe development is that it allows for combining different developer tools for new and interesting uses.
diff2html is a free tool to generate HTML side-by-side diffs to help see actual differences in diff output.
Install the diff2html CLI via npm install -g diff2html-cli. Then, pipe your Zowe CL plugin's output into diff2html to generate diff HTML and launch a web browser that contains the content in the screen shot at the top of this file.
zowe files-util diff data-sets "kelda16.work.jcl(iefbr14)" "kelda16.work.jcl(iefbr15)" | diff2html -i stdin
Next steps
Try the Implementing profiles in a plug-in tutorial to learn about using profiles with your plug-in.