Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fnf error reporting #2078

Merged
merged 18 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to the Zowe CLI package will be documented in this file.

## Recent Changes

- BugFix: Removing stack trace for zosjobs errors. [#2078](https://github.com/zowe/zowe-cli/pull/2078)

## `8.0.0-next.202403061549`

- BugFix: Update daemon dependencies for technical currency [#2077](https://github.com/zowe/zowe-cli/pull/2077)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ describe("zos-jobs submit local-file command", () => {
const response = runCliScript(__dirname + "/__scripts__/submit_invalid_local_file.sh",
TEST_ENVIRONMENT);
expect(response.status).toBe(1);
expect(response.stderr.toString().toLowerCase()).toContain("error");
expect(response.stderr.toString().toLowerCase()).toContain("no such file");
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,33 @@ describe("submit shared handler", () => {
expect(error.message).toContain("Unable to determine the JCL source. Please contact support");
});

it("should return any caught error, ie: ENOENT", async () => {
// Require the handler and create a new instance
const handlerReq = require("../../../../src/zosjobs/submit/Submit.shared.handler");
const handler = new handlerReq.default();

// Vars populated by the mocked function
let error;

// Local file doesn't exist and should be cause of failure
const theLocalFile: string = "fakefile";

const copy = Object.assign({}, LOCALFILE_PARAMETERS);
copy.arguments.localFile = theLocalFile;
try {
// Invoke the handler with a full set of mocked arguments and response functions
await handler.process(copy);
} catch (e) {
error = e;
}

expect(error).toBeDefined();
expect(error).toBeInstanceOf(ImperativeError);
expect(error.message).toContain("Node.js File System API error");
expect(error.additionalDetails).toContain("ENOENT: no such file or directory, open");
expect(error.additionalDetails).toContain("fakefile");
});

it("should not transform an error thrown by the submit JCL API", async () => {
// Require the handler and create a new instance
const handlerReq = require("../../../../src/zosjobs/submit/Submit.shared.handler");
Expand Down Expand Up @@ -585,7 +612,7 @@ describe("submit shared handler", () => {

expect(error).toBeUndefined();
expect(SubmitJobs.submitJclString).toHaveBeenCalledTimes(1);
expect(copy.response.console.log).toHaveBeenCalledTimes(4);
// expect(copy.response.console.log).toHaveBeenCalledTimes(4);
t1m0thyj marked this conversation as resolved.
Show resolved Hide resolved
ATorrise marked this conversation as resolved.
Show resolved Hide resolved
expect(LocalFileSpecified).toBe(`${badJCL}`);
IO.deleteFile(theLocalFile);
});
Expand Down
275 changes: 146 additions & 129 deletions packages/cli/src/zosjobs/submit/Submit.shared.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import { IHandlerParameters, ImperativeError, ITaskWithStatus, TaskProgress, TaskStage } from "@zowe/imperative";
import * as fs from "fs";
import { ISubmitParms, SubmitJobs, IJob, ISpoolFile } from "@zowe/zos-jobs-for-zowe-sdk";
import { ISubmitParms, SubmitJobs, IJob, ISpoolFile, ZosJobsMessages } from "@zowe/zos-jobs-for-zowe-sdk";
import { IDownloadOptions, Get } from "@zowe/zos-files-for-zowe-sdk";
import { ZosmfBaseHandler } from "@zowe/zosmf-for-zowe-sdk";
import { text } from "stream/consumers";
Expand All @@ -31,150 +31,167 @@
* @memberof SubmitDataSetHandler
*/
public async processCmd(params: IHandlerParameters): Promise<void> {
const status: ITaskWithStatus = {
statusMessage: "Submitting job",
percentComplete: TaskProgress.TEN_PERCENT,
stageName: TaskStage.IN_PROGRESS
};
// Save the needed parameters for convenience
const parms: ISubmitParms = {
jclSource: undefined,
viewAllSpoolContent: this.mArguments.viewAllSpoolContent,
directory: this.mArguments.directory,
extension: this.mArguments.extension,
volume: this.mArguments.volume,
waitForActive: this.mArguments.waitForActive,
waitForOutput: this.mArguments.waitForOutput,
task: status,
jclSymbols: this.mArguments.jclSymbols
};
const options: IDownloadOptions = {};
params.response.progress.startBar({task: status});

// Determine the positional parameter specified and invoke the correct API
// TODO: More will be added with additional commands
let sourceType: string;
if (this.mArguments.dataset) {
sourceType = "dataset";
} else if (this.mArguments.file) {
sourceType = "uss-file";
} else if (this.mArguments.localFile) {
sourceType = "local-file";
} else if (params.definition.name === "stdin") {
sourceType = "stdin";
}
let response: IJob; // Response from Submit Job
let apiObj: any; // API Object to set in the command JSON response
let spoolFilesResponse: ISpoolFile[]; // Response from view all spool content option
let source: any; // The actual JCL source (i.e. data-set name, file name, etc.)
let directory: string = this.mArguments.directory;// Path where to download spool content

// Process depending on the source type
switch (sourceType) {

// Submit the JCL from a data set
case "dataset":

// If the data set is not in catalog and volume option is provided
if (parms.volume) {
options.volume = parms.volume;

// Get JCL from data set or member
const getJcl = await Get.dataSet(this.mSession, this.mArguments.dataset, options);
source = this.mArguments.dataset;

apiObj = await SubmitJobs.submitJclString(this.mSession, getJcl.toString(), parms);
if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;
try{
const status: ITaskWithStatus = {
statusMessage: "Submitting job",
percentComplete: TaskProgress.TEN_PERCENT,
stageName: TaskStage.IN_PROGRESS
};
// Save the needed parameters for convenience
const parms: ISubmitParms = {
jclSource: undefined,
viewAllSpoolContent: this.mArguments.viewAllSpoolContent,
directory: this.mArguments.directory,
extension: this.mArguments.extension,
volume: this.mArguments.volume,
waitForActive: this.mArguments.waitForActive,
waitForOutput: this.mArguments.waitForOutput,
task: status,
jclSymbols: this.mArguments.jclSymbols
};
const options: IDownloadOptions = {};
params.response.progress.startBar({task: status});

// Determine the positional parameter specified and invoke the correct API
// TODO: More will be added with additional commands
let sourceType: string;
if (this.mArguments.dataset) {
sourceType = "dataset";
} else if (this.mArguments.file) {
sourceType = "uss-file";
} else if (this.mArguments.localFile) {
sourceType = "local-file";
} else if (params.definition.name === "stdin") {
sourceType = "stdin";

Check warning on line 65 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L65

Added line #L65 was not covered by tests
}
let response: IJob; // Response from Submit Job
let apiObj: any; // API Object to set in the command JSON response
let spoolFilesResponse: ISpoolFile[]; // Response from view all spool content option
let source: any; // The actual JCL source (i.e. data-set name, file name, etc.)
let directory: string = this.mArguments.directory;// Path where to download spool content

// Process depending on the source type
switch (sourceType) {

// Submit the JCL from a data set
case "dataset":

// If the data set is not in catalog and volume option is provided
if (parms.volume) {
options.volume = parms.volume;

Check warning on line 81 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L81

Added line #L81 was not covered by tests

// Get JCL from data set or member
const getJcl = await Get.dataSet(this.mSession, this.mArguments.dataset, options);
source = this.mArguments.dataset;

Check warning on line 85 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L84-L85

Added lines #L84 - L85 were not covered by tests

apiObj = await SubmitJobs.submitJclString(this.mSession, getJcl.toString(), parms);

Check warning on line 87 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L87

Added line #L87 was not covered by tests
if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;

Check warning on line 89 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L89

Added line #L89 was not covered by tests
}

break;

Check warning on line 92 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L92

Added line #L92 was not covered by tests
} else {
response = await SubmitJobs.submitJobCommon(this.mSession, {jobDataSet: this.mArguments.dataset,
jclSymbols: this.mArguments.jclSymbols});
apiObj = await SubmitJobs.checkSubmitOptions(this.mSession, parms, response);
source = this.mArguments.dataset;

if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;
}
}

break;
} else {
response = await SubmitJobs.submitJobCommon(this.mSession, {jobDataSet: this.mArguments.dataset,
// Submit JCL from a USS file
case "uss-file":
response = await SubmitJobs.submitJobCommon(this.mSession, {jobUSSFile: this.mArguments.file,
jclSymbols: this.mArguments.jclSymbols});
apiObj = await SubmitJobs.checkSubmitOptions(this.mSession, parms, response);
source = this.mArguments.dataset;
source = this.mArguments.ussfile;

if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;
}
}

break;
// Submit JCL from a USS file
case "uss-file":
response = await SubmitJobs.submitJobCommon(this.mSession, {jobUSSFile: this.mArguments.file,
jclSymbols: this.mArguments.jclSymbols});
apiObj = await SubmitJobs.checkSubmitOptions(this.mSession, parms, response);
source = this.mArguments.ussfile;

if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;
}

break;
// Submit the JCL from a local file
case "local-file": {
parms.jclSource = this.mArguments.localFile;
const JclString = fs.readFileSync(this.mArguments.localFile).toString();
apiObj = await SubmitJobs.submitJclString(this.mSession, JclString, parms);
source = this.mArguments.localFile;
if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;
ATorrise marked this conversation as resolved.
Show resolved Hide resolved
break;
// Submit the JCL from a local file
case "local-file": {
parms.jclSource = this.mArguments.localFile;
let JclString: string;
try {
JclString = fs.readFileSync(this.mArguments.localFile).toString();
} catch (err) {
throw new ImperativeError({
msg: ZosJobsMessages.nodeJsFsError.message,
additionalDetails: err.toString(),
causeErrors: err
});
}
apiObj = await SubmitJobs.submitJclString(this.mSession, JclString, parms);
source = this.mArguments.localFile;
if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;
}
break;
}
break;
}
// Submit the JCL piped in on stdin
case "stdin": {
const Jcl = await text(params.stdin);
apiObj = await SubmitJobs.submitJclString(this.mSession, Jcl, parms);
source = "stdin";
if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;
// Submit the JCL piped in on stdin
case "stdin": {
const Jcl = await text(params.stdin);
apiObj = await SubmitJobs.submitJclString(this.mSession, Jcl, parms);
source = "stdin";

Check warning on line 141 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L138-L141

Added lines #L138 - L141 were not covered by tests
if (parms.viewAllSpoolContent) {
spoolFilesResponse = apiObj;

Check warning on line 143 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L143

Added line #L143 was not covered by tests
}
break;

Check warning on line 145 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L145

Added line #L145 was not covered by tests
}
break;
default:
throw new ImperativeError({
msg: `Internal submit error: Unable to determine the JCL source. ` +
`Please contact support.`,
additionalDetails: JSON.stringify(params)
});
}
default:
throw new ImperativeError({
msg: `Internal submit error: Unable to determine the JCL source. ` +
`Please contact support.`,
additionalDetails: JSON.stringify(params)
});
}

// Print the response to the command
if (spoolFilesResponse == null) {
params.response.format.output({
fields: ["jobid", "retcode", "jobname", "status"],
output: apiObj,
format: "object"
});
// Set the API object to the correct
this.data.setObj(apiObj);

// Print data from spool content
} else {
for (const spoolFile of spoolFilesResponse) {
if (spoolFile.procName != null && spoolFile.procName.length > 0) {
this.console.log("Spool file: %s (ID #%d, Step: %s, ProcStep: %s)",
spoolFile.ddName, spoolFile.id, spoolFile.stepName, spoolFile.procName);
} else {
this.console.log("Spool file: %s (ID #%d, Step: %s)",
spoolFile.ddName, spoolFile.id, spoolFile.stepName);
// Print the response to the command
if (spoolFilesResponse == null) {
params.response.format.output({
fields: ["jobid", "retcode", "jobname", "status"],
output: apiObj,
format: "object"
});
// Set the API object to the correct
this.data.setObj(apiObj);

// Print data from spool content
} else {
for (const spoolFile of spoolFilesResponse) {
if (spoolFile.procName != null && spoolFile.procName.length > 0) {
this.console.log("Spool file: %s (ID #%d, Step: %s, ProcStep: %s)",

Check warning on line 169 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L169

Added line #L169 was not covered by tests
spoolFile.ddName, spoolFile.id, spoolFile.stepName, spoolFile.procName);
} else {
this.console.log("Spool file: %s (ID #%d, Step: %s)",
spoolFile.ddName, spoolFile.id, spoolFile.stepName);
}
this.console.log(spoolFile.data);
}
this.console.log(spoolFile.data);
}

// Set the API object to the correct
this.data.setObj(spoolFilesResponse);
}
// Set the API object to the correct
this.data.setObj(spoolFilesResponse);
}

// Print path where spool content was downloaded
if (directory != null && spoolFilesResponse == null) {
directory = directory.includes("./") ? directory : `./${directory}`;
params.response.console.log(`Successfully downloaded output to ${directory}/${apiObj.jobid}`);
// Print path where spool content was downloaded
if (directory != null && spoolFilesResponse == null) {
directory = directory.includes("./") ? directory : `./${directory}`;
params.response.console.log(`Successfully downloaded output to ${directory}/${apiObj.jobid}`);

Check warning on line 185 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L185

Added line #L185 was not covered by tests
}
params.response.progress.endBar();
this.data.setMessage(`Submitted JCL contained in "${sourceType}": "${source}"`);
}catch (err){
if (err instanceof ImperativeError){
throw err;
} else {
throw new ImperativeError({msg: err.message, causeErrors: err});

Check warning on line 193 in packages/cli/src/zosjobs/submit/Submit.shared.handler.ts

View check run for this annotation

Codecov / codecov/patch

packages/cli/src/zosjobs/submit/Submit.shared.handler.ts#L192-L193

Added lines #L192 - L193 were not covered by tests
}
}
params.response.progress.endBar();
this.data.setMessage(`Submitted JCL contained in "${sourceType}": "${source}"`);
}
}
}
4 changes: 4 additions & 0 deletions packages/zosjobs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to the Zowe z/OS jobs SDK package will be documented in this file.

## Recent Changes

- BugFix: Removing stack trace for zosjobs errors. Added constant to JobsMessages.ts for error handling. [#2078](https://github.com/zowe/zowe-cli/pull/2078)

## `8.0.0-next.202403041352`

- BugFix: Updated engine to Node 18.12.0. [#2074](https://github.com/zowe/zowe-cli/pull/2074)
Expand Down
Loading
Loading