Developing a new plug-in
Developing a new plug-in
Before you begin this tutorial, complete the Extending an existing plug-in tutorial.
Overview​
This tutorial demonstrates how to create 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 a third-party utility for a side-by-side diff of data set member contents.
Completed source for this tutorial can be found on the develop-a-plugin
branch of the zowe-cli-sample-plugin repository.
Cloning the sample plug-in source​
Clone the sample repo, delete the irrelevant source, and create a brand new plug-in. Follow these steps:
cd
into yourzowe-tutorial
foldergit clone https://github.com/zowe/zowe-cli-sample-plugin files-util
cd files-util
- Delete the
.git
(hidden) folder. - Delete all content within the
src/api
,src/cli
, anddocs
folders. - Delete all content within the
__tests__/__system__/api
,__tests__/__system__/cli
,__tests__/api
, and__tests__/cli
folders git init
git 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
against the local repository.
Adjusting Imperative CLI Framework configuration​
Change imperative.ts
to contain the following:
import { IImperativeConfig } from "@zowe/imperative";
const config: IImperativeConfig = {
commandModuleGlobs: ["**/cli/*/*.definition!(.d).*s"],
rootCommandDescription: "Files utility 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​
We'll use the following packages to create a programmatic API:
npm install --save diff
npm install -D @types/diff
Creating a Node.js programmatic API​
In files-util/src/api
, create a file named 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 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 plug-in via npm run build
.
Install your plug-in into Zowe CLI via zowe plugins install
.
Issue the following command. Replace the data set names with valid mainframe data set names on your system:
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 "IBMUSER.work.jcl(iefbr14)" "IBMUSER.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.