Developing a new plug-in
Developing a new plug-in
Before you begin this tutorial, complete the Extending an existing plug-in tutorial.
#
OverviewThis 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.
![Side by Side Diff](/assets/images/htmlDiff-9a79fb820a72f50de3b9b56d896e80d5.png)
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 sourceClone 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.jsonUse 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 configurationChange imperative.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 packagesWe'll use the following packages to create a programmatic API:
npm install --save diff
npm install -D @types/diff
#
Creating a Node.js programmatic APIIn 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 APIIn files-util/src
, change index.ts
to contain the following:
export * from "./api/DataSetDiff";
#
CheckpointAt 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 commandsIn 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 commandBe 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:
![Raw Diff Output](/assets/images/diffOutput-f577aa8aefd87853d6a1264107cdc756.png)
#
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 stepsTry the Implementing profiles in a plug-in tutorial to learn about using profiles with your plug-in.